Create & Init Project...

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

View File

@@ -0,0 +1,24 @@
package(default_visibility = ["//visibility:public"])
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/openplatform/ticket-item/api/grpc/v1:all-srcs",
"//app/service/openplatform/ticket-item/cmd:all-srcs",
"//app/service/openplatform/ticket-item/conf:all-srcs",
"//app/service/openplatform/ticket-item/dao:all-srcs",
"//app/service/openplatform/ticket-item/model:all-srcs",
"//app/service/openplatform/ticket-item/server/grpc:all-srcs",
"//app/service/openplatform/ticket-item/server/http:all-srcs",
"//app/service/openplatform/ticket-item/service:all-srcs",
],
tags = ["automanaged"],
)

View File

@@ -0,0 +1,22 @@
##### Version 0.0.1
> 1.初始化服务结构
> 2.项目信息,卡片,交易信息接口
##### Version 0.0.2
> 1.合并proto解决 bazel make update 报错
##### Version 0.0.3
> 1.replace redigo
> 2.添加场馆相关接口
##### Version 0.0.4
> 1. 修改目录结构
> 2. 添加审核编辑投放,初始化项目相关接口
> 3. 新增删除区域接口修复bug
##### Version 0.0.5
> 1. 新增banner审核删除缓存
> 2. 修复banner编辑审核bug
##### Version 0.0.6
> 1. banner新增target_user字段

View File

@@ -0,0 +1,12 @@
# Owner
yangyucheng
linjiaying
liuzhan
# Author
linjiaying
jiayanxiang
luhao
# Reviewer
liuzhan

View File

@@ -0,0 +1,19 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- jiayanxiang
- linjiaying
- liuzhan
- luhao
- yangyucheng
labels:
- openplatform
- service
- service/openplatform/ticket-item
options:
no_parent_owners: true
reviewers:
- jiayanxiang
- linjiaying
- liuzhan
- luhao

View File

@@ -0,0 +1,13 @@
#### ticket-item
`ticket-item`主要是为开放平台票务各个业务提供一个综合的商品grpc接口。
* 聚合了票务多个模块(`项目` `场馆` `嘉宾`)的服务接口
* 提供了grpc及http服务
1. 为项目(`item`)维度数据封装grpc接口
##### 依赖环境
Go 1.10.1或更高版本
##### API文档
TODO example code api

View File

@@ -0,0 +1,69 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
proto_library(
name = "v1_proto",
srcs = [
"area.proto",
"bulletin.proto",
"guest.proto",
"item.proto",
"place.proto",
"screen.proto",
"seat.proto",
"ticket.proto",
"time.proto",
"venue.proto",
],
tags = ["automanaged"],
deps = ["@gogo_special_proto//github.com/gogo/protobuf/gogoproto"],
)
go_proto_library(
name = "v1_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogofast_grpc"],
importpath = "go-common/app/service/openplatform/ticket-item/api/grpc/v1",
proto = ":v1_proto",
tags = ["automanaged"],
deps = ["@com_github_gogo_protobuf//gogoproto:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = ["client.go"],
embed = [":v1_go_proto"],
importpath = "go-common/app/service/openplatform/ticket-item/api/grpc/v1",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/log:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/net/rpc/warden/balancer/wrr:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@org_golang_google_grpc//:go_default_library",
"@org_golang_x_net//context:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,69 @@
syntax = "proto3";
package ticket.service.item.v1;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option (gogoproto.goproto_enum_prefix_all) = false;
option (gogoproto.goproto_getters_all) = false;
option (gogoproto.unmarshaler_all) = true;
option (gogoproto.marshaler_all) = true;
option (gogoproto.sizer_all) = true;
option go_package = "v1";
// The area service definition.
service Area {
rpc AreaInfo (AreaInfoRequest) returns (AreaInfoReply) {}
rpc DeleteArea (DeleteAreaRequest) returns (DeleteAreaReply) {}
}
// The response message containing the area info
message AreaInfo {
int64 id = 1 [(gogoproto.jsontag) = "id", (gogoproto.customname)= "ID"];
string a_id = 2 [(gogoproto.jsontag) = "a_id", (gogoproto.customname)= "AID"];
string name = 3 [(gogoproto.jsontag) = "name"];
int32 seat_num = 4 [(gogoproto.jsontag) = "seat_num"];
int32 width = 5 [(gogoproto.jsontag) = "width"];
int32 height = 6 [(gogoproto.jsontag) = "height"];
int64 place = 7 [(gogoproto.jsontag) = "place"];
int32 col_start = 8 [(gogoproto.jsontag) = "col_start"];
int32 col_type = 9 [(gogoproto.jsontag) = "col_type"];
int32 col_direction = 10 [(gogoproto.jsontag) = "col_direction"];
string row_list = 11 [(gogoproto.jsontag) = "row_list"];
string seat_start = 12 [(gogoproto.jsontag) = "seat_start"];
}
// areaInfo接口请求
message AreaInfoRequest {
// 待修改区域的ID为0表示创建
int64 ID = 1 [(gogoproto.jsontag) = "id", (gogoproto.moretags) = "validate:\"min=0\""];
// 区域自定义编号
string AID = 2 [(gogoproto.jsontag) = "a_id", (gogoproto.moretags) = "validate:\"min=1,max=16\""];
// 区域名
string Name = 3 [(gogoproto.jsontag) = "name", (gogoproto.moretags) = "validate:\"min=1,max=16\""];
// 所属场地ID
int64 Place = 4 [(gogoproto.jsontag) = "place", (gogoproto.moretags) = "validate:\"min=1\""];
// 区域坐标
string Coordinate = 5 [(gogoproto.jsontag) = "coordinate", (gogoproto.moretags) = "validate:\"min=1\""];
}
// areaInfo接口返回
message AreaInfoReply {
// 操作结果
bool Success = 1 [(gogoproto.jsontag) = "success"];
// 操作区域ID
int64 ID = 2 [(gogoproto.jsontag) = "id"];
// 场地坐标
string Coordinate = 3 [(gogoproto.jsontag) = "coordinate"];
}
// deleteArea接口请求
message DeleteAreaRequest {
// 待删除区域的ID
int64 ID = 1 [(gogoproto.jsontag) = "id", (gogoproto.moretags) = "validate:\"min=1\""];
}
// deleteArea接口返回
message DeleteAreaReply {
// 操作结果
bool Success = 1 [(gogoproto.jsontag) = "success"];
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,54 @@
syntax = "proto3";
package ticket.service.item.v1;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option go_package = "v1";
// The bulletin service definition.
service Bulletin {
rpc BulletinInfo (BulletinInfoRequest) returns (BulletinReply) {}
rpc BulletinCheck (BulletinCheckRequest) returns (BulletinReply) {}
rpc BulletinState (BulletinStateRequest) returns (BulletinReply) {}
}
// The response message containing the bulletin info
message BulletinInfo {
int64 id = 1 [(gogoproto.jsontag) = "id", (gogoproto.moretags) = "validate:\"min=1\"", (gogoproto.customname)= "ID"];
string title = 2 [(gogoproto.jsontag) = "title"];
string content = 3 [(gogoproto.jsontag) = "content"];
string detail = 4 [(gogoproto.jsontag) = "detail"];
string ctime = 5 [(gogoproto.jsontag) = "ctime", (gogoproto.moretags) = "validate:\"min=0\""];
string mtime = 6 [(gogoproto.jsontag) = "mtime", (gogoproto.moretags) = "validate:\"min=0\""];
uint64 ver_id = 7 [(gogoproto.jsontag) = "ver_id", (gogoproto.moretags) = "validate:\"min=0\"", (gogoproto.customname)= "VerID"];
}
// The request message containing the bulletin info to update
message BulletinInfoRequest {
uint64 ver_id = 1 [(gogoproto.jsontag) = "ver_id", (gogoproto.customname)= "VerID"];
string title = 2 [(gogoproto.jsontag) = "title", (gogoproto.moretags) = "validate:\"required,max=32\""];
string content = 3 [(gogoproto.jsontag) = "content", (gogoproto.moretags) = "validate:\"max=128\""];
string detail = 4 [(gogoproto.jsontag) = "detail"];
int64 target_item = 5 [(gogoproto.jsontag) = "target_item"];
int64 parent_id = 6 [(gogoproto.jsontag) = "parent_id", (gogoproto.moretags) = "validate:\"required,min=1\"", (gogoproto.customname)= "ParentID"];
}
// The request message containing the required version info to review the bulletin
message BulletinCheckRequest {
uint64 ver_id = 1 [(gogoproto.jsontag) = "ver_id", (gogoproto.moretags) = "validate:\"required,min=1\"", (gogoproto.customname)= "VerID"];
int32 op_type = 2 [(gogoproto.jsontag) = "op_type", (gogoproto.moretags) = "validate:\"min=0,max=1\""];
string comment = 3 [(gogoproto.jsontag) = "comment"];
string reviewer = 4 [(gogoproto.jsontag) = "reviewer", (gogoproto.moretags) = "validate:\"required\""];
}
// The request message containing the required version info to change the bulletin's status
message BulletinStateRequest {
uint64 ver_id = 1 [(gogoproto.jsontag) = "ver_id", (gogoproto.moretags) = "validate:\"required,min=1\"", (gogoproto.customname)= "VerID"];
int32 op_type = 2 [(gogoproto.jsontag) = "op_type", (gogoproto.moretags) = "validate:\"min=0,max=1\""];
int32 source = 3 [(gogoproto.jsontag) = "source", (gogoproto.moretags) = "validate:\"min=1,max=2\""];
}
// The general response message containing the result after updating/inserting the bulletin info
message BulletinReply {
bool success = 1 [(gogoproto.jsontag) = "success"];
}

View File

@@ -0,0 +1,44 @@
package v1
import (
"context"
"go-common/library/log"
"go-common/library/net/rpc/warden"
"go-common/library/net/rpc/warden/balancer/wrr"
"google.golang.org/grpc"
)
// AppID unique app id for service diSCovery
const AppID = "ticket.service.item"
//Client 客户端枚举
type Client struct {
IC ItemClient
GC GuestClient
BC BulletinClient
VC VenueClient
PC PlaceClient
AC AreaClient
SC SeatClient
}
// New 新建客户端实例
func New(c *warden.ClientConfig) (*Client, error) {
client := warden.NewClient(c, grpc.WithBalancerName(wrr.Name))
conn, err := client.Dial(context.Background(), "discovery://default/"+AppID)
if err != nil {
log.Error("client can not connect server: %v", err)
return nil, err
}
return &Client{
IC: NewItemClient(conn),
GC: NewGuestClient(conn),
BC: NewBulletinClient(conn),
VC: NewVenueClient(conn),
PC: NewPlaceClient(conn),
AC: NewAreaClient(conn),
SC: NewSeatClient(conn),
}, nil
}

View File

@@ -0,0 +1,811 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: app/service/openplatform/ticket-item/api/grpc/v1/guest.proto
package v1
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import _ "github.com/gogo/protobuf/gogoproto"
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// The request message containing the guest info to update/insert
type GuestInfoRequest struct {
ID uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id" validate:"min=0"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name" validate:"max=32"`
GuestImg string `protobuf:"bytes,3,opt,name=guest_img,json=guestImg,proto3" json:"guest_img" validate:"min=0"`
Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description" validate:"max=128"`
GuestID int64 `protobuf:"varint,5,opt,name=guest_id,json=guestId,proto3" json:"guest_id"`
}
func (m *GuestInfoRequest) Reset() { *m = GuestInfoRequest{} }
func (m *GuestInfoRequest) String() string { return proto.CompactTextString(m) }
func (*GuestInfoRequest) ProtoMessage() {}
func (*GuestInfoRequest) Descriptor() ([]byte, []int) { return fileDescriptorGuest, []int{0} }
// The request message containing the required info to change guest's status
type GuestStatusRequest struct {
ID int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id" validate:"required,min=1"`
Status int32 `protobuf:"varint,2,opt,name=status,proto3" json:"status" validate:"max=1"`
}
func (m *GuestStatusRequest) Reset() { *m = GuestStatusRequest{} }
func (m *GuestStatusRequest) String() string { return proto.CompactTextString(m) }
func (*GuestStatusRequest) ProtoMessage() {}
func (*GuestStatusRequest) Descriptor() ([]byte, []int) { return fileDescriptorGuest, []int{1} }
// The general response message contaning the result after updating/inserting the guest info
type GuestInfoReply struct {
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success"`
}
func (m *GuestInfoReply) Reset() { *m = GuestInfoReply{} }
func (m *GuestInfoReply) String() string { return proto.CompactTextString(m) }
func (*GuestInfoReply) ProtoMessage() {}
func (*GuestInfoReply) Descriptor() ([]byte, []int) { return fileDescriptorGuest, []int{2} }
func init() {
proto.RegisterType((*GuestInfoRequest)(nil), "ticket.service.item.v1.GuestInfoRequest")
proto.RegisterType((*GuestStatusRequest)(nil), "ticket.service.item.v1.GuestStatusRequest")
proto.RegisterType((*GuestInfoReply)(nil), "ticket.service.item.v1.GuestInfoReply")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// Client API for Guest service
type GuestClient interface {
GuestInfo(ctx context.Context, in *GuestInfoRequest, opts ...grpc.CallOption) (*GuestInfoReply, error)
GuestStatus(ctx context.Context, in *GuestStatusRequest, opts ...grpc.CallOption) (*GuestInfoReply, error)
}
type guestClient struct {
cc *grpc.ClientConn
}
func NewGuestClient(cc *grpc.ClientConn) GuestClient {
return &guestClient{cc}
}
func (c *guestClient) GuestInfo(ctx context.Context, in *GuestInfoRequest, opts ...grpc.CallOption) (*GuestInfoReply, error) {
out := new(GuestInfoReply)
err := grpc.Invoke(ctx, "/ticket.service.item.v1.Guest/GuestInfo", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *guestClient) GuestStatus(ctx context.Context, in *GuestStatusRequest, opts ...grpc.CallOption) (*GuestInfoReply, error) {
out := new(GuestInfoReply)
err := grpc.Invoke(ctx, "/ticket.service.item.v1.Guest/GuestStatus", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Guest service
type GuestServer interface {
GuestInfo(context.Context, *GuestInfoRequest) (*GuestInfoReply, error)
GuestStatus(context.Context, *GuestStatusRequest) (*GuestInfoReply, error)
}
func RegisterGuestServer(s *grpc.Server, srv GuestServer) {
s.RegisterService(&_Guest_serviceDesc, srv)
}
func _Guest_GuestInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GuestInfoRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(GuestServer).GuestInfo(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/ticket.service.item.v1.Guest/GuestInfo",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(GuestServer).GuestInfo(ctx, req.(*GuestInfoRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Guest_GuestStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GuestStatusRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(GuestServer).GuestStatus(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/ticket.service.item.v1.Guest/GuestStatus",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(GuestServer).GuestStatus(ctx, req.(*GuestStatusRequest))
}
return interceptor(ctx, in, info, handler)
}
var _Guest_serviceDesc = grpc.ServiceDesc{
ServiceName: "ticket.service.item.v1.Guest",
HandlerType: (*GuestServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GuestInfo",
Handler: _Guest_GuestInfo_Handler,
},
{
MethodName: "GuestStatus",
Handler: _Guest_GuestStatus_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "app/service/openplatform/ticket-item/api/grpc/v1/guest.proto",
}
func (m *GuestInfoRequest) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *GuestInfoRequest) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.ID != 0 {
dAtA[i] = 0x8
i++
i = encodeVarintGuest(dAtA, i, uint64(m.ID))
}
if len(m.Name) > 0 {
dAtA[i] = 0x12
i++
i = encodeVarintGuest(dAtA, i, uint64(len(m.Name)))
i += copy(dAtA[i:], m.Name)
}
if len(m.GuestImg) > 0 {
dAtA[i] = 0x1a
i++
i = encodeVarintGuest(dAtA, i, uint64(len(m.GuestImg)))
i += copy(dAtA[i:], m.GuestImg)
}
if len(m.Description) > 0 {
dAtA[i] = 0x22
i++
i = encodeVarintGuest(dAtA, i, uint64(len(m.Description)))
i += copy(dAtA[i:], m.Description)
}
if m.GuestID != 0 {
dAtA[i] = 0x28
i++
i = encodeVarintGuest(dAtA, i, uint64(m.GuestID))
}
return i, nil
}
func (m *GuestStatusRequest) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *GuestStatusRequest) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.ID != 0 {
dAtA[i] = 0x8
i++
i = encodeVarintGuest(dAtA, i, uint64(m.ID))
}
if m.Status != 0 {
dAtA[i] = 0x10
i++
i = encodeVarintGuest(dAtA, i, uint64(m.Status))
}
return i, nil
}
func (m *GuestInfoReply) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *GuestInfoReply) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.Success {
dAtA[i] = 0x8
i++
if m.Success {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i++
}
return i, nil
}
func encodeVarintGuest(dAtA []byte, offset int, v uint64) int {
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return offset + 1
}
func (m *GuestInfoRequest) Size() (n int) {
var l int
_ = l
if m.ID != 0 {
n += 1 + sovGuest(uint64(m.ID))
}
l = len(m.Name)
if l > 0 {
n += 1 + l + sovGuest(uint64(l))
}
l = len(m.GuestImg)
if l > 0 {
n += 1 + l + sovGuest(uint64(l))
}
l = len(m.Description)
if l > 0 {
n += 1 + l + sovGuest(uint64(l))
}
if m.GuestID != 0 {
n += 1 + sovGuest(uint64(m.GuestID))
}
return n
}
func (m *GuestStatusRequest) Size() (n int) {
var l int
_ = l
if m.ID != 0 {
n += 1 + sovGuest(uint64(m.ID))
}
if m.Status != 0 {
n += 1 + sovGuest(uint64(m.Status))
}
return n
}
func (m *GuestInfoReply) Size() (n int) {
var l int
_ = l
if m.Success {
n += 2
}
return n
}
func sovGuest(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
func sozGuest(x uint64) (n int) {
return sovGuest(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *GuestInfoRequest) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGuest
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: GuestInfoRequest: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: GuestInfoRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType)
}
m.ID = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGuest
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.ID |= (uint32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGuest
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthGuest
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Name = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field GuestImg", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGuest
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthGuest
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.GuestImg = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGuest
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthGuest
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Description = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 5:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field GuestID", wireType)
}
m.GuestID = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGuest
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.GuestID |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipGuest(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthGuest
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *GuestStatusRequest) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGuest
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: GuestStatusRequest: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: GuestStatusRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType)
}
m.ID = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGuest
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.ID |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType)
}
m.Status = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGuest
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Status |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipGuest(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthGuest
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *GuestInfoReply) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGuest
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: GuestInfoReply: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: GuestInfoReply: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Success", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGuest
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.Success = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := skipGuest(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthGuest
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipGuest(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGuest
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGuest
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
return iNdEx, nil
case 1:
iNdEx += 8
return iNdEx, nil
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGuest
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
iNdEx += length
if length < 0 {
return 0, ErrInvalidLengthGuest
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGuest
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
innerWire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
innerWireType := int(innerWire & 0x7)
if innerWireType == 4 {
break
}
next, err := skipGuest(dAtA[start:])
if err != nil {
return 0, err
}
iNdEx = start + next
}
return iNdEx, nil
case 4:
return iNdEx, nil
case 5:
iNdEx += 4
return iNdEx, nil
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
}
panic("unreachable")
}
var (
ErrInvalidLengthGuest = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowGuest = fmt.Errorf("proto: integer overflow")
)
func init() {
proto.RegisterFile("app/service/openplatform/ticket-item/api/grpc/v1/guest.proto", fileDescriptorGuest)
}
var fileDescriptorGuest = []byte{
// 491 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0xcd, 0x6e, 0xd3, 0x40,
0x10, 0x8e, 0x9d, 0xa6, 0x49, 0x36, 0x02, 0x95, 0x3d, 0x80, 0xa9, 0x84, 0x37, 0x58, 0x2a, 0x0a,
0x88, 0x7a, 0xeb, 0x54, 0xe2, 0x4f, 0x94, 0x83, 0x85, 0x54, 0xe5, 0x6a, 0x6e, 0x5c, 0x2a, 0xc7,
0xde, 0x98, 0x15, 0x71, 0x76, 0x6b, 0xaf, 0x2d, 0xfa, 0x04, 0xbc, 0x10, 0x0f, 0xd1, 0x0b, 0x52,
0x9f, 0x60, 0x45, 0x7d, 0xf4, 0x31, 0x4f, 0x80, 0xbc, 0x4e, 0x52, 0x37, 0xaa, 0xaa, 0xde, 0x76,
0x66, 0xbe, 0xf9, 0x66, 0xbe, 0x6f, 0x07, 0x7c, 0xf6, 0x39, 0xc7, 0x29, 0x49, 0x72, 0x1a, 0x10,
0xcc, 0x38, 0x59, 0xf0, 0xb9, 0x2f, 0x66, 0x2c, 0x89, 0xb1, 0xa0, 0xc1, 0x4f, 0x22, 0x0e, 0xa9,
0x20, 0x31, 0xf6, 0x39, 0xc5, 0x51, 0xc2, 0x03, 0x9c, 0x3b, 0x38, 0xca, 0x48, 0x2a, 0x6c, 0x9e,
0x30, 0xc1, 0xe0, 0xd3, 0x1a, 0x64, 0xaf, 0x08, 0xec, 0x0a, 0x6c, 0xe7, 0xce, 0xfe, 0x61, 0x44,
0xc5, 0x8f, 0x6c, 0x6a, 0x07, 0x2c, 0xc6, 0x11, 0x8b, 0x18, 0x56, 0xf0, 0x69, 0x36, 0x53, 0x91,
0x0a, 0xd4, 0xab, 0xa6, 0xb1, 0xfe, 0xe8, 0x60, 0xef, 0xb4, 0xa2, 0x9d, 0x2c, 0x66, 0xcc, 0x23,
0xe7, 0xd5, 0x13, 0x1e, 0x01, 0x9d, 0x86, 0x86, 0x36, 0xd4, 0x46, 0x8f, 0xdc, 0x61, 0x21, 0x91,
0x3e, 0xf9, 0x5a, 0x4a, 0xa4, 0xd3, 0x70, 0x29, 0xd1, 0x5e, 0xee, 0xcf, 0x69, 0xe8, 0x0b, 0xf2,
0xc9, 0x8a, 0xe9, 0xe2, 0xe4, 0xc8, 0xf2, 0x74, 0x1a, 0x42, 0x07, 0xec, 0x2c, 0xfc, 0x98, 0x18,
0xfa, 0x50, 0x1b, 0xf5, 0xdd, 0x17, 0xa5, 0x44, 0x2a, 0x5e, 0x4a, 0xf4, 0xa4, 0x81, 0xf7, 0x7f,
0x9d, 0x1c, 0x8f, 0x2d, 0x4f, 0x95, 0xe0, 0x17, 0xd0, 0x57, 0x7a, 0xce, 0x68, 0x1c, 0x19, 0x6d,
0xd5, 0xf7, 0xb2, 0x94, 0xe8, 0x26, 0x79, 0xe7, 0xb0, 0x9e, 0x2a, 0x4f, 0xe2, 0x08, 0x9e, 0x82,
0x41, 0x48, 0xd2, 0x20, 0xa1, 0x5c, 0x50, 0xb6, 0x30, 0x76, 0x14, 0xc3, 0x41, 0x29, 0x51, 0x33,
0xbd, 0x94, 0x08, 0xde, 0x5e, 0xc0, 0x19, 0x7f, 0xb0, 0xbc, 0x26, 0x04, 0x8e, 0x41, 0x6f, 0x35,
0x33, 0x34, 0x3a, 0x43, 0x6d, 0xd4, 0x76, 0x9f, 0x15, 0x12, 0x75, 0x6b, 0x57, 0x2a, 0xe1, 0x9b,
0xb2, 0xd7, 0xad, 0xa7, 0x87, 0xd6, 0x6f, 0x0d, 0x40, 0x05, 0xf8, 0x26, 0x7c, 0x91, 0xa5, 0x6b,
0xe3, 0x3e, 0x6e, 0x8c, 0x6b, 0xbb, 0xaf, 0xb7, 0x8c, 0x7b, 0x7e, 0xb3, 0x47, 0x42, 0xce, 0x33,
0x9a, 0x90, 0xf0, 0x6d, 0x25, 0xca, 0xa9, 0x1d, 0x7c, 0x07, 0x76, 0x53, 0xc5, 0xa5, 0x3c, 0xec,
0xb8, 0x66, 0x29, 0xd1, 0x2a, 0xb3, 0x65, 0x44, 0x25, 0xc2, 0xf2, 0x56, 0x35, 0xeb, 0x3d, 0x78,
0xdc, 0xf8, 0x3f, 0x3e, 0xbf, 0x80, 0x07, 0xa0, 0x9b, 0x66, 0x41, 0x40, 0xd2, 0x54, 0x6d, 0xd2,
0x73, 0x07, 0xa5, 0x44, 0xeb, 0x94, 0xb7, 0x7e, 0x8c, 0xff, 0x6a, 0xa0, 0xa3, 0x3a, 0xe1, 0x19,
0xe8, 0x6f, 0x28, 0xe0, 0xc8, 0xbe, 0xfb, 0xb0, 0xec, 0xed, 0x2b, 0xd9, 0x7f, 0xf5, 0x00, 0x24,
0x9f, 0x5f, 0x58, 0x2d, 0x18, 0x80, 0x41, 0xc3, 0x2c, 0xf8, 0xe6, 0xde, 0xc6, 0x5b, 0x8e, 0x3e,
0x7c, 0x88, 0x6b, 0x5c, 0x5e, 0x9b, 0xad, 0xab, 0x6b, 0xb3, 0x75, 0x59, 0x98, 0xda, 0x55, 0x61,
0x6a, 0xff, 0x0a, 0x53, 0xfb, 0xae, 0xe7, 0xce, 0x74, 0x57, 0x9d, 0xfa, 0xf1, 0xff, 0x00, 0x00,
0x00, 0xff, 0xff, 0x44, 0x78, 0x81, 0x56, 0x71, 0x03, 0x00, 0x00,
}

View File

@@ -0,0 +1,37 @@
syntax = "proto3";
package ticket.service.item.v1;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option (gogoproto.goproto_enum_prefix_all) = false;
option (gogoproto.goproto_getters_all) = false;
option (gogoproto.unmarshaler_all) = true;
option (gogoproto.marshaler_all) = true;
option (gogoproto.sizer_all) = true;
option go_package = "v1";
// The guest service definition.
service Guest {
rpc GuestInfo (GuestInfoRequest) returns (GuestInfoReply) {}
rpc GuestStatus (GuestStatusRequest) returns (GuestInfoReply) {}
}
// The request message containing the guest info to update/insert
message GuestInfoRequest {
uint32 id = 1 [(gogoproto.jsontag) = "id", (gogoproto.moretags) = "validate:\"min=0\"", (gogoproto.customname)= "ID"];
string name = 2 [(gogoproto.jsontag) = "name", (gogoproto.moretags) = "validate:\"max=32\""];
string guest_img = 3 [(gogoproto.jsontag) = "guest_img", (gogoproto.moretags) = "validate:\"min=0\""];
string description = 4 [(gogoproto.jsontag) = "description", (gogoproto.moretags) = "validate:\"max=128\""];
int64 guest_id = 5 [(gogoproto.jsontag) = "guest_id", (gogoproto.customname)= "GuestID"];
}
// The request message containing the required info to change guest's status
message GuestStatusRequest {
int64 id = 1 [(gogoproto.jsontag) = "id", (gogoproto.moretags) = "validate:\"required,min=1\"", (gogoproto.customname)= "ID"];
int32 status = 2 [(gogoproto.jsontag) = "status", (gogoproto.moretags) = "validate:\"max=1\""];
}
// The general response message contaning the result after updating/inserting the guest info
message GuestInfoReply {
bool success = 1 [(gogoproto.jsontag) = "success"];
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,247 @@
syntax = "proto3";
package ticket.service.item.v1;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
import "app/service/openplatform/ticket-item/api/grpc/v1/screen.proto";
import "app/service/openplatform/ticket-item/api/grpc/v1/bulletin.proto";
import "app/service/openplatform/ticket-item/api/grpc/v1/guest.proto";
import "app/service/openplatform/ticket-item/api/grpc/v1/time.proto";
import "app/service/openplatform/ticket-item/api/grpc/v1/venue.proto";
option (gogoproto.goproto_enum_prefix_all) = false;
option (gogoproto.goproto_getters_all) = false;
option (gogoproto.unmarshaler_all) = true;
option (gogoproto.marshaler_all) = true;
option (gogoproto.sizer_all) = true;
option go_package = "v1";
// The get service definition.
service Item {
// Info Servcie
rpc Info (InfoRequest) returns (InfoReply) {}
// cards Servcie
rpc Cards (CardsRequest) returns (CardsReply) {}
// BillInfo Servcie
rpc BillInfo (BillRequest) returns (BillReply) {}
// Wish Service
rpc Wish (WishRequest) returns (WishReply) {}
// Version Service
rpc Version (VersionRequest) returns (VersionReply) {}
// VersionReview Service
rpc VersionReview (VersionReviewRequest) returns (VersionReviewReply) {}
// VersionStatus Service
rpc VersionStatus (VersionStatusRequest) returns (VersionStatusReply) {}
// BannerEdit Service
rpc BannerEdit (BannerEditRequest) returns (BannerEditReply) {}
}
// The request message containing the itemID.
message InfoRequest {
int64 id = 1 [(gogoproto.jsontag) = "id", (gogoproto.moretags) = "validate:\"required\"", (gogoproto.customname)= "ID"];
}
// The request message containing the itemIDs.
message CardsRequest {
repeated int64 ids = 1 [(gogoproto.jsontag) = "ids", (gogoproto.moretags) = "validate:\"required\"", (gogoproto.customname)= "IDs"];
}
// The request message containing the itemIDs ScIDs TicketIDs.
message BillRequest {
repeated int64 ids = 1 [(gogoproto.jsontag) = "ids", (gogoproto.moretags) = "validate:\"required\"",(gogoproto.customname)= "IDs"];
repeated int64 tk_ids = 2 [(gogoproto.jsontag) = "sc_ids", (gogoproto.moretags) = "validate:\"required\"", (gogoproto.customname)= "ScIDs"];
repeated int64 sc_ids = 3 [(gogoproto.jsontag) = "tk_ids", (gogoproto.moretags) = "validate:\"required\"", (gogoproto.customname)= "TkIDs"];
}
// The response message containing the itembaseinfo and related screeninfo,ticketinfo
message InfoReply {
int64 id = 1 [(gogoproto.jsontag) = "id", (gogoproto.moretags) = "validate:\"min=1\"", (gogoproto.customname)= "ID"];
string name = 2 [(gogoproto.jsontag) = "name"];
int32 status = 3 [(gogoproto.jsontag) = "status", (gogoproto.moretags) = "validate:\"min=1\""];
int32 type = 4 [(gogoproto.jsontag) = "type", (gogoproto.moretags) = "validate:\"min=0\""];
int32 rec = 5 [(gogoproto.jsontag) = "rec", (gogoproto.moretags) = "validate:\"min=0\""];
int32 is_sale = 6 [(gogoproto.jsontag) = "is_sale", (gogoproto.moretags) = "validate:\"min=0\""];
string ticket_desc = 7 [(gogoproto.jsontag) = "desc"];
int32 sale_flag = 8 [(gogoproto.jsontag) = "sale_flag", (gogoproto.moretags) = "validate:\"min=1\""];
string prom_tag = 9 [(gogoproto.jsontag) = "promo_tags"];
ImgList img = 10 [(gogoproto.jsontag) = "img"];
ItemTime time = 11 [(gogoproto.jsontag) = "time"];
map<int64,ScreenInfo> screen = 12 [(gogoproto.jsontag) = "screen"];
ItemExt ext = 13 [(gogoproto.jsontag) = "ext"];
BillOpt bill_opt = 14 [(gogoproto.jsontag) = "bill_opt"];
}
// The response message containing the map type cardinfo
message CardsReply{
map<int64,CardReply> cards = 1 [(gogoproto.jsontag) = "list"];
}
// The response message containing the itembaseInfo
message CardReply {
int64 id = 1 [(gogoproto.jsontag) = "id", (gogoproto.moretags) = "validate:\"min=1\"", (gogoproto.customname)= "ID"];
string name = 2 [(gogoproto.jsontag) = "name"];
int32 status = 3 [(gogoproto.jsontag) = "status", (gogoproto.moretags) = "validate:\"min=1\""];
int32 type = 4 [(gogoproto.jsontag) = "type", (gogoproto.moretags) = "validate:\"min=0\""];
int32 rec = 5 [(gogoproto.jsontag) = "rec", (gogoproto.moretags) = "validate:\"min=0\""];
int32 is_sale = 6 [(gogoproto.jsontag) = "is_sale", (gogoproto.moretags) = "validate:\"min=0\""];
string ticket_desc = 7 [(gogoproto.jsontag) = "desc"];
int32 sale_flag = 8 [(gogoproto.jsontag) = "sale_flag", (gogoproto.moretags) = "validate:\"min=1\""];
string prom_tag = 9 [(gogoproto.jsontag) = "promo_tags"];
ImgList img = 10 [(gogoproto.jsontag) = "img"];
ItemTime time = 11 [(gogoproto.jsontag) = "time"];
VenueInfo venue = 12 [(gogoproto.jsontag) = "venue"];
}
// The response message containing billinfo
message BillReply {
map<int64,ItemBase> base_info= 1 [(gogoproto.jsontag) = "base_info"];
map<int64,BillOpt> bill_opt= 2 [(gogoproto.jsontag) = "bill_opt"];
}
// The response message containing the itembaseinfo and map type screeninfo
message ItemBase {
int64 id = 1 [(gogoproto.jsontag) = "id", (gogoproto.moretags) = "validate:\"min=1\"", (gogoproto.customname)= "ID"];
int32 status = 2 [(gogoproto.jsontag) = "status", (gogoproto.moretags) = "validate:\"min=0\""];
string name = 3 [(gogoproto.jsontag) = "name"];
int32 type = 4 [(gogoproto.jsontag) = "type", (gogoproto.moretags) = "validate:\"min=0\""];
int32 is_sale = 5 [(gogoproto.jsontag) = "is_sale", (gogoproto.moretags) = "validate:\"min=0\""];
string prom_tag = 6 [(gogoproto.jsontag) = "promo_tags"];
uint64 ver_id = 7 [(gogoproto.jsontag) = "ver_id", (gogoproto.moretags) = "validate:\"min=0\"", (gogoproto.customname)= "VerID"];
ItemTime time = 8 [(gogoproto.jsontag) = "time"];
ImgList img = 9 [(gogoproto.jsontag) = "img"];
map<int64,ScreenInfo> screen = 10 [(gogoproto.jsontag) = "screen"];
}
// The response message containing the ItemExtinfo
message ItemExt {
string label = 1 [(gogoproto.jsontag) = "label"];
int32 sp_type = 2 [(gogoproto.jsontag) = "sponsor_type", (gogoproto.moretags) = "validate:\"min=0\""];
uint64 ver_id = 3 [(gogoproto.jsontag) = "ver_id", (gogoproto.moretags) = "validate:\"min=0\"", (gogoproto.customname)= "VerID"];
string detail = 4 [(gogoproto.jsontag) = "detail"];
VenueInfo venue = 5 [(gogoproto.jsontag) = "venue"];
repeated BulletinInfo bulletin = 6 [(gogoproto.jsontag) = "bulletin"];
repeated GuestInfoRequest guest = 7 [(gogoproto.jsontag) = "guest"];
}
// The response message containing the ImgList
message ImgList {
string first = 1 [(gogoproto.jsontag) = "first"];
string banner = 2 [(gogoproto.jsontag) = "banner"];
}
// The response message containing the ItemBillOption
message BillOpt {
string buyerInfo = 1 [(gogoproto.jsontag) = "buyer_info"];
int32 exp_tip = 2 [(gogoproto.jsontag) = "exptip"];
int32 exp_free = 3 [(gogoproto.jsontag) = "expfree"];
int32 vip_exp_free = 4 [(gogoproto.jsontag) = "vip_exp_free"];
BuyNumLimit buy_limit = 5 [(gogoproto.jsontag) = "buy_num_limit"];
}
// 项目限购结构
message BuyNumLimit {
repeated BnlLevel level = 1 [(gogoproto.jsontag) = "level"];
int32 per = 2 [(gogoproto.jsontag) = "per"];
map<int32, BnlLevel> vip = 3 [(gogoproto.jsontag) = "vip", (gogoproto.customname) = "VIP"];
}
message BnlLevel {
int32 apply_to_vip = 1 [(gogoproto.jsontag) = "apply_to_vip"];
int32 max = 2 [(gogoproto.jsontag) = "max"];
int32 min = 3 [(gogoproto.jsontag) = "min"];
}
// The request message containing ItemID MID Face.
message WishRequest {
int64 item_id = 1 [(gogoproto.jsontag) = "item_id", (gogoproto.moretags) = "validate:\"required\"", (gogoproto.customname)= "ItemID"];
int64 mid = 2 [(gogoproto.jsontag) = "mid", (gogoproto.moretags) = "validate:\"required\"", (gogoproto.customname)= "MID"];
string face = 3 [(gogoproto.jsontag) = "face"];
}
// The response message containing the ITEMID MID
message WishReply {
int64 item_id = 1 [(gogoproto.jsontag) = "item_id", (gogoproto.moretags) = "validate:\"required\"", (gogoproto.customname)= "ItemID"];
int64 mid = 2 [(gogoproto.jsontag) = "mid", (gogoproto.moretags) = "validate:\"required\"", (gogoproto.customname)= "MID"];
}
// FavRequest 收藏
message FavRequest {
int64 item_id = 1 [(gogoproto.jsontag) = "item_id", (gogoproto.moretags) = "validate:\"required\"", (gogoproto.customname)= "ItemID"];
int64 mid = 2 [(gogoproto.jsontag) = "mid", (gogoproto.moretags) = "validate:\"required\"", (gogoproto.customname)= "MID"];
int32 type = 3 [(gogoproto.jsontag) = "type", (gogoproto.moretags) = "validate:\"required,min=1,max=3\"", (gogoproto.customname)= "Type"];
int32 Status = 4 [(gogoproto.jsontag) = "status", (gogoproto.moretags) = "validate:\"required,min=0,max=1\"", (gogoproto.customname)= "Status"];
}
// FavReply 收藏
message FavReply {
int64 item_id = 1 [(gogoproto.jsontag) = "item_id", (gogoproto.moretags) = "validate:\"required\"", (gogoproto.customname)= "ItemID"];
int64 mid = 2 [(gogoproto.jsontag) = "mid", (gogoproto.moretags) = "validate:\"required\"", (gogoproto.customname)= "MID"];
int32 type = 3 [(gogoproto.jsontag) = "type", (gogoproto.moretags) = "validate:\"required,min=0,max=1\"", (gogoproto.customname)= "Type"];
int32 Status = 4 [(gogoproto.jsontag) = "status", (gogoproto.moretags) = "validate:\"required,min=0,max=1\"", (gogoproto.customname)= "Status"];
}
// The request message containing the version info to update/insert project
message VersionRequest {
uint64 ver_id = 1 [(gogoproto.jsontag) = "ver_id", (gogoproto.moretags) = "validate:\"required,min=0\""];
uint32 op_type = 2 [(gogoproto.jsontag) = "op_type", (gogoproto.moretags) = "validate:\"max=1\""];
}
// The general response message containing the result after updating/inserting the project info
message VersionReply {
int64 project_id = 1 [(gogoproto.jsontag) = "project_id"];
}
// The request message containing the info to add/edit a banner
message BannerEditRequest {
uint64 ver_id = 1 [(gogoproto.jsontag) = "ver_id"];
int32 op_type = 2 [(gogoproto.jsontag) = "op_type"];
string name = 3 [(gogoproto.jsontag) = "name"];
int32 position = 4 [(gogoproto.jsontag) = "position"];
int32 sub_position = 5 [(gogoproto.jsontag) = "sub_position"];
int32 order = 6 [(gogoproto.jsontag) = "order"];
int64 pub_start = 7 [(gogoproto.jsontag) = "pub_start"];
int64 pub_end = 8 [(gogoproto.jsontag) = "pub_end"];
string pic = 9 [(gogoproto.jsontag) = "pic"];
string url = 10 [(gogoproto.jsontag) = "url"];
string from = 11 [(gogoproto.jsontag) = "from"];
string location = 12 [(gogoproto.jsontag) = "location"];
string uname = 13 [(gogoproto.jsontag) = "uname"];
int32 target_user = 14 [(gogoproto.jsontag) = "target_user"];
}
// The response message containing the result after adding/editing a banner
message BannerEditReply {
int64 banner_id = 1 [(gogoproto.jsontag) = "banner_id"];
}
// The request message containing the info to pass/reject a version
message VersionReviewRequest {
uint64 ver_id = 1 [(gogoproto.jsontag) = "ver_id"];
int32 op_type = 2 [(gogoproto.jsontag) = "op_type"];
int32 ver_type = 3 [(gogoproto.jsontag) = "ver_type"];
string msg = 4 [(gogoproto.jsontag) = "msg"];
string uname = 5 [(gogoproto.jsontag) = "uname"];
}
// The response message containing the result after passing/rejecting a version
message VersionReviewReply {
uint64 ver_id = 1 [(gogoproto.jsontag) = "ver_id"];
}
// The request message containing the info to change a version's status
message VersionStatusRequest {
uint64 ver_id = 1 [(gogoproto.jsontag) = "ver_id"];
int32 op_type = 2 [(gogoproto.jsontag) = "op_type"];
int32 ver_type = 3 [(gogoproto.jsontag) = "ver_type"];
string uname = 4 [(gogoproto.jsontag) = "uname"];
}
// The response message containing the result after changing a version's status
message VersionStatusReply {
uint64 ver_id = 1 [(gogoproto.jsontag) = "ver_id"];
}

View File

@@ -0,0 +1,4 @@
#! /bin/sh
# 在环境变量中设置好$GOPATH即可食用
cd $GOPATH/src/go-common/app/service/openplatform/ticket-item/api/grpc/v1
$GOPATH/src/go-common/app/tool/warden/protoc.sh

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,58 @@
syntax = "proto3";
package ticket.service.item.v1;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option (gogoproto.goproto_enum_prefix_all) = false;
option (gogoproto.goproto_getters_all) = false;
option (gogoproto.unmarshaler_all) = true;
option (gogoproto.marshaler_all) = true;
option (gogoproto.sizer_all) = true;
option go_package = "v1";
// The place service definition.
service Place {
rpc PlaceInfo (PlaceInfoRequest) returns (PlaceInfoReply) {}
}
// The response message containing the Place info
message PlaceInfo {
// 状态
int64 id = 1 [(gogoproto.jsontag) = "id",(gogoproto.customname)= "ID"];
// 场地名
int32 status = 2 [(gogoproto.jsontag) = "status"];
// 场地底图
string name = 3 [(gogoproto.jsontag) = "name"];
// 场馆ID
string base_pic = 4 [(gogoproto.jsontag) = "base_pic"];
// mis画框宽度
int32 d_width = 5 [(gogoproto.jsontag) = "d_width"];
// mis画框高度
int32 d_height = 6 [(gogoproto.jsontag) = "d_height"];
}
// placeInfo接口请求
message PlaceInfoRequest {
// 待修改场地的ID为0表示创建
int64 ID = 1 [(gogoproto.jsontag) = "id", (gogoproto.moretags) = "validate:\"min=0\""];
// 状态
int32 Status = 2 [(gogoproto.jsontag) = "status", (gogoproto.moretags) = "validate:\"min=0,max=1\""];
// 场地名
string Name = 3 [(gogoproto.jsontag) = "name", (gogoproto.moretags) = "validate:\"max=16\""];
// 场地底图
string BasePic = 4 [(gogoproto.jsontag) = "base_pic", (gogoproto.moretags) = "validate:\"max=128\""];
// 场馆ID
int64 Venue = 5 [(gogoproto.jsontag) = "venue", (gogoproto.moretags) = "validate:\"min=1\""];
// mis画框宽度
int32 DWidth = 6 [(gogoproto.jsontag) = "d_width", (gogoproto.moretags) = "validate:\"min=0\""];
// mis画框高度
int32 DHeight = 7 [(gogoproto.jsontag) = "d_height", (gogoproto.moretags) = "validate:\"min=0\""];
}
// placeInfo接口返回
message PlaceInfoReply {
// 操作结果
bool Success = 1 [(gogoproto.jsontag) = "success"];
// 操作场地ID
int64 ID = 2 [(gogoproto.jsontag) = "id"];
}

View File

@@ -0,0 +1,818 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: app/service/openplatform/ticket-item/api/grpc/v1/screen.proto
package v1
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import _ "github.com/gogo/protobuf/gogoproto"
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// The response message containing the ScreenInfo
type ScreenInfo struct {
ID int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id" validate:"min=0"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name"`
Status int32 `protobuf:"varint,3,opt,name=status,proto3" json:"status" validate:"min=0"`
// 类型: 1-坐, 2-站
Type int32 `protobuf:"varint,4,opt,name=type,proto3" json:"type" validate:"min=0"`
// 出票方式: 1-纸质票, 2-电子票, 3-外部票
TicketType int32 `protobuf:"varint,5,opt,name=ticket_type,json=ticketType,proto3" json:"ticket_type" validate:"min=0"`
// 票区分的场次类型: 1-普通场次, 2-通票场次 3-联票场次
ScreenType int32 `protobuf:"varint,6,opt,name=screen_type,json=screenType,proto3" json:"screen_type" validate:"min=0"`
// 配送方式: 1-不配送, 2-自取, 3-快递
DeliveryType int32 `protobuf:"varint,7,opt,name=delivery_type,json=deliveryType,proto3" json:"delivery_type" validate:"min=0"`
// 是否选座 是-1否-0
PickSeat int32 `protobuf:"varint,8,opt,name=pick_seat,json=pickSeat,proto3" json:"pick_seat" validate:"min=0"`
// 售卖状态
SaleFlag int32 `protobuf:"varint,9,opt,name=sale_flag,json=saleFlag,proto3" json:"sale_flag" validate:"min=0"`
ScTime *ScreenTime `protobuf:"bytes,10,opt,name=sc_time,json=scTime" json:"time"`
Ticket map[int64]*TicketInfo `protobuf:"bytes,11,rep,name=Ticket" json:"ticket" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value"`
}
func (m *ScreenInfo) Reset() { *m = ScreenInfo{} }
func (m *ScreenInfo) String() string { return proto.CompactTextString(m) }
func (*ScreenInfo) ProtoMessage() {}
func (*ScreenInfo) Descriptor() ([]byte, []int) { return fileDescriptorScreen, []int{0} }
func (m *ScreenInfo) GetID() int64 {
if m != nil {
return m.ID
}
return 0
}
func (m *ScreenInfo) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *ScreenInfo) GetStatus() int32 {
if m != nil {
return m.Status
}
return 0
}
func (m *ScreenInfo) GetType() int32 {
if m != nil {
return m.Type
}
return 0
}
func (m *ScreenInfo) GetTicketType() int32 {
if m != nil {
return m.TicketType
}
return 0
}
func (m *ScreenInfo) GetScreenType() int32 {
if m != nil {
return m.ScreenType
}
return 0
}
func (m *ScreenInfo) GetDeliveryType() int32 {
if m != nil {
return m.DeliveryType
}
return 0
}
func (m *ScreenInfo) GetPickSeat() int32 {
if m != nil {
return m.PickSeat
}
return 0
}
func (m *ScreenInfo) GetSaleFlag() int32 {
if m != nil {
return m.SaleFlag
}
return 0
}
func (m *ScreenInfo) GetScTime() *ScreenTime {
if m != nil {
return m.ScTime
}
return nil
}
func (m *ScreenInfo) GetTicket() map[int64]*TicketInfo {
if m != nil {
return m.Ticket
}
return nil
}
func init() {
proto.RegisterType((*ScreenInfo)(nil), "ticket.service.item.v1.ScreenInfo")
}
func (m *ScreenInfo) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *ScreenInfo) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.ID != 0 {
dAtA[i] = 0x8
i++
i = encodeVarintScreen(dAtA, i, uint64(m.ID))
}
if len(m.Name) > 0 {
dAtA[i] = 0x12
i++
i = encodeVarintScreen(dAtA, i, uint64(len(m.Name)))
i += copy(dAtA[i:], m.Name)
}
if m.Status != 0 {
dAtA[i] = 0x18
i++
i = encodeVarintScreen(dAtA, i, uint64(m.Status))
}
if m.Type != 0 {
dAtA[i] = 0x20
i++
i = encodeVarintScreen(dAtA, i, uint64(m.Type))
}
if m.TicketType != 0 {
dAtA[i] = 0x28
i++
i = encodeVarintScreen(dAtA, i, uint64(m.TicketType))
}
if m.ScreenType != 0 {
dAtA[i] = 0x30
i++
i = encodeVarintScreen(dAtA, i, uint64(m.ScreenType))
}
if m.DeliveryType != 0 {
dAtA[i] = 0x38
i++
i = encodeVarintScreen(dAtA, i, uint64(m.DeliveryType))
}
if m.PickSeat != 0 {
dAtA[i] = 0x40
i++
i = encodeVarintScreen(dAtA, i, uint64(m.PickSeat))
}
if m.SaleFlag != 0 {
dAtA[i] = 0x48
i++
i = encodeVarintScreen(dAtA, i, uint64(m.SaleFlag))
}
if m.ScTime != nil {
dAtA[i] = 0x52
i++
i = encodeVarintScreen(dAtA, i, uint64(m.ScTime.Size()))
n1, err := m.ScTime.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n1
}
if len(m.Ticket) > 0 {
for k, _ := range m.Ticket {
dAtA[i] = 0x5a
i++
v := m.Ticket[k]
msgSize := 0
if v != nil {
msgSize = v.Size()
msgSize += 1 + sovScreen(uint64(msgSize))
}
mapSize := 1 + sovScreen(uint64(k)) + msgSize
i = encodeVarintScreen(dAtA, i, uint64(mapSize))
dAtA[i] = 0x8
i++
i = encodeVarintScreen(dAtA, i, uint64(k))
if v != nil {
dAtA[i] = 0x12
i++
i = encodeVarintScreen(dAtA, i, uint64(v.Size()))
n2, err := v.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n2
}
}
}
return i, nil
}
func encodeVarintScreen(dAtA []byte, offset int, v uint64) int {
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return offset + 1
}
func (m *ScreenInfo) Size() (n int) {
var l int
_ = l
if m.ID != 0 {
n += 1 + sovScreen(uint64(m.ID))
}
l = len(m.Name)
if l > 0 {
n += 1 + l + sovScreen(uint64(l))
}
if m.Status != 0 {
n += 1 + sovScreen(uint64(m.Status))
}
if m.Type != 0 {
n += 1 + sovScreen(uint64(m.Type))
}
if m.TicketType != 0 {
n += 1 + sovScreen(uint64(m.TicketType))
}
if m.ScreenType != 0 {
n += 1 + sovScreen(uint64(m.ScreenType))
}
if m.DeliveryType != 0 {
n += 1 + sovScreen(uint64(m.DeliveryType))
}
if m.PickSeat != 0 {
n += 1 + sovScreen(uint64(m.PickSeat))
}
if m.SaleFlag != 0 {
n += 1 + sovScreen(uint64(m.SaleFlag))
}
if m.ScTime != nil {
l = m.ScTime.Size()
n += 1 + l + sovScreen(uint64(l))
}
if len(m.Ticket) > 0 {
for k, v := range m.Ticket {
_ = k
_ = v
l = 0
if v != nil {
l = v.Size()
l += 1 + sovScreen(uint64(l))
}
mapEntrySize := 1 + sovScreen(uint64(k)) + l
n += mapEntrySize + 1 + sovScreen(uint64(mapEntrySize))
}
}
return n
}
func sovScreen(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
func sozScreen(x uint64) (n int) {
return sovScreen(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *ScreenInfo) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowScreen
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: ScreenInfo: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ScreenInfo: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType)
}
m.ID = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowScreen
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.ID |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowScreen
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthScreen
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Name = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType)
}
m.Status = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowScreen
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Status |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 4:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType)
}
m.Type = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowScreen
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Type |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 5:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field TicketType", wireType)
}
m.TicketType = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowScreen
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.TicketType |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 6:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ScreenType", wireType)
}
m.ScreenType = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowScreen
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.ScreenType |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 7:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field DeliveryType", wireType)
}
m.DeliveryType = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowScreen
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.DeliveryType |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 8:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field PickSeat", wireType)
}
m.PickSeat = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowScreen
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.PickSeat |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 9:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field SaleFlag", wireType)
}
m.SaleFlag = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowScreen
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.SaleFlag |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 10:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ScTime", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowScreen
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthScreen
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.ScTime == nil {
m.ScTime = &ScreenTime{}
}
if err := m.ScTime.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 11:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Ticket", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowScreen
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthScreen
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.Ticket == nil {
m.Ticket = make(map[int64]*TicketInfo)
}
var mapkey int64
var mapvalue *TicketInfo
for iNdEx < postIndex {
entryPreIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowScreen
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
if fieldNum == 1 {
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowScreen
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
mapkey |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
} else if fieldNum == 2 {
var mapmsglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowScreen
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
mapmsglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if mapmsglen < 0 {
return ErrInvalidLengthScreen
}
postmsgIndex := iNdEx + mapmsglen
if mapmsglen < 0 {
return ErrInvalidLengthScreen
}
if postmsgIndex > l {
return io.ErrUnexpectedEOF
}
mapvalue = &TicketInfo{}
if err := mapvalue.Unmarshal(dAtA[iNdEx:postmsgIndex]); err != nil {
return err
}
iNdEx = postmsgIndex
} else {
iNdEx = entryPreIndex
skippy, err := skipScreen(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthScreen
}
if (iNdEx + skippy) > postIndex {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
m.Ticket[mapkey] = mapvalue
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipScreen(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthScreen
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipScreen(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowScreen
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowScreen
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
return iNdEx, nil
case 1:
iNdEx += 8
return iNdEx, nil
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowScreen
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
iNdEx += length
if length < 0 {
return 0, ErrInvalidLengthScreen
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowScreen
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
innerWire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
innerWireType := int(innerWire & 0x7)
if innerWireType == 4 {
break
}
next, err := skipScreen(dAtA[start:])
if err != nil {
return 0, err
}
iNdEx = start + next
}
return iNdEx, nil
case 4:
return iNdEx, nil
case 5:
iNdEx += 4
return iNdEx, nil
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
}
panic("unreachable")
}
var (
ErrInvalidLengthScreen = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowScreen = fmt.Errorf("proto: integer overflow")
)
func init() {
proto.RegisterFile("app/service/openplatform/ticket-item/api/grpc/v1/screen.proto", fileDescriptorScreen)
}
var fileDescriptorScreen = []byte{
// 514 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0xcf, 0x8a, 0xd3, 0x40,
0x1c, 0xc7, 0x49, 0xda, 0x66, 0xdb, 0x89, 0x42, 0x99, 0x83, 0x84, 0xb2, 0x34, 0xb1, 0x22, 0xe4,
0xb2, 0x49, 0xbb, 0x82, 0x2c, 0x2b, 0xf5, 0x10, 0x76, 0x85, 0xf5, 0x98, 0xed, 0x49, 0x90, 0x32,
0x4d, 0xa6, 0x71, 0x68, 0xfe, 0x91, 0x4c, 0x03, 0x7d, 0x13, 0x1f, 0xc9, 0xa3, 0x4f, 0x10, 0xa4,
0xc7, 0x1c, 0x7d, 0x02, 0x99, 0xdf, 0x44, 0x5b, 0x21, 0x2c, 0xe8, 0xa5, 0xcc, 0xef, 0xcf, 0xe7,
0xd3, 0x19, 0xfa, 0x2d, 0x5a, 0x92, 0x3c, 0x77, 0x4b, 0x5a, 0x54, 0x2c, 0xa0, 0x6e, 0x96, 0xd3,
0x34, 0x8f, 0x09, 0xdf, 0x66, 0x45, 0xe2, 0x72, 0x16, 0xec, 0x28, 0xbf, 0x62, 0x9c, 0x26, 0x2e,
0xc9, 0x99, 0x1b, 0x15, 0x79, 0xe0, 0x56, 0x0b, 0xb7, 0x0c, 0x0a, 0x4a, 0x53, 0x27, 0x2f, 0x32,
0x9e, 0xe1, 0x17, 0x72, 0xcb, 0x69, 0x0d, 0x8e, 0xd8, 0x76, 0xaa, 0xc5, 0xe4, 0x2a, 0x62, 0xfc,
0xcb, 0x7e, 0xe3, 0x04, 0x59, 0xe2, 0x46, 0x59, 0x94, 0xb9, 0xb0, 0xbe, 0xd9, 0x6f, 0xa1, 0x82,
0x02, 0x4e, 0x52, 0x33, 0x79, 0xf7, 0xcf, 0xb7, 0xe0, 0x2c, 0xa1, 0x2d, 0xbc, 0xfc, 0x0f, 0x18,
0x2e, 0x0d, 0xf8, 0xec, 0xab, 0x86, 0xd0, 0x23, 0xbc, 0xe9, 0x21, 0xdd, 0x66, 0x78, 0x8e, 0x54,
0x16, 0x1a, 0x8a, 0xa5, 0xd8, 0x3d, 0xcf, 0x3a, 0xd6, 0xa6, 0xfa, 0x70, 0xd7, 0xd4, 0xa6, 0xca,
0xc2, 0x9f, 0xb5, 0x39, 0xae, 0x48, 0xcc, 0x42, 0xc2, 0xe9, 0xed, 0x2c, 0x61, 0xe9, 0x72, 0x3e,
0xf3, 0x55, 0x16, 0xe2, 0x4b, 0xd4, 0x4f, 0x49, 0x42, 0x0d, 0xd5, 0x52, 0xec, 0x91, 0x37, 0x6c,
0x6a, 0x13, 0x6a, 0x1f, 0x3e, 0xf1, 0x5b, 0xa4, 0x95, 0x9c, 0xf0, 0x7d, 0x69, 0xf4, 0x2c, 0xc5,
0x1e, 0x78, 0xd3, 0xa6, 0x36, 0xdb, 0x4e, 0xa7, 0xb1, 0x9d, 0xe1, 0x39, 0xea, 0xf3, 0x43, 0x4e,
0x8d, 0x3e, 0x50, 0x97, 0xc2, 0x2a, 0xea, 0x4e, 0x06, 0x26, 0xf8, 0x0e, 0xe9, 0xf2, 0x61, 0x6b,
0x00, 0x07, 0x00, 0xbe, 0x6a, 0x6a, 0xf3, 0xbc, 0xdd, 0xc9, 0x23, 0xb9, 0xb0, 0x6a, 0x2d, 0xf2,
0x17, 0x96, 0x16, 0xed, 0x64, 0x39, 0x6b, 0x77, 0x5b, 0xe4, 0x02, 0x58, 0x3e, 0xa2, 0xe7, 0x21,
0x8d, 0x59, 0x45, 0x8b, 0x83, 0xf4, 0x5c, 0x80, 0xe7, 0x75, 0x53, 0x9b, 0x7f, 0x0f, 0x3a, 0x4d,
0xcf, 0x7e, 0xaf, 0x80, 0xeb, 0x3d, 0x1a, 0xe5, 0x2c, 0xd8, 0xad, 0x4b, 0x4a, 0xb8, 0x31, 0x04,
0xcf, 0xcb, 0xa6, 0x36, 0x4f, 0xcd, 0x4e, 0xc7, 0x50, 0x8c, 0x1f, 0x29, 0xe1, 0x82, 0x2f, 0x49,
0x4c, 0xd7, 0xdb, 0x98, 0x44, 0xc6, 0xe8, 0xc4, 0xff, 0x69, 0x76, 0xf3, 0x62, 0xfc, 0x21, 0x26,
0x11, 0xbe, 0x47, 0x17, 0x65, 0xb0, 0x16, 0x81, 0x33, 0x90, 0xa5, 0xd8, 0xfa, 0xf5, 0xcc, 0xe9,
0x4e, 0xbd, 0x23, 0x63, 0xb4, 0x62, 0x09, 0x95, 0x31, 0x10, 0x8c, 0xaf, 0x95, 0x81, 0xe8, 0x60,
0x1f, 0x69, 0x2b, 0xc0, 0x0c, 0xdd, 0xea, 0xd9, 0xfa, 0xb5, 0xf3, 0xb4, 0x45, 0x84, 0xd1, 0x91,
0xc0, 0x7d, 0xca, 0x8b, 0x83, 0x87, 0x44, 0x70, 0x24, 0xe2, 0xb7, 0xa6, 0xc9, 0x67, 0xa4, 0x9f,
0xad, 0xe0, 0x31, 0xea, 0xed, 0xe8, 0x41, 0x86, 0xd7, 0x17, 0x47, 0x7c, 0x83, 0x06, 0x15, 0x89,
0xf7, 0x32, 0x9c, 0x4f, 0xdc, 0x5c, 0x5a, 0xc4, 0x77, 0xfa, 0x12, 0xb8, 0x55, 0x6f, 0x14, 0x6f,
0xfc, 0xed, 0x38, 0x55, 0xbe, 0x1f, 0xa7, 0xca, 0x8f, 0xe3, 0x54, 0xf9, 0xa4, 0x56, 0x8b, 0x8d,
0x06, 0xff, 0x99, 0x37, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0x7c, 0x79, 0x0d, 0x96, 0x37, 0x04,
0x00, 0x00,
}

View File

@@ -0,0 +1,29 @@
syntax = "proto3";
package ticket.service.item.v1;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
import "app/service/openplatform/ticket-item/api/grpc/v1/time.proto";
import "app/service/openplatform/ticket-item/api/grpc/v1/ticket.proto";
option go_package = "v1";
// The response message containing the ScreenInfo
message ScreenInfo {
int64 id = 1 [(gogoproto.jsontag) = "id", (gogoproto.moretags) = "validate:\"min=0\"", (gogoproto.customname)= "ID"];
string name = 2 [(gogoproto.jsontag) = "name"];
int32 status = 3 [(gogoproto.jsontag) = "status", (gogoproto.moretags) = "validate:\"min=0\""];
// 类型: 1-坐, 2-站
int32 type = 4 [(gogoproto.jsontag) = "type", (gogoproto.moretags) = "validate:\"min=0\""];
// 出票方式: 1-纸质票, 2-电子票, 3-外部票
int32 ticket_type = 5 [(gogoproto.jsontag) = "ticket_type", (gogoproto.moretags) = "validate:\"min=0\""];
// 票区分的场次类型: 1-普通场次, 2-通票场次 3-联票场次
int32 screen_type = 6 [(gogoproto.jsontag) = "screen_type", (gogoproto.moretags) = "validate:\"min=0\""];
// 配送方式: 1-不配送, 2-自取, 3-快递
int32 delivery_type = 7 [(gogoproto.jsontag) = "delivery_type", (gogoproto.moretags) = "validate:\"min=0\""];
// 是否选座 是-1否-0
int32 pick_seat = 8 [(gogoproto.jsontag) = "pick_seat", (gogoproto.moretags) = "validate:\"min=0\""];
// 售卖状态
int32 sale_flag = 9 [(gogoproto.jsontag) = "sale_flag", (gogoproto.moretags) = "validate:\"min=0\""];
ScreenTime sc_time = 10 [(gogoproto.jsontag) = "time"];
map<int64,TicketInfo> Ticket = 11 [(gogoproto.jsontag) = "ticket"];
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,96 @@
syntax = "proto3";
package ticket.service.item.v1;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option (gogoproto.goproto_enum_prefix_all) = false;
option (gogoproto.goproto_getters_all) = false;
option (gogoproto.unmarshaler_all) = true;
option (gogoproto.marshaler_all) = true;
option (gogoproto.sizer_all) = true;
option go_package = "v1";
// The seat service definition.
service Seat {
rpc SeatInfo (SeatInfoRequest) returns (SeatInfoReply) {}
rpc SeatStock (SeatStockRequest) returns (SeatStockReply) {}
rpc RemoveSeatOrders (RemoveSeatOrdersRequest) returns (RemoveSeatOrdersReply) {}
}
// 单个座位信息
message AreaSeatInfo {
// 座位图x
int32 X = 1 [(gogoproto.jsontag) = "x", (gogoproto.moretags) = "validate:\"min=0\""];
// 座位图y
int32 Y = 2 [(gogoproto.jsontag) = "y", (gogoproto.moretags) = "validate:\"min=0\""];
// 座位号
string Label = 3 [(gogoproto.jsontag) = "label", (gogoproto.moretags) = "validate:\"min=1\""];
// 背景色
string Bgcolor = 4 [(gogoproto.jsontag) = "bgcolor", (gogoproto.moretags) = "validate:\"min=1\""];
// 区域ID
int64 Area = 5 [(gogoproto.jsontag) = "area", (gogoproto.moretags) = "validate:\"min=1\""];
}
// seatInfo接口请求
message SeatInfoRequest {
// 区域ID
int64 Area = 1 [(gogoproto.jsontag) = "area", (gogoproto.moretags) = "validate:\"min=1\""];
// 座位数
int32 SeatsNum = 2 [(gogoproto.jsontag) = "seats_num", (gogoproto.moretags) = "validate:\"min=1\""];
// 座位图
string SeatMap = 3 [(gogoproto.jsontag) = "seat_map", (gogoproto.moretags) = "validate:\"min=1\""];
// 座位数组
repeated AreaSeatInfo Seats = 4 [(gogoproto.jsontag) = "seats", (gogoproto.moretags) = "validate:\"min=1\""];
// 坐区宽度
int32 Width = 5 [(gogoproto.jsontag) = "width", (gogoproto.moretags) = "validate:\"min=1\""];
// 坐区高度
int32 Height = 6 [(gogoproto.jsontag) = "height", (gogoproto.moretags) = "validate:\"min=1\""];
// 行号序列
string RowList = 7 [(gogoproto.jsontag) = "row_list", (gogoproto.moretags) = "validate:\"min=1\""];
// 座位起始坐标
string SeatStart = 8 [(gogoproto.jsontag) = "seat_start", (gogoproto.moretags) = "validate:\"min=1\""];
}
// seatInfo接口返回
message SeatInfoReply {
// 操作结果
bool Success = 1 [(gogoproto.jsontag) = "success"];
}
// 座位票种
message SeatPrice {
// 座位图x
int32 X = 1 [(gogoproto.jsontag) = "x", (gogoproto.moretags) = "validate:\"min=0\""];
// 座位图y
int32 Y = 2 [(gogoproto.jsontag) = "y", (gogoproto.moretags) = "validate:\"min=0\""];
// 票种ID
int64 Price = 3 [(gogoproto.jsontag) = "price", (gogoproto.moretags) = "validate:\"min=1\""];
}
// seatStock接口请求
message SeatStockRequest {
// 场次ID
int64 Screen = 1 [(gogoproto.jsontag) = "screen", (gogoproto.moretags) = "validate:\"min=1\""];
// 区域ID
int64 Area = 2 [(gogoproto.jsontag) = "area", (gogoproto.moretags) = "validate:\"min=1\""];
// 座位票种定义数组
repeated SeatPrice SeatInfo = 3 [(gogoproto.jsontag) = "seatInfo", (gogoproto.moretags) = "validate:\"min=1\""];
}
// seatStock接口返回
message SeatStockReply {
// 操作结果
bool Success = 1 [(gogoproto.jsontag) = "success"];
}
// removeSeatOrders接口请求
message RemoveSeatOrdersRequest {
// 票价ID
int64 Price = 1 [(gogoproto.jsontag) = "price", (gogoproto.moretags) = "validate:\"min=1\""];
}
// removeSeatOrders接口返回
message RemoveSeatOrdersReply {
// 影响的区域
repeated int64 Areas = 1 [(gogoproto.jsontag) = "areas"];
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,48 @@
syntax = "proto3";
package ticket.service.item.v1;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
import "app/service/openplatform/ticket-item/api/grpc/v1/time.proto";
option go_package = "v1";
// The response message containing the TicketInfo
message TicketInfo {
int64 id = 1 [(gogoproto.jsontag) = "id", (gogoproto.moretags) = "validate:\"min=1\"", (gogoproto.customname)= "ID"];
string desc = 2 [(gogoproto.jsontag) = "name"];
// 票类型1-单场票 2-通票 3-联票
int32 type = 3 [(gogoproto.jsontag) = "type", (gogoproto.moretags) = "validate:\"min=0\""];
// 售卖类型 1-预售票 2-现场票
int32 sale_type = 4 [(gogoproto.jsontag) = "stype", (gogoproto.moretags) = "validate:\"min=0\""];
string link_sc = 5 [(gogoproto.jsontag) = "lk_screen"];
string link_ticket_id = 6 [(gogoproto.jsontag) = "lk_ticket", (gogoproto.customname)= "LinkTicketID"];
string symbol = 7 [(gogoproto.jsontag) = "symbol"];
string color = 8 [(gogoproto.jsontag) = "color"];
int32 buy_limit = 9 [(gogoproto.jsontag) = "buy_limit", (gogoproto.moretags) = "validate:\"min=0\""];
string desc_detail = 10 [(gogoproto.jsontag) = "desc"];
int32 sale_flag = 11 [(gogoproto.jsontag) = "sale_flag", (gogoproto.moretags) = "validate:\"min=0\""];
TicketPriceList price_list = 12[(gogoproto.jsontag) = "price"];
TicketStatus status_list = 13 [(gogoproto.jsontag) = "status"];
TicketTime time = 14 [(gogoproto.jsontag) = "time"];
TicketBuyNumLimit buy_num_limit = 15 [(gogoproto.jsontag) = "buy_num_limit"];
}
message TicketBuyNumLimit {
map<int32,int64> normal = 1 [(gogoproto.jsontag) = "normal"];
map<int32,int64> vip = 2 [(gogoproto.jsontag) = "vip"];
map<int32,int64> annual_vip = 3 [(gogoproto.jsontag) = "annual_vip"];
}
// The response message containing the IsSale IsVisible IsRefund
message TicketStatus {
int32 is_sale = 1 [(gogoproto.jsontag) = "is_sale", (gogoproto.moretags) = "validate:\"min=0\""];
int32 is_visible = 2[(gogoproto.jsontag) = "is_visible", (gogoproto.moretags) = "validate:\"min=0\""];
int32 is_refund =3 [(gogoproto.jsontag) = "is_refund", (gogoproto.moretags) = "validate:\"min=0\""];
}
// The response message containing the Price OriginPrice MarketPrice
message TicketPriceList {
int32 price = 1 [(gogoproto.jsontag) = "price", (gogoproto.moretags) = "validate:\"min=0\""];
int32 ori_price = 2 [(gogoproto.jsontag) = "oprice", (gogoproto.moretags) = "validate:\"min=0\""];
int32 mkt_price = 3 [(gogoproto.jsontag) = "mprice", (gogoproto.moretags) = "validate:\"min=0\""];
}

View File

@@ -0,0 +1,705 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: app/service/openplatform/ticket-item/api/grpc/v1/time.proto
package v1
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import _ "github.com/gogo/protobuf/gogoproto"
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// The response message containing the Item related time
type ItemTime struct {
Stime int32 `protobuf:"varint,1,opt,name=stime,proto3" json:"stime"`
Etime int32 `protobuf:"varint,2,opt,name=etime,proto3" json:"etime"`
}
func (m *ItemTime) Reset() { *m = ItemTime{} }
func (m *ItemTime) String() string { return proto.CompactTextString(m) }
func (*ItemTime) ProtoMessage() {}
func (*ItemTime) Descriptor() ([]byte, []int) { return fileDescriptorTime, []int{0} }
func (m *ItemTime) GetStime() int32 {
if m != nil {
return m.Stime
}
return 0
}
func (m *ItemTime) GetEtime() int32 {
if m != nil {
return m.Etime
}
return 0
}
// The response message containing the Screen related time
type ScreenTime struct {
Stime int32 `protobuf:"varint,1,opt,name=stime,proto3" json:"stime" validate:"min=0"`
Etime int32 `protobuf:"varint,2,opt,name=etime,proto3" json:"etime" validate:"min=0"`
SaleStime int32 `protobuf:"varint,3,opt,name=sale_stime,json=saleStime,proto3" json:"sales" validate:"min=0"`
SaleEtime int32 `protobuf:"varint,4,opt,name=sale_etime,json=saleEtime,proto3" json:"salee" validate:"min=0"`
}
func (m *ScreenTime) Reset() { *m = ScreenTime{} }
func (m *ScreenTime) String() string { return proto.CompactTextString(m) }
func (*ScreenTime) ProtoMessage() {}
func (*ScreenTime) Descriptor() ([]byte, []int) { return fileDescriptorTime, []int{1} }
func (m *ScreenTime) GetStime() int32 {
if m != nil {
return m.Stime
}
return 0
}
func (m *ScreenTime) GetEtime() int32 {
if m != nil {
return m.Etime
}
return 0
}
func (m *ScreenTime) GetSaleStime() int32 {
if m != nil {
return m.SaleStime
}
return 0
}
func (m *ScreenTime) GetSaleEtime() int32 {
if m != nil {
return m.SaleEtime
}
return 0
}
// The response message containing the Ticket related time
type TicketTime struct {
SaleStime int64 `protobuf:"varint,1,opt,name=sale_stime,json=saleStime,proto3" json:"sales" validate:"min=0"`
SaleEtime int64 `protobuf:"varint,2,opt,name=sale_etime,json=saleEtime,proto3" json:"salee" validate:"min=0"`
}
func (m *TicketTime) Reset() { *m = TicketTime{} }
func (m *TicketTime) String() string { return proto.CompactTextString(m) }
func (*TicketTime) ProtoMessage() {}
func (*TicketTime) Descriptor() ([]byte, []int) { return fileDescriptorTime, []int{2} }
func (m *TicketTime) GetSaleStime() int64 {
if m != nil {
return m.SaleStime
}
return 0
}
func (m *TicketTime) GetSaleEtime() int64 {
if m != nil {
return m.SaleEtime
}
return 0
}
func init() {
proto.RegisterType((*ItemTime)(nil), "ticket.service.item.v1.ItemTime")
proto.RegisterType((*ScreenTime)(nil), "ticket.service.item.v1.ScreenTime")
proto.RegisterType((*TicketTime)(nil), "ticket.service.item.v1.TicketTime")
}
func (m *ItemTime) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *ItemTime) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.Stime != 0 {
dAtA[i] = 0x8
i++
i = encodeVarintTime(dAtA, i, uint64(m.Stime))
}
if m.Etime != 0 {
dAtA[i] = 0x10
i++
i = encodeVarintTime(dAtA, i, uint64(m.Etime))
}
return i, nil
}
func (m *ScreenTime) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *ScreenTime) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.Stime != 0 {
dAtA[i] = 0x8
i++
i = encodeVarintTime(dAtA, i, uint64(m.Stime))
}
if m.Etime != 0 {
dAtA[i] = 0x10
i++
i = encodeVarintTime(dAtA, i, uint64(m.Etime))
}
if m.SaleStime != 0 {
dAtA[i] = 0x18
i++
i = encodeVarintTime(dAtA, i, uint64(m.SaleStime))
}
if m.SaleEtime != 0 {
dAtA[i] = 0x20
i++
i = encodeVarintTime(dAtA, i, uint64(m.SaleEtime))
}
return i, nil
}
func (m *TicketTime) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *TicketTime) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.SaleStime != 0 {
dAtA[i] = 0x8
i++
i = encodeVarintTime(dAtA, i, uint64(m.SaleStime))
}
if m.SaleEtime != 0 {
dAtA[i] = 0x10
i++
i = encodeVarintTime(dAtA, i, uint64(m.SaleEtime))
}
return i, nil
}
func encodeVarintTime(dAtA []byte, offset int, v uint64) int {
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return offset + 1
}
func (m *ItemTime) Size() (n int) {
var l int
_ = l
if m.Stime != 0 {
n += 1 + sovTime(uint64(m.Stime))
}
if m.Etime != 0 {
n += 1 + sovTime(uint64(m.Etime))
}
return n
}
func (m *ScreenTime) Size() (n int) {
var l int
_ = l
if m.Stime != 0 {
n += 1 + sovTime(uint64(m.Stime))
}
if m.Etime != 0 {
n += 1 + sovTime(uint64(m.Etime))
}
if m.SaleStime != 0 {
n += 1 + sovTime(uint64(m.SaleStime))
}
if m.SaleEtime != 0 {
n += 1 + sovTime(uint64(m.SaleEtime))
}
return n
}
func (m *TicketTime) Size() (n int) {
var l int
_ = l
if m.SaleStime != 0 {
n += 1 + sovTime(uint64(m.SaleStime))
}
if m.SaleEtime != 0 {
n += 1 + sovTime(uint64(m.SaleEtime))
}
return n
}
func sovTime(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
func sozTime(x uint64) (n int) {
return sovTime(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *ItemTime) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTime
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: ItemTime: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ItemTime: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Stime", wireType)
}
m.Stime = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTime
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Stime |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Etime", wireType)
}
m.Etime = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTime
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Etime |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipTime(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthTime
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *ScreenTime) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTime
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: ScreenTime: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ScreenTime: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Stime", wireType)
}
m.Stime = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTime
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Stime |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Etime", wireType)
}
m.Etime = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTime
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Etime |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field SaleStime", wireType)
}
m.SaleStime = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTime
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.SaleStime |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 4:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field SaleEtime", wireType)
}
m.SaleEtime = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTime
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.SaleEtime |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipTime(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthTime
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *TicketTime) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTime
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: TicketTime: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: TicketTime: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field SaleStime", wireType)
}
m.SaleStime = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTime
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.SaleStime |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field SaleEtime", wireType)
}
m.SaleEtime = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTime
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.SaleEtime |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipTime(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthTime
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipTime(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowTime
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowTime
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
return iNdEx, nil
case 1:
iNdEx += 8
return iNdEx, nil
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowTime
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
iNdEx += length
if length < 0 {
return 0, ErrInvalidLengthTime
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowTime
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
innerWire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
innerWireType := int(innerWire & 0x7)
if innerWireType == 4 {
break
}
next, err := skipTime(dAtA[start:])
if err != nil {
return 0, err
}
iNdEx = start + next
}
return iNdEx, nil
case 4:
return iNdEx, nil
case 5:
iNdEx += 4
return iNdEx, nil
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
}
panic("unreachable")
}
var (
ErrInvalidLengthTime = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowTime = fmt.Errorf("proto: integer overflow")
)
func init() {
proto.RegisterFile("app/service/openplatform/ticket-item/api/grpc/v1/time.proto", fileDescriptorTime)
}
var fileDescriptorTime = []byte{
// 310 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x91, 0xbf, 0x4e, 0xc3, 0x30,
0x10, 0xc6, 0xe5, 0x94, 0x22, 0xea, 0xa9, 0xca, 0x80, 0x10, 0x52, 0x13, 0x94, 0x89, 0xa5, 0x31,
0x51, 0x36, 0xfe, 0x2c, 0x95, 0x18, 0x90, 0x98, 0x68, 0x26, 0x16, 0xe4, 0x84, 0x6b, 0xb0, 0x88,
0x63, 0x2b, 0x71, 0xf3, 0x0c, 0x3c, 0x1a, 0x23, 0x4f, 0x50, 0xa1, 0x8c, 0x8c, 0x7d, 0x02, 0x94,
0x33, 0x14, 0x22, 0x8a, 0x90, 0x98, 0x9c, 0xcb, 0x7d, 0xdf, 0xf7, 0xbb, 0xd3, 0xd1, 0x33, 0xae,
0x35, 0xab, 0xa1, 0x6a, 0x44, 0x06, 0x4c, 0x69, 0x28, 0x75, 0xc1, 0xcd, 0x42, 0x55, 0x92, 0x19,
0x91, 0x3d, 0x82, 0x99, 0x0a, 0x03, 0x92, 0x71, 0x2d, 0x58, 0x5e, 0xe9, 0x8c, 0x35, 0x11, 0x33,
0x42, 0x42, 0xa8, 0x2b, 0x65, 0x94, 0xbb, 0x6f, 0x35, 0xe1, 0x87, 0x3f, 0xec, 0xb4, 0x61, 0x13,
0x1d, 0x4e, 0x73, 0x61, 0x1e, 0x96, 0x69, 0x98, 0x29, 0xc9, 0x72, 0x95, 0x2b, 0x86, 0xf2, 0x74,
0xb9, 0xc0, 0x0a, 0x0b, 0xfc, 0xb2, 0x31, 0xc1, 0x35, 0xdd, 0xbb, 0x32, 0x20, 0x13, 0x21, 0xc1,
0xf5, 0xe9, 0xb0, 0xee, 0x08, 0x07, 0xe4, 0x88, 0x1c, 0x0f, 0x67, 0xa3, 0xb7, 0x95, 0x6f, 0x7f,
0xdc, 0xd8, 0xa7, 0x13, 0x00, 0x0a, 0x9c, 0x2f, 0x01, 0x58, 0x01, 0x3e, 0xc1, 0x9a, 0x50, 0x3a,
0xcf, 0x2a, 0x80, 0x12, 0x03, 0xe3, 0x7e, 0xe0, 0x64, 0x13, 0xb8, 0x5e, 0xf9, 0xe3, 0x86, 0x17,
0xe2, 0x9e, 0x1b, 0x38, 0x0d, 0xa4, 0x28, 0x2f, 0x4e, 0x82, 0x4f, 0x48, 0xdc, 0x87, 0x4c, 0x36,
0x90, 0xed, 0x26, 0x6c, 0xb9, 0xe7, 0x94, 0xd6, 0xbc, 0x80, 0x3b, 0x8b, 0x1b, 0x7c, 0xc3, 0xf1,
0x02, 0xea, 0xad, 0xce, 0x51, 0xd7, 0x9a, 0xf7, 0xdc, 0x96, 0xbb, 0xd3, 0x77, 0xc3, 0xef, 0xee,
0x4b, 0x5c, 0xfa, 0x89, 0x50, 0x9a, 0xe0, 0x31, 0x92, 0x9f, 0xa3, 0x74, 0x9b, 0x0f, 0xfe, 0x3d,
0x8a, 0xd3, 0x77, 0xff, 0x35, 0xca, 0x6c, 0xfc, 0xdc, 0x7a, 0xe4, 0xa5, 0xf5, 0xc8, 0x6b, 0xeb,
0x91, 0x5b, 0xa7, 0x89, 0xd2, 0x5d, 0x3c, 0x73, 0xfc, 0x1e, 0x00, 0x00, 0xff, 0xff, 0x47, 0x84,
0xeb, 0xce, 0x6c, 0x02, 0x00, 0x00,
}

View File

@@ -0,0 +1,26 @@
syntax = "proto3";
package ticket.service.item.v1;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option go_package = "v1";
// The response message containing the Item related time
message ItemTime {
int32 stime = 1 [(gogoproto.jsontag) = "stime"];
int32 etime = 2 [(gogoproto.jsontag) = "etime"];
}
// The response message containing the Screen related time
message ScreenTime {
int32 stime = 1 [(gogoproto.jsontag) = "stime", (gogoproto.moretags) = "validate:\"min=0\""];
int32 etime = 2 [(gogoproto.jsontag) = "etime", (gogoproto.moretags) = "validate:\"min=0\""];
int32 sale_stime = 3 [(gogoproto.jsontag) = "sales", (gogoproto.moretags) = "validate:\"min=0\""];
int32 sale_etime = 4 [(gogoproto.jsontag) = "salee", (gogoproto.moretags) = "validate:\"min=0\""];
}
// The response message containing the Ticket related time
message TicketTime {
int64 sale_stime = 1 [(gogoproto.jsontag) = "sales", (gogoproto.moretags) = "validate:\"min=0\""];
int64 sale_etime = 2 [(gogoproto.jsontag) = "salee", (gogoproto.moretags) = "validate:\"min=0\""];
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,65 @@
syntax = "proto3";
package ticket.service.item.v1;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
import "app/service/openplatform/ticket-item/api/grpc/v1/place.proto";
option (gogoproto.goproto_enum_prefix_all) = false;
option (gogoproto.goproto_getters_all) = false;
option (gogoproto.unmarshaler_all) = true;
option (gogoproto.marshaler_all) = true;
option (gogoproto.sizer_all) = true;
option go_package = "v1";
// The venue service definition.
service Venue {
rpc VenueInfo (VenueInfoRequest) returns (VenueInfoReply) {}
}
// The response message containing the VenueInfo
message VenueInfo {
int64 id = 1 [(gogoproto.jsontag) = "id",(gogoproto.customname)= "ID"];
string name = 2 [(gogoproto.jsontag) = "name"];
int32 status= 3 [(gogoproto.jsontag) = "status"];
VenueAddrInfo addrInfo = 4 [(gogoproto.jsontag) = "addr"];
PlaceInfo place_info = 5 [(gogoproto.jsontag) = "place"];
}
// The response message containing the Venue location info
message VenueAddrInfo {
int64 province = 1 [(gogoproto.jsontag) = "provid"];
int64 city = 2 [(gogoproto.jsontag) = "cityid"];
int64 district = 3 [(gogoproto.jsontag) = "distid"];
string addressDetail = 4 [(gogoproto.jsontag) = "addr"];
string traffic = 5 [(gogoproto.jsontag) = "traff"];
string lon_lat_type = 6 [(gogoproto.jsontag) = "lonlat_type"];
string lonLat = 7 [(gogoproto.jsontag) = "lonlat"];
}
// venueInfo接口请求
message VenueInfoRequest {
// 待修改场馆的ID为0表示创建
int64 ID = 1 [(gogoproto.jsontag) = "id", (gogoproto.moretags) = "validate:\"min=0\""];
// 场馆名
string Name = 2 [(gogoproto.jsontag) = "name", (gogoproto.moretags) = "validate:\"max=25\""];
// 状态 1-启用 0-停用
int32 Status = 3 [(gogoproto.jsontag) = "status", (gogoproto.moretags) = "validate:\"min=0,max=1\""];
// 省份ID
int64 Province = 4 [(gogoproto.jsontag) = "provid", (gogoproto.moretags) = "validate:\"min=0\""];
// 城市ID
int64 City = 5 [(gogoproto.jsontag) = "cityid", (gogoproto.moretags) = "validate:\"min=0\""];
// 区县ID
int64 District = 6 [(gogoproto.jsontag) = "distid", (gogoproto.moretags) = "validate:\"min=0\""];
// 详细地址
string AddressDetail = 7 [(gogoproto.jsontag) = "addr", (gogoproto.moretags) = "validate:\"min=0,max=60\""];
// 交通信息
string Traffic = 8 [(gogoproto.jsontag) = "traff", (gogoproto.moretags) = "validate:\"min=0,max=100\""];
}
// venue接口返回
message VenueInfoReply {
// 操作结果
bool Success = 1 [(gogoproto.jsontag) = "success"];
// 操作场馆ID
int64 ID = 2 [(gogoproto.jsontag) = "id"];
}

View File

@@ -0,0 +1,44 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "cmd",
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
data = ["item.toml"],
importpath = "go-common/app/service/openplatform/ticket-item/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/openplatform/ticket-item/conf:go_default_library",
"//app/service/openplatform/ticket-item/server/grpc:go_default_library",
"//app/service/openplatform/ticket-item/server/http:go_default_library",
"//app/service/openplatform/ticket-item/service:go_default_library",
"//library/log:go_default_library",
"//library/net/trace: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,142 @@
# This is a TOML document. Boom.
version = "0.0.1"
user = "nobody"
pid = "/tmp/ticket-item.pid"
dir = "./"
family = "ticket-item"
perf="0.0.0.0:3014"
[log]
dir = "/tmp/golog/ticket-item/"
[db]
[db.master]
name = "172.16.33.203:3306"
dsn = "root:123456@tcp(172.16.33.203:3306)/tickets?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
# name = "172.22.34.101:3310"
# dsn = "ticket:i9HXWAvzWiqPxMxlfsQ8DRqYydjf3pYa@tcp(172.22.34.101:3310)/open_ticket?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 5
idleTimeout = "4h"
queryTimeout = "1s"
execTimeout = "1s"
tranTimeout = "1s"
[db.master.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[redis]
[redis.master]
name = "ticket-service"
proto = "tcp"
addr = "127.0.0.1:6379"
#addr = "172.16.33.203:6379"
idle = 10
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "10s"
[rpcServer]
addr = ':9301'
timeout = "3s"
[bm]
[bm.inner]
addr = "0.0.0.0:8801"
timeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
[bm.local]
addr = "0.0.0.0:8802"
timeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
[httpClient]
[httpClient.read]
key = "7c7ac0db1aa05587"
secret = "9a6d62d93290c5f771ad381e9ca23f26"
dial = "1s"
timeout = "4s"
keepAlive = "60s"
timer = 1000
[httpClient.read.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[httpClient.write]
key = "7c7ac0db1aa05587"
secret = "9a6d62d93290c5f771ad381e9ca23f26"
dial = "1s"
timeout = "3s"
keepAlive = "60s"
timer = 1000
[httpClient.write.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[app]
key = "7d9f6f6fe2a898e8"
secret = "test"
[identify]
whiteAccessKey = ""
whiteMid = 0
csrfOn = false
[identify.app]
key = "7d9f6f6fe2a898e8"
secret = "test"
[identify.host]
auth = "http://uat-passport.bilibili.co"
secret = "http://uat-open.bilibili.co"
[identify.httpClient]
key = "7d9f6f6fe2a898e8"
secret = "test"
dial = "30ms"
timeout = "100ms"
keepAlive = "60s"
[identify.httpClient.breaker]
window = "10s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[identify.httpClient.url]
"http://uat-passport.bilibili.co/intranet/auth/tokenInfo" = {timeout = "100ms"}
"http://uat-passport.bilibili.co/intranet/auth/cookieInfo" = {timeout = "100ms"}
"http://uat-open.bilibili.co/api/getsecret" = {timeout = "500ms"}
[orm]
dsn = "root:123456@tcp(172.16.33.203:3306)/tickets?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
#dsn = "ticket:i9HXWAvzWiqPxMxlfsQ8DRqYydjf3pYa@tcp(172.22.34.101:3310)/open_ticket?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 5
idleTimeout = "4h"
[ut]
distPrefix = "http://localhost:8801/x/internal/ticket/sales"
[url]
elasticHost = "http://uat-manager.bilibili.co"
defaultHead = "https://static.hdslb.com/images/member/noface.gif"
[baseCenter]
appId = "nBF6jpB7"
appToken = "XZUGqmAf1rRmu7l0dhogFIPPvveHOgSy2WtQ957JPeE="
url = "http://172.16.33.203/api/basecenter/"
[tag]
tags = "10001=漫展,10002=同人展,10003=漫展嘉年华,10004=游戏展,10005=见面会,10006=茶会,10007=展示会,10008=演唱会,10009=音乐会,10010=话剧,10011=比赛,10012=舞蹈,10013=画展,10014=乐园,10015=cosplay展,10016=only展,10017=古风展"

View File

@@ -0,0 +1,56 @@
package main
import (
"context"
"flag"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/service/openplatform/ticket-item/conf"
rpc "go-common/app/service/openplatform/ticket-item/server/grpc"
"go-common/app/service/openplatform/ticket-item/server/http"
"go-common/app/service/openplatform/ticket-item/service"
"go-common/library/log"
"go-common/library/net/trace"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
defer log.Close()
trace.Init(nil)
defer trace.Close()
log.Info("ticket-item start")
svr := service.New(conf.Conf)
// http Service init
http.Init(conf.Conf, svr)
// grpc service init
gsvr := rpc.New(conf.Conf)
// init pprof conf.Conf.Perf
// signal handler
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
defer cancel()
log.Info("ticket-item get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGSTOP, syscall.SIGINT:
svr.Close()
gsvr.Shutdown(ctx)
log.Info("ticket-item exit")
time.Sleep(time.Second) // 休眠10s
return
case syscall.SIGHUP:
// TODO reload
default:
return
}
}
}

View File

@@ -0,0 +1,41 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["conf.go"],
importpath = "go-common/app/service/openplatform/ticket-item/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/redis:go_default_library",
"//library/conf:go_default_library",
"//library/database/orm:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/auth:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/BurntSushi/toml:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,155 @@
package conf
import (
"errors"
"flag"
"go-common/library/cache/redis"
"go-common/library/conf"
"go-common/library/database/orm"
"go-common/library/database/sql"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/auth"
"go-common/library/net/http/blademaster/middleware/verify"
"go-common/library/net/rpc/warden"
"go-common/library/time"
"github.com/BurntSushi/toml"
)
var (
// Conf common conf
Conf = &Config{}
client *conf.Client
confPath string
)
// Config config struct
type Config struct {
// base
// 数据库配置
DB *DB
// redis
Redis *Redis
// http client
HTTPClient HTTPClient
// http
BM *HTTPServers
// grpc server
RPCServer *warden.ServerConfig
// log
Log *log.Config
// auth
Auth *auth.Config
Verify *verify.Config
// orm
ORM *orm.Config
// UT
UT *UT
// URL
URL *URL
// BASECenter
BASECenter *BASECenter
// Tag
Tag *Tag
}
// HTTPClient config
type HTTPClient struct {
Read *bm.ClientConfig
Write *bm.ClientConfig
}
// URL external resources
type URL struct {
ElasticHost string
DefaultHead string
}
// BASECenter config
type BASECenter struct {
AppID string
AppToken string
URL string
}
// HTTPServers Http Servers
type HTTPServers struct {
Inner *bm.ServerConfig
Local *bm.ServerConfig
}
// Redis config
type Redis struct {
Master *redis.Config
Expire time.Duration
}
// DB config
type DB struct {
Master *sql.Config
}
// UT config
type UT struct {
DistPrefix string
}
// Tag config
type Tag struct {
Tags string
}
func local() (err error) {
_, err = toml.DecodeFile(confPath, &Conf)
return
}
func remote() (err error) {
if client, err = conf.New(); err != nil {
return
}
if err = load(); err != nil {
return
}
go func() {
for range client.Event() {
log.Info("config event")
}
}()
return
}
func load() (err error) {
var (
s string
ok bool
tmpConf *Config
)
if s, ok = client.Value("item.toml"); !ok {
return errors.New("load config center error")
}
if _, err = toml.Decode(s, &tmpConf); err != nil {
return errors.New("could not decode config")
}
*Conf = *tmpConf
return
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init init config
func Init() error {
if confPath == "" {
return remote()
}
return local()
}

View File

@@ -0,0 +1,92 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"bulletin_test.go",
"dao_test.go",
"guest_test.go",
"item_test.go",
"promotion_test.go",
"screen_test.go",
"seat_test.go",
"stock_test.go",
"tag_test.go",
"ticket_test.go",
"venue_test.go",
"version_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/openplatform/ticket-item/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-item/conf:go_default_library",
"//app/service/openplatform/ticket-item/model:go_default_library",
"//library/log:go_default_library",
"//vendor/github.com/davecgh/go-spew/spew:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"banner.go",
"bulletin.go",
"dao.cache.go",
"dao.go",
"fav.go",
"guest.go",
"item.go",
"project.go",
"promotion.go",
"screen.go",
"seat.go",
"stock.go",
"tag.go",
"ticket.go",
"venue.go",
"version.go",
"wish.go",
],
importpath = "go-common/app/service/openplatform/ticket-item/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/common/openplatform/random:go_default_library",
"//app/service/openplatform/ticket-item/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-item/conf:go_default_library",
"//app/service/openplatform/ticket-item/model:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/elastic:go_default_library",
"//library/database/orm:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/stat/prom:go_default_library",
"//library/sync/pipeline/fanout:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/jinzhu/gorm: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,526 @@
package dao
import (
"context"
"encoding/json"
"fmt"
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/time"
"strconv"
"strings"
xtime "time"
"github.com/jinzhu/gorm"
)
// DelBannerInfo 删除缓存所需banner信息
type DelBannerInfo struct {
Order int32
Position int32
SubPosition int32
DistrictIDs []string
}
// AddBanner 添加新投放
func (d *Dao) AddBanner(c context.Context, info *item.BannerEditRequest) (bannerID int64, verID uint64, err error) {
// 开启事务
tx := d.db.Begin()
//创建banner信息
banner := model.Banner{
PubStart: time.Time(info.PubStart),
PubEnd: time.Time(info.PubEnd),
Name: info.Name,
Pic: info.Pic,
URL: info.Url,
From: info.From,
TargetUser: info.TargetUser,
}
if err = tx.Create(&banner).Error; err != nil {
log.Error("创建banner失败:%s", err)
tx.Rollback()
return 0, 0, err
}
bannerID = banner.ID
if bannerID == 0 {
log.Error("bannerID为0")
tx.Rollback()
return 0, 0, err
}
var mainInfo []byte
mainInfo, err = json.Marshal(info)
if err != nil {
log.Error("jsonMarshal版本详情失败:%s", err)
tx.Rollback()
return bannerID, 0, err
}
//生成新审核版本ver,verExt
str := fmt.Sprintf("%d%d%.2d", info.Position, info.SubPosition, info.Order)
forInt, _ := strconv.ParseInt(str, 10, 64)
verInfo := model.Version{
Type: model.VerTypeBanner,
Status: info.OpType,
ItemName: info.Name,
TargetItem: bannerID,
AutoPub: 1, // 自动上架
PubStart: time.Time(info.PubStart),
PubEnd: time.Time(info.PubEnd),
For: forInt,
}
err = d.AddVersion(c, tx, &verInfo, &model.VersionExt{
Type: model.VerTypeBanner,
MainInfo: string(mainInfo),
})
if err != nil {
log.Error("创建banner版本失败: %s", err)
return 0, verInfo.VerID, ecode.TicketAddVersionFailed
}
if verInfo.VerID == 0 {
log.Error("创建后获取verID为0")
return 0, verInfo.VerID, ecode.TicketAddVersionFailed
}
// 提交事务
tx.Commit()
return bannerID, verInfo.VerID, nil
}
// EditBanner 编辑投放
func (d *Dao) EditBanner(c context.Context, info *item.BannerEditRequest) (err error) {
// 开启事务
tx := d.db.Begin()
var mainInfo []byte
mainInfo, err = json.Marshal(info)
if err != nil {
log.Error("jsonMarshal版本详情失败:%s", err)
tx.Rollback()
return err
}
//更新审核版本ver,verExt
str := fmt.Sprintf("%d%d%.2d", info.Position, info.SubPosition, info.Order)
forInt, _ := strconv.ParseInt(str, 10, 64)
if err = tx.Model(&model.Version{}).Where("ver_id = ?", info.VerId).Updates(
map[string]interface{}{
"item_name": info.Name,
"status": info.OpType,
"pub_start": time.Time(info.PubStart),
"pub_end": time.Time(info.PubEnd),
"for": forInt,
}).Error; err != nil {
log.Error("更新banner版本失败:%s", err)
tx.Rollback()
return err
}
if err = tx.Model(&model.VersionExt{}).Where("ver_id = ?", info.VerId).Updates(
map[string]interface{}{
"main_info": mainInfo,
}).Error; err != nil {
log.Error("更新banner版本详情失败:%s", err)
tx.Rollback()
return err
}
// 提交事务
tx.Commit()
return nil
}
// PassOrPublishBanner 审核通过或上架banner版本
func (d *Dao) PassOrPublishBanner(c context.Context, verID uint64) (err error) {
//获取版本信息
verInfo, verExtInfo, getErr := d.GetVersion(c, verID, true)
if getErr != nil {
return getErr
}
//解析mainInfo
var decodedMainInfo item.BannerEditRequest
err = json.Unmarshal([]byte(verExtInfo.MainInfo), &decodedMainInfo)
if err != nil {
return err
}
bannerID := verInfo.TargetItem
tx := d.db.Begin()
//如果存在审核通过/进行中版本 删除版本
var bannerVersions []model.Version
if err = tx.Where("target_item = ? and status in (?) and ver_id != ? and deleted_at='0000-00-00 00:00:00'",
bannerID, []int32{model.VerStatusReadyForSale, model.VerStatusOnShelf}, verID).Find(&bannerVersions).Error; err != nil {
log.Error("获取banner所有审核通过/已上架版本失败:%s", err)
tx.Rollback()
return err
}
var delCacheInfos []DelBannerInfo
var verIDs []uint64
var delPosition int32
var delSubPosition int32
var delOrder int32
var delDistrictIDs []string
for _, v := range bannerVersions {
//获取该版本详情 删除对应bannerDistrict信息
if delPosition, delSubPosition, delOrder, delDistrictIDs, err = d.DelBannerDistrictByVerID(c, tx, v.VerID, bannerID); err != nil {
return
}
delCacheInfos = append(delCacheInfos, DelBannerInfo{
Order: delOrder,
Position: delPosition,
SubPosition: delSubPosition,
DistrictIDs: delDistrictIDs,
})
verIDs = append(verIDs, v.VerID)
}
if verIDs != nil {
if err = tx.Exec("UPDATE version SET deleted_at=? WHERE ver_id in (?)", xtime.Now().Format("2006-01-02 15:04:05"), verIDs).Error; err != nil {
log.Error("删除banner版本失败:%s", err)
tx.Rollback()
return err
}
if err = tx.Exec("UPDATE version_ext SET deleted_at=? WHERE ver_id in (?)", xtime.Now().Format("2006-01-02 15:04:05"), verIDs).Error; err != nil {
log.Error("删除banner ext版本失败:%s", err)
tx.Rollback()
return err
}
}
//如果达到投放开始时间 还要更新bannerDistrict并直接上架
var newVerStatus int32
var newBannerStatus int32
var districtIDs []string
if decodedMainInfo.PubStart <= xtime.Now().Unix() {
districtIDs = strings.Split(decodedMainInfo.Location, ",")
for _, districtID := range districtIDs {
newDistrictID, _ := strconv.ParseInt(districtID, 10, 64)
if err = d.CreateOrUpdateBannerDistrict(c, tx, model.BannerDistrict{
BannerID: bannerID,
Position: decodedMainInfo.Position,
SubPosition: decodedMainInfo.SubPosition,
Order: decodedMainInfo.Order,
DistrictID: newDistrictID,
}); err != nil {
return err
}
}
newVerStatus = model.VerStatusOnShelf
newBannerStatus = 1
} else {
newVerStatus = model.VerStatusReadyForSale
newBannerStatus = 0
}
//更新banner表
if err = tx.Model(&model.Banner{}).Where("id = ?", bannerID).Updates(
map[string]interface{}{
"pub_start": time.Time(decodedMainInfo.PubStart),
"pub_end": time.Time(decodedMainInfo.PubEnd),
"name": decodedMainInfo.Name,
"pic": decodedMainInfo.Pic,
"url": decodedMainInfo.Url,
"from": decodedMainInfo.From,
"status": newBannerStatus,
"target_user": decodedMainInfo.TargetUser,
}).Error; err != nil {
log.Error("更新banner失败:%s", err)
tx.Rollback()
return err
}
//更新version状态为审核通过(待上架)或已上架
if err = tx.Model(&model.Version{}).Where("ver_id = ?", verID).Updates(
map[string]interface{}{
"status": newVerStatus,
}).Error; err != nil {
log.Error("更新banner审核版本失败:%s", err)
tx.Rollback()
return err
}
tx.Commit()
//如果新状态是上架状态 删除相关缓存
if newVerStatus == model.VerStatusOnShelf {
_, err = d.DelBannerCache(c, decodedMainInfo.Position, decodedMainInfo.SubPosition, decodedMainInfo.Order, districtIDs, bannerID)
if err != nil {
return
}
for _, v := range delCacheInfos {
_, err = d.DelBannerCache(c, v.Position, v.SubPosition, v.Order, v.DistrictIDs, 0)
if err != nil {
return
}
}
}
return
}
// DelBannerCache 删除banner相关缓存
func (d *Dao) DelBannerCache(c context.Context, position int32, subPosition int32, order int32, districtIDs []string, bannerID int64) (res bool, err error) {
var (
keys []interface{}
)
conn := d.redis.Get(c)
defer func() {
conn.Flush()
conn.Close()
}()
for _, districtID := range districtIDs {
// DEL bannerList
keys = append(keys, keyBannerList(order, districtID, position, subPosition))
}
//删除bannerInfo缓存
if bannerID != 0 {
keys = append(keys, keyBannerInfo(bannerID))
}
log.Info("DEL %v", keys)
//DEL bannerList
if err = conn.Send("DEL", keys...); err != nil {
log.Error("DEL %v, error(%v)", keys, err)
}
if err != nil {
return false, err
}
return true, err
}
//DelBannerDistrictByVerID 删除版本详情内对应的关系表信息
func (d *Dao) DelBannerDistrictByVerID(c context.Context, tx *gorm.DB, verID uint64, bannerID int64) (position int32, subPosition int32, order int32, districtIDs []string, err error) {
var verExtInfo model.VersionExt
var delDecodedInfo item.BannerEditRequest
//获取该版本详情 删除对应bannerDistrict信息
if err = tx.Where("ver_id = ?", verID).First(&verExtInfo).Error; err != nil {
log.Error("获取需要删除版本详情失败:%s", err)
tx.Rollback()
return 0, 0, 0, nil, err
}
//解析mainInfo
err = json.Unmarshal([]byte(verExtInfo.MainInfo), &delDecodedInfo)
if err != nil {
tx.Rollback()
return 0, 0, 0, nil, err
}
districtIDs = strings.Split(delDecodedInfo.Location, ",")
for _, districtID := range districtIDs {
if err = tx.Exec("UPDATE banner_district SET is_deleted=1 WHERE banner_id = ? and district_id = ? and position = ? and sub_position = ? and `order` = ?",
bannerID, districtID, delDecodedInfo.Position, delDecodedInfo.SubPosition, delDecodedInfo.Order).Error; err != nil {
log.Error("删除bannerDistrict失败:%s", err)
tx.Rollback()
return 0, 0, 0, nil, err
}
}
return delDecodedInfo.Position, delDecodedInfo.SubPosition, delDecodedInfo.Order, districtIDs, err
}
// CreateOrUpdateBannerDistrict 更新或新建bannerDistrict关系记录
func (d *Dao) CreateOrUpdateBannerDistrict(c context.Context, tx *gorm.DB, info model.BannerDistrict) (err error) {
var bannerDist model.BannerDistrict
log.Info("bannerDist:%v", info)
err = tx.Where("district_id = ? and position = ? and sub_position = ? and `order` = ?",
info.DistrictID, info.Position, info.SubPosition, info.Order).First(&bannerDist).Error
//除去没查找到记录的报错 其他直接抛错
if err != nil && err != ecode.NothingFound {
log.Error("获取banner dist信息失败:%s", err)
tx.Rollback()
return
}
if bannerDist.ID != 0 {
//update
log.Info("update bannerDistrict")
if err = tx.Exec("UPDATE banner_district SET banner_id=?,is_deleted=0 WHERE district_id = ? and position = ? and sub_position = ? and `order` = ?",
info.BannerID, info.DistrictID, info.Position, info.SubPosition, info.Order).Error; err != nil {
log.Error("更新bannerDistrict失败:%s", err)
tx.Rollback()
return err
}
} else {
//create
log.Info("insert bannerDistrict")
if err = tx.Create(&model.BannerDistrict{
BannerID: info.BannerID,
Position: info.Position,
SubPosition: info.SubPosition,
Order: info.Order,
DistrictID: info.DistrictID,
}).Error; err != nil {
log.Error("创建bannerDistrict失败:%s", err)
tx.Rollback()
return err
}
}
return nil
}
// DeleteBanner 删除banner
func (d *Dao) DeleteBanner(c context.Context, verID uint64) (err error) {
tx := d.db.Begin()
if err = tx.Exec("UPDATE version SET deleted_at=? WHERE ver_id = ?", xtime.Now().Format("2006-01-02 15:04:05"), verID).Error; err != nil {
tx.Rollback()
log.Error("删除banner版本失败:%s", err)
return err
}
if err = tx.Exec("UPDATE version_ext SET deleted_at=? WHERE ver_id=?", xtime.Now().Format("2006-01-02 15:04:05"), verID).Error; err != nil {
tx.Rollback()
log.Error("删除banner ext版本失败:%s", err)
return err
}
tx.Commit()
return
}
// UnpublishBannerManual 手动取消激活banner
func (d *Dao) UnpublishBannerManual(c context.Context, verID uint64) (err error) {
//取消激活banner
//获取版本信息
tx := d.db.Begin()
verInfo, _, getErr := d.GetVersion(c, verID, true)
if getErr != nil {
return getErr
}
bannerID := verInfo.TargetItem
if err = tx.Exec("UPDATE banner SET status = 0 WHERE id = ?", bannerID).Error; err != nil {
tx.Rollback()
log.Error("更新banner未激活状态失败:%s", err)
return err
}
//更新版本为草稿状态
if err = tx.Exec("UPDATE version SET status = ? WHERE ver_id = ?", model.VerStatusNotReviewed, verID).Error; err != nil {
tx.Rollback()
log.Error("更新banner版本为草稿状态失败:%s", err)
return err
}
//删除此版本bannerDistrict信息
var delPosition int32
var delSubPosition int32
var delOrder int32
var delDistrictIDs []string
if delPosition, delSubPosition, delOrder, delDistrictIDs, err = d.DelBannerDistrictByVerID(c, tx, verID, bannerID); err != nil {
return
}
//如果存在除这个版本以外同个投放id的版本 删除版本
var bannerVersions []model.Version
if err = tx.Where("target_item = ? and ver_id != ? and deleted_at='0000-00-00 00:00:00'",
bannerID, verID).Find(&bannerVersions).Error; err != nil {
log.Error("获取banner所有其他版本失败:%s", err)
tx.Rollback()
return err
}
var verIDs []uint64
for _, v := range bannerVersions {
//获取该版本详情 删除对应bannerDistrict信息
_, _, _, _, err = d.DelBannerDistrictByVerID(c, tx, v.VerID, bannerID)
if err != nil {
return
}
verIDs = append(verIDs, v.VerID)
}
if verIDs != nil {
if err = tx.Exec("UPDATE version SET deleted_at=? WHERE ver_id in (?)", xtime.Now().Format("2006-01-02 15:04:05"), verIDs).Error; err != nil {
log.Error("删除banner版本失败:%s", err)
tx.Rollback()
return err
}
if err = tx.Exec("UPDATE version_ext SET deleted_at=? WHERE ver_id in (?)", xtime.Now().Format("2006-01-02 15:04:05"), verIDs).Error; err != nil {
log.Error("删除banner ext版本失败:%s", err)
tx.Rollback()
return err
}
}
tx.Commit()
//删除下架相关缓存
_, err = d.DelBannerCache(c, delPosition, delSubPosition, delOrder, delDistrictIDs, bannerID)
return
}
// UnpublishBannerForced 已过期自动下架操作
func (d *Dao) UnpublishBannerForced(c context.Context, verID uint64) (err error) {
//获取版本信息
tx := d.db.Begin()
verInfo, _, getErr := d.GetVersion(c, verID, true)
if getErr != nil {
return getErr
}
//取消激活banner
bannerID := verInfo.TargetItem
if err = tx.Exec("UPDATE banner SET status = 0 WHERE id = ?", bannerID).Error; err != nil {
tx.Rollback()
log.Error("更新banner未激活状态失败:%s", err)
return err
}
//删除bannerDistrict信息
var delPosition int32
var delSubPosition int32
var delOrder int32
var delDistrictIDs []string
if delPosition, delSubPosition, delOrder, delDistrictIDs, err = d.DelBannerDistrictByVerID(c, tx, verID, bannerID); err != nil {
return
}
//更新版本为强制下架状态
if err = tx.Exec("UPDATE version SET status = ? WHERE ver_id = ?", model.VerStatusOffShelfForced, verID).Error; err != nil {
tx.Rollback()
log.Error("更新banner版本为强制下架状态失败:%s", err)
return err
}
tx.Commit()
//删除下架相关缓存
_, err = d.DelBannerCache(c, delPosition, delSubPosition, delOrder, delDistrictIDs, bannerID)
return
}
// CgBannerStatus 更改banner版本状态
func (d *Dao) CgBannerStatus(c context.Context, info *item.VersionStatusRequest) (err error) {
switch info.OpType {
case 0:
//手动取消激活操作
err = d.UnpublishBannerManual(c, info.VerId)
case 1:
//提交审核操作
err = d.db.Exec("UPDATE version SET status = ? WHERE ver_id = ?", model.VerStatusReadyForReview, info.VerId).Error
if err != nil {
return err
}
//提交审核时 记入versionLog
err = d.AddVersionLog(c, &model.VersionLog{
VerID: info.VerId,
Type: 2, //用户操作记录
Log: "提交审核",
Uname: info.Uname,
})
case 2:
//删除操作
err = d.DeleteBanner(c, info.VerId)
case 3:
//上架操作
err = d.PassOrPublishBanner(c, info.VerId)
case 4:
//已过期自动下架操作
err = d.UnpublishBannerForced(c, info.VerId)
default:
return ecode.NothingFound
}
return
}

View File

@@ -0,0 +1,305 @@
package dao
import (
"context"
"encoding/json"
"go-common/app/common/openplatform/random"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/ecode"
"go-common/library/log"
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
)
// BulletinMainInfo 公告版本内容
type BulletinMainInfo struct {
Name string `json:"name"`
Introduction string `json:"introduction"`
Content string `json:"content"`
ProjectName string `json:"project_name"`
Pid int64 `json:"pid"`
}
// GetBulletins 获取项目下所有公告
func (d *Dao) GetBulletins(c context.Context, pid int64) (res []*item.BulletinInfo, err error) {
// 获取项目下所有bulletin基础信息
var projectBulletins []*model.Bulletin
if dbErr := d.db.Order("ctime desc").Where("project_id = ? and status = 1", pid).Find(&projectBulletins).Error; dbErr != nil {
log.Error("获取项目公告基础信息失败: %s", dbErr)
return nil, ecode.NothingFound
}
var bulIDs []int64
for _, value := range projectBulletins {
bulIDs = append(bulIDs, value.ID)
}
// 获取公告详情并用id当键值组成map
var bulletinDetail []*model.BulletinExtra
if dbErr := d.db.Where("id in (?)", bulIDs).Find(&bulletinDetail).Error; dbErr != nil {
log.Error("获取项目公告详情失败: %s", dbErr)
return nil, ecode.NothingFound
}
bulletinDetailMap := make(map[int64]*model.BulletinExtra)
for _, value := range bulletinDetail {
bulletinDetailMap[value.ID] = value
}
// 添加详情信息到公告信息中
for _, value := range projectBulletins {
tmpBul := &item.BulletinInfo{
ID: value.ID,
Title: value.Title,
Content: value.Content,
Ctime: value.Ctime.Time().Format("2006-01-02 15:04:05"),
Mtime: value.Mtime.Time().Format("2006-01-02 15:04:05"),
VerID: value.VerID,
}
detailInfo, ok := bulletinDetailMap[value.ID]
if ok {
tmpBul.Detail = detailInfo.Detail
} else {
tmpBul.Detail = ""
}
res = append(res, tmpBul)
}
return
}
// AddBulletin 添加公告
func (d *Dao) AddBulletin(c context.Context, info *item.BulletinInfoRequest) (bool, error) {
pid := info.ParentID
mainInfo, jsonErr := d.GenBulMainInfo(pid, info.Title, info.Content, info.Detail)
if jsonErr != nil {
log.Error("获取整合maininfo失败: %s", jsonErr)
return false, ecode.NothingFound
}
// add version and version ext
verErr := d.AddVersion(c, nil, &model.Version{
Type: model.VerTypeBulletin,
Status: 1, // 审核中
ItemName: info.Title,
ParentID: pid,
TargetItem: info.TargetItem,
AutoPub: 1, // 自动上架
PubStart: model.TimeNull,
PubEnd: model.TimeNull,
}, &model.VersionExt{
Type: model.VerTypeBulletin,
MainInfo: string(mainInfo),
})
if verErr != nil {
log.Error("创建公告版本失败: %s", verErr)
return false, ecode.NothingFound
}
return true, nil
}
// PassBulletin 审核通过公告
func (d *Dao) PassBulletin(c context.Context, verID uint64) (bool, error) {
verInfo, verExtInfo, err := d.GetVersion(c, verID, true)
if err != nil {
return false, ecode.NothingFound
}
targetItem := verInfo.TargetItem
var decodedMainInfo BulletinMainInfo
err = json.Unmarshal([]byte(verExtInfo.MainInfo), &decodedMainInfo)
if err != nil {
return false, err
}
var finalTargetItem int64
// 开启事务
tx := d.db.Begin()
if targetItem == 0 {
// 没新建过bulletin信息
bulletinID := random.Uniqid(19)
bulData := &model.Bulletin{
Status: 1,
Title: decodedMainInfo.Name,
Content: decodedMainInfo.Introduction,
ProjectID: decodedMainInfo.Pid,
VerID: verID,
BulletinID: bulletinID,
}
insertErr := tx.Save(&bulData).Error
if insertErr != nil {
tx.Rollback()
log.Error("新建bulletin失败: %s", insertErr)
return false, ecode.NotModified
}
// 获取新建的bulletin自增id
bulPrimID := bulData.ID
if bulPrimID == 0 {
tx.Rollback()
log.Error("获取新建bulletin自增id失败")
return false, ecode.NothingFound
}
// 新建bulletin_extra
insertExtErr := tx.Create(&model.BulletinExtra{
ID: bulPrimID,
Detail: decodedMainInfo.Content,
BulletinID: bulletinID,
}).Error
if insertExtErr != nil {
tx.Rollback()
log.Error("新建bulletin_extra失败%s", insertExtErr)
return false, ecode.NotModified
}
finalTargetItem = bulPrimID
} else {
// 已建过的直接更新bulletin
updateErr := tx.Where("id = ?", targetItem).Model(&model.Bulletin{}).Updates(
map[string]interface{}{
"status": 1,
"title": decodedMainInfo.Name,
"content": decodedMainInfo.Introduction,
"ver_id": verID,
}).Error
if updateErr != nil {
tx.Rollback()
log.Error("UPDATE BULLETIN FAILED")
return false, ecode.NotModified
}
// 更新bulletin_extra
updateExtErr := tx.Where("id = ?", targetItem).Model(&model.BulletinExtra{}).Updates(
map[string]interface{}{
"detail": decodedMainInfo.Content,
}).Error
if updateExtErr != nil {
tx.Rollback()
log.Error("UPDATE BULLETIN_EXTRA FAILED")
return false, ecode.NotModified
}
finalTargetItem = targetItem
}
// 更新版本为已审核状态
updateVerErr := tx.Where("ver_id = ?", verID).Model(&model.Version{}).Updates(
map[string]interface{}{
"status": 4, // 已上架状态
"ver": "1.0",
"target_item": finalTargetItem,
}).Error
if updateVerErr != nil {
tx.Rollback()
log.Error("UPDATE BULLETIN VERSION FAILED")
return false, ecode.NotModified
}
tx.Commit()
return true, nil
}
// UpdateBulletin 编辑公告版本
func (d *Dao) UpdateBulletin(c context.Context, info *item.BulletinInfoRequest) (bool, error) {
// 获取JSONEncode好的maininfo
pid := info.ParentID
mainInfo, jsonErr := d.GenBulMainInfo(pid, info.Title, info.Content, info.Detail)
if jsonErr != nil || mainInfo == "" {
log.Error("获取maininfo失败: %s", jsonErr)
return false, ecode.NothingFound
}
// 开启事务
tx := d.db.Begin()
// 编辑version_ext
updateExtErr := tx.Model(&model.VersionExt{}).Where("ver_id = ? and type = ?", info.VerID, model.VerTypeBulletin).Update("main_info", mainInfo).Error
if updateExtErr != nil {
tx.Rollback()
log.Error("更新versionext失败:%s", updateExtErr)
return false, ecode.NotModified
}
// 编辑version
updateErr := d.db.Model(&model.Version{}).Where("ver_id = ? and type = ?", info.VerID, model.VerTypeBulletin).Updates(
map[string]interface{}{
"status": 1, // 审核中
"item_name": info.Title,
}).Error
if updateErr != nil {
tx.Rollback()
log.Error("VERSION UPDATE FAILED:%s", updateErr)
return false, ecode.NotModified
}
tx.Commit()
return true, nil
}
// GenBulMainInfo 整合公告的详情maininfo字段
func (d *Dao) GenBulMainInfo(pid int64, name string, introduction string, content string) (string, error) {
var projectInfo []model.Item
if dbErr := d.db.Select("name").Where("id = ?", pid).Find(&projectInfo).Error; dbErr != nil {
log.Error("获取项目信息失败:%s", dbErr)
return "", ecode.NothingFound
}
extInfo := BulletinMainInfo{
Name: name,
Introduction: introduction,
Content: content,
ProjectName: projectInfo[0].Name,
Pid: pid,
}
mainInfo, jsonErr := json.Marshal(extInfo)
if jsonErr != nil {
log.Error("JSONEncode失败: %s", jsonErr)
return "", ecode.NothingFound
}
return string(mainInfo), nil
}
// UnpublishBulletin 下架版本
func (d *Dao) UnpublishBulletin(c context.Context, verID uint64, status int8) (bool, error) {
// 获取版本信息
verInfo, _, err := d.GetVersion(c, verID, false)
if err != nil {
return false, ecode.NothingFound
}
bulletinID := verInfo.TargetItem
// 开启事务
tx := d.db.Begin()
// 取消激活公告
updateErr := tx.Model(&model.Bulletin{}).Where("id = ? and ver_id = ?", bulletinID, verID).Updates(
map[string]interface{}{
"status": 0,
}).Error
if updateErr != nil {
tx.Rollback()
log.Error("取消激活公告失败:%s", updateErr)
return false, ecode.NotModified
}
// 更新版本为已下架状态
updateVerErr := tx.Model(&model.Version{}).Where("ver_id = ? and type = ?", verID, model.VerTypeBulletin).Updates(
map[string]interface{}{
"status": status,
}).Error
if updateVerErr != nil {
tx.Rollback()
log.Error("版本更新状态失败:%s", updateVerErr)
}
tx.Commit()
return true, nil
}

View File

@@ -0,0 +1,73 @@
package dao
import (
"context"
"testing"
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
. "github.com/smartystreets/goconvey/convey"
)
// TestGetBulletins
func TestDao_GetBulletins(t *testing.T) {
Convey("GetBulletins", t, func() {
once.Do(startService)
res, err := d.GetBulletins(context.TODO(), 72)
So(res, ShouldNotBeNil)
So(err, ShouldBeNil)
})
}
// TestAddBulletin
func TestDao_AddBulletin(t *testing.T) {
Convey("AddBulletin", t, func() {
once.Do(startService)
res, err := d.AddBulletin(context.TODO(), &item.BulletinInfoRequest{
ParentID: 72,
Title: "go test bulletin",
Content: "goooo",
Detail: "goo",
TargetItem: 0,
})
So(res, ShouldBeTrue)
So(err, ShouldBeNil)
})
}
// TestUpdateBulletin
func TestDao_UpdateBulletin(t *testing.T) {
Convey("UpdateBulletin", t, func() {
once.Do(startService)
res, err := d.UpdateBulletin(context.TODO(), &item.BulletinInfoRequest{
ParentID: 72,
Title: "go test bulletin22",
Content: "gooossso",
Detail: "goo",
TargetItem: 0,
VerID: 2692936350844594047,
})
So(res, ShouldBeTrue)
So(err, ShouldBeNil)
})
}
// TestPassBulletin
func TestDao_PassBulletin(t *testing.T) {
Convey("PassBulletin", t, func() {
once.Do(startService)
res, err := d.PassBulletin(context.TODO(), 2692936350844594047)
So(res, ShouldBeTrue)
So(err, ShouldBeNil)
})
}
// TestUnpublishBulletin
func TestDao_UnpublishBulletin(t *testing.T) {
Convey("UnpublishBulletin", t, func() {
once.Do(startService)
res, err := d.UnpublishBulletin(context.TODO(), 2692936350844594047, -1)
So(res, ShouldBeTrue)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,441 @@
// 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.Item{ID:-1} -check_null_code=$!=nil&&$.ID==-1
Items(c context.Context, pid []int64) (info map[int64]*model.Item, err error)
// cache: -nullcache=&model.ItemDetail{ProjectID:-1} -check_null_code=$!=nil&&$.ProjectID==-1
ItemDetails(c context.Context, pid []int64) (details map[int64]*model.ItemDetail, err error)
// cache: -nullcache=[]*model.TicketInfo{{TicketPrice:model.TicketPrice{ProjectID:-1}}} -check_null_code=len($)==1&&$[0].ProjectID==-1
TkListByItem(c context.Context, pid []int64) (info map[int64][]*model.TicketInfo, err error)
// cache: -nullcache=&model.Venue{ID:-1} -check_null_code=$!=nil&&$.ID==-1
Venues(c context.Context, id []int64) (venues map[int64]*model.Venue, err error)
// cache: -nullcache=&model.Place{ID:-1} -check_null_code=$!=nil&&$.ID==-1
Place(c context.Context, id int64) (place *model.Place, err error)
// cache: -nullcache=[]*model.Screen{{ProjectID:-1}} -check_null_code=len($)==1&&$[0].ProjectID==-1
ScListByItem(c context.Context, pid []int64) (info map[int64][]*model.Screen, err error)
// cache: -nullcache=&model.Screen{ProjectID:-1} -check_null_code=$!=nil&&$.ProjectID==-1
ScList(c context.Context, sids []int64) (info map[int64]*model.Screen, err error)
// cache: -nullcache=&model.TicketInfo{TicketPrice:model.TicketPrice{ProjectID:-1}} -check_null_code=$!=nil&&$.ProjectID==-1
TkList(c context.Context, tids []int64) (info map[int64]*model.TicketInfo, err error)
}
*/
package dao
import (
"context"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/stat/prom"
)
var _ _cache
// Items get data from cache if miss will call source method, then add to cache.
func (d *Dao) Items(c context.Context, keys []int64) (res map[int64]*model.Item, err error) {
if len(keys) == 0 {
return
}
addCache := true
if res, err = d.CacheItems(c, keys); 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("Items", int64(len(keys)-len(miss)))
for k, v := range res {
if v != nil && v.ID == -1 {
delete(res, k)
}
}
missLen := len(miss)
if missLen == 0 {
return
}
var missData map[int64]*model.Item
prom.CacheMiss.Add("Items", int64(len(miss)))
missData, err = d.RawItems(c, miss)
if res == nil {
res = make(map[int64]*model.Item, len(keys))
}
for k, v := range missData {
res[k] = v
}
if err != nil {
return
}
for _, key := range miss {
if res[key] == nil {
missData[key] = &model.Item{ID: -1}
}
}
if !addCache {
return
}
d.cache.Do(c, func(c context.Context) {
d.AddCacheItems(c, missData)
})
return
}
// ItemDetails get data from cache if miss will call source method, then add to cache.
func (d *Dao) ItemDetails(c context.Context, keys []int64) (res map[int64]*model.ItemDetail, err error) {
if len(keys) == 0 {
return
}
addCache := true
if res, err = d.CacheItemDetails(c, keys); 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("ItemDetails", int64(len(keys)-len(miss)))
for k, v := range res {
if v != nil && v.ProjectID == -1 {
delete(res, k)
}
}
missLen := len(miss)
if missLen == 0 {
return
}
var missData map[int64]*model.ItemDetail
prom.CacheMiss.Add("ItemDetails", int64(len(miss)))
missData, err = d.RawItemDetails(c, miss)
if res == nil {
res = make(map[int64]*model.ItemDetail, len(keys))
}
for k, v := range missData {
res[k] = v
}
if err != nil {
return
}
for _, key := range miss {
if res[key] == nil {
missData[key] = &model.ItemDetail{ProjectID: -1}
}
}
if !addCache {
return
}
d.cache.Do(c, func(c context.Context) {
d.AddCacheItemDetails(c, missData)
})
return
}
// TkListByItem get data from cache if miss will call source method, then add to cache.
func (d *Dao) TkListByItem(c context.Context, keys []int64) (res map[int64][]*model.TicketInfo, err error) {
if len(keys) == 0 {
return
}
addCache := true
if res, err = d.CacheTkListByItem(c, keys); 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("TkListByItem", int64(len(keys)-len(miss)))
for k, v := range res {
if len(v) == 1 && v[0].ProjectID == -1 {
delete(res, k)
}
}
missLen := len(miss)
if missLen == 0 {
return
}
var missData map[int64][]*model.TicketInfo
prom.CacheMiss.Add("TkListByItem", int64(len(miss)))
missData, err = d.RawTkListByItem(c, miss)
if res == nil {
res = make(map[int64][]*model.TicketInfo, len(keys))
}
for k, v := range missData {
res[k] = v
}
if err != nil {
return
}
for _, key := range miss {
if len(res[key]) == 0 {
missData[key] = []*model.TicketInfo{{TicketPrice: model.TicketPrice{ProjectID: -1}}}
}
}
if !addCache {
return
}
d.cache.Do(c, func(c context.Context) {
d.AddCacheTkListByItem(c, missData)
})
return
}
// Venues get data from cache if miss will call source method, then add to cache.
func (d *Dao) Venues(c context.Context, keys []int64) (res map[int64]*model.Venue, err error) {
if len(keys) == 0 {
return
}
addCache := true
if res, err = d.CacheVenues(c, keys); 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("Venues", int64(len(keys)-len(miss)))
for k, v := range res {
if v != nil && v.ID == -1 {
delete(res, k)
}
}
missLen := len(miss)
if missLen == 0 {
return
}
var missData map[int64]*model.Venue
prom.CacheMiss.Add("Venues", int64(len(miss)))
missData, err = d.RawVenues(c, miss)
if res == nil {
res = make(map[int64]*model.Venue, len(keys))
}
for k, v := range missData {
res[k] = v
}
if err != nil {
return
}
for _, key := range miss {
if res[key] == nil {
missData[key] = &model.Venue{ID: -1}
}
}
if !addCache {
return
}
d.cache.Do(c, func(c context.Context) {
d.AddCacheVenues(c, missData)
})
return
}
// Place get data from cache if miss will call source method, then add to cache.
func (d *Dao) Place(c context.Context, id int64) (res *model.Place, err error) {
addCache := true
res, err = d.CachePlace(c, id)
if err != nil {
addCache = false
err = nil
}
defer func() {
if res != nil && res.ID == -1 {
res = nil
}
}()
if res != nil {
prom.CacheHit.Incr("Place")
return
}
prom.CacheMiss.Incr("Place")
res, err = d.RawPlace(c, id)
if err != nil {
return
}
miss := res
if miss == nil {
miss = &model.Place{ID: -1}
}
if !addCache {
return
}
d.cache.Do(c, func(c context.Context) {
d.AddCachePlace(c, id, miss)
})
return
}
// ScListByItem get data from cache if miss will call source method, then add to cache.
func (d *Dao) ScListByItem(c context.Context, keys []int64) (res map[int64][]*model.Screen, err error) {
if len(keys) == 0 {
return
}
addCache := true
if res, err = d.CacheScListByItem(c, keys); 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("ScListByItem", int64(len(keys)-len(miss)))
for k, v := range res {
if len(v) == 1 && v[0].ProjectID == -1 {
delete(res, k)
}
}
missLen := len(miss)
if missLen == 0 {
return
}
var missData map[int64][]*model.Screen
prom.CacheMiss.Add("ScListByItem", int64(len(miss)))
missData, err = d.RawScListByItem(c, miss)
if res == nil {
res = make(map[int64][]*model.Screen, len(keys))
}
for k, v := range missData {
res[k] = v
}
if err != nil {
return
}
for _, key := range miss {
if len(res[key]) == 0 {
missData[key] = []*model.Screen{{ProjectID: -1}}
}
}
if !addCache {
return
}
d.cache.Do(c, func(c context.Context) {
d.AddCacheScListByItem(c, missData)
})
return
}
// ScList get data from cache if miss will call source method, then add to cache.
func (d *Dao) ScList(c context.Context, keys []int64) (res map[int64]*model.Screen, err error) {
if len(keys) == 0 {
return
}
addCache := true
if res, err = d.CacheScList(c, keys); 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("ScList", int64(len(keys)-len(miss)))
for k, v := range res {
if v != nil && v.ProjectID == -1 {
delete(res, k)
}
}
missLen := len(miss)
if missLen == 0 {
return
}
var missData map[int64]*model.Screen
prom.CacheMiss.Add("ScList", int64(len(miss)))
missData, err = d.RawScList(c, miss)
if res == nil {
res = make(map[int64]*model.Screen, len(keys))
}
for k, v := range missData {
res[k] = v
}
if err != nil {
return
}
for _, key := range miss {
if res[key] == nil {
missData[key] = &model.Screen{ProjectID: -1}
}
}
if !addCache {
return
}
d.cache.Do(c, func(c context.Context) {
d.AddCacheScList(c, missData)
})
return
}
// TkList get data from cache if miss will call source method, then add to cache.
func (d *Dao) TkList(c context.Context, keys []int64) (res map[int64]*model.TicketInfo, err error) {
if len(keys) == 0 {
return
}
addCache := true
if res, err = d.CacheTkList(c, keys); 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("TkList", int64(len(keys)-len(miss)))
for k, v := range res {
if v != nil && v.ProjectID == -1 {
delete(res, k)
}
}
missLen := len(miss)
if missLen == 0 {
return
}
var missData map[int64]*model.TicketInfo
prom.CacheMiss.Add("TkList", int64(len(miss)))
missData, err = d.RawTkList(c, miss)
if res == nil {
res = make(map[int64]*model.TicketInfo, len(keys))
}
for k, v := range missData {
res[k] = v
}
if err != nil {
return
}
for _, key := range miss {
if res[key] == nil {
missData[key] = &model.TicketInfo{TicketPrice: model.TicketPrice{ProjectID: -1}}
}
}
if !addCache {
return
}
d.cache.Do(c, func(c context.Context) {
d.AddCacheTkList(c, missData)
})
return
}

View File

@@ -0,0 +1,152 @@
package dao
import (
"context"
"fmt"
"strconv"
"time"
"go-common/app/service/openplatform/ticket-item/conf"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/cache/redis"
"go-common/library/database/orm"
"go-common/library/log"
"go-common/library/database/elastic"
"go-common/library/sync/pipeline/fanout"
"github.com/jinzhu/gorm"
)
// Expire time
const (
CacheTimeout = 120
_expireHalfhour = 1800 // 半小时过期
)
// Dao dao
type Dao struct {
c *conf.Config
redis *redis.Pool
cache *fanout.Fanout
// DB
db *gorm.DB
expire int32
es *elastic.Elastic
}
func keyItem(id int64) string {
return "open_item_" + strconv.FormatInt(id, 10)
}
func keyItemDetail(id int64) string {
return "open_item_detail_" + strconv.FormatInt(id, 10)
}
func keyItemTicket(id int64) string {
return "open_itemticket_" + strconv.FormatInt(id, 10)
}
func keyTicket(id int64) string {
return "open_ticket_" + strconv.FormatInt(id, 10)
}
func keyVenue(id int64) string {
return "open_venue_" + strconv.FormatInt(id, 10)
}
func keyPlace(id int64) string {
return "open_place_" + strconv.FormatInt(id, 10)
}
func keyItemScreen(id int64) string {
return "open_itemscreen_" + strconv.FormatInt(id, 10)
}
func keyScreen(id int64) string {
return "open_screen_" + strconv.FormatInt(id, 10)
}
func keyBannerList(order int32, districtID string, position int32, subPosition int32) string {
return fmt.Sprintf("BANNERLISTV3:%d:%s:%d:%d", order, districtID, position, subPosition)
}
func keyBannerInfo(bannerID int64) string {
return fmt.Sprintf("%d:BANNERINFOV2", bannerID)
}
//go:generate $GOPATH/src/go-common/app/tool/cache/gen
type _cache interface {
// cache: -nullcache=&model.Item{ID:-1} -check_null_code=$!=nil&&$.ID==-1
Items(c context.Context, pid []int64) (info map[int64]*model.Item, err error)
// cache: -nullcache=&model.ItemDetail{ProjectID:-1} -check_null_code=$!=nil&&$.ProjectID==-1
ItemDetails(c context.Context, pid []int64) (details map[int64]*model.ItemDetail, err error)
// cache: -nullcache=[]*model.TicketInfo{{TicketPrice:model.TicketPrice{ProjectID:-1}}} -check_null_code=len($)==1&&$[0].ProjectID==-1
TkListByItem(c context.Context, pid []int64) (info map[int64][]*model.TicketInfo, err error)
// cache: -nullcache=&model.Venue{ID:-1} -check_null_code=$!=nil&&$.ID==-1
Venues(c context.Context, id []int64) (venues map[int64]*model.Venue, err error)
// cache: -nullcache=&model.Place{ID:-1} -check_null_code=$!=nil&&$.ID==-1
Place(c context.Context, id int64) (place *model.Place, err error)
// cache: -nullcache=[]*model.Screen{{ProjectID:-1}} -check_null_code=len($)==1&&$[0].ProjectID==-1
ScListByItem(c context.Context, pid []int64) (info map[int64][]*model.Screen, err error)
// cache: -nullcache=&model.Screen{ProjectID:-1} -check_null_code=$!=nil&&$.ProjectID==-1
ScList(c context.Context, sids []int64) (info map[int64]*model.Screen, err error)
// cache: -nullcache=&model.TicketInfo{TicketPrice:model.TicketPrice{ProjectID:-1}} -check_null_code=$!=nil&&$.ProjectID==-1
TkList(c context.Context, tids []int64) (info map[int64]*model.TicketInfo, err error)
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
// orm
db: orm.NewMySQL(c.ORM),
redis: redis.NewPool(c.Redis.Master),
expire: int32(time.Duration(c.Redis.Expire) / time.Second),
cache: fanout.New("cache", fanout.Worker(1), fanout.Buffer(1024)),
es: elastic.NewElastic(&elastic.Config{
Host: c.URL.ElasticHost,
HTTPClient: c.HTTPClient.Read,
}),
}
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
}
return d.db.DB().PingContext(c)
}
// Close 关闭redis 和 db 连接
func (d *Dao) Close() (err error) {
d.redis.Close()
d.db.Close()
return
}
// BeginTran 开启事务
func (d *Dao) BeginTran(c context.Context) (tx *gorm.DB, err error) {
tx = d.db.Begin()
if tx.Error != nil {
err = tx.Error
tx = nil
log.Error("开启事务失败:%s", err)
}
return
}
// CommitTran 提交事务
func (d *Dao) CommitTran(c context.Context, tx *gorm.DB) (err error) {
if err = tx.Commit().Error; err != nil {
tx = nil
log.Error("提交事务失败:%s", err)
}
return
}

View File

@@ -0,0 +1,22 @@
package dao
import (
"time"
"go-common/app/service/openplatform/ticket-item/conf"
"go-common/library/log"
)
func initConf() {
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
defer log.Close()
}
func startService() {
initConf()
d = New(conf.Conf)
time.Sleep(time.Second * 2)
}

View File

@@ -0,0 +1,97 @@
package dao
import (
"context"
"fmt"
"time"
"go-common/library/database/sql"
"go-common/library/log"
xtime "go-common/library/time"
)
// sql cachekey
const (
_addUserFavSQL = "INSERT INTO user_favorite (mid, item_id, type, status) VALUES(?, ?, ?, ?)"
_selectUserFavSQL = "SELECT status, mtime FROM user_favorite WHERE mid=? AND type=? AND item_id=? LIMIT 1"
_updateUserFavSQL = "UPDATE user_favorite SET status=? where mid=? AND type=? AND item_id=? AND mtime=? LIMIT 1"
_userFavList = "%d:USERFAVLIST"
_userFavState = "%d:USERFAVSTATE:%d:%d"
)
// FavUpdate 收藏状态更新
func (d *Dao) FavUpdate(c context.Context, itemID int64, mid int64, typ int32, status int32) (err error) {
res := d.db.Raw(_selectUserFavSQL, mid, typ, itemID)
if err = res.Error; err != nil {
log.Error("d.FavUpdate() error(%v)", err)
return
}
var (
oldStatus int32
lastMtime xtime.Time
notFound bool
)
if err = res.Row().Scan(&oldStatus, &lastMtime); err != nil {
if err == sql.ErrNoRows {
notFound = true
} else {
log.Error("d.FavUpdate() res.Row().Scan() error(%v)", err)
return
}
}
if notFound {
// 插入
if err = d.db.Exec(_addUserFavSQL, mid, itemID, typ, status).Error; err != nil {
log.Error("d.FavUpdate(%d, %d, %d, %d) Exec(%s) error(%v)", mid, itemID, typ, status, _addUserFavSQL, err)
return
}
} else {
// 更新
if oldStatus == status {
log.Info("d.FavUpdate(%d, %d, %d, %d) 前后状态相同 oldStatus %d ", mid, itemID, typ, status, oldStatus)
return
}
if err = d.db.Exec(_updateUserFavSQL, status, mid, typ, itemID, lastMtime.Time().Format("2006-01-02 15:04:05")).Error; err != nil {
log.Error("d.FavUpdate(%d, %d, %d, %d) Exec(%s) error(%v)", mid, itemID, typ, status, _updateUserFavSQL, err)
return
}
}
return
}
// UserFavStateCache 设置用户收藏缓存 支持多种类型
func (d *Dao) UserFavStateCache(c context.Context, itemID int64, mid int64, typ int32, status int32) (err error) {
conn := d.redis.Get(c)
defer conn.Close()
_, err = conn.Do("SETEX", fmt.Sprintf(_userFavState, mid, itemID, typ), _expireHalfhour, status)
if err != nil {
log.Error("d.UserFavState(%d, %d, %d, %d) SETEX error(%v)", itemID, mid, typ, status, err)
return
}
return
}
// UpdateFavListCache 更新收藏列表缓存
func (d *Dao) UpdateFavListCache(c context.Context, itemID int64, mid int64, status int32) (err error) {
conn := d.redis.Get(c)
defer conn.Close()
if status == 1 {
_, err = conn.Do("ZADD", fmt.Sprintf(_userFavList, mid), time.Now().Unix(), itemID)
} else {
_, err = conn.Do("ZREM", fmt.Sprintf(_userFavList, mid), itemID)
}
if err != nil {
log.Error("d.UpdateFavListCache(%d, %d, %d) error(%v)", itemID, mid, status, err)
return
}
return
}

View File

@@ -0,0 +1,144 @@
package dao
import (
"context"
"fmt"
"strconv"
"go-common/app/common/openplatform/random"
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/database/elastic"
"go-common/library/ecode"
"go-common/library/log"
)
// AddGuest 添加新嘉宾
func (d *Dao) AddGuest(c context.Context, info *item.GuestInfoRequest) (ret bool, err error) {
// 此处guest_id调用订单号生成器
guestID := random.Uniqid(19)
// 插入新数据
if dbErr := d.db.Create(&model.Guest{
Name: info.Name,
GuestImg: info.GuestImg,
Description: info.Description,
GuestID: guestID,
}).Error; dbErr != nil {
log.Error("insertion failed")
return false, ecode.NothingFound
}
return true, nil
}
// UpdateGuest 编辑嘉宾信息
func (d *Dao) UpdateGuest(c context.Context, info *item.GuestInfoRequest) (res bool, err error) {
// find original guest with id
var oriGuest model.Guest
if dbErr := d.db.First(&oriGuest, info.ID).Error; dbErr != nil {
log.Error("guest(%d) not found", info.ID)
return false, ecode.NothingFound
}
// update guest with new info (using map can update the column with empty string)
updateErr := d.db.Model(&oriGuest).Updates(
map[string]interface{}{
"name": info.Name,
"guest_img": info.GuestImg,
"description": info.Description,
}).Error
if updateErr != nil {
log.Error("UPDATE FAILED")
return false, ecode.NotModified
}
return true, nil
}
// GuestStatus 更新嘉宾状态
func (d *Dao) GuestStatus(c context.Context, id int64, status int8) (res bool, err error) {
// find original guest with id
var oriGuest model.Guest
if dbErr := d.db.First(&oriGuest, id).Error; dbErr != nil {
log.Error("guest (%d) not found", id)
return false, ecode.NothingFound
}
// update guest with new info (using map can update the column with empty string)
updateErr := d.db.Model(&oriGuest).Update("status", status).Error
if updateErr != nil {
log.Error("CHANGE STATUS FAILED")
return false, ecode.NotModified
}
return true, nil
}
// GetGuests 获取项目下所有嘉宾
func (d *Dao) GetGuests(c context.Context, pid int64) (res []*model.Guest, err error) {
// 获取项目下所有guestID
var projectGuests []*model.ProjectGuest
if dbErr := d.db.Select("guest_id").Order("position").Where("project_id = ? and delete_status = 0", pid).Find(&projectGuests).Error; dbErr != nil {
log.Error("获取项目嘉宾id失败: %s", dbErr)
err = ecode.NothingFound
return
}
var guestIDs []int64
for idx := range projectGuests {
guestIDs = append(guestIDs, projectGuests[idx].GuestID)
}
// 获取未禁用嘉宾信息 并用id当键值组成map
var guestInfo []*model.Guest
if dbErr := d.db.Where("status = 1 and id in (?)", guestIDs).Find(&guestInfo).Error; dbErr != nil {
log.Error("获取项目嘉宾信息失败: %s", dbErr)
err = ecode.NothingFound
return
}
guestInfoMap := make(map[int64]*model.Guest)
for _, value := range guestInfo {
guestInfoMap[value.ID] = value
}
// 根据guestIDs重新排序嘉宾信息
for _, value := range guestIDs {
if guestInfoMap[value].Status == 1 {
res = append(res, guestInfoMap[value])
}
}
return
}
// GuestSearch guest es search.
func (d *Dao) GuestSearch(c context.Context, arg *model.GuestSearchParam) (guests *model.GuestSearchList, err error) {
r := d.es.NewRequest("ticket_guest").
Index("ticket_guest").
Order("ctime", elastic.OrderDesc).
Order("id", elastic.OrderAsc).
Ps(arg.Ps).Pn(arg.Pn)
if arg.Keyword != "" {
if id, err1 := strconv.Atoi(arg.Keyword); err1 == nil {
r = r.WhereEq("id", id)
} else {
r = r.WhereLike([]string{"name"}, []string{arg.Keyword}, true, elastic.LikeLevelLow)
}
}
log.Info(fmt.Sprintf("%s/x/admin/search/query?%s", d.c.URL.ElasticHost, r.Params()))
guests = new(model.GuestSearchList)
err = r.Scan(c, guests)
if err != nil {
log.Error("GuestSearch() Scan() error(%v)", err)
}
return
}

View File

@@ -0,0 +1,59 @@
package dao
import (
"context"
"testing"
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
. "github.com/smartystreets/goconvey/convey"
)
// TestAddGuest
func TestDao_AddGuest(t *testing.T) {
Convey("AddGuest", t, func() {
once.Do(startService)
res, err := d.AddGuest(context.TODO(), &item.GuestInfoRequest{
Name: "gotester",
GuestImg: "testerimg.jpg",
Description: "this is a description",
})
So(res, ShouldBeTrue)
So(err, ShouldBeNil)
})
}
// TestUpdateGuest
func TestDao_UpdateGuest(t *testing.T) {
Convey("UpdateGuest", t, func() {
once.Do(startService)
res, err := d.UpdateGuest(context.TODO(), &item.GuestInfoRequest{
ID: 55,
Name: "gotester22",
GuestImg: "testerimg.jpg2222",
Description: "this is a description222",
})
So(res, ShouldBeTrue)
So(err, ShouldBeNil)
})
}
// TestGuestStatus
func TestDao_GuestStatus(t *testing.T) {
Convey("GuestStatus", t, func() {
once.Do(startService)
res, err := d.GuestStatus(context.TODO(), 57, 1)
So(res, ShouldBeTrue)
So(err, ShouldBeNil)
})
}
// TestGetGuests
func TestDao_GetGuests(t *testing.T) {
Convey("GetGuest", t, func() {
once.Do(startService)
res, err := d.GetGuests(context.TODO(), 60)
So(res, ShouldNotBeNil)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,187 @@
package dao
import (
"context"
"encoding/json"
"go-common/library/cache/redis"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/log"
)
// RawItems 取项目信息
func (d *Dao) RawItems(c context.Context, ids []int64) (info map[int64]*model.Item, err error) {
rows, err := d.db.Model(&model.Item{}).Where("id in (?)", ids).Rows()
info = make(map[int64]*model.Item)
if err != nil {
log.Error("QueryItem(%v) error(%v)", ids, err)
return
}
defer rows.Close()
for rows.Next() {
var item model.Item
err = d.db.ScanRows(rows, &item)
json.Unmarshal([]byte(item.PerformanceImage), &item.Img)
info[item.ID] = &item
}
return
}
// CacheItems 缓存取项目信息
func (d *Dao) CacheItems(c context.Context, ids []int64) (info map[int64]*model.Item, err error) {
var data [][]byte
keys := make([]interface{}, len(ids))
conn := d.redis.Get(c)
defer conn.Close()
keyPidMap := make(map[string]int64, len(ids))
for k, id := range ids {
key := keyItem(id)
if _, ok := keyPidMap[key]; !ok {
// duplicate id
keyPidMap[key] = id
keys[k] = key
}
}
log.Info("MGET %v", model.JSONEncode(keys))
if data, err = redis.ByteSlices(conn.Do("MGET", keys...)); err != nil {
log.Error("MGET ERR: %v", err)
return
}
info = make(map[int64]*model.Item)
for _, d := range data {
if d != nil {
item := &model.Item{}
json.Unmarshal(d, item)
info[item.ID] = item
}
}
return
}
// AddCacheItems 缓存取项目信息
func (d *Dao) AddCacheItems(c context.Context, info map[int64]*model.Item) (err error) {
conn := d.redis.Get(c)
defer func() {
conn.Flush()
conn.Close()
}()
var data []interface{}
var keys []string
for k, v := range info {
b, _ := json.Marshal(v)
key := keyItem(k)
keys = append(keys, key)
data = append(data, key, b)
}
log.Info("MSET %v", keys)
if err = conn.Send("MSET", data...); err != nil {
return
}
for i := 0; i < len(data); i += 2 {
conn.Send("EXPIRE", data[i], CacheTimeout)
}
return
}
// RawItemDetails 批量获取项目详情
func (d *Dao) RawItemDetails(c context.Context, ids []int64) (detail map[int64]*model.ItemDetail, err error) {
rows, err := d.db.Model(&model.ItemDetail{}).Where("project_id in (?)", ids).Rows()
detail = make(map[int64]*model.ItemDetail)
if err != nil {
log.Error("RawItemDetail(%v) error(%v)", ids, err)
return
}
defer rows.Close()
for rows.Next() {
var item model.ItemDetail
err = d.db.ScanRows(rows, &item)
detail[item.ProjectID] = &item
}
return
}
// CacheItemDetails 缓存批量获取项目详情
func (d *Dao) CacheItemDetails(c context.Context, ids []int64) (detail map[int64]*model.ItemDetail, err error) {
var data [][]byte
var keys []interface{}
keyPidMap := make(map[string]int64, len(ids))
for _, id := range ids {
key := keyItemDetail(id)
if _, ok := keyPidMap[key]; !ok {
// duplicate pid
keyPidMap[key] = id
keys = append(keys, key)
}
}
conn := d.redis.Get(c)
defer conn.Close()
log.Info("MGET %v", model.JSONEncode(keys))
if data, err = redis.ByteSlices((conn.Do("MGET", keys...))); err != nil {
return
}
detail = make(map[int64]*model.ItemDetail)
for _, d := range data {
if d != nil {
var v *model.ItemDetail
json.Unmarshal(d, &v)
detail[v.ProjectID] = v
}
}
return
}
// AddCacheItemDetails 缓存取项目详情
func (d *Dao) AddCacheItemDetails(c context.Context, detail map[int64]*model.ItemDetail) (err error) {
conn := d.redis.Get(c)
defer func() {
conn.Flush()
conn.Close()
}()
var keys []string
var data []interface{}
for k, v := range detail {
b, _ := json.Marshal(v)
key := keyItemDetail(k)
keys = append(keys, key)
data = append(data, key, b)
}
log.Info("MSET %v", keys)
if err = conn.Send("MSET", data...); err != nil {
return
}
for i := 0; i < len(data); i += 2 {
conn.Send("EXPIRE", data[i], CacheTimeout)
}
return
}
// DelItemCache 删除项目相关缓存
func (d *Dao) DelItemCache(c context.Context, ids []int64) (res bool, err error) {
var (
keys []interface{}
)
conn := d.redis.Get(c)
defer func() {
conn.Flush()
conn.Close()
}()
for _, id := range ids {
keys = append(keys, keyItem(id))
keys = append(keys, keyItemDetail(id))
}
log.Info("DEL %v", keys)
if err = conn.Send("DEL", keys...); err != nil {
return
}
return
}

View File

@@ -0,0 +1,32 @@
package dao
import (
"context"
. "github.com/smartystreets/goconvey/convey"
"go-common/app/service/openplatform/ticket-item/model"
"sync"
"testing"
)
var (
once sync.Once
d *Dao
ctx = context.TODO()
)
// Test_RawItems
func TestRawItems(t *testing.T) {
Convey("RawItems", t, func() {
once.Do(startService)
res, err := d.RawItems(ctx, model.DataIDs)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
So(res, ShouldNotBeEmpty)
})
Convey("RawItems", t, func() {
once.Do(startService)
res, err := d.RawItems(ctx, model.NoDataIDs)
So(err, ShouldNotBeNil)
So(res, ShouldBeEmpty)
})
}

View File

@@ -0,0 +1,377 @@
package dao
import (
"context"
"encoding/json"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/ecode"
"go-common/library/log"
"strconv"
"github.com/jinzhu/gorm"
)
// ProjectMainInfo 项目版本内容
type ProjectMainInfo struct {
Name string `json:"name"`
Type string `json:"type"`
Size string `json:"size"`
ProvinceID string `json:"province_id"`
CityID string `json:"city_id"`
DistrictID string `json:"district_id"`
VenueID string `json:"venue_id"`
PlaceID string `json:"place_id"`
StartTime int32 `json:"start_time"`
EndTime int32 `json:"end_time"`
Docs []ImgInfo `json:"docs"`
Screens []Screen `json:"screens"`
TicketsSingle []TicketSingle `json:"tickets_single"`
TicketsPass []TicketPass `json:"tickets_pass"`
TicketsAllPass []TicketPass `json:"tickets_allpass"`
PerformanceImg PerformanceImg `json:"performance_image"`
PerformanceDesc string `json:"performance_desc"`
SellingProp string `json:"selling_prop"`
TagIDs []string `json:"tag_ids"`
GuestIDs []int64 `json:"guest_ids"`
GuestImgs []GuestImg `json:"guest_imgs"`
CompID string `json:"comp_id"`
Label string `json:"label"`
SponsorType string `json:"sponsor_type"`
}
// ImgInfo 图片信息
type ImgInfo struct {
URL string `json:"url"`
Desc string `json:"desc"`
}
// GuestImg 嘉宾图片信息
type GuestImg struct {
ID int64 `json:"id"`
ImgURL string `json:"img_url"`
}
// Screen 场次信息
type Screen struct {
ScreenName string `json:"screen_name"`
ScreenStartTime int32 `json:"screen_start_time"`
ScreenEndTime int32 `json:"screen_end_time"`
ScreenType string `json:"screen_type"`
PickSeat int32 `json:"pick_seat"`
TicketType string `json:"ticket_type"`
DeliveryType string `json:"delivery_type"`
ScreenID string `json:"screen_id"`
}
// TicketSingle 单场票信息
type TicketSingle struct {
Name string `json:"name"`
Type string `json:"type"`
Color string `json:"color"`
BuyLimit string `json:"buy_limit"`
PayValue int64 `json:"pay_value"`
PayMethod string `json:"pay_method"`
Desc string `json:"descrp"`
TicketID string `json:"ticket_sc_id"`
BuyLimitNum []string `json:"buy_limit_num"`
}
// TicketPass 通票信息
type TicketPass struct {
Name string `json:"name"`
LinkTicket int32 `json:"link_ticket"`
LinkScreens []int32 `json:"link_screens"`
Color string `json:"color"`
BuyLimit string `json:"buy_limit"`
PayValue int64 `json:"pay_value"`
PayMethod string `json:"pay_method"`
Desc string `json:"descrp"`
TicketID string `json:"ticket_sc_id"`
BuyLimitNum []string `json:"buy_limit_num"`
}
// PerformanceImg 项目图片信息
type PerformanceImg struct {
First ImgInfo `json:"first"`
Banner ImgInfo `json:"banner"`
}
const (
// BuyNumLimit 默认限购值
BuyNumLimit = `{"per":8}`
)
// AddProject 项目初始化
func (d *Dao) AddProject(c context.Context, verID uint64) (pid int64, err error) {
var verExtInfo model.VersionExt
if dbErr := d.db.Where("ver_id = ?", verID).First(&verExtInfo).Error; dbErr != nil {
log.Error("获取项目版本详情失败:%s", dbErr)
return 0, dbErr
}
decodedMainInfo := d.GetDefaultMainInfo()
err = json.Unmarshal([]byte(verExtInfo.MainInfo), &decodedMainInfo)
if err != nil {
return
}
// 开启事务
tx := d.db.Begin()
// 创建新project
var project model.Item
if project, err = d.CreateProject(c, tx, verID, decodedMainInfo); err != nil {
return
}
pid = project.ID
if pid == 0 {
tx.Rollback()
log.Error("pid not initialized")
return 0, ecode.TicketPidIsEmpty
}
// 创建新项目详情在project_extra表
if err = d.CreateProjectExtInfo(c, tx, pid, decodedMainInfo.PerformanceDesc); err != nil {
return
}
// 创建场次screen
scIDList := make(map[int32]int64)
scStartTimes := make(map[int32]int32)
scEndTimes := make(map[int32]int32)
var screen model.Screen
for k, v := range decodedMainInfo.Screens {
screenType, _ := strconv.ParseInt(v.ScreenType, 10, 64)
ticketType, _ := strconv.ParseInt(v.TicketType, 10, 64)
deliveryType, _ := strconv.ParseInt(v.DeliveryType, 10, 64)
screen = model.Screen{
ProjectID: pid,
Name: v.ScreenName,
StartTime: v.ScreenStartTime,
EndTime: v.ScreenEndTime,
Type: int32(screenType),
TicketType: int32(ticketType),
DeliveryType: int32(deliveryType),
PickSeat: v.PickSeat,
ScreenType: 1, // 单场票场次
}
if screen, err = d.CreateOrUpdateScreen(c, tx, screen); err != nil {
return
}
// 获取的screen自增id复制到maininfo内
decodedMainInfo.Screens[k].ScreenID = strconv.FormatInt(screen.ID, 10)
scIDList[int32(k)] = screen.ID
scStartTimes[int32(k)] = screen.StartTime
scEndTimes[int32(k)] = screen.EndTime
}
// 创建票价
TkSingleIDList := make(map[int32]int64)
TkSingleTypeList := make(map[int32]int32)
var tkPrice model.TicketPrice
for k, v := range decodedMainInfo.TicketsSingle {
saleType, _ := strconv.ParseInt(v.Type, 10, 64)
buyLimit, _ := strconv.ParseInt(v.BuyLimit, 10, 64)
payMethod, _ := strconv.ParseInt(v.PayMethod, 10, 64)
ticketID, baseErr := model.GetTicketIDFromBase()
if ticketID == 0 || baseErr != nil {
tx.Rollback()
log.Error("baseCenter获取ticketID失败 ticketid:%s,baseErr:%s", ticketID, baseErr)
return 0, baseErr
}
tkPrice = model.TicketPrice{
ID: ticketID,
ProjectID: pid,
Desc: v.Name,
Type: 1, // 单场票
SaleType: int32(saleType),
Color: v.Color,
BuyLimit: int32(buyLimit),
PaymentMethod: int32(payMethod),
PaymentValue: v.PayValue,
DescDetail: v.Desc,
IsSale: 1, // 可售
IsRefund: -10, // 不可退
OriginPrice: -1, // 未設置
MarketPrice: -1,
SaleStart: TimeNull, // 0000-00-00 00:00:00
SaleEnd: TimeNull,
}
if tkPrice, err = d.CreateOrUpdateTkPrice(c, tx, tkPrice, 0); err != nil {
return
}
//票价限购
limitData := d.FormatByPrefix(v.BuyLimitNum, "buy_limit_")
if err = d.CreateOrUpdateTkPriceExtra(c, tx, limitData, ticketID, pid); err != nil {
return
}
// 获取的ticketPrice自增id复制到mainInfo内
decodedMainInfo.TicketsSingle[k].TicketID = strconv.FormatInt(tkPrice.ID, 10)
TkSingleIDList[int32(k)] = ticketID
TkSingleTypeList[int32(k)] = int32(saleType)
}
var passScID, allPassScID int64
// 创建通票场次
passScID, err = d.GetOrUpdatePassSc(c, tx, pid, decodedMainInfo.TicketsPass, scStartTimes, scEndTimes, scTypePass, 0)
if err != nil {
return
}
decodedMainInfo.TicketsPass, err = d.InsertOrUpdateTkPass(c, tx, pid, passScID, decodedMainInfo.TicketsPass, TkTypePass, scIDList, TkSingleIDList, TkSingleTypeList)
if err != nil {
return
}
// 创建联票场次
allPassScID, err = d.GetOrUpdatePassSc(c, tx, pid, decodedMainInfo.TicketsAllPass, scStartTimes, scEndTimes, scTypeAllPass, 0)
if err != nil {
return
}
decodedMainInfo.TicketsAllPass, err = d.InsertOrUpdateTkPass(c, tx, pid, allPassScID, decodedMainInfo.TicketsAllPass, TkTypeAllPass, scIDList, TkSingleIDList, TkSingleTypeList)
if err != nil {
return
}
// 创建标签
for _, tagID := range decodedMainInfo.TagIDs {
err = d.CreateTag(c, tx, pid, tagID)
if err != nil {
return
}
}
// 创建嘉宾
guestImgMap := make(map[int64]string)
// 组合嘉宾对应头像map
if decodedMainInfo.GuestIDs != nil {
if decodedMainInfo.GuestImgs == nil {
var guestInfoList []model.Guest
if err = d.db.Select("id, guest_img").Where("id IN (?)", decodedMainInfo.GuestIDs).Find(&guestInfoList).Error; err != nil {
log.Error("获取嘉宾信息失败:%s", err)
tx.Rollback()
return
}
for _, v := range guestInfoList {
guestImgMap[v.ID] = v.GuestImg
}
} else {
for _, v := range decodedMainInfo.GuestImgs {
guestImgMap[v.ID] = v.ImgURL
}
}
}
var position int64
for _, guestID := range decodedMainInfo.GuestIDs {
if err = tx.Create(&model.ProjectGuest{
ProjectID: pid,
GuestID: guestID,
Position: position,
GuestImg: guestImgMap[guestID],
}).Error; err != nil {
log.Error("项目嘉宾添加失败:%s", err)
tx.Rollback()
return
}
position++
}
// 将有场次票价id的mainInfo更新到version_ext
encodedMainInfo, jsonErr := json.Marshal(decodedMainInfo)
if jsonErr != nil {
log.Error("JSONEncode MainInfo失败")
tx.Rollback()
return pid, jsonErr
}
finalMainInfo := string(encodedMainInfo)
if len(finalMainInfo) > 4000 {
log.Error("信息量过大")
tx.Rollback()
return pid, ecode.TicketMainInfoTooLarge
}
// 编辑version_ext
err = tx.Model(&model.VersionExt{}).Where("ver_id = ? and type = ?", verID, 1).Update("main_info", finalMainInfo).Error
if err != nil {
tx.Rollback()
log.Error("更新versionext失败: %s", err)
}
// 提交事务
tx.Commit()
return pid, nil
}
// CreateProject 灌入项目表
func (d *Dao) CreateProject(c context.Context, tx *gorm.DB, verID uint64, decodedMainInfo ProjectMainInfo) (project model.Item, err error) {
// 创建新project
venueID, _ := strconv.ParseInt(decodedMainInfo.VenueID, 10, 64)
placeID, _ := strconv.ParseInt(decodedMainInfo.PlaceID, 10, 64)
compID, _ := strconv.ParseInt(decodedMainInfo.CompID, 10, 64)
projectType, _ := strconv.ParseInt(decodedMainInfo.Type, 10, 64)
projectSponsorType, _ := strconv.ParseInt(decodedMainInfo.SponsorType, 10, 64)
performanceImg, _ := json.Marshal(decodedMainInfo.PerformanceImg)
projectInfo := model.Item{
Name: decodedMainInfo.Name,
StartTime: decodedMainInfo.StartTime,
EndTime: decodedMainInfo.EndTime,
VenueID: venueID,
PlaceID: placeID,
CompID: compID,
PerformanceImage: string(performanceImg),
TicketDesc: decodedMainInfo.SellingProp,
Type: int32(projectType),
VerID: verID,
SponsorType: int32(projectSponsorType),
Label: decodedMainInfo.Label,
BuyNumLimit: BuyNumLimit,
IsSale: 1, // 默认值可售
ExpressFee: -2, //默认值
}
if err = tx.Create(&projectInfo).Error; err != nil {
log.Error("新建项目失败:%s", err)
tx.Rollback()
return model.Item{}, err
}
return projectInfo, nil
}
// CreateProjectExtInfo 灌入项目详情表
func (d *Dao) CreateProjectExtInfo(c context.Context, tx *gorm.DB, projectID int64, performanceDesc string) (err error) {
projectExtInfo := model.ItemDetail{
ProjectID: projectID,
PerformanceDesc: performanceDesc,
}
if err = tx.Create(&projectExtInfo).Error; err != nil {
log.Error("新建项目详情失败:%s", err)
tx.Rollback()
return err
}
return nil
}
// GetDefaultMainInfo 获取初始化数组的mainInfo
func (d *Dao) GetDefaultMainInfo() ProjectMainInfo {
return ProjectMainInfo{
Docs: []ImgInfo{},
Screens: []Screen{},
TicketsSingle: []TicketSingle{},
TicketsPass: []TicketPass{},
TicketsAllPass: []TicketPass{},
TagIDs: []string{},
GuestIDs: []int64{},
GuestImgs: []GuestImg{},
}
}

View File

@@ -0,0 +1,37 @@
package dao
import (
"go-common/app/service/openplatform/ticket-item/model"
"time"
)
const (
// StatusWaitShelf 待上架
StatusWaitShelf = 1
// StatusUpShelf 已上架
StatusUpShelf = 2
)
// HasPromotion 检查场次id或者票价id下是否有未开售,售卖中的待上架和已上架拼团 checkType 1-场次id 2-票价id
func (d *Dao) HasPromotion(ids []int64, checkType int32) bool {
if ids == nil {
return false
}
status := []int{StatusWaitShelf, StatusUpShelf}
whereStr := "(begin_time > ? OR (begin_time <= ? AND end_time > ?)) AND status IN (?) AND "
if checkType == 1 {
// screen
whereStr += "extra IN (?)"
} else {
// sku
whereStr += "sku_id IN (?)"
}
var count int64
currTime := time.Now().Unix()
d.db.Model(&model.Promotion{}).Where(whereStr, currTime, currTime, currTime, status, ids).Count(&count)
return count > 0
}

View File

@@ -0,0 +1,17 @@
package dao
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
// TestHasPromotion
func TestDao_HasPromotion(t *testing.T) {
Convey("HasPromotion", t, func() {
once.Do(startService)
res := d.HasPromotion([]int64{78}, 1)
So(res, ShouldBeFalse)
})
}

View File

@@ -0,0 +1,353 @@
package dao
import (
"context"
"encoding/json"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/cache/redis"
"go-common/library/ecode"
"go-common/library/log"
"time"
"github.com/jinzhu/gorm"
)
const (
// TypeWithoutSeat 场次类型 站票
TypeWithoutSeat = 2
// TicketTypeElec 场次票类型 电子票
TicketTypeElec = 2
// scTypeNormal 普通场次
scTypeNormal = 1
// scTypePass 通票场次
scTypePass = 2
// scTypeAllPass 联票场次
scTypeAllPass = 3
)
var scTypeName = map[int32]string{
scTypeNormal: "普通场次",
scTypePass: "通票",
scTypeAllPass: "联票",
}
// RawScListByItem 批量取项目场次
func (d *Dao) RawScListByItem(c context.Context, ids []int64) (info map[int64][]*model.Screen, err error) {
info = make(map[int64][]*model.Screen)
rows, err := d.db.Model(&model.Screen{}).Where("project_id in (?)", ids).Rows()
if err != nil {
log.Error("RawScListByItem(%v) error(%v)", ids, err)
return
}
defer rows.Close()
for rows.Next() {
var sc model.Screen
err = d.db.ScanRows(rows, &sc)
if err != nil {
log.Error("RawScListByItem(%v) scan error(%v)", ids, err)
return
}
info[sc.ProjectID] = append(info[sc.ProjectID], &sc)
}
return
}
// CacheScListByItem 缓存取项目票价
func (d *Dao) CacheScListByItem(c context.Context, ids []int64) (info map[int64][]*model.Screen, err error) {
var keys []interface{}
keyPidMap := make(map[string]int64, len(ids))
for _, id := range ids {
key := keyItemScreen(id)
if _, ok := keyPidMap[key]; !ok {
// duplicate mid
keyPidMap[key] = id
keys = append(keys, key)
}
}
conn := d.redis.Get(c)
defer conn.Close()
var data [][]byte
log.Info("MGET %v", model.JSONEncode(keys))
if data, err = redis.ByteSlices(conn.Do("mget", keys...)); err != nil {
log.Error("ItemScList MGET %v ERR: %v", model.JSONEncode(keys), err)
return
}
info = make(map[int64][]*model.Screen)
for _, d := range data {
if d != nil {
var scs []*model.Screen
json.Unmarshal(d, &scs)
info[scs[0].ProjectID] = scs
}
}
return
}
// AddCacheScListByItem 为项目场次添加缓存
func (d *Dao) AddCacheScListByItem(c context.Context, info map[int64][]*model.Screen) (err error) {
conn := d.redis.Get(c)
defer func() {
conn.Flush()
conn.Close()
}()
var data []interface{}
var keys []string
for k, v := range info {
b, _ := json.Marshal(v)
key := keyItemScreen(k)
keys = append(keys, key)
data = append(data, key, b)
}
log.Info("MSET %v", keys)
if err = conn.Send("MSET", data...); err != nil {
return
}
for i := 0; i < len(data); i += 2 {
conn.Send("EXPIRE", data[i], CacheTimeout)
}
return
}
// RawScList 批量取场次
func (d *Dao) RawScList(c context.Context, ids []int64) (info map[int64]*model.Screen, err error) {
info = make(map[int64]*model.Screen)
rows, err := d.db.Model(&model.Screen{}).Where("id in (?)", ids).Rows()
if err != nil {
log.Error("RawScList(%v) error(%v)", ids, err)
return
}
defer rows.Close()
for rows.Next() {
var sc model.Screen
err = d.db.ScanRows(rows, &sc)
if err != nil {
log.Error("RawScList(%v) scan error(%v)", ids, err)
return
}
info[sc.ID] = &sc
}
return
}
// CacheScList 缓存批量取场次
func (d *Dao) CacheScList(c context.Context, ids []int64) (info map[int64]*model.Screen, err error) {
var keys []interface{}
keyPidMap := make(map[string]int64, len(ids))
for _, id := range ids {
key := keyScreen(id)
if _, ok := keyPidMap[key]; !ok {
// duplicate id
keyPidMap[key] = id
keys = append(keys, key)
}
}
conn := d.redis.Get(c)
defer conn.Close()
var data [][]byte
log.Info("MGET %v", model.JSONEncode(keys))
if data, err = redis.ByteSlices(conn.Do("mget", keys...)); err != nil {
log.Error("ScList MGET %v ERR: %v", model.JSONEncode(keys), err)
return
}
info = make(map[int64]*model.Screen)
for _, d := range data {
if d != nil {
var sc model.Screen
json.Unmarshal(d, &sc)
info[sc.ID] = &sc
}
}
return
}
// AddCacheScList 为场次添加缓存
func (d *Dao) AddCacheScList(c context.Context, info map[int64]*model.Screen) (err error) {
conn := d.redis.Get(c)
defer func() {
conn.Flush()
conn.Close()
}()
var data []interface{}
var keys []string
for k, v := range info {
b, _ := json.Marshal(v)
key := keyScreen(k)
keys = append(keys, key)
data = append(data, key, b)
}
log.Info("MSET %v", keys)
if err = conn.Send("MSET", data...); err != nil {
return
}
for i := 0; i < len(data); i += 2 {
conn.Send("EXPIRE", data[i], CacheTimeout)
}
return
}
// CreateOrUpdateScreen 创建或更新场次
func (d *Dao) CreateOrUpdateScreen(c context.Context, tx *gorm.DB, screenInfo model.Screen) (model.Screen, error) {
if screenInfo.ID == 0 {
// create
if err := tx.Create(&screenInfo).Error; err != nil {
log.Error("创建场次失败:%s", err)
tx.Rollback()
return model.Screen{}, err
}
} else {
// update
if err := tx.Model(&model.Screen{}).Where("id = ?", screenInfo.ID).Updates(map[string]interface{}{
"name": screenInfo.Name,
"status": screenInfo.Status,
"type": screenInfo.Type,
"ticket_type": screenInfo.TicketType,
"screen_type": screenInfo.ScreenType,
"delivery_type": screenInfo.DeliveryType,
"pick_seat": screenInfo.PickSeat,
"start_time": screenInfo.StartTime,
"end_time": screenInfo.EndTime,
"project_id": screenInfo.ProjectID,
}).Error; err != nil {
log.Error("更新场次失败:%s", err)
tx.Rollback()
return model.Screen{}, err
}
}
return screenInfo, nil
}
// GetOrUpdatePassSc 更新或新建通联票场次 返回id
func (d *Dao) GetOrUpdatePassSc(c context.Context, tx *gorm.DB, pid int64, tksPass []TicketPass, scStartTimes map[int32]int32,
scEndTimes map[int32]int32, scType int32, opType int32) (int64, error) {
var passScID int64
scTime, err := d.CalPassScTime(scStartTimes, scEndTimes, tksPass)
if err != nil {
tx.Rollback()
return 0, err
}
var screen model.Screen
if d.db.Where("project_id = ? and screen_type = ? and deleted_at = 0", pid, scType).First(&screen).RecordNotFound() {
// 不存在场次并且有票种存在则新建一个
if len(tksPass) > 0 {
passScreen := model.Screen{
ProjectID: pid,
Name: scTypeName[scType],
StartTime: scTime[0],
EndTime: scTime[1],
Type: TypeWithoutSeat, // 站票
TicketType: TicketTypeElec, // 电子票
DeliveryType: 1, // 默认不配送
ScreenType: scType,
Status: opType,
}
if err := tx.Create(&passScreen).Error; err != nil {
log.Error("创建通票或联票场次失败:%s", err)
tx.Rollback()
return 0, err
}
passScID = passScreen.ID
}
} else {
if len(tksPass) > 0 {
// update
if err := tx.Model(&model.Screen{}).Where("id = ?", screen.ID).Updates(map[string]interface{}{
"status": opType,
"start_time": scTime[0],
"end_time": scTime[1],
}).Error; err != nil {
log.Error("更新通票联票场次失败:%s", err)
tx.Rollback()
return 0, err
}
passScID = screen.ID
} else {
// 如果没有通票/联票 删除通票/联票场次
if err := d.DelScreen(c, tx, []int64{screen.ID}, nil, pid); err != nil {
return 0, err
}
passScID = screen.ID
}
}
return passScID, nil
}
// DelScreen 删除场次
func (d *Dao) DelScreen(c context.Context, tx *gorm.DB, oldIDs []int64, newIDs []int64, pid int64) error {
delIDs, _ := model.ClassifyIDs(oldIDs, newIDs)
for _, delID := range delIDs {
if !d.CanDelScreen(delID) {
tx.Rollback()
return ecode.TicketCannotDelSc
}
// 删除场次前把改场次下的票价一起删除
priceIDs, err := d.GetPriceIDs(delID, 1)
if err != nil {
return err
}
if err := d.DelTicket(c, tx, priceIDs, nil, pid, true); err != nil {
return err
}
// 删除场次
if err := tx.Exec("UPDATE screen SET deleted_at=? WHERE id = ? AND project_id = ?", time.Now().Format("2006-01-02 15:04:05"), delID, pid).Error; err != nil {
log.Error("删除场次失败:%s", err)
tx.Rollback()
return err
}
}
return nil
}
// CalPassScTime 获取通联场次的开始结束时间, 取关联场次时间的极值。返回[0]=starttime [1]=endtime
func (d *Dao) CalPassScTime(scStartTimes map[int32]int32, scEndTimes map[int32]int32, tksPass []TicketPass) ([]int32, error) {
var startTimes, endTimes, currStartTimes, currEndTimes []int32
for _, v := range tksPass {
currStartTimes = []int32{}
currEndTimes = []int32{}
for _, v2 := range v.LinkScreens {
if _, ok := scStartTimes[v2]; !ok {
log.Error("关联的场次开始时间不存在")
return []int32{}, ecode.TicketLkScTimeNotFound
}
if _, ok := scEndTimes[v2]; !ok {
log.Error("关联的场次结束时间不存在")
return []int32{}, ecode.TicketLkScTimeNotFound
}
currStartTimes = append(currStartTimes, scStartTimes[v2])
currEndTimes = append(currEndTimes, scEndTimes[v2])
}
startTimes = append(startTimes, model.Min(currStartTimes))
endTimes = append(endTimes, model.Max(currEndTimes))
}
return []int32{model.Min(startTimes), model.Max(endTimes)}, nil
}
// CanDelScreen 检查是否可以删除场次
func (d *Dao) CanDelScreen(id int64) bool {
var priceIDs []int64
// 获取场次下 所有票价id
var prices []model.TicketPrice
if err := d.db.Select("id").Where("screen_id = ? and deleted_at = 0", id).Find(&prices).Error; err != nil {
log.Error("获取场次下所有票价id失败:%s", err)
return false
}
for _, v := range prices {
priceIDs = append(priceIDs, v.ID)
}
if d.HasPromotion(priceIDs, 2) || d.StockChanged(priceIDs) {
log.Error("场次的票价下存在拼团或者库存有变动")
return false
}
return true
}

View File

@@ -0,0 +1,22 @@
package dao
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
// TestDao_CalPassScTime
func TestDao_CalPassScTime(t *testing.T) {
Convey("CalPassScTime", t, func() {
once.Do(startService)
startTimes := map[int32]int32{0: 1530860100, 1: 1530860122}
endTimes := map[int32]int32{0: 1533365702, 1: 1533970523}
var tksPass []TicketPass
tksPass = append(tksPass, TicketPass{Name: "test1", LinkScreens: []int32{0, 1}})
tksPass = append(tksPass, TicketPass{Name: "test2", LinkScreens: []int32{0, 1}})
res, err := d.CalPassScTime(startTimes, endTimes, tksPass)
So(res, ShouldNotBeNil)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,268 @@
package dao
import (
"context"
"fmt"
"strings"
"time"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/ecode"
"go-common/library/log"
"github.com/jinzhu/gorm"
)
// 管理area_seats、area_seatmap、seat_set、seat_order座位相关表
// area_seats为区域座位表每个座位一行
// area_seatmap为区域座位图表每个区域一行与area_seats对应
// seat_order为场次的座位订单表每个座位一行创建场次座位图时生成
// seat_set为场次的座位设置图表每个区域一行基于area_seatmap生成针对场次含有不同的票价标记
const (
// StatusCansale 可售
StatusCansale = 0
// StatusIssue 已出票
StatusIssue = 2
// StatusLocked 已锁定
StatusLocked = 3
// StatusBooked 已预订
StatusBooked = 4
)
// TxUpdateSeat 编辑区域座位信息(事务)
func (d *Dao) TxUpdateSeat(c context.Context, tx *gorm.DB, area *model.Area) (err error) {
if err = tx.Table("area").Where("id = ?", area.ID).Updates(
map[string]interface{}{
"seats_num": area.SeatsNum,
"width": area.Width,
"height": area.Height,
"deleted_status": area.DeletedStatus,
"col_start": area.ColStart,
"col_type": area.ColType,
"col_direction": area.ColDirection,
"row_list": area.RowList,
"seat_start": area.SeatStart,
}).Error; err != nil {
log.Error("更新区域座位信息ID:%d失败:%s", area.ID, err)
err = ecode.NotModified
return
}
return
}
// TxGetAreaSeats 批量获取区域对应的区域座位信息(事务)
func (d *Dao) TxGetAreaSeats(c context.Context, tx *gorm.DB, area int64) (areaSeats []*model.AreaSeats, err error) {
if err = tx.Find(&areaSeats, "area = ?", area).Error; err != nil {
log.Error("批量获取区域座位信息area:%d失败:%s", area, err)
return
}
return
}
// TxBatchAddAreaSeats 批量添加区域座位信息(事务)
func (d *Dao) TxBatchAddAreaSeats(c context.Context, tx *gorm.DB, areaSeats []*model.AreaSeats) (err error) {
if len(areaSeats) == 0 {
return
}
var values = make([]string, len(areaSeats))
for i, areaSeat := range areaSeats {
values[i] = fmt.Sprintf("(%d,%d,'%s','%s',%d,%d)", areaSeat.X, areaSeat.Y, areaSeat.Label, areaSeat.Bgcolor, areaSeat.Area, 0)
}
var sql = fmt.Sprintf("INSERT INTO `area_seats` (`x`, `y`, `label`, `bgcolor`, `area`, `dstatus`) VALUES %s;", strings.Join(values, ","))
if err = tx.Exec(sql).Error; err != nil {
log.Error("批量添加区域座位信息(%s失败:%s", sql, err)
err = ecode.NotModified
return
}
return
}
// TxBatchDeleteAreaSeats 软删除区域对应的区域座位表信息
func (d *Dao) TxBatchDeleteAreaSeats(c context.Context, tx *gorm.DB, area int64) (err error) {
if err = tx.Table("area_seats").Where("area = ?", area).Updates(
map[string]interface{}{
"dstatus": 1,
}).Error; err != nil {
log.Error("删除区域座位信息area:%d失败:%s", area, err)
err = ecode.NotModified
return
}
return
}
// TxBatchRecoverAreaSeats 恢复软删除的区域座位表信息
func (d *Dao) TxBatchRecoverAreaSeats(c context.Context, tx *gorm.DB, ids []int64) (err error) {
if err = tx.Table("area_seats").Where("id in (?)", ids).Updates(
map[string]interface{}{
"dstatus": 0,
}).Error; err != nil {
log.Error("批量恢复区域座位信息失败:%s", err)
err = ecode.NotModified
return
}
return
}
// TxRawAreaSeatmap 获取区域座位图信息(事务)
func (d *Dao) TxRawAreaSeatmap(c context.Context, tx *gorm.DB, id int64) (areaSeatmap *model.AreaSeatmap, err error) {
areaSeatmap = new(model.AreaSeatmap)
if err = tx.First(&areaSeatmap, id).Error; err != nil {
log.Error("获取区域座位信息ID:%d失败:%s", id, err)
return
}
return
}
// TxSaveAreaSeatmap 添加/修改区域座位图信息(事务)
func (d *Dao) TxSaveAreaSeatmap(c context.Context, tx *gorm.DB, areaSeatmap *model.AreaSeatmap) (err error) {
if res := tx.Save(areaSeatmap); res.Error != nil {
log.Error("添加区域座位信息失败:%s", res.Error)
err = ecode.NotModified
return
}
return
}
// TxGetSeatChart 根据场次ID和区域ID查询ID和票价设置图事务
func (d *Dao) TxGetSeatChart(c context.Context, tx *gorm.DB, screen int64, area int64) (seatSet *model.SeatSet, err error) {
seatSet = new(model.SeatSet)
if res := tx.Select("id, seat_chart").Where("screen_id = ? AND area_id = ? AND deleted_at = 0", screen, area).First(seatSet); res.Error != nil {
if res.RecordNotFound() {
return
}
err = res.Error
log.Error("TxGetSeatChart error(%v)", err)
}
return
}
// TxGetSeatCharts 根据场次ID和多个区域ID批量查询多个票价设置ID和票价设置图事务
func (d *Dao) TxGetSeatCharts(c context.Context, tx *gorm.DB, screen int64, areas []int64) (seatSets []*model.SeatSet, err error) {
if err = tx.Select("id, seat_chart").Where("screen_id = ? AND area_id in (?) AND deleted_at = 0", screen, areas).Find(&seatSets).Error; err != nil {
log.Error("TxGetSeatCharts error(%v)", err)
}
return
}
// TxGetSeatSets 根据区域ID批量查询多个票价设置ID和场次ID事务
func (d *Dao) TxGetSeatSets(c context.Context, tx *gorm.DB, area int64) (seatSets []*model.SeatSet, err error) {
if err = tx.Select("id, screen_id").Where("area_id = ? AND deleted_at = 0", area).Find(&seatSets).Error; err != nil {
log.Error("TxGetSeatSets error(%v)", err)
}
return
}
// TxAddSeatChart 添加票价设置图(事务)
func (d *Dao) TxAddSeatChart(c context.Context, tx *gorm.DB, seatSet *model.SeatSet) (err error) {
if res := tx.Create(seatSet); res.Error != nil {
log.Error("添加票价设置图失败:%s", res.Error)
err = ecode.NotModified
return
}
return
}
// TxUpdateSeatChart 更新票价设置图(事务)
func (d *Dao) TxUpdateSeatChart(c context.Context, tx *gorm.DB, id int64, seatChart string) (err error) {
if err = tx.Table("seat_set").Where("id = ? AND deleted_at = 0", id).Updates(
map[string]interface{}{
"seat_chart": seatChart,
}).Error; err != nil {
log.Error("更新票价设置图ID:%d失败:%s", id, err)
}
return
}
// TxClearSeatCharts 清空票价设置图(事务)
func (d *Dao) TxClearSeatCharts(c context.Context, tx *gorm.DB, ids []int64) (err error) {
if err = tx.Table("seat_set").Where("id IN (?) AND deleted_at = 0", ids).Updates(
map[string]interface{}{
"seat_chart": "",
}).Error; err != nil {
log.Error("清空票价设置图失败:%s", err)
}
return
}
// TxGetUnsaleableSeatOrders 根据场次和区域ID查询不可售座位订单信息事务
func (d *Dao) TxGetUnsaleableSeatOrders(c context.Context, tx *gorm.DB, screen int64, area int64) (seatOrders []*model.SeatOrder, err error) {
if err = tx.Unscoped().Where("screen_id = ? AND area_id = ? AND status in (?) AND deleted_at = 0", screen, area, []int32{StatusIssue, StatusLocked, StatusBooked}).Find(&seatOrders).Error; err != nil {
log.Error("TxGetUnsaleableSeatOrders error(%v)", err)
}
return
}
// TxGetSaleableSeatOrders 根据场次ID和票价ID查询可售座位订单ID和区域ID信息事务
func (d *Dao) TxGetSaleableSeatOrders(c context.Context, tx *gorm.DB, screen int64, price int64) (seatOrders []*model.SeatOrder, err error) {
if err = tx.Select("id, area_id").Unscoped().Where("screen_id = ? AND price_id = ? AND status = ? AND deleted_at = 0", screen, price, StatusCansale).Find(&seatOrders).Error; err != nil {
log.Error("TxGetSaleableSeatOrders error(%v)", err)
}
return
}
// TxBatchDelUnsoldSeatOrders 根据区域ID清空未售出的座位订单事务
func (d *Dao) TxBatchDelUnsoldSeatOrders(c context.Context, tx *gorm.DB, area int64) (err error) {
if err = tx.Table("seat_order").Where("area_id = ? AND status IN (?) AND deleted_at = 0", area, []int32{StatusCansale, StatusLocked}).Updates(
map[string]interface{}{
"deleted_at": time.Now(),
}).Error; err != nil {
log.Error("批量删除座位订单信息失败:%s", err)
err = ecode.NotModified
return
}
return
}
// TxAddSeatOrder 添加座位订单信息(事务,暂未使用)
func (d *Dao) TxAddSeatOrder(c context.Context, tx *gorm.DB, seatOrder *model.SeatOrder) (err error) {
if res := tx.Create(seatOrder); res.Error != nil {
log.Error("添加座位订单信息失败:%s", res.Error)
err = ecode.NotModified
return
}
return
}
// TxUpdateSeatOrder 编辑座位订单信息(事务,暂未使用)
// TODO: 具体字段未指定
func (d *Dao) TxUpdateSeatOrder(c context.Context, tx *gorm.DB, seatOrder *model.SeatOrder) (err error) {
if err = tx.Table("seat_order").Where("id = ? AND deleted_at = 0", seatOrder.ID).Updates(
map[string]interface{}{}).Error; err != nil {
log.Error("更新座位订单信息ID:%d失败:%s", seatOrder.ID, err)
err = ecode.NotModified
return
}
return
}
// TxBatchDeleteSeatOrder 批量软删除座位订单信息(事务)
func (d *Dao) TxBatchDeleteSeatOrder(c context.Context, tx *gorm.DB, ids []int64) (err error) {
if err = tx.Table("seat_order").Where("id in (?)", ids).Updates(
map[string]interface{}{
"deleted_at": time.Now(),
}).Error; err != nil {
log.Error("批量删除座位订单信息失败:%s", err)
err = ecode.NotModified
return
}
return
}
// TxBatchAddSeatOrder 批量添加座位订单(事务)
func (d *Dao) TxBatchAddSeatOrder(c context.Context, tx *gorm.DB, seatOrders []*model.SeatOrder) (err error) {
if len(seatOrders) == 0 {
return
}
var values = make([]string, len(seatOrders))
for i, so := range seatOrders {
values[i] = fmt.Sprintf("(%d,%d,%d,%d,%d,%d)", so.AreaID, so.ScreenID, so.Row, so.Col, so.PriceID, so.Price)
}
var sql = fmt.Sprintf("INSERT INTO `seat_order` (`area_id`, `screen_id`, `row`, `col`, `price_id`, `price`) VALUES %s;", strings.Join(values, ","))
if err = tx.Exec(sql).Error; err != nil {
log.Error("批量添加区域座位信息(%s失败:%s", sql, err)
err = ecode.NotModified
return
}
return
}

View File

@@ -0,0 +1,289 @@
package dao
import (
"context"
"go-common/app/service/openplatform/ticket-item/model"
"strconv"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
// TestDaoAreaSeats
func TestDaoAreaSeats(t *testing.T) {
var id int64
Convey("TxGetAreaSeats", t, func() {
once.Do(startService)
c := context.TODO()
tx, _ := d.BeginTran(c)
So(tx, ShouldNotBeNil)
area := &model.Area{
AID: "test" + strconv.FormatInt(time.Now().Unix(), 10),
Name: "可删",
Place: 132,
}
err := d.TxAddArea(c, tx, area)
So(err, ShouldBeNil)
So(area.ID, ShouldNotEqual, 0)
id = area.ID
res, err := d.TxGetAreaSeats(c, tx, id)
So(err, ShouldBeNil)
So(len(res), ShouldEqual, 0)
err = d.CommitTran(c, tx)
So(err, ShouldBeNil)
})
var seatsIDs []int64
Convey("TxBatchAddAreaSeats", t, func() {
once.Do(startService)
c := context.TODO()
tx, _ := d.BeginTran(c)
So(tx, ShouldNotBeNil)
seatsArr := []*model.AreaSeats{
{
X: 1,
Y: 2,
Label: "3",
Bgcolor: "#FFFFFF",
Area: id,
Dstatus: 0,
},
{
X: 2,
Y: 2,
Label: "4",
Bgcolor: "#FFFFFF",
Area: id,
Dstatus: 0,
},
}
err := d.TxBatchAddAreaSeats(c, tx, seatsArr)
So(err, ShouldBeNil)
err = d.CommitTran(c, tx)
So(err, ShouldBeNil)
tx, _ = d.BeginTran(c)
So(tx, ShouldNotBeNil)
res, err := d.TxGetAreaSeats(c, tx, id)
So(err, ShouldBeNil)
So(len(res), ShouldEqual, 2)
seatsIDs = []int64{res[0].ID, res[1].ID}
err = d.CommitTran(c, tx)
So(err, ShouldBeNil)
})
Convey("TxBatchDeleteAreaSeats", t, func() {
once.Do(startService)
c := context.TODO()
tx, _ := d.BeginTran(c)
So(tx, ShouldNotBeNil)
err := d.TxBatchDeleteAreaSeats(c, tx, id)
So(err, ShouldBeNil)
err = d.CommitTran(c, tx)
So(err, ShouldBeNil)
tx, _ = d.BeginTran(c)
So(tx, ShouldNotBeNil)
res, err := d.TxGetAreaSeats(c, tx, id)
So(err, ShouldBeNil)
So(len(res), ShouldEqual, 2)
So(res[0].Dstatus, ShouldEqual, 1)
So(res[1].Dstatus, ShouldEqual, 1)
err = d.CommitTran(c, tx)
So(err, ShouldBeNil)
})
Convey("TxBatchRecoverAreaSeats", t, func() {
once.Do(startService)
c := context.TODO()
tx, _ := d.BeginTran(c)
So(tx, ShouldNotBeNil)
err := d.TxBatchRecoverAreaSeats(c, tx, seatsIDs)
So(err, ShouldBeNil)
err = d.CommitTran(c, tx)
So(err, ShouldBeNil)
tx, _ = d.BeginTran(c)
So(tx, ShouldNotBeNil)
res, err := d.TxGetAreaSeats(c, tx, id)
So(err, ShouldBeNil)
So(len(res), ShouldEqual, 2)
So(res[0].Dstatus, ShouldEqual, 0)
So(res[1].Dstatus, ShouldEqual, 0)
err = d.CommitTran(c, tx)
So(err, ShouldBeNil)
})
}
// TestDaoAreaSeats
func TestDaoAreaSeatmap(t *testing.T) {
once.Do(startService)
c := context.TODO()
tx, _ := d.BeginTran(c)
Convey("TxRawAreaSeatmap", t, func() {
So(tx, ShouldNotBeNil)
asm, err := d.TxRawAreaSeatmap(c, tx, 239)
So(asm.ID, ShouldEqual, 239)
So(asm.SeatMap, ShouldNotBeBlank)
So(err, ShouldBeNil)
})
Convey("TxRawAreaSeatmap", t, func() {
So(tx, ShouldNotBeNil)
asm := &model.AreaSeatmap{
ID: 239,
SeatMap: "[\"abc\"]",
}
err := d.TxSaveAreaSeatmap(c, tx, asm)
So(err, ShouldBeNil)
asm, err = d.TxRawAreaSeatmap(c, tx, 239)
So(asm.ID, ShouldEqual, 239)
So(asm.SeatMap, ShouldEqual, "[\"abc\"]")
So(err, ShouldBeNil)
})
tx.Rollback()
}
func TestSeatSet(t *testing.T) {
once.Do(startService)
c := context.TODO()
tx, _ := d.BeginTran(c)
Convey("TxGetSeatChart", t, func() {
So(tx, ShouldNotBeNil)
sc, err := d.TxGetSeatChart(c, tx, 1633, 239)
So(sc.ID, ShouldBeZeroValue)
So(sc.SeatChart, ShouldBeEmpty)
So(err, ShouldBeNil)
})
Convey("TxGetSeatCharts", t, func() {
So(tx, ShouldNotBeNil)
scs, err := d.TxGetSeatCharts(c, tx, 1633, []int64{239})
So(len(scs), ShouldBeZeroValue)
So(err, ShouldBeNil)
})
Convey("TxAddSeatChart", t, func() {
So(tx, ShouldNotBeNil)
err := d.TxAddSeatChart(c, tx, &model.SeatSet{
AreaID: 239,
ScreenID: 1633,
})
So(err, ShouldBeNil)
})
var id int64
Convey("TxGetSeatCharts", t, func() {
So(tx, ShouldNotBeNil)
scs, err := d.TxGetSeatCharts(c, tx, 1633, []int64{239})
So(len(scs), ShouldEqual, 1)
So(scs[0].SeatChart, ShouldBeEmpty)
So(err, ShouldBeNil)
id = scs[0].ID
})
Convey("TxUpdateSeatChart", t, func() {
So(tx, ShouldNotBeNil)
err := d.TxUpdateSeatChart(c, tx, id, "[\"_______aaaaaaaaaaaaa\",\"_______aaaaaaaaaaaaa\",\"______aaaaaaaaaaaaaa\",\"______aaaaaaaaaaaaaa\",\"_____aaaaaaaaaaaaaaa\",\"_____aaaaaaaaaaaaaaa\",\"____aaaaaaaaaaaaaaaa\",\"____aaaaaaaaaaaaaaaa\",\"___aaaaaaaaaaaaaaaaa\",\"___aaaaaaaaaaaaaaaaa\",\"__aaaaaaaaaaaaaaaaaa\",\"__aaaaaaaaaaaaaaaaaa\",\"aaaaaaaaaaaaaaaaaaaa\",\"aaaaaaaaaaaaaaaaaaaa\",\"___aaaaaaaaaaaaaa___\",\"_aaaaaaaaaaaaaaaaaa_\"]")
So(err, ShouldBeNil)
})
Convey("TxGetSeatChart", t, func() {
So(tx, ShouldNotBeNil)
sc, err := d.TxGetSeatChart(c, tx, 1633, 239)
So(sc.ID, ShouldEqual, id)
So(sc.SeatChart, ShouldNotBeEmpty)
So(err, ShouldBeNil)
})
tx.Rollback()
}
// TestSeatOrder
func TestSeatOrder(t *testing.T) {
once.Do(startService)
c := context.TODO()
tx, _ := d.BeginTran(c)
Convey("TxBatchAddSeatOrder", t, func() {
So(tx, ShouldNotBeNil)
err := d.TxBatchAddSeatOrder(c, tx, []*model.SeatOrder{
{
AreaID: 239,
ScreenID: 1633,
Row: 1,
Col: 1,
PriceID: 36093,
Price: 123456,
}, {
AreaID: 239,
ScreenID: 1633,
Row: 2,
Col: 2,
PriceID: 36093,
Price: 123456,
}, {
AreaID: 239,
ScreenID: 1633,
Row: 3,
Col: 3,
PriceID: 36093,
Price: 123456,
},
})
So(err, ShouldBeNil)
})
Convey("TxGetUnsaleableSeatOrders", t, func() {
res, err := d.TxGetUnsaleableSeatOrders(c, tx, 1633, 239)
So(err, ShouldBeNil)
So(len(res), ShouldEqual, 0)
})
var ids [3]int64
Convey("TxGetSaleableSeatOrders", t, func() {
res, err := d.TxGetSaleableSeatOrders(c, tx, 1633, 36093)
So(err, ShouldBeNil)
So(len(res), ShouldEqual, 3)
for i, so := range res {
ids[i] = so.ID
}
})
Convey("TxBatchDeleteSeatOrder", t, func() {
err := d.TxBatchDeleteSeatOrder(c, tx, ids[:])
So(err, ShouldBeNil)
})
tx.Commit()
tx, _ = d.BeginTran(c)
Convey("TxGetSaleableSeatOrders", t, func() {
res, err := d.TxGetSaleableSeatOrders(c, tx, 1633, 36093)
So(err, ShouldBeNil)
So(len(res), ShouldEqual, 0)
})
tx.Rollback()
}

View File

@@ -0,0 +1,27 @@
package dao
import (
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/log"
)
// StockChanged 检查票价下库存是否有变动
func (d *Dao) StockChanged(ids []int64) bool {
if ids == nil {
return false
}
var stocks []model.Stock
if err := d.db.Select("total_stock, stock").Where("sku_id IN (?)", ids).Find(&stocks).Error; err != nil {
log.Error("获取票价库存信息失败:%s", err)
return true
}
for _, v := range stocks {
if (v.TotalStock - v.Stock) != 0 {
log.Error("票价存在库存有变动")
return true
}
}
return false
}

View File

@@ -0,0 +1,17 @@
package dao
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
// TestStockChanged
func TestDao_StockChanged(t *testing.T) {
Convey("StockChanged", t, func() {
once.Do(startService)
res := d.StockChanged([]int64{1015, 1016})
So(res, ShouldBeTrue)
})
}

View File

@@ -0,0 +1,55 @@
package dao
import (
"context"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/log"
"strconv"
"strings"
"github.com/jinzhu/gorm"
"go-common/app/service/openplatform/ticket-item/conf"
"go-common/library/ecode"
)
// CreateTag 创建项目标签
func (d *Dao) CreateTag(c context.Context, tx *gorm.DB, pid int64, tagID string) error {
tagMap := d.GetTagConfigInfo(c)
covTagID, _ := strconv.ParseInt(tagID, 10, 64)
if _, ok := tagMap[tagID]; !ok {
//key不存在
log.Error("标签id不存在对应标签名")
tx.Rollback()
return ecode.TicketAddTagFailed
}
// create
if err := tx.Create(&model.ProjectTags{
TagID: covTagID,
TagName: tagMap[tagID],
ProjectID: pid,
Status: 1,
}).Error; err != nil {
log.Error("创建标签失败:%s", err)
tx.Rollback()
return err
}
return nil
}
// GetTagConfigInfo 获取标签配置信息返回map
func (d *Dao) GetTagConfigInfo(c context.Context) map[string]string {
tagStr := conf.Conf.Tag.Tags
allTags := strings.Split(tagStr, ",")
tagMap := make(map[string]string)
var tagInfo []string
for _, v := range allTags {
tagInfo = strings.Split(v, "=")
tagMap[tagInfo[0]] = tagInfo[1]
}
return tagMap
}

View File

@@ -0,0 +1,19 @@
package dao
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
// TestCreateTag
func TestDao_CreateTag(t *testing.T) {
Convey("CreateTag", t, func() {
once.Do(startService)
tx := d.db.Begin()
err := d.CreateTag(context.TODO(), tx, 1, "10003")
tx.Commit()
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,569 @@
package dao
import (
"context"
"encoding/json"
"fmt"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/cache/redis"
"go-common/library/ecode"
"go-common/library/log"
"strconv"
"strings"
"time"
"github.com/jinzhu/gorm"
)
const (
// TkTypeSingle 单场票
TkTypeSingle = 1
// TkTypePass 通票
TkTypePass = 2
// TkTypeAllPass 联票
TkTypeAllPass = 3
// TimeNull 空时间0000-00-00 00:00:00
TimeNull = -62135596800
)
// RawTkListByItem 批量取项目票价
func (d *Dao) RawTkListByItem(c context.Context, ids []int64) (info map[int64][]*model.TicketInfo, err error) {
info = make(map[int64][]*model.TicketInfo)
tkExt := make(map[int64]map[string]*model.TicketPriceExtra)
rows, err := d.db.Model(&model.TicketPrice{}).Where("project_id in (?) and deleted_at = 0", ids).Rows()
extRows, err := d.db.Model(&model.TicketPriceExtra{}).Where("project_id in (?) and is_deleted = 0", ids).Rows()
if err != nil {
log.Error("RawListByItem(%v) error(%v)", model.JSONEncode(ids), err)
return
}
defer rows.Close()
defer extRows.Close()
for extRows.Next() {
var ext model.TicketPriceExtra
err = d.db.ScanRows(extRows, &ext)
if err != nil {
log.Error("RawListByItem(%v) error(%v)", model.JSONEncode(ids), err)
return
}
if _, ok := tkExt[ext.SkuID]; !ok {
tkExt[ext.SkuID] = make(map[string]*model.TicketPriceExtra)
}
if _, ok := tkExt[ext.SkuID][ext.Attrib]; !ok {
tkExt[ext.SkuID][ext.Attrib] = new(model.TicketPriceExtra)
}
tkExt[ext.SkuID][ext.Attrib] = &ext
}
for rows.Next() {
var tk model.TicketInfo
err = d.db.ScanRows(rows, &tk)
if err != nil {
log.Error("RawListByItem(%v) error(%v)", model.JSONEncode(ids), err)
return
}
if _, ok := tkExt[tk.ID]; ok {
tk.BuyNumLimit = tkExt[tk.ID]
}
info[tk.ProjectID] = append(info[tk.ProjectID], &tk)
}
return
}
// CacheTkListByItem 缓存取项目票价
func (d *Dao) CacheTkListByItem(c context.Context, ids []int64) (info map[int64][]*model.TicketInfo, err error) {
var keys []interface{}
keyPidMap := make(map[string]int64, len(ids))
for _, id := range ids {
key := keyItemTicket(id)
if _, ok := keyPidMap[key]; !ok {
// duplicate mid
keyPidMap[key] = id
keys = append(keys, key)
}
}
conn := d.redis.Get(c)
defer conn.Close()
var data [][]byte
log.Info("MGET %v", model.JSONEncode(keys))
if data, err = redis.ByteSlices(conn.Do("mget", keys...)); err != nil {
log.Error("TkList MGET %v ERR: %v", model.JSONEncode(keys), err)
return
}
info = make(map[int64][]*model.TicketInfo)
for _, d := range data {
if d != nil {
var tks []*model.TicketInfo
json.Unmarshal(d, &tks)
info[tks[0].ProjectID] = tks
}
}
return
}
// AddCacheTkListByItem 取项目票价添加缓存
func (d *Dao) AddCacheTkListByItem(c context.Context, info map[int64][]*model.TicketInfo) (err error) {
conn := d.redis.Get(c)
defer func() {
conn.Flush()
conn.Close()
}()
var data []interface{}
var keys []string
for k, v := range info {
b, _ := json.Marshal(v)
key := keyItemTicket(k)
keys = append(keys, key)
data = append(data, key, b)
}
log.Info("MSET %v", keys)
if err = conn.Send("MSET", data...); err != nil {
return
}
for i := 0; i < len(data); i += 2 {
conn.Send("EXPIRE", data[i], CacheTimeout)
}
return
}
// RawTkList 批量取票价
func (d *Dao) RawTkList(c context.Context, ids []int64) (list map[int64]*model.TicketInfo, err error) {
list = make(map[int64]*model.TicketInfo)
tkExt := make(map[int64]map[string]*model.TicketPriceExtra)
rows, err := d.db.Model(&model.TicketPrice{}).Where("id in (?) and deleted_at = 0", ids).Rows()
extRows, err := d.db.Model(&model.TicketPriceExtra{}).Where("sku_id in (?) and is_deleted = 0", ids).Rows()
if err != nil {
log.Error("RawTkList(%v) error(%v)", model.JSONEncode(ids), err)
return
}
defer rows.Close()
defer extRows.Close()
for extRows.Next() {
var ext model.TicketPriceExtra
err = d.db.ScanRows(extRows, &ext)
if err != nil {
log.Error("RawListByItem(%v) error(%v)", model.JSONEncode(ids), err)
return
}
if _, ok := tkExt[ext.SkuID]; !ok {
tkExt[ext.SkuID] = make(map[string]*model.TicketPriceExtra)
}
if _, ok := tkExt[ext.SkuID][ext.Attrib]; !ok {
tkExt[ext.SkuID][ext.Attrib] = new(model.TicketPriceExtra)
}
tkExt[ext.SkuID][ext.Attrib] = &ext
}
for rows.Next() {
var tk model.TicketInfo
err = d.db.ScanRows(rows, &tk)
if err != nil {
log.Error("RawTkList(%v) error(%v)", model.JSONEncode(ids), err)
return
}
if _, ok := tkExt[tk.ID]; ok {
tk.BuyNumLimit = tkExt[tk.ID]
}
list[tk.ID] = &tk
}
return
}
// CacheTkList 缓存取项目票价
func (d *Dao) CacheTkList(c context.Context, ids []int64) (list map[int64]*model.TicketInfo, err error) {
var keys []interface{}
keyPidMap := make(map[string]int64, len(ids))
for _, id := range ids {
key := keyTicket(id)
if _, ok := keyPidMap[key]; !ok {
// duplicate mid
keyPidMap[key] = id
keys = append(keys, key)
}
}
conn := d.redis.Get(c)
defer conn.Close()
var data [][]byte
log.Info("MGET %v", model.JSONEncode(keys))
if data, err = redis.ByteSlices(conn.Do("mget", keys...)); err != nil {
log.Error("TkList MGET %v ERR: %v", model.JSONEncode(keys), err)
return
}
list = make(map[int64]*model.TicketInfo)
for _, d := range data {
if d != nil {
var tk *model.TicketInfo
json.Unmarshal(d, &tk)
list[tk.ID] = tk
}
}
return
}
// AddCacheTkList 取项目票价添加缓存
func (d *Dao) AddCacheTkList(c context.Context, list map[int64]*model.TicketInfo) (err error) {
conn := d.redis.Get(c)
defer func() {
conn.Flush()
conn.Close()
}()
var data []interface{}
var keys []string
for k, v := range list {
b, _ := json.Marshal(v)
key := keyTicket(k)
keys = append(keys, key)
data = append(data, key, b)
}
log.Info("MSET %v", keys)
if err = conn.Send("MSET", data...); err != nil {
return
}
for i := 0; i < len(data); i += 2 {
conn.Send("EXPIRE", data[i], CacheTimeout)
}
return
}
// CreateOrUpdateTkPrice 创建或更新票种
func (d *Dao) CreateOrUpdateTkPrice(c context.Context, tx *gorm.DB, priceInfo model.TicketPrice, opType int32) (model.TicketPrice, error) {
if opType == 0 {
// create
if err := tx.Create(&priceInfo).Error; err != nil {
log.Error("创建票种失败:%s", err)
tx.Rollback()
return model.TicketPrice{}, err
}
} else {
// update
if err := tx.Model(&model.TicketPrice{}).Where("id = ?", priceInfo.ID).Updates(
map[string]interface{}{
"project_id": priceInfo.ProjectID,
"desc": priceInfo.Desc,
"type": priceInfo.Type,
"sale_type": priceInfo.SaleType,
"color": priceInfo.Color,
"buy_limit": priceInfo.BuyLimit,
"payment_method": priceInfo.PaymentMethod,
"payment_value": priceInfo.PaymentValue,
"desc_detail": priceInfo.DescDetail,
}).Error; err != nil {
log.Error("更新票种失败:%s", err)
tx.Rollback()
return model.TicketPrice{}, err
}
}
return priceInfo, nil
}
// InsertOrUpdateTkPass 新建或更新通票联票票价
func (d *Dao) InsertOrUpdateTkPass(c context.Context, tx *gorm.DB, pid int64, scID int64, tksPass []TicketPass, tkType int32,
scIDList map[int32]int64, TkSingleIDList map[int32]int64, TkSingleTypeList map[int32]int32) ([]TicketPass, error) {
alphabetTable := model.AlphabetTable()
for k, v := range tksPass {
if _, ok := TkSingleIDList[v.LinkTicket]; !ok {
tx.Rollback()
log.Error("关联票种不存在")
return nil, ecode.TicketLkTkNotFound
}
if _, ok := TkSingleTypeList[v.LinkTicket]; !ok {
tx.Rollback()
log.Error("关联票种类型不存在")
return nil, ecode.TicketLkTkTypeNotFound
}
var linkScIDs []int64
for _, linkScID := range v.LinkScreens {
if _, ok := scIDList[linkScID]; !ok {
tx.Rollback()
log.Error("关联场次不存在")
return nil, ecode.TicketLkScNotFound
}
linkScIDs = append(linkScIDs, scIDList[linkScID])
}
tkID, _ := strconv.ParseInt(v.TicketID, 10, 64)
symbol := alphabetTable[k]
if tkID == 0 {
// create
newTkID, err := model.GetTicketIDFromBase()
if err != nil {
tx.Rollback()
log.Error("basecenter获取通票票价id失败:%s", err)
return nil, err
}
buyLimit, _ := strconv.ParseInt(v.BuyLimit, 10, 64)
payMethod, _ := strconv.ParseInt(v.PayMethod, 10, 64)
if err = tx.Create(&model.TicketPrice{
ID: newTkID,
ProjectID: pid,
ScreenID: scID,
Desc: v.Name,
BuyLimit: int32(buyLimit),
ParentID: TkSingleIDList[v.LinkTicket],
Color: v.Color,
DescDetail: v.Desc,
PaymentMethod: int32(payMethod),
PaymentValue: v.PayValue,
Type: tkType,
SaleType: TkSingleTypeList[v.LinkTicket],
Symbol: symbol,
LinkSc: model.Implode(",", linkScIDs),
IsSale: 0, // 不可售
IsRefund: -10, // 不可退
OriginPrice: -1, // 未設置
MarketPrice: -1,
SaleStart: TimeNull, // 0000-00-00 00:00:00
SaleEnd: TimeNull,
}).Error; err != nil {
log.Error("通票或联票创建失败:%s", err)
tx.Rollback()
return nil, err
}
//票价限购
limitData := d.FormatByPrefix(v.BuyLimitNum, "buy_limit_")
if err = d.CreateOrUpdateTkPriceExtra(c, tx, limitData, newTkID, pid); err != nil {
return nil, err
}
tksPass[k].TicketID = strconv.FormatInt(newTkID, 10)
} else {
// update
if err := tx.Model(&model.TicketPrice{}).Where("id = ?", tkID).Updates(map[string]interface{}{
"screen_id": scID,
"desc": v.Name,
"buy_limit": v.BuyLimit,
"parent_id": TkSingleIDList[v.LinkTicket],
"color": v.Color,
"desc_detail": v.Desc,
"payment_method": v.PayMethod,
"payment_value": v.PayValue,
"type": tkType,
"sale_type": TkSingleTypeList[v.LinkTicket],
"symbol": symbol,
"link_sc": model.Implode(",", linkScIDs),
}).Error; err != nil {
log.Error("通票或联票票价信息更新失败:%s", err)
tx.Rollback()
return nil, err
}
//票价限购
limitData := d.FormatByPrefix(v.BuyLimitNum, "buy_limit_")
if err := d.CreateOrUpdateTkPriceExtra(c, tx, limitData, tkID, pid); err != nil {
return nil, err
}
}
}
return tksPass, nil
}
// DelTicket 根据id删除票种或票价
func (d *Dao) DelTicket(c context.Context, tx *gorm.DB, oldIDs []int64, newIDs []int64, pid int64, isPrice bool) error {
delIDs, _ := model.ClassifyIDs(oldIDs, newIDs)
for _, delID := range delIDs {
if !d.CanDelTicket(delID, isPrice) {
tx.Rollback()
return ecode.TicketCannotDelTk
}
if isPrice {
// TODO 存在需要删除的票价时 检查票价是否在坐票可选座场次下 是的话需要删除对应的座位图
// 删除票价
if err := tx.Exec("UPDATE ticket_price SET deleted_at=? WHERE id = ? AND project_id = ?", time.Now().Format("2006-01-02 15:04:05"), delID, pid).Error; err != nil {
log.Error("删除票价失败:%s", err)
tx.Rollback()
return ecode.TicketDelTkFailed
}
// 删除票价额外信息表
if err := tx.Model(&model.TicketPriceExtra{}).Where("sku_id = ? project_id = ?", delID, pid).Update("is_deleted", 1).Error; err != nil {
log.Error("删除票种额外信息记录失败:%s", err)
tx.Rollback()
return ecode.TicketDelTkExFailed
}
} else {
// 票种 需要获取 所有票价id
priceIDs, err := d.GetPriceIDs(delID, 2)
if err != nil {
tx.Rollback()
return err
}
// TODO 存在需要删除的票价时 检查票价是否在坐票可选座场次下 是的话需要删除对应的座位图
// 将票种id加到需要删除的票价array里
priceIDs = append(priceIDs, delID)
// 删除票种票价
if err := tx.Exec("UPDATE ticket_price SET deleted_at=? WHERE id IN (?) AND project_id = ?", time.Now().Format("2006-01-02 15:04:05"), priceIDs, pid).Error; err != nil {
log.Error("删除票种及其票价失败:%s", err)
tx.Rollback()
return ecode.TicketDelTkFailed
}
//删除票价额外信息表
if err := tx.Model(&model.TicketPriceExtra{}).Where("sku_id IN (?) AND project_id = ?", priceIDs, pid).Update("is_deleted", 1).Error; err != nil {
log.Error("删除票种及票价额外信息记录失败:%s", err)
tx.Rollback()
return ecode.TicketDelTkExFailed
}
}
}
return nil
}
// CanDelTicket 检查是否可以删除票价或票种
func (d *Dao) CanDelTicket(id int64, isPrice bool) bool {
var priceIDs []int64
if isPrice {
// 票价
priceIDs = append(priceIDs, id)
} else {
// 票种 需要获取 所有票价id
ids, err := d.GetPriceIDs(id, 2)
if err != nil {
return false
}
priceIDs = ids
}
if d.HasPromotion(priceIDs, 2) || d.StockChanged(priceIDs) {
log.Error("票价下存在拼团或者库存有变动:%d", id)
return false
}
return true
}
// GetPriceIDs 获取场次或票种下所有票价id inputType 1-场次id 2-票种id
func (d *Dao) GetPriceIDs(id int64, inputType int32) ([]int64, error) {
var priceIDs []int64
var prices []model.TicketPrice
var whereStr string
if inputType == 1 {
// id = screenID
whereStr = "screen_id = ? and deleted_at = 0"
} else {
// id = skuID
whereStr = "parent_id = ? and deleted_at = 0"
}
if err := d.db.Select("id").Where(whereStr, id).Find(&prices).Error; err != nil {
log.Error("获取场次或票种下所有票价id失败:%s", err)
return nil, err
}
for _, v := range prices {
priceIDs = append(priceIDs, v.ID)
}
return priceIDs, nil
}
// ticket_price表同时包含票价和票种票种的parent_id为0票价的parent_id为票种ID
// 票种不直接使用于场次,票价继承自票种,指定某一场次
// 以此实现“票种可以在一个项目下多个场次通用”
// 坐票只存在单场票
// TxGetTicketPrice 获取票价的价格标志和场次(事务)
func (d *Dao) TxGetTicketPrice(c context.Context, tx *gorm.DB, id int64) (ticketPrice *model.TicketPrice, err error) {
ticketPrice = new(model.TicketPrice)
if err = tx.Select("symbol, screen_id").Where("id = ? AND parent_id <> 0 AND deleted_at = 0", id).First(ticketPrice).Error; err != nil {
log.Error("TxGetTicketPrice error(%v)", err)
}
return
}
// TxGetPriceSymbols 获取场次下的所有票价的父票种ID、价格和标志事务
func (d *Dao) TxGetPriceSymbols(c context.Context, tx *gorm.DB, screen int64) (ticketPrices []*model.TicketPrice, err error) {
if err = tx.Select("parent_id, price, symbol").Where("screen_id = ? AND type = ? AND parent_id <> 0 AND deleted_at = 0", screen, TkTypeSingle).Find(&ticketPrices).Error; err != nil {
log.Error("TxGetPriceSymbols error(%v)", err)
}
return
}
// TxGetParentTicketPrice 获取票种-单场票(事务)
func (d *Dao) TxGetParentTicketPrice(c context.Context, tx *gorm.DB, id int64) (ticketPrice *model.TicketPrice, err error) {
ticketPrice = new(model.TicketPrice)
if err = tx.Where("id = ? AND type = ? AND deleted_at = 0", id, TkTypeSingle).First(ticketPrice).Error; err != nil {
log.Error("TxGetParentTicketPrice error(%v)", err)
}
return
}
// TxBatchAddTicketPrice 批量添加票价(事务)
func (d *Dao) TxBatchAddTicketPrice(c context.Context, tx *gorm.DB, ticketPrices []*model.TicketPrice) (err error) {
if len(ticketPrices) == 0 {
return
}
var values = make([]string, len(ticketPrices))
for i, tp := range ticketPrices {
values[i] = fmt.Sprintf("(%d,%d,%d,%d,%d,'%s','%s',%d,'%s',%d,%d,%d,%d,%d,%d,%d,'%s',%d,'%s',%d,'%s',%d,%d,%d)", tp.ID, tp.ProjectID, tp.ScreenID, tp.Price, tp.BuyLimit, tp.Desc, tp.Color, tp.ParentID, tp.Symbol, tp.IsSale, tp.OriginPrice, tp.PaymentMethod, tp.PaymentValue, tp.Type, tp.IsRefund, tp.IsVisible, tp.DescDetail, tp.SaleType, tp.SaleTime, tp.LinkTicketID, tp.LinkSc, tp.SaleStart, tp.SaleEnd, tp.MarketPrice)
}
var sql = fmt.Sprintf("INSERT INTO `ticket_price` (`id`, `project_id`, `screen_id`, `price`, `buy_limit`, `desc`, `color`, `parent_id`, `symbol`, `is_sale`, `origin_price`, `payment_method`, `payment_value`, `type`, `is_refund`, `is_visible`, `desc_detail`, `sale_type`, `sale_time`, `link_ticket_id`, `link_sc`, `sale_start`, `sale_end`, `market_price`) VALUES %s;", strings.Join(values, ","))
if err = tx.Exec(sql).Error; err != nil {
log.Error("批量添加票种(%s失败:%s", sql, err)
err = ecode.NotModified
return
}
return
}
// CreateOrUpdateTkPriceExtra 创建票价额外信息记录
func (d *Dao) CreateOrUpdateTkPriceExtra(c context.Context, tx *gorm.DB, input map[string]string, skuID int64, pid int64) (err error) {
data := d.FormatInputData(input, skuID, pid)
var tmpTkExtra model.TicketPriceExtra
for attrib, val := range data {
if err = tx.Where("sku_id = ? and project_id = ? and attrib = ? and is_deleted=0", skuID, pid, attrib).First(&tmpTkExtra).Error; err != nil {
//除去没查找到记录的报错 其他直接抛错
if err != ecode.NothingFound {
log.Error("获取票价%s额外信息失败:%s", skuID, err)
tx.Rollback()
return
}
}
if tmpTkExtra.ID == 0 {
// create
if err = tx.Create(&val).Error; err != nil {
log.Error("创建票价额外信息记录失败:%s", err)
tx.Rollback()
return
}
} else {
// update
if err = tx.Model(&model.TicketPriceExtra{}).Where("sku_id = ? and project_id = ? and attrib = ?", skuID, pid, attrib).Update("value", val).Error; err != nil {
log.Error("更新票价额外信息记录失败:%s", err)
tx.Rollback()
return
}
}
}
return
}
// FormatInputData 格式化input数据
func (d *Dao) FormatInputData(input map[string]string, skuID int64, pid int64) (res []model.TicketPriceExtra) {
for key, value := range input {
res = append(res, model.TicketPriceExtra{
Attrib: key,
Value: value,
SkuID: skuID,
ProjectID: pid,
})
}
return
}
// FormatByPrefix 给键值加前缀
func (d *Dao) FormatByPrefix(input []string, prefix string) map[string]string {
result := make(map[string]string)
for k, v := range input {
result[prefix+strconv.Itoa(k)] = v
}
return result
}

View File

@@ -0,0 +1,180 @@
package dao
import (
"testing"
"time"
"context"
"go-common/app/service/openplatform/ticket-item/model"
"github.com/davecgh/go-spew/spew"
. "github.com/smartystreets/goconvey/convey"
)
// TestGetPriceIDs
func TestDao_GetPriceIDs(t *testing.T) {
Convey("GetPriceIDs", t, func() {
once.Do(startService)
res, err := d.GetPriceIDs(1, 2)
So(res, ShouldNotBeNil)
So(err, ShouldBeNil)
})
}
// TestCanDelTicket
func TestDao_CanDelTicket(t *testing.T) {
Convey("CanDelTicket", t, func() {
once.Do(startService)
res := d.CanDelTicket(33, true)
So(res, ShouldBeTrue)
})
}
/**
// TestDelTicket
func TestDao_DelTicket(t *testing.T) {
Convey("DelTicket", t, func() {
once.Do(startService)
tx := d.db.Begin()
err := d.DelTicket(context.TODO(), tx, []int64{33}, []int64{25}, 2, true)
tx.Commit()
So(err, ShouldBeNil)
})
}**/
// TestCreateOrUpdateTkPrice
func TestDao_CreateOrUpdateTkPrice(t *testing.T) {
Convey("CreateOrUpdateTkPrice", t, func() {
once.Do(startService)
tx := d.db.Begin()
priceInfo, err := d.CreateOrUpdateTkPrice(context.TODO(), tx, model.TicketPrice{
ID: 0,
ProjectID: 33,
Desc: "DESCCCC",
Type: 1, // 单场票
SaleType: 1,
Color: "#FF0000",
BuyLimit: 0,
PaymentMethod: 1,
PaymentValue: 0,
DescDetail: "DESCDETAIL",
IsSale: 1, // 可售
IsRefund: -10, // 不可退
OriginPrice: -1, // 未設置
MarketPrice: -1,
SaleStart: -62135596800, // 0000-00-00 00:00:00
SaleEnd: -62135596800,
}, 0)
spew.Dump(priceInfo)
tx.Commit()
So(priceInfo, ShouldNotBeNil)
So(err, ShouldBeNil)
})
}
/**
// TestInsertOrUpdateTkPass
func TestDao_InsertOrUpdateTkPass(t *testing.T) {
Convey("InsertOrUpdateTkPass", t, func() {
once.Do(startService)
tx := d.db.Begin()
priceInfo, err := d.InsertOrUpdateTkPass(context.TODO(), tx, model.TicketPrice{
ID: 0,
ProjectID: 33,
Desc: "DESCCCC",
Type: 1, // 单场票
SaleType: 1,
Color: "#FF0000",
BuyLimit: 0,
PaymentMethod: 1,
PaymentValue: 0,
DescDetail: "DESCDETAIL",
IsSale: 1, // 可售
IsRefund: -10, // 不可退
OriginPrice: -1, // 未設置
MarketPrice: -1,
SaleStart: -62135596800, // 0000-00-00 00:00:00
SaleEnd: -62135596800,
}, 0)
spew.Dump(priceInfo)
tx.Commit()
So(priceInfo, ShouldNotBeNil)
So(err, ShouldBeNil)
})
}**/
// TestTicketPrice
func TestTicketPrice(t *testing.T) {
var (
tp *model.TicketPrice
tps []*model.TicketPrice
err error
)
Convey("TxGetParentTicketPrice", t, func() {
once.Do(startService)
c := context.TODO()
tx, _ := d.BeginTran(c)
So(tx, ShouldNotBeNil)
tp, err = d.TxGetParentTicketPrice(c, tx, 13424)
So(tp.Desc, ShouldEqual, "海尔测试票")
So(err, ShouldBeNil)
err = d.CommitTran(c, tx)
So(err, ShouldBeNil)
})
var cnt int
Convey("TxGetPriceSymbols", t, func() {
once.Do(startService)
c := context.TODO()
tx, _ := d.BeginTran(c)
So(tx, ShouldNotBeNil)
tps, err = d.TxGetPriceSymbols(c, tx, 1633)
cnt = len(tps)
So(err, ShouldBeNil)
err = d.CommitTran(c, tx)
So(err, ShouldBeNil)
})
var genID int64
once.Do(startService)
c := context.TODO()
tx, _ := d.BeginTran(c)
Convey("TxBatchAddTicketPrice", t, func() {
genID, err = model.GetTicketIDFromBase()
So(genID, ShouldNotEqual, 0)
So(err, ShouldBeNil)
tp.ParentID = tp.ID
tp.ID = genID
tp.ScreenID = 1633
tp.Symbol = string(int(time.Now().Unix())%26 + 'A')
tp.OriginPrice = -1
tp.MarketPrice = -1
tp.IsSale = 0
tp.IsVisible = 0
tp.IsRefund = 10
So(tx, ShouldNotBeNil)
err = d.TxBatchAddTicketPrice(c, tx, []*model.TicketPrice{tp})
So(err, ShouldBeNil)
tps, err := d.TxGetPriceSymbols(c, tx, 1633)
So(len(tps)-cnt, ShouldEqual, 1)
So(err, ShouldBeNil)
})
Convey("TxGetTicketPrice", t, func() {
So(tx, ShouldNotBeNil)
tp, err := d.TxGetTicketPrice(c, tx, genID)
So(tp.ScreenID, ShouldEqual, 1633)
So(err, ShouldBeNil)
})
tx.Rollback()
Convey("TxGetTicketPrice", t, func() {
tx, _ := d.BeginTran(c)
So(tx, ShouldNotBeNil)
_, err := d.TxGetTicketPrice(c, tx, genID)
So(err, ShouldBeError)
})
}

View File

@@ -0,0 +1,449 @@
/*
Package dao venue
场馆venue=>场地place=>区域area的三级层次均为一对多
venue表冗余place_num表示场地数
place表通过ID对应place_polygon存有area的地理位置信息
*/
package dao
import (
"context"
"encoding/json"
"fmt"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/cache/redis"
"go-common/library/database/elastic"
"go-common/library/ecode"
"go-common/library/log"
"github.com/jinzhu/gorm"
)
// RawVenues 批量获取场馆
func (d *Dao) RawVenues(c context.Context, ids []int64) (vl map[int64]*model.Venue, err error) {
vrows, err := d.db.Model(&model.Venue{}).Where("id in (?)", ids).Rows()
vl = make(map[int64]*model.Venue)
if err != nil {
log.Error("RawVenues(%v) error(%v)", ids, err)
return
}
defer vrows.Close()
for vrows.Next() {
var v model.Venue
err = d.db.ScanRows(vrows, &v)
vl[v.ID] = &v
}
return
}
// CacheVenues 缓存批量获取场馆
func (d *Dao) CacheVenues(c context.Context, ids []int64) (vl map[int64]*model.Venue, err error) {
var keys []interface{}
keyVidMap := make(map[string]int64, len(ids))
for _, id := range ids {
key := keyVenue(id)
if _, ok := keyVidMap[key]; !ok {
// duplicate pid
keyVidMap[key] = id
keys = append(keys, key)
}
}
conn := d.redis.Get(c)
defer conn.Close()
var data [][]byte
log.Info("MGET %v", model.JSONEncode(keys))
if data, err = redis.ByteSlices((conn.Do("MGET", keys))); err != nil {
log.Error("VenueList MGET %v ERR: %v", model.JSONEncode(keys), err)
return
}
vl = make(map[int64]*model.Venue)
for _, d := range data {
if d != nil {
var v *model.Venue
vl[v.ID] = v
json.Unmarshal(d, &v)
}
}
return
}
// AddCacheVenues 缓存场馆信息
func (d *Dao) AddCacheVenues(c context.Context, vl map[int64]*model.Venue) (err error) {
conn := d.redis.Get(c)
defer func() {
conn.Flush()
conn.Close()
}()
var data []interface{}
var keys []string
for k, v := range vl {
b, _ := json.Marshal(v)
key := keyVenue(k)
keys = append(keys, key)
data = append(data, key, b)
}
log.Info("MSET %v", keys)
if err = conn.Send("MSET", data...); err != nil {
return
}
for i := 0; i < len(data); i += 2 {
conn.Send("EXPIRE", data[i], CacheTimeout)
}
return
}
// VenueSearch 场馆搜索
func (d *Dao) VenueSearch(c context.Context, req *model.VenueSearchParam) (venues *model.VenueSearchList, err error) {
r := d.es.NewRequest("ticket_venue").Index("ticket_venue")
if req.ID > 0 {
r.WhereEq("id", req.ID)
} else if req.Name != "" {
r.WhereLike([]string{"name"}, []string{req.Name}, false, elastic.LikeLevelLow)
}
if req.ProvinceID > 0 {
r.WhereEq("province", req.ProvinceID)
}
if req.CityID > 0 {
r.WhereEq("city", req.CityID)
}
r.Order("ctime", elastic.OrderDesc).Ps(req.Ps).Pn(req.Pn)
log.Info(fmt.Sprintf("%s/x/admin/search/query?%s", d.c.URL.ElasticHost, r.Params()))
venues = new(model.VenueSearchList)
if err = r.Scan(c, venues); err != nil {
log.Error("VenueSearch(%v) r.Query(%s) error(%s)", req, r.Params(), err)
}
return
}
// AddVenue 添加场馆信息
func (d *Dao) AddVenue(c context.Context, venue *model.Venue) (err error) {
if err = d.db.Create(venue).Error; err != nil {
log.Error("添加场馆信息失败:%s", err)
err = ecode.NotModified
return
}
return
}
// UpdateVenue 编辑场馆信息
func (d *Dao) UpdateVenue(c context.Context, venue *model.Venue) (err error) {
// update venue with new info (using map can update the column with empty string)
if err = d.db.Table("venue").Where("id = ?", venue.ID).Updates(
map[string]interface{}{
"name": venue.Name,
"city": venue.City,
"province": venue.Province,
"district": venue.District,
"address_detail": venue.AddressDetail,
"status": venue.Status,
"traffic": venue.Traffic,
}).Error; err != nil {
log.Error("更新场馆信息失败:%s", err)
err = ecode.NotModified
return
}
return
}
// TxIncPlaceNum 增加场馆的场地数(事务)
func (d *Dao) TxIncPlaceNum(c context.Context, tx *gorm.DB, venueID int64) (err error) {
var oriVenue model.Venue
if err = tx.First(&oriVenue, venueID).Error; err != nil {
log.Error("查找对应的场馆信息ID:%d失败:%s", venueID, err)
err = ecode.NotModified
return
}
if err = tx.Model(&oriVenue).Updates(
map[string]interface{}{
"place_num": oriVenue.PlaceNum + 1,
}).Error; err != nil {
log.Error("更新场馆信息ID:%d失败:%s", venueID, err)
err = ecode.NotModified
return
}
return
}
// TxDecPlaceNum 减少场馆的场地数(事务)
func (d *Dao) TxDecPlaceNum(c context.Context, tx *gorm.DB, venueID int64) (err error) {
var oriVenue model.Venue
if err = tx.First(&oriVenue, venueID).Error; err != nil {
log.Error("查找对应的场馆信息ID:%d失败:%s", venueID, err)
err = ecode.NotModified
return
}
if oriVenue.PlaceNum < 1 {
log.Error("更新场馆信息ID:%d失败:场地数小于1", venueID)
err = ecode.NotModified
return
}
if err = tx.Model(&oriVenue).Updates(
map[string]interface{}{
"place_num": oriVenue.PlaceNum - 1,
}).Error; err != nil {
log.Error("更新场馆信息ID:%d失败:%s", venueID, err)
err = ecode.NotModified
return
}
return
}
// RawPlace 获取场地
func (d *Dao) RawPlace(c context.Context, id int64) (place *model.Place, err error) {
place = new(model.Place)
err = d.db.Model(&model.Place{}).First(&place, id).Scan(&place).Error
if err != nil {
log.Error("RawPlace(%v) error(%v)", id, err)
}
return
}
// RawPlacePolygon 获取场地坐标
func (d *Dao) RawPlacePolygon(c context.Context, id int64) (placePolygon *model.PlacePolygon, err error) {
placePolygon = new(model.PlacePolygon)
err = d.db.Model(&model.PlacePolygon{}).First(&placePolygon, id).Scan(&placePolygon).Error
if err != nil {
log.Error("RawPlacePolygon(%v) error(%v)", id, err)
}
return
}
// TxRawPlace 获取场地(事务)
func (d *Dao) TxRawPlace(c context.Context, tx *gorm.DB, id int64) (place *model.Place, err error) {
place = new(model.Place)
err = tx.Model(&model.Place{}).First(&place, id).Scan(&place).Error
if err != nil {
log.Error("TxRawPlace(%v) error(%v)", id, err)
}
return
}
// CachePlace 缓存获取场地
func (d *Dao) CachePlace(c context.Context, id int64) (place *model.Place, err error) {
var data []byte
key := keyPlace(id)
conn := d.redis.Get(c)
defer conn.Close()
log.Info("GET %v", key)
if data, err = redis.Bytes((conn.Do("GET", key))); err != nil {
if err == redis.ErrNil {
err = nil
}
return
}
json.Unmarshal(data, &place)
return
}
// AddCachePlace 缓存场地信息
func (d *Dao) AddCachePlace(c context.Context, id int64, place *model.Place) (err error) {
conn := d.redis.Get(c)
defer func() {
conn.Flush()
conn.Close()
}()
var data []interface{}
key := keyPlace(id)
data = append(data, key, place)
log.Info("SET %v", key)
if err = conn.Send("SET", data...); err != nil {
return
}
conn.Send("EXPIRE", data[0], CacheTimeout)
return
}
// TxAddPlace 添加场地信息(事务)
func (d *Dao) TxAddPlace(c context.Context, tx *gorm.DB, place *model.Place) (err error) {
if err = tx.Create(place).Error; err != nil {
log.Error("添加场地信息失败:%s", err)
err = ecode.NotModified
return
}
return
}
// TxUpdatePlace 编辑场地信息(事务)
func (d *Dao) TxUpdatePlace(c context.Context, tx *gorm.DB, place *model.Place) (err error) {
// find original place with id
if err = tx.Table("place").Where("id = ?", place.ID).Update(
map[string]interface{}{
"name": place.Name,
"base_pic": place.BasePic,
"status": place.Status,
"venue": place.Venue,
"d_width": place.DWidth,
"d_height": place.DHeight,
}).Error; err != nil {
log.Error("更新场地信息ID:%d失败:%s", place.ID, err)
err = ecode.NotModified
return
}
return
}
// TxAddOrUpdateAreaPolygon 添加或更新区域的场地坐标信息(事务)
func (d *Dao) TxAddOrUpdateAreaPolygon(c context.Context, tx *gorm.DB, place int64, area int64, coordinate *string) (err error) {
var (
oriPlacePolygon model.PlacePolygon
coordinates map[int64]string
found bool
)
if res := tx.First(&oriPlacePolygon, place); res.Error != nil {
if !res.RecordNotFound() {
log.Error("查找对应的场地坐标信息ID:%d失败:%s", place, res.Error)
err = ecode.NotModified
return
}
coordinates = make(map[int64]string)
oriPlacePolygon.ID = place
found = false
} else {
// 反序列化出coordinate字段
if err = json.Unmarshal([]byte(oriPlacePolygon.Coordinate), &coordinates); err != nil {
log.Error("数据库中的场地坐标信息ID:%d反序列化失败:%s", place, err)
err = ecode.NotModified
return
}
found = true
}
// 添加新的coordinate并序列化
coordinates[area] = *coordinate
b, _ := json.Marshal(coordinates)
oriPlacePolygon.Coordinate = string(b)
if found {
if err = tx.Model(&oriPlacePolygon).Updates(
map[string]interface{}{
"coordinate": oriPlacePolygon.Coordinate,
}).Error; err != nil {
log.Error("更新场地坐标信息ID:%d失败:%s", place, err)
err = ecode.NotModified
return
}
} else {
if err = tx.Create(oriPlacePolygon).Error; err != nil {
log.Error("创建场地坐标信息ID:%d失败:%s", place, err)
err = ecode.NotModified
return
}
}
*coordinate = oriPlacePolygon.Coordinate
return
}
// TxDelAreaPolygon 删除区域的场地坐标信息(事务)
func (d *Dao) TxDelAreaPolygon(c context.Context, tx *gorm.DB, place int64, area int64) (err error) {
var (
oriPlacePolygon model.PlacePolygon
coordinates map[int64]string
)
if err = tx.First(&oriPlacePolygon, place).Error; err != nil {
log.Error("查找对应的场地坐标信息ID:%d失败:%s", place, err)
err = ecode.NotModified
return
}
if oriPlacePolygon.Coordinate != "" {
if err = json.Unmarshal([]byte(oriPlacePolygon.Coordinate), &coordinates); err != nil {
log.Error("数据库中的场地坐标信息ID:%d反序列化失败:%s", place, err)
err = ecode.NotModified
return
}
} else {
coordinates = make(map[int64]string)
}
// 添加新的coordinate并序列化
if _, ok := coordinates[area]; !ok {
log.Error("数据库中的场地坐标信息ID:%d并未包含该区域ID:%d删除失败", place, area)
err = ecode.NotModified
return
}
delete(coordinates, area)
b, _ := json.Marshal(coordinates)
oriPlacePolygon.Coordinate = string(b)
if err = tx.Model(&oriPlacePolygon).Updates(
map[string]interface{}{
"coordinate": oriPlacePolygon.Coordinate,
}).Error; err != nil {
log.Error("创建场地坐标信息ID:%d失败:%s", place, err)
err = ecode.NotModified
return
}
return
}
// RawArea 获取区域
func (d *Dao) RawArea(c context.Context, id int64) (area *model.Area, err error) {
area = new(model.Area)
if err = d.db.Where("deleted_status = 0").First(&area, id).Error; err != nil {
log.Error("RawArea(%v) error(%v)", id, err)
}
return
}
// TxRawArea 获取区域
func (d *Dao) TxRawArea(c context.Context, tx *gorm.DB, id int64) (area *model.Area, err error) {
area = new(model.Area)
if err = tx.Where("deleted_status = 0").First(&area, id).Error; err != nil {
log.Error("TxRawArea(%v) error(%v)", id, err)
}
return
}
// TxRawDeletedAreaByAID 通过场地ID和自定义区域编号获取已删除的区域
func (d *Dao) TxRawDeletedAreaByAID(c context.Context, tx *gorm.DB, aid string, place int64) (area *model.Area, err error) {
area = new(model.Area)
if res := tx.Where("deleted_status = 1").Where("a_id = ? AND place = ?", aid, place).First(&area); res.Error != nil {
if res.RecordNotFound() {
return nil, nil
}
err = res.Error
log.Error("TxRawAreaByAID(%v, %v) error(%v)", aid, place, err)
}
return
}
// TxAddArea 添加区域信息(事务)
func (d *Dao) TxAddArea(c context.Context, tx *gorm.DB, area *model.Area) (err error) {
if res := tx.Create(area); res.Error != nil {
log.Error("添加区域信息失败:%s", res.Error)
err = ecode.NotModified
return
}
return
}
// TxUpdateArea 编辑区域信息(事务)
func (d *Dao) TxUpdateArea(c context.Context, tx *gorm.DB, area *model.Area) (err error) {
if err = tx.Table("area").Where("id = ?", area.ID).Updates(
map[string]interface{}{
"a_id": area.AID,
"name": area.Name,
"place": area.Place,
"deleted_status": area.DeletedStatus,
}).Error; err != nil {
log.Error("更新区域信息ID:%d失败:%s", area.ID, err)
err = ecode.NotModified
return
}
return
}
// TxDelArea 软删除区域(事务)
func (d *Dao) TxDelArea(c context.Context, tx *gorm.DB, id int64) (err error) {
if err = tx.Table("area").Where("id = ?", id).Updates(
map[string]interface{}{
"deleted_status": 1,
}).Error; err != nil {
log.Error("删除区域信息失败:%s", err)
err = ecode.NotModified
return
}
return
}

View File

@@ -0,0 +1,337 @@
package dao
import (
"context"
"go-common/app/service/openplatform/ticket-item/model"
"strconv"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
// TestRawVenues
func TestRawVenues(t *testing.T) {
Convey("RawVenues", t, func() {
once.Do(startService)
res, err := d.RawVenues(context.TODO(), []int64{77, 78})
So(err, ShouldBeNil)
So(len(res), ShouldEqual, 2)
So(res[77].Name, ShouldEqual, "海尔测试-勿动")
})
}
// TestDaoVenue
func TestDaoVenue(t *testing.T) {
var id int64
Convey("AddVenue", t, func() {
once.Do(startService)
venue := model.Venue{
Name: "可删",
Province: 100000,
City: 100000,
District: 100000,
Status: 0,
AddressDetail: "地址详细",
Traffic: "交通",
}
err := d.AddVenue(context.TODO(), &venue)
So(err, ShouldBeNil)
So(venue.ID, ShouldNotEqual, 0)
id = venue.ID
})
Convey("UpdateVenue", t, func() {
once.Do(startService)
venue := model.Venue{
ID: id,
Name: "可删",
Province: 100000,
City: 100000,
District: 100010,
Status: 1,
AddressDetail: "地址详细",
Traffic: "交通",
}
err := d.UpdateVenue(context.TODO(), &venue)
So(err, ShouldBeNil)
So(venue.Status, ShouldEqual, 1)
})
var placeNum int32
Convey("TxIncPlaceNum", t, func() {
once.Do(startService)
c := context.TODO()
res, err := d.RawVenues(c, []int64{id})
placeNum = res[id].PlaceNum
So(err, ShouldBeNil)
tx, _ := d.BeginTran(c)
So(tx, ShouldNotBeNil)
err = d.TxIncPlaceNum(c, tx, id)
So(err, ShouldBeNil)
err = d.CommitTran(c, tx)
So(err, ShouldBeNil)
res, err = d.RawVenues(c, []int64{id})
So(err, ShouldBeNil)
So(res[id].PlaceNum, ShouldEqual, placeNum+1)
})
Convey("TxDecPlaceNum", t, func() {
once.Do(startService)
c := context.TODO()
tx, _ := d.BeginTran(c)
So(tx, ShouldNotBeNil)
err := d.TxDecPlaceNum(c, tx, id)
So(err, ShouldBeNil)
err = d.CommitTran(c, tx)
So(err, ShouldBeNil)
res, _ := d.RawVenues(c, []int64{id})
So(res[id].PlaceNum, ShouldEqual, placeNum)
})
}
// TestRawPlace
func TestRawPlace(t *testing.T) {
Convey("RawPlace", t, func() {
once.Do(startService)
res, err := d.RawPlace(context.TODO(), 132)
So(err, ShouldBeNil)
So(res.Name, ShouldEqual, "海尔测试-勿动")
})
}
// TestTxRawPlace
func TestTxRawPlace(t *testing.T) {
Convey("TxRawPlace", t, func() {
once.Do(startService)
c := context.TODO()
tx, _ := d.BeginTran(c)
So(tx, ShouldNotBeNil)
res, err := d.TxRawPlace(c, tx, 132)
So(err, ShouldBeNil)
So(res.Name, ShouldEqual, "海尔测试-勿动")
err = d.CommitTran(c, tx)
So(err, ShouldBeNil)
So(res.Name, ShouldEqual, "海尔测试-勿动")
})
}
// TestDaoPlace
func TestDaoPlace(t *testing.T) {
var id int64
Convey("TxAddPlace", t, func() {
once.Do(startService)
c := context.TODO()
tx, _ := d.BeginTran(c)
So(tx, ShouldNotBeNil)
place := &model.Place{
Name: "可删",
BasePic: "url",
Status: 1,
Venue: 81,
DWidth: 800,
DHeight: 800,
}
err := d.TxAddPlace(c, tx, place)
So(err, ShouldBeNil)
So(place.ID, ShouldNotEqual, 0)
id = place.ID
err = d.CommitTran(c, tx)
So(err, ShouldBeNil)
place, err = d.RawPlace(c, id)
So(err, ShouldBeNil)
So(place.ID, ShouldNotEqual, 0)
})
Convey("TxUpdatePlace", t, func() {
once.Do(startService)
c := context.TODO()
tx, _ := d.BeginTran(c)
So(tx, ShouldNotBeNil)
place := &model.Place{
ID: id,
Name: "可删",
BasePic: "url2",
Status: 1,
Venue: 81,
DWidth: 800,
DHeight: 800,
}
err := d.TxUpdatePlace(c, tx, place)
So(err, ShouldBeNil)
So(place.BasePic, ShouldEqual, "url2")
err = d.CommitTran(c, tx)
So(err, ShouldBeNil)
place, err = d.RawPlace(c, id)
So(err, ShouldBeNil)
So(place.BasePic, ShouldEqual, "url2")
})
var placePolygon *model.PlacePolygon
Convey("TxAddOrUpdateAreaPolygon", t, func() {
once.Do(startService)
c := context.TODO()
tx, _ := d.BeginTran(c)
So(tx, ShouldNotBeNil)
var co = "292 103,443 113,414 263,230 247"
err := d.TxAddOrUpdateAreaPolygon(c, tx, id, 239, &co)
So(err, ShouldBeNil)
err = d.CommitTran(c, tx)
So(err, ShouldBeNil)
placePolygon, err = d.RawPlacePolygon(c, id)
So(err, ShouldBeNil)
So(placePolygon.Coordinate, ShouldEqual, "{\"239\":\"292 103,443 113,414 263,230 247\"}")
})
Convey("TxDelAreaPolygon", t, func() {
once.Do(startService)
c := context.TODO()
tx, _ := d.BeginTran(c)
So(tx, ShouldNotBeNil)
err := d.TxDelAreaPolygon(c, tx, id, 239)
So(err, ShouldBeNil)
err = d.CommitTran(c, tx)
So(err, ShouldBeNil)
placePolygon, err = d.RawPlacePolygon(c, id)
So(err, ShouldBeNil)
So(placePolygon.Coordinate, ShouldEqual, "{}")
})
}
// TestRawArea
func TestRawArea(t *testing.T) {
Convey("RawArea", t, func() {
once.Do(startService)
res, err := d.RawArea(context.TODO(), 239)
So(err, ShouldBeNil)
So(res.Name, ShouldEqual, "海尔测试-勿动")
})
}
func TestTxRawArea(t *testing.T) {
Convey("RawArea", t, func() {
once.Do(startService)
c := context.TODO()
tx, _ := d.BeginTran(c)
So(tx, ShouldNotBeNil)
res, err := d.TxRawArea(c, tx, 239)
So(err, ShouldBeNil)
So(res.Name, ShouldEqual, "海尔测试-勿动")
err = d.CommitTran(c, tx)
So(err, ShouldBeNil)
res, err = d.RawArea(context.TODO(), 239)
So(err, ShouldBeNil)
So(res.Name, ShouldEqual, "海尔测试-勿动")
})
}
// TestDaoArea
func TestDaoArea(t *testing.T) {
var id int64
Convey("TxAddArea", t, func() {
once.Do(startService)
c := context.TODO()
tx, _ := d.BeginTran(c)
So(tx, ShouldNotBeNil)
area := &model.Area{
AID: "test" + strconv.FormatInt(time.Now().Unix(), 10),
Name: "可删",
Place: 132,
}
err := d.TxAddArea(c, tx, area)
So(err, ShouldBeNil)
So(area.ID, ShouldNotEqual, 0)
id = area.ID
err = d.CommitTran(c, tx)
So(err, ShouldBeNil)
area, err = d.RawArea(c, id)
So(err, ShouldBeNil)
So(area.ID, ShouldNotEqual, 0)
})
Convey("TxUpdateArea", t, func() {
once.Do(startService)
c := context.TODO()
tx, _ := d.BeginTran(c)
So(tx, ShouldNotBeNil)
area := &model.Area{
ID: id,
AID: "test" + strconv.FormatInt(time.Now().Unix(), 10),
Name: "可删-1",
Place: 132,
}
err := d.TxUpdateArea(c, tx, area)
So(err, ShouldBeNil)
err = d.CommitTran(c, tx)
So(err, ShouldBeNil)
area, err = d.RawArea(c, id)
So(err, ShouldBeNil)
So(area.Name, ShouldEqual, "可删-1")
So(area.Place, ShouldEqual, 132)
})
Convey("TxUpdateSeat", t, func() {
once.Do(startService)
c := context.TODO()
tx, _ := d.BeginTran(c)
So(tx, ShouldNotBeNil)
area := &model.Area{
ID: id,
SeatsNum: 10,
Width: 1,
Height: 2,
DeletedStatus: 0,
ColStart: 3,
ColType: 4,
ColDirection: 1,
RowList: "[\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"10\",\"11\",\"12\",\"13\",\"14\",\"15\",\"16\",\"17\",\"18\",\"19\",\"20\"]",
SeatStart: "",
}
err := d.TxUpdateSeat(c, tx, area)
So(err, ShouldBeNil)
So(area.SeatsNum, ShouldEqual, 10)
area, err = d.RawArea(c, id)
So(err, ShouldBeNil)
So(area.SeatsNum, ShouldEqual, 0)
err = d.CommitTran(c, tx)
So(err, ShouldBeNil)
area, err = d.RawArea(c, id)
So(err, ShouldBeNil)
So(area.SeatsNum, ShouldEqual, 10)
})
}

View File

@@ -0,0 +1,149 @@
package dao
import (
"context"
"fmt"
"github.com/jinzhu/gorm"
"go-common/app/common/openplatform/random"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/database/elastic"
"go-common/library/ecode"
"go-common/library/log"
)
// AddVersion 添加新版本
func (d *Dao) AddVersion(c context.Context, requiredTx *gorm.DB, verInfo *model.Version, verExtInfo *model.VersionExt) (err error) {
// 此处ver_id调用订单号生成器
verID := uint64(random.Uniqid(19))
// 版本号赋值与信息
verInfo.VerID = verID
verExtInfo.VerID = verID
var tx *gorm.DB
if requiredTx == nil {
// 开启事务
tx = d.db.Begin()
} else {
tx = requiredTx
}
// 插入新数据
if verError := tx.Create(&verInfo).Error; verError != nil {
log.Error("version insertion failed:%s", verError)
tx.Rollback()
return ecode.TicketAddVersionFailed
}
if extError := tx.Create(&verExtInfo).Error; extError != nil {
log.Error("version ext insertion failed:%s", extError)
tx.Rollback()
return ecode.TicketAddVerExtFailed
}
if requiredTx == nil {
tx.Commit()
}
return nil
}
// UpdateVersion 编辑版本信息
func (d *Dao) UpdateVersion(c context.Context, verInfo *model.Version) (bool, error) {
// update guest with new info (using map can update the column with empty string)
updateErr := d.db.Model(&model.Version{}).Where("ver_id = ?", verInfo.VerID).Updates(
map[string]interface{}{
"type": verInfo.Type,
"status": verInfo.Status,
"item_name": verInfo.ItemName,
"ver": verInfo.Ver,
"target_item": verInfo.TargetItem,
"auto_pub": verInfo.AutoPub,
"parent_id": verInfo.ParentID,
}).Error
if updateErr != nil {
log.Error("VERSION UPDATE FAILED:%s", updateErr)
return false, ecode.NotModified
}
return true, nil
}
// GetVersion 获取版本信息外加详情
func (d *Dao) GetVersion(c context.Context, verID uint64, needExt bool) (*model.Version, *model.VersionExt, error) {
var verInfo model.Version
var verExtInfo model.VersionExt
if dbErr := d.db.Where("ver_id = ?", verID).First(&verInfo).Error; dbErr != nil {
log.Error("verinfo:(%v) not found with err:%s", verID, dbErr)
return nil, nil, ecode.NothingFound
}
if needExt {
if dbErr := d.db.Where("ver_id = ?", verID).First(&verExtInfo).Error; dbErr != nil {
log.Error("ver_ext_info:(%v) not found with err:%s", verID, dbErr)
return nil, nil, ecode.NothingFound
}
}
return &verInfo, &verExtInfo, nil
}
// RejectVersion 驳回版本
func (d *Dao) RejectVersion(c context.Context, verID uint64, verType int32) (bool, error) {
var newStatus int32
switch verType {
case model.VerTypeBanner:
newStatus = model.VerStatusNotReviewed
default:
newStatus = model.VerStatusRejected
}
updateErr := d.db.Where("ver_id = ? and type = ?", verID, verType).Model(&model.Version{}).Update("status", newStatus).Error
if updateErr != nil {
log.Error("更新版本状态失败:%s", updateErr)
return false, ecode.NotModified
}
return true, nil
}
// AddVersionLog 新建版本审核记录
func (d *Dao) AddVersionLog(c context.Context, info *model.VersionLog) error {
if insertErr := d.db.Create(&info).Error; insertErr != nil {
log.Error("新建版本审核记录失败:%s", insertErr)
return ecode.NotModified
}
return nil
}
// VersionSearch 项目版本查询
func (d *Dao) VersionSearch(c context.Context, in *model.VersionSearchParam) (versions *model.VersionSearchList, err error) {
r := d.es.NewRequest("ticket_version").Index("ticket_version")
if in.TargetItem > 0 {
r.WhereEq("target_item", in.TargetItem)
} else if in.ItemName != "" {
r.WhereLike([]string{"item_name"}, []string{in.ItemName}, false, elastic.LikeLevelLow)
}
if in.Type > 0 {
r.WhereEq("type", in.Type)
}
if length := len(in.Status); length == 1 {
r.WhereEq("status", in.Status[0])
} else if length > 1 {
r.WhereIn("status", in.Status)
}
r.Order("ctime", elastic.OrderDesc).Ps(in.Ps).Pn(in.Pn)
log.Info(fmt.Sprintf("%s/x/admin/search/query?%s", d.c.URL.ElasticHost, r.Params()))
versions = new(model.VersionSearchList)
err = r.Scan(c, versions)
if err != nil {
log.Error("VersionSearch(%v) r.Query(%s) error(%s)", in, r.Params(), err)
return
}
return
}

View File

@@ -0,0 +1,83 @@
package dao
import (
"context"
"testing"
"go-common/app/service/openplatform/ticket-item/model"
. "github.com/smartystreets/goconvey/convey"
)
// TestAddVersion
func TestDao_AddVersion(t *testing.T) {
Convey("AddVersion", t, func() {
once.Do(startService)
err := d.AddVersion(context.TODO(), nil, &model.Version{
Type: 2,
Status: 1, // 审核中
ItemName: "gotest",
ParentID: 10164,
TargetItem: 0,
AutoPub: 1, // 自动上架
}, &model.VersionExt{
Type: 1,
MainInfo: "{'name':'公告test','introduction':'公告简介','content':'公告内容','pid':10164,'project_name':'删通票删票种'}",
})
So(err, ShouldBeNil)
})
}
// TestUpdateVersion
func TestDao_UpdateVersion(t *testing.T) {
Convey("UpdateVersion", t, func() {
once.Do(startService)
res, err := d.UpdateVersion(context.TODO(), &model.Version{
VerID: 2691387070776769288,
Type: 2,
Status: 2, // 审核中
ItemName: "gotest公告",
ParentID: 0,
TargetItem: 10164,
AutoPub: 1, // 自动上架
})
So(res, ShouldBeTrue)
So(err, ShouldBeNil)
})
}
// TestGetVersion
func TestDao_GetVersion(t *testing.T) {
Convey("GetVersion", t, func() {
once.Do(startService)
verInfo, verExtInfo, err := d.GetVersion(context.TODO(), 153008633987459678, true)
So(verInfo, ShouldNotBeNil)
So(verExtInfo, ShouldNotBeNil)
So(err, ShouldBeNil)
})
}
// TestRejectVersion
func TestDao_RejectVersion(t *testing.T) {
Convey("RejectVersion", t, func() {
once.Do(startService)
res, err := d.RejectVersion(context.TODO(), 2691387070776769288, 2)
So(res, ShouldBeTrue)
So(err, ShouldBeNil)
})
}
// TestAddVersionLog
func TestDao_AddVersionLog(t *testing.T) {
Convey("AddVersionLog", t, func() {
once.Do(startService)
err := d.AddVersionLog(context.TODO(), &model.VersionLog{
VerID: 2691387070776769288,
Type: 1,
Log: "reject",
IsPass: 0,
Uname: "tester",
})
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,64 @@
package dao
import (
"context"
"encoding/json"
"fmt"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/cache/redis"
"go-common/library/log"
)
const (
_addWishSQL = "INSERT INTO user_wish (mid, item_id, face) VALUES(?, ?, ?)"
// 缓存 key
_userWishCountKey = "USER:WISH:COUNT:%d"
_userWishActiveKey = "USER:WISH:ACTIVE:%d:%d"
_userWishListKey = "USER:WISH:LIST:%d"
)
// AddWish 添加想去
func (d *Dao) AddWish(c context.Context, wish *model.UserWish) (err error) {
err = d.db.Exec(_addWishSQL, wish.MID, wish.ItemID, wish.Face).Error
return
}
// WishCacheUpdate 更新想去缓存
func (d *Dao) WishCacheUpdate(c context.Context, wish *model.UserWish) (err error) {
conn := d.redis.Get(c)
defer conn.Close()
if _, err = conn.Do("SETEX", fmt.Sprintf(_userWishActiveKey, wish.ItemID, wish.MID), _expireHalfhour, 1); err != nil {
log.Error("d.WishCacheUpdate(%+v) SETEX error(%v)", wish, err)
return
}
if _, err = conn.Do("INCR", fmt.Sprintf(_userWishCountKey, wish.ItemID)); err != nil {
log.Error("d.WishCacheUpdate(%+v) INCR error(%v)", wish, err)
return
}
wishCache, err := json.Marshal(map[string]interface{}{
"mid": wish.MID,
"face": wish.Face,
})
if err != nil {
log.Error("d.WishCacheUpdate(%+v) json.Marshal() error(%v)", wish, err)
return
}
listKey := fmt.Sprintf(_userWishListKey, wish.ItemID)
length, err := redis.Int64(conn.Do("RPUSH", listKey, wishCache))
if err != nil {
log.Error("d.WishCacheUpdate(%+v) RPUSH error(%v)", wish, err)
return
}
if length > 5 {
if _, err = conn.Do("LTRIM", listKey, -5, -1); err != nil {
log.Error("d.WishCacheUpdate(%+v) LTRIM error(%v)", wish, err)
return
}
}
return
}

View File

@@ -0,0 +1,42 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"const.go",
"param.go",
"reponse.go",
"saleflag.go",
"tables.go",
"ticket.go",
"util.go",
],
importpath = "go-common/app/service/openplatform/ticket-item/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/openplatform/ticket-item/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-item/conf:go_default_library",
"//library/log:go_default_library",
"//library/time: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,33 @@
package model
// 票价
// 额外属性字段名
const (
TkBuyNumLimitNormal = "buy_limit_0"
TkBuyNumLimitVip = "buy_limit_1"
TkBuyNumLimitAnnualVip = "buy_limit_2"
// TimeNull 空时间0000-00-00 00:00:00
TimeNull = -62135596800
// 版本类型
//VerTypeProject = 1
VerTypeBulletin = 2
//VerTypePjCancel = 3
VerTypeBanner = 4
//版本状态
VerStatusOffShelfManual = -1
VerStatusOffShelfForced = -2
VerStatusNotReviewed = 0
VerStatusReadyForReview = 1
VerStatusRejected = 2
VerStatusReadyForSale = 3
VerStatusOnShelf = 4
VerStatusNoSalesinfo = 5
//版本审核操作
VerReviewReject = 0
VerReviewPass = 1
)

View File

@@ -0,0 +1,123 @@
package model
// ParamID ID类型请求
type ParamID struct {
ID int64 `form:"id" validate:"gt=0,required"`
}
// ParamCards 卡片类型请求
type ParamCards struct {
IDs string `form:"ids" validate:"gt=0,required"`
}
// ParamBill 项目订单信息请求
type ParamBill struct {
IDs string `form:"ids" validate:"gt=0,required"`
Sids string `form:"sids"`
Tids string `form:"tids"`
}
// GuestParam 嘉宾参数
type GuestParam struct {
ID uint32 `form:"id"`
Name string `form:"name" validate:"required"`
GuestImg string `form:"guestimg" validate:"required"`
Description string `form:"description"`
GuestID int64 `form:"guestid"`
}
// GuestStatusParam 嘉宾状态
type GuestStatusParam struct {
ID int64 `form:"id" validate:"required"`
Status int8 `form:"status"`
}
// GuestSearchParam 嘉宾搜索
type GuestSearchParam struct {
Keyword string `form:"keyword"`
Ps int `form:"ps"`
Pn int `form:"pn"`
}
// VenueSearchParam 场馆搜索参数
type VenueSearchParam struct {
PageParam
ProvinceID int `form:"province_id"`
CityID int `form:"city_id"`
ID int `form:"id"`
Name string `form:"name"`
}
// VersionSearchParam 版本搜索参数
type VersionSearchParam struct {
Type int `form:"type"`
TargetItem int `form:"target_item"`
ItemName string `form:"item_name"`
Status []int `form:"status"`
PageParam
}
// PageParam 分页参数
type PageParam struct {
Pn int `form:"pn" validate:"min=1,gte=1"`
Ps int `form:"ps" validate:"min=1,max=10000"`
}
// AreaInfoParam areaInfo接口请求
type AreaInfoParam struct {
ID int64 `form:"id" validate:"min=0"` // 待修改区域的ID为0表示创建
AID string `form:"a_id" validate:"min=1,max=16"` // 区域自定义编号
Name string `form:"name" validate:"min=1,max=16"` // 区域名
Place int64 `form:"place" validate:"min=1"` // 所属场地ID
Coordinate string `form:"coordinate" validate:"min=1"` // 区域坐标
}
// PlaceInfoParam placeInfo接口请求
type PlaceInfoParam struct {
ID int64 `form:"id" validate:"min=0"` // 待修改场地的ID为0表示创建
Status int32 `form:"status" validate:"min=0,max=1"` // 状态
Name string `form:"name" validate:"max=16"` // 场地名
BasePic string `form:"base_pic" validate:"max=128"` // 场地底图
Venue int64 `form:"venue" validate:"min=1"` // 场馆ID
DWidth int32 `form:"d_width" validate:"min=0"` // mis画框宽度
DHeight int32 `form:"d_height" validate:"min=0"` // mis画框高度
}
// SeatInfoParam seatInfo接口请求
type SeatInfoParam struct {
Area int64 `form:"area" validate:"min=1"` // 区域ID
SeatsNum int32 `form:"seats_num" validate:"min=0"` // 座位数
SeatMap string `form:"seat_map" validate:"min=1"` // 座位图
Seats string `form:"seats"` // 座位数组JSON
Width int32 `form:"width" validate:"min=1"` // 坐区宽度
Height int32 `form:"height" validate:"min=1"` // 坐区高度
RowList string `form:"row_list" validate:"min=1"` // 行号序列
SeatStart string `form:"seat_start" validate:"min=1"` // 座位起始坐标
}
// SeatStockParam seatStock接口请求
type SeatStockParam struct {
Screen int64 `form:"screen" validate:"min=1"` // 场次ID
Area int64 `form:"area" validate:"min=1"` // 区域ID
SeatInfo string `form:"seat_info"` // 座位票种定义数组JSON
}
// RemoveSeatOrdersParam removeSeatOrders接口请求
type RemoveSeatOrdersParam struct {
Price int64 `form:"price" validate:"min=1"` // 票价ID
}
// VenueInfoParam venueInfo接口请求
type VenueInfoParam struct {
ID int64 `form:"id" validate:"min=0"` // 待修改场馆的ID为0表示创建
Name string `form:"name" validate:"max=25"` // 场馆名
Status int32 `form:"status" validate:"min=0,max=1"` // 状态 1-启用 0-停用
Province int64 `form:"provid" validate:"min=0"` // 省份ID
City int64 `form:"cityid" validate:"min=0"` // 城市ID
District int64 `form:"distid" validate:"min=0"` // 区县ID
AddressDetail string `form:"addr" validate:"min=0,max=60"` // 详细地址
Coordinate string `form:"coordinate" validate:"min=0"` // 场馆地图坐标及类型字段
Traffic string `form:"traff" validate:"min=0,max=100"` // 交通信息
}

View File

@@ -0,0 +1,58 @@
package model
// Response 标准返回结构
type Response struct {
Errno int64 `json:"errno"`
Msg string `json:"msg"`
Data []int64 `json:"data"`
}
// ListResp pagination
type ListResp struct {
Total int `json:"total"`
List interface{} `json:"list"`
}
// Page pagination
type Page struct {
Num int `json:"num"`
Size int `json:"size"`
Total int `json:"total"`
}
// VenueData 场馆
type VenueData struct {
ID int64 `json:"id"`
Name string `json:"name"`
CityID int `json:"city"`
CityName string `json:"city_name"`
ProvinceID int `json:"province"`
ProvinceName string `json:"province_name"`
DistrictID int `json:"district"`
DistrictName string `json:"district_name"`
AddressDetail string `json:"address_detail"`
PlaceNum int `json:"place_num"`
Status int `json:"status"`
Coordinate string `json:"coordinate"`
Traffic string `json:"traffic"`
Ctime string `json:"ctime"`
Mtime string `json:"mtime"`
}
// VersionSearchList .
type VersionSearchList struct {
Result []*Version `json:"result"`
Page *Page `json:"page"`
}
// GuestSearchList .
type GuestSearchList struct {
Result []*Guest `json:"result"`
Page *Page `json:"page"`
}
// VenueSearchList .
type VenueSearchList struct {
Result []*VenueData `json:"result"`
Page *Page `json:"page"`
}

View File

@@ -0,0 +1,31 @@
package model
import (
"time"
)
// SaleFlag...售卖状态状态
const (
SaleFlagNotBegin = 1 // 未开售
SaleFlagBegin = 2 // 预售中
SaleFlagEnd = 3 // 已停售
SaleFlagNotSale = 5 // 不可售
SaleFlagOut = 4 // 已售罄
SaleFlagTight = 6 // 库存紧张
)
// CalTkSaleFlag 计算SaleFlag
func (tk *TicketInfo) CalTkSaleFlag() (flag int32) {
current := time.Now().Unix()
if tk.IsSale == 0 {
flag = SaleFlagNotSale
} else if int64(tk.SaleStart) > current {
flag = SaleFlagNotBegin
} else if int64(tk.SaleEnd) < current {
flag = SaleFlagEnd
} else {
flag = SaleFlagBegin
}
return
}

View File

@@ -0,0 +1,491 @@
package model
import (
"go-common/library/time"
)
// Venue 场馆表
type Venue struct {
ID int64
Name string
Status int32
Province int64
City int64
District int64
AddressDetail string
Traffic string
Coordinate string
PlaceNum int32
Ctime time.Time
Mtime time.Time
}
// Coor 项目图片结构
type Coor struct {
Type string
Coor string
}
// ItemDetail 项目详情表
type ItemDetail struct {
ProjectID int64 `json:"id"`
PerformanceDesc string `json:"detail"`
}
// Item 项目表
type Item struct {
ID int64
Name string
Status int32
IsSale int32
StartTime int32
EndTime int32
VenueID int64
PlaceID int64
CompID int64
ExpressFee int32
HasExpressFee int32
ExpressFreeFlag int32
PerformanceImage string
TicketDesc string
BuyNumLimit string
Recommend int32
PromoTags string
VerID uint64
BuyerInfo string
Type int32
SponsorType int32
Label string
Img *ItemImg
}
// ItemImg 项目图片结构
type ItemImg struct {
First struct {
URL string
Desc string
}
Banner struct {
URL string
Desc string
}
}
// Screen 场次表.
type Screen struct {
ID int64
Name string
Status int32
Type int32
TicketType int32
ScreenType int32
DeliveryType int32
PickSeat int32
StartTime int32
EndTime int32
ProjectID int64
SaleStart int64
SaleEnd int64
}
// TicketPrice 票价表
type TicketPrice struct {
ID int64
ParentID int64
Desc string
Type int32
SaleType int32
LinkSc string
LinkTicketID int64
Symbol string
Color string
BuyLimit int32
DescDetail string
ScreenID int64
IsSale int32
IsVisible int32
IsRefund int32
Price int32
OriginPrice int32
MarketPrice int32
ProjectID int64
PaymentMethod int32
PaymentValue int64
SaleTime string
SaleStart time.Time
SaleEnd time.Time
}
// TicketPriceExtra 票价额外表
type TicketPriceExtra struct {
ID int64
ProjectID int64
SkuID int64
Attrib string
Value string
IsDeleted int32
}
// Guest Build guest
type Guest struct {
ID int64 `json:"id"`
GuestImg string `json:"guest_img"`
Name string `json:"name"`
Description string `json:"description"`
Status int8 `json:"status"`
GuestID int64 `json:"guest_id"`
}
// ProjectGuest Build project_guest
type ProjectGuest struct {
ID int64 `json:"id"`
ProjectID int64 `json:"project_id"`
GuestID int64 `json:"guest_id"`
Position int64 `json:"position"`
GuestImg string `json:"guest_img"`
DeleteStatus int32 `json:"delete_status"`
}
// Bulletin Build bulletin
type Bulletin struct {
ID int64 `json:"id"`
Status int8 `json:"status"`
Title string `json:"title"`
Content string `json:"content"`
ProjectID int64 `json:"project_id"`
VerID uint64 `json:"ver_id"`
BulletinID int64 `json:"bulletin_id"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// BulletinExtra Build BulletinExtra
type BulletinExtra struct {
ID int64 `json:"id"`
Detail string `json:"detail"`
BulletinID int64 `json:"bulletin_id"`
}
// Version Build Version
type Version struct {
ID int64 `json:"id"`
VerID uint64 `json:"ver_id"`
Type int32 `json:"type"`
Status int32 `json:"status"`
ItemName string `json:"item_name"`
Ver string `json:"ver"`
TargetItem int64 `json:"target_item"`
AutoPub int32 `json:"auto_pub"`
ParentID int64 `json:"parent_id"`
PubStart time.Time `json:"pub_start"`
PubEnd time.Time `json:"pub_end"`
For int64 `json:"for"`
}
// VersionExt Build
type VersionExt struct {
ID int64 `json:"id"`
VerID uint64 `json:"ver_id"`
Type int32 `json:"type"`
MainInfo string `json:"main_info"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// VersionLog Build VersionLog
type VersionLog struct {
ID int64 `json:"id"`
VerID uint64 `json:"ver_id"`
Type int32 `json:"type"`
Log string `json:"item_name"`
IsPass int32 `json:"is_pass"`
Uname string `json:"uname"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// UserWish 想去表
type UserWish struct {
ID int64 `json:"id"`
MID int64 `json:"mid"`
ItemID int64 `json:"item_id"`
Face string `json:"face"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// Place 场地表
type Place struct {
ID int64 `json:"id"`
Name string `json:"name"`
BasePic string `json:"base_pic"`
Status int32 `json:"status"`
Venue int64 `json:"venue"`
DWidth int32 `json:"d_width"`
DHeight int32 `json:"d_height"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// PlacePolygon 场地坐标表
type PlacePolygon struct {
ID int64 `json:"id"`
Coordinate string `json:"coordinate"`
}
// Area 区域表
type Area struct {
ID int64 `json:"id"`
AID string `json:"name"`
Name string `json:"base_pic"`
SeatsNum int32 `json:"seats_num"`
Width int32 `json:"width"`
Height int32 `json:"height"`
Place int64 `json:"venue"`
DeletedStatus int32 `json:"deleted_status"`
ColStart int32 `json:"col_start"`
ColType int32 `json:"col_type"`
ColDirection int32 `json:"col_direction"`
RowList string `json:"row_list"`
SeatStart string `json:"seat_start"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// AreaSeats 区域座位表
type AreaSeats struct {
ID int64 `json:"id"`
X int32 `json:"x"`
Y int32 `json:"y"`
Label string `json:"label"`
Bgcolor string `json:"bgcolor"`
Area int64 `json:"area"`
Dstatus int32 `json:"dstatus"`
}
// AreaSeatmap 区域座位表
type AreaSeatmap struct {
ID int64 `json:"id"`
SeatMap string `json:"seat_map"`
}
//Promotion 拼团表
type Promotion struct {
ID int64 `json:"id"`
ItemID int64 `json:"item_id"`
SkuID int64 `json:"sku_id"`
Extra int64 `json:"extra"`
BeginTime int32 `json:"begin_time"`
EndTime int32 `json:"end_time"`
Status int32 `json:"status"`
}
//Stock 库存表
type Stock struct {
SkuID int64 `json:"sku_id"`
ParentSkuID int64 `json:"parent_sku_id"`
ItemID int64 `json:"item_id"`
Specs string `json:"specs"`
TotalStock int64 `json:"total_stock"`
Stock int64 `json:"stock"`
}
//ProjectTags 项目标签表
type ProjectTags struct {
ID int64 `json:"id"`
Status int32 `json:"status"`
ProjectID int64 `json:"project_id"`
TagID int64 `json:"tag_id"`
TagName string `json:"tag_name"`
}
// SeatOrder 座位
type SeatOrder struct {
ID int64 `json:"id"`
// 区域ID
AreaID int64 `json:"area_id"`
// 场次ID
ScreenID int64 `json:"screen_id"`
// 订单号
OrderID int64 `json:"order_id"`
// 行号
Row int32 `json:"row"`
// 列号
Col int32 `json:"col"`
// 状态 0-可售 1-已退票 2-已出票 3-已锁定 4-已预订
Status int32 `json:"status"`
// 价格ID
PriceID int64 `json:"price_id"`
// 价格
Price int32 `json:"price"`
// 操作IDbook.id或lock_rec.id
OpID int64 `json:"op_id"`
// 删除时间
DeletedAt time.Time `json:"deleted_at"`
}
// SeatSet 单场座位及价格配置表
type SeatSet struct {
ID int64 `json:"id"`
// 区域ID
AreaID int64 `json:"area_id"`
// 场次ID
ScreenID int64 `json:"screen_id"`
// 票价设置图
SeatChart string `json:"seat_chart"`
}
// Banner banner广告投放信息表
type Banner struct {
ID int64 `json:"id"`
PubStart time.Time `json:"pub_start"`
PubEnd time.Time `json:"pub_end"`
Status int32 `json:"status"`
Name string `json:"name"`
Pic string `json:"pic"`
URL string `json:"url"`
From string `json:"from"`
TargetID int64 `json:"target_id"`
TargetUser int32 `json:"target_user"`
}
// BannerDistrict banner区域关系表
type BannerDistrict struct {
ID int64 `json:"id"`
BannerID int64 `json:"banner_id"`
DistrictID int64 `json:"district_id"`
Position int32 `json:"position"`
SubPosition int32 `json:"sub_position"`
Order int32 `json:"order"`
}
// TableName project.
func (Item) TableName() string {
return "project"
}
// TableName project_extra.
func (ItemDetail) TableName() string {
return "project_extra"
}
// TableName project_guests
func (ProjectGuest) TableName() string {
return "project_guests"
}
// TableName project_bulletin
func (Bulletin) TableName() string {
return "project_bulletin"
}
// TableName bulletin_extra
func (BulletinExtra) TableName() string {
return "bulletin_extra"
}
// TableName venue.
func (Venue) TableName() string {
return "venue"
}
// TableName guest
func (Guest) TableName() string {
return "guest"
}
// TableName version
func (Version) TableName() string {
return "version"
}
// TableName version_ext
func (VersionExt) TableName() string {
return "version_ext"
}
// TableName version_log
func (VersionLog) TableName() string {
return "version_log"
}
// TableName screen
func (Screen) TableName() string {
return "screen"
}
// TableName ticket_price
func (TicketPrice) TableName() string {
return "ticket_price"
}
// TableName ticket_price_extra
func (TicketPriceExtra) TableName() string {
return "ticket_price_extra"
}
// TableName place
func (Place) TableName() string {
return "place"
}
// TableName place_polygon
func (PlacePolygon) TableName() string {
return "place_polygon"
}
// TableName user_wish
func (UserWish) TableName() string {
return "user_wish"
}
// TableName area
func (Area) TableName() string {
return "area"
}
// TableName area_seats
func (AreaSeats) TableName() string {
return "area_seats"
}
// TableName area_seatmap
func (AreaSeatmap) TableName() string {
return "area_seatmap"
}
// TableName promotion
func (Promotion) TableName() string {
return "promotion"
}
// TableName sku_stock
func (Stock) TableName() string {
return "sku_stock"
}
// TableName project_tag
func (ProjectTags) TableName() string {
return "project_tags"
}
// TableName seat_order
func (SeatOrder) TableName() string {
return "seat_order"
}
// TableName seat_set
func (SeatSet) TableName() string {
return "seat_set"
}
// TableName banner
func (Banner) TableName() string {
return "banner"
}
// TableName banner_district
func (BannerDistrict) TableName() string {
return "banner_district"
}

View File

@@ -0,0 +1,58 @@
package model
import (
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
"strconv"
)
// TicketInfo 票价综合字段
type TicketInfo struct {
TicketPrice
BuyNumLimit map[string]*TicketPriceExtra
}
// FormatTicketBuyLimit 格式化票价购票限制
func (t *TicketInfo) FormatTicketBuyLimit(limit *item.TicketBuyNumLimit) {
limit.Normal = make(map[int32]int64)
limit.Vip = make(map[int32]int64)
limit.AnnualVip = make(map[int32]int64)
if ext, ok := t.BuyNumLimit[TkBuyNumLimitNormal]; ok {
limit.Normal = ext.ParseBuyLimit()
}
if ext, ok := t.BuyNumLimit[TkBuyNumLimitVip]; ok {
limit.Vip = ext.ParseBuyLimit()
}
if ext, ok := t.BuyNumLimit[TkBuyNumLimitAnnualVip]; ok {
limit.AnnualVip = ext.ParseBuyLimit()
}
}
// ParseBuyLimit parse 购票限制成map
func (ext *TicketPriceExtra) ParseBuyLimit() (m map[int32]int64) {
var (
i int32
max int32
l int32
)
l = 2
max = 6
r := []rune(ext.Value)
m = make(map[int32]int64)
for i = 0; i < max+1; i++ {
m[i] = ext.SliceBuyLimit(r, i*l, (i+1)*l)
}
return m
}
// SliceBuyLimit 分割等级购票限制
func (ext *TicketPriceExtra) SliceBuyLimit(r []rune, start int32, end int32) int64 {
slice := string(r[start:end])
if i, err := strconv.ParseInt(slice, 10, 64); err == nil {
return i
} else if slice == "**" {
return -1
} else {
return 0
}
}

View File

@@ -0,0 +1,179 @@
package model
import (
"encoding/json"
"fmt"
"go-common/app/service/openplatform/ticket-item/conf"
"go-common/library/log"
"io/ioutil"
"net/http"
"net/url"
"reflect"
"strconv"
"strings"
)
// UT Data
var (
DataID = int64(75)
DataIDs = []int64{75, 80}
DataSIDs = []int64{90, 133, 136}
DataTIDs = []int64{1179, 1180, 1368, 1360}
NoDataID = int64(100000000)
NoDataIDs = []int64{100000000, 100000001}
NoDataSIDs = []int64{100000000, 100000001}
NoDataTIDs = []int64{100000000, 100000001}
)
// JSONEncode 仿phpJSONEncode
func JSONEncode(v interface{}) string {
b, err := json.Marshal(v)
if err != nil {
log.Error("JSONEncode error(%v)", err)
return ""
}
return string(b)
}
// String2Int64 convert string slice([]string) to int64 slice([]int64)
func String2Int64(arr []string) (r []int64) {
var (
id int64
err error
)
for _, v := range arr {
if id, err = strconv.ParseInt(v, 10, 64); err != nil {
continue
}
r = append(r, id)
}
return
}
// UniqueInt64 Ints returns a unique subset of the int slice provided.
func UniqueInt64(input []int64) []int64 {
u := make([]int64, 0, len(input))
m := make(map[int64]bool)
for _, val := range input {
if _, ok := m[val]; !ok {
m[val] = true
u = append(u, val)
}
}
return u
}
// Min 获取数组中最小值
func Min(vars []int32) (minVar int32) {
if vars != nil {
minVar = vars[0]
for _, v := range vars {
if v < minVar {
minVar = v
}
}
}
return
}
// Max 获取数组中最大值
func Max(vars []int32) (maxVar int32) {
for _, v := range vars {
if v > maxVar {
maxVar = v
}
}
return
}
// GetTicketIDFromBase baseCenter获取票价id
func GetTicketIDFromBase() (int64, error) {
params := url.Values{}
params.Add("count", "1")
params.Add("biz_tag", "price")
params.Add("app_id", conf.Conf.BASECenter.AppID)
params.Add("app_token", conf.Conf.BASECenter.AppToken)
reqParam := params.Encode()
resp, err := http.Get(fmt.Sprintf(conf.Conf.BASECenter.URL+"orderid/get?%s", reqParam))
if err != nil {
log.Error("获取票价id HTTP REQUEST失败")
return 0, err
}
defer resp.Body.Close()
content, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Error("读取HTTP RESPONSE失败")
return 0, err
}
var result Response
if err := json.Unmarshal(content, &result); err != nil {
log.Error("json解析失败")
}
return result.Data[0], nil
}
var alphabetTable []string
// AlphabetTable 获取票价所需symbol的字母表
func AlphabetTable() []string {
if alphabetTable != nil {
return alphabetTable
}
result := make([]string, 52)
var i int
ch := 97
for i = 0; i < 26; i++ {
result[i] = string(ch + i)
}
ch = 65
j := i
for i = 0; i < 26; i++ {
result[j] = string(ch + i)
j++
}
alphabetTable = result
return alphabetTable
}
// ClassifyIDs 获取已经存在和需要被删除的id list
func ClassifyIDs(oldIDs []int64, newIDs []int64) (needDel []int64, existed []int64) {
newIDsMap := make(map[int64]int64)
for _, newID := range newIDs {
newIDsMap[newID] = newID
}
for _, oldID := range oldIDs {
if oldID == 0 {
continue
}
if _, ok := newIDsMap[oldID]; !ok {
needDel = append(needDel, oldID)
} else {
existed = append(existed, oldID)
}
}
return
}
// Implode 仅支持不同类型的数组
func Implode(glue string, list interface{}) string {
listValue := reflect.Indirect(reflect.ValueOf(list))
if listValue.Kind() != reflect.Slice {
// 数组以外类型返回空字符串
return ""
}
count := listValue.Len()
listStr := make([]string, 0, count)
for i := 0; i < count; i++ {
str := fmt.Sprint(listValue.Index(i).Interface())
listStr = append(listStr, str)
}
return strings.Join(listStr, glue)
}

View File

@@ -0,0 +1,52 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["server_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/openplatform/ticket-item/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-item/conf:go_default_library",
"//app/service/openplatform/ticket-item/model:go_default_library",
"//app/service/openplatform/ticket-item/service:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["server.go"],
importpath = "go-common/app/service/openplatform/ticket-item/server/grpc",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/openplatform/ticket-item/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-item/conf:go_default_library",
"//app/service/openplatform/ticket-item/service:go_default_library",
"//library/log:go_default_library",
"//library/net/rpc/warden:go_default_library",
"@org_golang_google_grpc//: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,135 @@
package server
import (
"context"
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
"go-common/app/service/openplatform/ticket-item/conf"
"go-common/app/service/openplatform/ticket-item/service"
"go-common/library/log"
"go-common/library/net/rpc/warden"
"google.golang.org/grpc"
)
// New 新建warden实例
func New(c *conf.Config) *warden.Server {
//server := warden.NewServer(c.RPCServer)
server := warden.NewServer(nil)
server.Use(middleware())
item.RegisterItemServer(server.Server(), service.New(c))
item.RegisterGuestServer(server.Server(), service.New(c))
item.RegisterBulletinServer(server.Server(), service.New(c))
item.RegisterVenueServer(server.Server(), service.New(c))
item.RegisterPlaceServer(server.Server(), service.New(c))
item.RegisterAreaServer(server.Server(), service.New(c))
item.RegisterSeatServer(server.Server(), service.New(c))
/**go func() {
err := server.Run(c.RPCServer.Addr)
if err != nil {
panic("run server failed!" + err.Error())
}
}()
log.Info("warden run@%s", c.RPCServer.Addr)
**/
_, err := server.Start()
if err != nil {
panic("run server failed!" + err.Error())
}
return server
}
// 拦截器作用类似于http中间件
func middleware() grpc.UnaryServerInterceptor {
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
// 记录调用方法
log.Info("method:", info.FullMethod)
// call chain
resp, err = handler(ctx, req)
return
}
}
type server struct {
is *service.ItemService
}
func (s *server) Info(ctx context.Context, in *item.InfoRequest) (*item.InfoReply, error) {
return s.is.Info(ctx, in)
}
func (s *server) Cards(ctx context.Context, in *item.CardsRequest) (*item.CardsReply, error) {
return s.is.Cards(ctx, in)
}
func (s *server) BillInfo(ctx context.Context, in *item.BillRequest) (*item.BillReply, error) {
return s.is.BillInfo(ctx, in)
}
func (s *server) GuestInfo(ctx context.Context, in *item.GuestInfoRequest) (*item.GuestInfoReply, error) {
return s.is.GuestInfo(ctx, in)
}
func (s *server) GuestStatus(ctx context.Context, in *item.GuestStatusRequest) (*item.GuestInfoReply, error) {
return s.is.GuestStatus(ctx, in)
}
func (s *server) BulletinInfo(ctx context.Context, in *item.BulletinInfoRequest) (*item.BulletinReply, error) {
return s.is.BulletinInfo(ctx, in)
}
func (s *server) BulletinCheck(ctx context.Context, in *item.BulletinCheckRequest) (*item.BulletinReply, error) {
return s.is.BulletinCheck(ctx, in)
}
func (s *server) BulletinState(ctx context.Context, in *item.BulletinStateRequest) (*item.BulletinReply, error) {
return s.is.BulletinState(ctx, in)
}
func (s *server) Wish(ctx context.Context, in *item.WishRequest) (*item.WishReply, error) {
return s.is.Wish(ctx, in)
}
func (s *server) Fav(ctx context.Context, in *item.FavRequest) (*item.FavReply, error) {
return s.is.Fav(ctx, in)
}
// VenueInfo 添加/修改场馆信息
func (s *server) VenueInfo(ctx context.Context, in *item.VenueInfoRequest) (*item.VenueInfoReply, error) {
return s.is.VenueInfo(ctx, in)
}
// PlaceInfo 添加/修改场地信息
func (s *server) PlaceInfo(ctx context.Context, in *item.PlaceInfoRequest) (*item.PlaceInfoReply, error) {
return s.is.PlaceInfo(ctx, in)
}
// AreaInfo 添加/修改区域信息
func (s *server) AreaInfo(ctx context.Context, in *item.AreaInfoRequest) (*item.AreaInfoReply, error) {
return s.is.AreaInfo(ctx, in)
}
// DeleteArea 删除区域信息
func (s *server) DeleteArea(ctx context.Context, in *item.DeleteAreaRequest) (*item.DeleteAreaReply, error) {
return s.is.DeleteArea(ctx, in)
}
// SeatInfo 添加/修改座位信息
func (s *server) SeatInfo(ctx context.Context, in *item.SeatInfoRequest) (*item.SeatInfoReply, error) {
return s.is.SeatInfo(ctx, in)
}
// SeatStock 设置座位库存
func (s *server) SeatStock(ctx context.Context, in *item.SeatStockRequest) (*item.SeatStockReply, error) {
return s.is.SeatStock(ctx, in)
}
// RemoveSeatOrders 删除坐票票价下所有座位
func (s *server) RemoveSeatOrders(ctx context.Context, in *item.RemoveSeatOrdersRequest) (*item.RemoveSeatOrdersReply, error) {
return s.is.RemoveSeatOrders(ctx, in)
}
// Version 添加/修改项目信息
func (s *server) Version(ctx context.Context, in *item.VersionRequest) (*item.VersionReply, error) {
return s.is.Version(ctx, in)
}

View File

@@ -0,0 +1,123 @@
package server
import (
"context"
"flag"
"fmt"
"path/filepath"
"testing"
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
"go-common/app/service/openplatform/ticket-item/conf"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/app/service/openplatform/ticket-item/service"
. "github.com/smartystreets/goconvey/convey"
)
var (
s *server
ctx = context.TODO()
)
func init() {
dir, _ := filepath.Abs("../../cmd/item.toml")
flag.Set("conf", dir)
if err := conf.Init(); err != nil {
panic(fmt.Sprintf("conf.Init() error(%v)", err))
}
s = &server{
is: service.New(conf.Conf),
}
}
// Test_Info
func TestInfo(t *testing.T) {
Convey("get data", t, func() {
res, err := s.Info(ctx, &item.InfoRequest{ID: model.DataID})
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
So(res, ShouldNotBeEmpty)
})
Convey("no data", t, func() {
res, err := s.Info(ctx, &item.InfoRequest{ID: model.NoDataID})
So(err, ShouldNotBeNil)
So(res, ShouldNotBeEmpty)
})
}
// Test_Cards
func TestCards(t *testing.T) {
Convey("get data", t, func() {
res, err := s.Cards(ctx, &item.CardsRequest{IDs: model.DataIDs})
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
So(res, ShouldNotBeEmpty)
})
Convey("no data", t, func() {
res, err := s.Cards(ctx, &item.CardsRequest{IDs: model.NoDataIDs})
So(err, ShouldNotBeNil)
So(res, ShouldNotBeNil)
})
}
// TestBillInfo
func TestBillInfo(t *testing.T) {
Convey("get data", t, func() {
res, err := s.BillInfo(ctx, &item.BillRequest{
IDs: model.DataIDs,
ScIDs: model.DataSIDs,
TkIDs: model.DataTIDs,
})
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
So(res, ShouldNotBeEmpty)
})
Convey("no data", t, func() {
res, err := s.BillInfo(ctx, &item.BillRequest{
IDs: model.NoDataIDs,
ScIDs: model.NoDataSIDs,
TkIDs: model.NoDataTIDs,
})
So(err, ShouldNotBeNil)
So(res, ShouldNotBeNil)
})
}
// TestWish
func TestWish(t *testing.T) {
Convey("add wish", t, func() {
res, err := s.Wish(ctx, &item.WishRequest{
ItemID: 1,
MID: 1,
Face: "",
})
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
// TestWish
func TestFav(t *testing.T) {
Convey("fav add", t, func() {
res, err := s.Fav(ctx, &item.FavRequest{
ItemID: 1,
MID: 1,
Type: 1,
Status: 1,
})
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
Convey("fav del", t, func() {
res, err := s.Fav(ctx, &item.FavRequest{
ItemID: 1,
MID: 1,
Type: 1,
Status: 0,
})
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}

View File

@@ -0,0 +1,49 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"area.go",
"bulletin.go",
"guest.go",
"http.go",
"item.go",
"place.go",
"seat.go",
"venue.go",
"version.go",
],
importpath = "go-common/app/service/openplatform/ticket-item/server/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/openplatform/ticket-item/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-item/conf:go_default_library",
"//app/service/openplatform/ticket-item/model:go_default_library",
"//app/service/openplatform/ticket-item/service:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/binding:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,27 @@
package http
import (
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
"go-common/app/service/openplatform/ticket-item/model"
bm "go-common/library/net/http/blademaster"
"github.com/pkg/errors"
)
// @params AreaInfoParam
// @router post /openplatform/internal/ticket/item/areaInfo
// @response AreaInfoReply
func areaInfo(c *bm.Context) {
arg := new(model.AreaInfoParam)
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
c.JSON(itemSvc.AreaInfo(c, &item.AreaInfoRequest{
ID: arg.ID,
AID: arg.AID,
Name: arg.Name,
Place: arg.Place,
Coordinate: arg.Coordinate,
}))
}

View File

@@ -0,0 +1,20 @@
package http
/**import (
"github.com/pkg/errors"
"go-common/app/service/openplatform/ticket-item/model"
bm "go-common/library/net/http/blademaster"
)
// @params ParamID
// @router get /openplatform/internal/ticket/item/getbulletins
// @response BulletinInfo
func getBulletins(c *bm.Context) {
arg := new(model.ParamID)
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
c.JSON(itemSvc.GetBulletins(c, &arg.ID))
}**/

View File

@@ -0,0 +1,50 @@
package http
import (
"go-common/app/service/openplatform/ticket-item/model"
bm "go-common/library/net/http/blademaster"
)
/** test http
func guestInfo(c *bm.Context) {
arg := new(model.GuestParam)
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
c.JSON(itemSvc.GuestInfo(c, &model.GuestInfoRequest{ID: arg.ID, Name: arg.Name, GuestImg: arg.GuestImg, Description: arg.Description, GuestID: arg.GuestID}))
}
func guestStatus(c *bm.Context) {
arg := new(model.GuestStatusParam)
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
c.JSON(itemSvc.GuestStatus(c, arg.ID, arg.Status))
}**/
// @params ParamID
// @router get /openplatform/internal/ticket/item/getguests
// @response Guest
/**func getGuests(c *bm.Context) {
arg := new(model.ParamID)
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
c.JSON(itemSvc.GetGuests(c, &arg.ID))
}**/
// @params GuestSearchParam
// @router get /openplatform/internal/ticket/item/guest/search
// @response GuestSearchList
func guestSearch(c *bm.Context) {
arg := new(model.GuestSearchParam)
if err := c.Bind(arg); err != nil {
return
}
c.JSON(itemSvc.GuestSearch(c, arg))
}

View File

@@ -0,0 +1,74 @@
package http
import (
"net/http"
"go-common/app/service/openplatform/ticket-item/conf"
"go-common/app/service/openplatform/ticket-item/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
var (
itemSvc *service.ItemService
)
// Init init item service.
func Init(c *conf.Config, s *service.ItemService) {
itemSvc = s
//engineIn := bm.DefaultServer(c.BM.Inner)
engineIn := bm.DefaultServer(nil)
innerRouter(engineIn)
// init inner server
if err := engineIn.Start(); err != nil {
log.Error("engineIn.Start error(%v)", err)
panic(err)
}
/** unused
engineLocal := bm.DefaultServer(c.BM.Local)
localRouter(engineLocal)
// init local router
if err := engineLocal.Start(); err != nil {
log.Error("engineLocal.Start error(%v)", err)
panic(err)
}**/
}
// innerRouter init inner router.
func innerRouter(e *bm.Engine) {
e.Ping(ping)
// item
group := e.Group("/openplatform/internal/ticket/item")
{
group.GET("/info", info)
group.GET("/billinfo", billInfo)
group.GET("/cards", cards)
// group.GET("/guestinfo", guestInfo)
// group.GET("/gueststatus", guestStatus)
//group.GET("/getguests", getGuests)
//group.GET("/getbulletins", getBulletins)
group.GET("/guest/search", guestSearch)
group.GET("/venue/search", venueSearch) // 场馆搜索
group.GET("/version/search", versionSearch) // 项目版本搜索
group.POST("/wishstatus", wish) // 想去项目
group.POST("/favstatus", fav) // 收藏/取消收藏项目
group.POST("/venueinfo", venueInfo)
group.POST("/placeinfo", placeInfo)
group.POST("/areainfo", areaInfo)
group.POST("/seatinfo", seatInfo)
group.POST("/seatStock", seatStock)
group.POST("/removeSeatOrders", removeSeatOrders)
}
}
// localRouter init local router.
/**func localRouter(e *bm.Engine) {
}**/
// ping check server ok.
func ping(c *bm.Context) {
if err := itemSvc.Ping(c); err != nil {
log.Error("ticket http service ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}

View File

@@ -0,0 +1,104 @@
package http
import (
"strings"
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/binding"
"github.com/pkg/errors"
)
// @params ParamID
// @router get /openplatform/internal/ticket/item/info
// @response InfoReply
func info(c *bm.Context) {
arg := new(model.ParamID)
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
c.JSON(itemSvc.Info(c, &item.InfoRequest{ID: arg.ID}))
}
// @params ParamCards
// @router get /openplatform/internal/ticket/item/cards
// @response CardsReply
func cards(c *bm.Context) {
arg := new(model.ParamCards)
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
ids := model.UniqueInt64(model.String2Int64(strings.Split(arg.IDs, ",")))
if len(ids) == 0 {
err := ecode.RequestErr
errors.Wrap(err, "参数验证失败")
log.Error("ItemID invalid %v", arg.IDs)
return
}
c.JSON(itemSvc.Cards(c, &item.CardsRequest{IDs: ids}))
}
// @params ParamBill
// @router get /openplatform/internal/ticket/item/billinfo
// @response BillReply
func billInfo(c *bm.Context) {
arg := new(model.ParamBill)
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
ids := model.UniqueInt64(model.String2Int64(strings.Split(arg.IDs, ",")))
if len(ids) == 0 {
err := ecode.RequestErr
errors.Wrap(err, "参数验证失败")
log.Error("ItemID empty %v", arg.IDs)
return
}
sids := model.UniqueInt64(model.String2Int64(strings.Split(arg.Sids, ",")))
if len(ids) == 0 {
log.Info("ScreenID empty %v", arg.Sids)
return
}
tids := model.UniqueInt64(model.String2Int64(strings.Split(arg.Tids, ",")))
if len(ids) == 0 {
log.Info("TicketID empty %v", arg.Tids)
return
}
c.JSON(itemSvc.BillInfo(c, &item.BillRequest{IDs: ids, ScIDs: sids, TkIDs: tids}))
}
// @params WishRequest
// @router post /openplatform/internal/ticket/item/wishstatus
// @response WishReply
func wish(c *bm.Context) {
arg := new(item.WishRequest)
if err := c.BindWith(arg, binding.JSON); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
c.JSON(itemSvc.Wish(c, arg))
}
// @params FavRequest
// @router post /openplatform/internal/ticket/item/favstatus
// @response FavReply
func fav(c *bm.Context) {
arg := new(item.FavRequest)
if err := c.BindWith(arg, binding.JSON); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
c.JSON(itemSvc.Fav(c, arg))
}

View File

@@ -0,0 +1,29 @@
package http
import (
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
"go-common/app/service/openplatform/ticket-item/model"
bm "go-common/library/net/http/blademaster"
"github.com/pkg/errors"
)
// @params PlaceInfoParam
// @router post /openplatform/internal/ticket/item/placeInfo
// @response PlaceInfoReply
func placeInfo(c *bm.Context) {
arg := new(model.PlaceInfoParam)
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
c.JSON(itemSvc.PlaceInfo(c, &item.PlaceInfoRequest{
ID: arg.ID,
Status: arg.Status,
Name: arg.Name,
BasePic: arg.BasePic,
Venue: arg.Venue,
DWidth: arg.DWidth,
DHeight: arg.DHeight,
}))
}

View File

@@ -0,0 +1,65 @@
package http
import (
"encoding/json"
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
"go-common/app/service/openplatform/ticket-item/model"
bm "go-common/library/net/http/blademaster"
"github.com/pkg/errors"
)
// @params SeatInfoParam
// @router post /openplatform/internal/ticket/item/seatInfo
// @response SeatInfoReply
func seatInfo(c *bm.Context) {
arg := new(model.SeatInfoParam)
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
var seats []*item.AreaSeatInfo
json.Unmarshal([]byte(arg.Seats), &seats)
c.JSON(itemSvc.SeatInfo(c, &item.SeatInfoRequest{
Area: arg.Area,
SeatsNum: arg.SeatsNum,
Seats: seats,
Width: arg.Width,
Height: arg.Height,
RowList: arg.RowList,
SeatStart: arg.SeatStart,
}))
}
// @params SeatStockParam
// @router post /openplatform/internal/ticket/item/seatStock
// @response SeatStockReply
func seatStock(c *bm.Context) {
arg := new(model.SeatStockParam)
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
var seatinfo []*item.SeatPrice
json.Unmarshal([]byte(arg.SeatInfo), &seatinfo)
c.JSON(itemSvc.SeatStock(c, &item.SeatStockRequest{
Screen: arg.Screen,
Area: arg.Area,
SeatInfo: seatinfo,
}))
}
// @params RemoveSeatOrdersParam
// @router post /openplatform/internal/ticket/item/RemoveSeatOrders
// @response RemoveSeatOrdersReply
func removeSeatOrders(c *bm.Context) {
arg := new(model.RemoveSeatOrdersParam)
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
c.JSON(itemSvc.RemoveSeatOrders(c, &item.RemoveSeatOrdersRequest{
Price: arg.Price,
}))
}

View File

@@ -0,0 +1,41 @@
package http
import (
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
"go-common/app/service/openplatform/ticket-item/model"
bm "go-common/library/net/http/blademaster"
"github.com/pkg/errors"
)
// @params VenueSearchParam
// @router get /openplatform/internal/ticket/item/venue/search
// @response VenueSearchList
func venueSearch(c *bm.Context) {
req := &model.VenueSearchParam{}
if err := c.Bind(req); err != nil {
return
}
c.JSON(itemSvc.VenueSearch(c, req))
}
// @params VenueInfoParam
// @router post /openplatform/internal/ticket/item/venueInfo
// @response VenueInfoReply
func venueInfo(c *bm.Context) {
arg := new(model.VenueInfoParam)
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
c.JSON(itemSvc.VenueInfo(c, &item.VenueInfoRequest{
ID: arg.ID,
Name: arg.Name,
Status: arg.Status,
Province: arg.Province,
City: arg.City,
District: arg.District,
AddressDetail: arg.AddressDetail,
Traffic: arg.Traffic,
}))
}

View File

@@ -0,0 +1,17 @@
package http
import (
"go-common/app/service/openplatform/ticket-item/model"
bm "go-common/library/net/http/blademaster"
)
// @params VersionSearchParam
// @router get /openplatform/internal/ticket/item/version/search
// @response VersionSearchList
func versionSearch(c *bm.Context) {
req := &model.VersionSearchParam{}
if err := c.Bind(req); err != nil {
return
}
c.JSON(itemSvc.VersionSearch(c, req))
}

View File

@@ -0,0 +1,71 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"guest_test.go",
"item_test.go",
"seat_test.go",
"service_test.go",
"venue_test.go",
"version_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/openplatform/ticket-item/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-item/conf:go_default_library",
"//app/service/openplatform/ticket-item/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"area.go",
"bulletin.go",
"guest.go",
"item.go",
"place.go",
"seat.go",
"service.go",
"venue.go",
"version.go",
],
importpath = "go-common/app/service/openplatform/ticket-item/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/openplatform/ticket-item/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-item/conf:go_default_library",
"//app/service/openplatform/ticket-item/dao:go_default_library",
"//app/service/openplatform/ticket-item/model:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/jinzhu/gorm:go_default_library",
"//vendor/gopkg.in/go-playground/validator.v9: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,166 @@
package service
import (
"context"
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/ecode"
"github.com/jinzhu/gorm"
)
// AreaInfo 添加/修改区域信息
func (s *ItemService) AreaInfo(c context.Context, info *item.AreaInfoRequest) (res *item.AreaInfoReply, err error) {
var (
oriArea *model.Area
oldArea *model.Area
tx *gorm.DB
)
oriArea = &model.Area{
ID: info.ID,
AID: info.AID,
Name: info.Name,
Place: info.Place,
DeletedStatus: 0,
}
if err = v.Struct(info); err != nil {
err = ecode.RequestErr
return
}
// 开启事务
if tx, err = s.dao.BeginTran(c); err != nil {
err = ecode.NotModified
return
}
if info.ID == 0 {
// 查询是否存在被删除的旧区域
if oldArea, err = s.dao.TxRawDeletedAreaByAID(c, tx, oriArea.AID, oriArea.Place); err != nil {
tx.Rollback()
return
}
if oldArea == nil {
// 添加主体信息
if err = s.dao.TxAddArea(c, tx, oriArea); err != nil {
tx.Rollback()
return
}
} else {
// 更新主体信息
oriArea.ID = oldArea.ID
if err = s.dao.TxUpdateArea(c, tx, oriArea); err != nil {
tx.Rollback()
return
}
}
} else {
// 查询并保存旧的区域信息
if oldArea, err = s.dao.TxRawArea(c, tx, oriArea.ID); err != nil {
tx.Rollback()
return
}
// 更新主体信息
if err = s.dao.TxUpdateArea(c, tx, oriArea); err != nil {
tx.Rollback()
return
}
// 删除旧场地的区域位置
if oldArea.Place != info.Place {
if err = s.dao.TxDelAreaPolygon(c, tx, oriArea.Place, info.ID); err != nil {
tx.Rollback()
return
}
}
}
// 更新新场地的区域位置
if err = s.dao.TxAddOrUpdateAreaPolygon(c, tx, info.Place, oriArea.ID, &info.Coordinate); err != nil {
tx.Rollback()
return
}
// 提交事务
if err = s.dao.CommitTran(c, tx); err != nil {
err = ecode.NotModified
return
}
res = &item.AreaInfoReply{
Success: true,
ID: oriArea.ID,
Coordinate: info.Coordinate,
}
return
}
// DeleteArea 软删除区域信息
func (s *ItemService) DeleteArea(c context.Context, info *item.DeleteAreaRequest) (res *item.DeleteAreaReply, err error) {
var (
tx *gorm.DB
area *model.Area
seatSets []*model.SeatSet
)
if err = v.Struct(info); err != nil {
err = ecode.RequestErr
return
}
// 开启事务
if tx, err = s.dao.BeginTran(c); err != nil {
err = ecode.NotModified
return
}
if area, err = s.dao.TxRawArea(c, tx, info.ID); err != nil {
tx.Rollback()
return
}
// 清除区域座位图信息area_seatmap表
if err = s.dao.TxSaveAreaSeatmap(c, tx, &model.AreaSeatmap{
ID: info.ID,
SeatMap: "",
}); err != nil {
tx.Rollback()
return
}
// 清除区域座位信息area_seats表
if err = s.dao.TxBatchDeleteAreaSeats(c, tx, info.ID); err != nil {
tx.Rollback()
return
}
// 清空未售出的座位订单seat_order表
if err = s.dao.TxBatchDelUnsoldSeatOrders(c, tx, info.ID); err != nil {
tx.Rollback()
return
}
if seatSets, err = s.dao.TxGetSeatSets(c, tx, info.ID); err != nil {
tx.Rollback()
return
}
delIDs := make([]int64, 0)
for _, ss := range seatSets {
delIDs = append(delIDs, ss.ID)
}
// 清空票价设置图seat_set表
if err = s.dao.TxClearSeatCharts(c, tx, delIDs); err != nil {
tx.Rollback()
return
}
// 软删除area表
if err = s.dao.TxDelArea(c, tx, info.ID); err != nil {
tx.Rollback()
return
}
// 删除区域的场地坐标信息
if err = s.dao.TxDelAreaPolygon(c, tx, area.Place, info.ID); err != nil {
tx.Rollback()
return
}
// TODO: 删除所有相关缓存
// 提交事务
if err = s.dao.CommitTran(c, tx); err != nil {
err = ecode.NotModified
return
}
res = &item.DeleteAreaReply{Success: true}
return
}

View File

@@ -0,0 +1,76 @@
package service
import (
"context"
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/log"
)
// GetBulletins 获取公告信息 测试用
/**func (s *ItemService) GetBulletins(c context.Context, id *int64) (res []*item.BulletinInfo, err error) {
res, err = s.dao.GetBulletins(c, *id)
return
}**/
// BulletinInfo 添加新公告版本
func (s *ItemService) BulletinInfo(c context.Context, info *item.BulletinInfoRequest) (res *item.BulletinReply, err error) {
var dbReturn bool
var dbErr error
if info.VerID == 0 {
dbReturn, dbErr = s.dao.AddBulletin(c, info)
} else {
dbReturn, dbErr = s.dao.UpdateBulletin(c, info)
}
return &item.BulletinReply{Success: dbReturn}, dbErr
}
// BulletinCheck 审核公告
func (s *ItemService) BulletinCheck(c context.Context, info *item.BulletinCheckRequest) (res *item.BulletinReply, err error) {
var dbReturn bool
var dbErr error
versionLogData := &model.VersionLog{
VerID: info.VerID,
Type: 1,
Log: info.Comment,
Uname: info.Reviewer,
}
if info.OpType == 1 {
dbReturn, dbErr = s.dao.PassBulletin(c, info.VerID)
versionLogData.IsPass = 1
} else {
dbReturn, dbErr = s.dao.RejectVersion(c, info.VerID, model.VerTypeBulletin)
versionLogData.IsPass = 0
}
// 添加审核记录
if logErr := s.dao.AddVersionLog(c, versionLogData); logErr != nil {
log.Error("新建审核记录失败")
dbReturn = false
dbErr = logErr
}
return &item.BulletinReply{Success: dbReturn}, dbErr
}
// BulletinState 添加新公告版本
func (s *ItemService) BulletinState(c context.Context, info *item.BulletinStateRequest) (res *item.BulletinReply, err error) {
var dbReturn bool
var dbErr error
if info.OpType == 1 {
// 上架
dbReturn, dbErr = s.dao.PassBulletin(c, info.VerID)
} else {
// 下架
var status int8
if info.Source == 1 {
status = -1 // 手动下架
} else {
status = -2 // 强制下架
}
dbReturn, dbErr = s.dao.UnpublishBulletin(c, info.VerID, status)
}
return &item.BulletinReply{Success: dbReturn}, dbErr
}

View File

@@ -0,0 +1,48 @@
package service
import (
"context"
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/ecode"
)
// GuestInfo Add or Update Guest
func (s *ItemService) GuestInfo(c context.Context, info *item.GuestInfoRequest) (ret *item.GuestInfoReply, err error) {
if paramErr := v.Struct(info); paramErr != nil {
return ret, ecode.RequestErr
}
var result bool
var daoErr error
if info.ID == 0 {
result, daoErr = s.dao.AddGuest(c, info)
} else {
result, daoErr = s.dao.UpdateGuest(c, info)
}
return &item.GuestInfoReply{Success: result}, daoErr
}
// GuestStatus Change Guest Status
func (s *ItemService) GuestStatus(c context.Context, info *item.GuestStatusRequest) (ret *item.GuestInfoReply, err error) {
if paramErr := v.Struct(info); paramErr != nil {
return ret, ecode.RequestErr
}
result, daoError := s.dao.GuestStatus(c, info.ID, int8(info.Status))
return &item.GuestInfoReply{Success: result}, daoError
}
// GetGuests 获取单个宾客信息 测试用
/**func (s *ItemService) GetGuests(c context.Context, id *int64) (res []*model.Guest, err error) {
res, err = s.dao.GetGuests(c, *id)
return
}**/
// GuestSearch 场馆搜索
func (s *ItemService) GuestSearch(c context.Context, arg *model.GuestSearchParam) (res *model.GuestSearchList, err error) {
res, err = s.dao.GuestSearch(c, arg)
return
}

View File

@@ -0,0 +1,22 @@
package service
import (
"testing"
"go-common/app/service/openplatform/ticket-item/model"
. "github.com/smartystreets/goconvey/convey"
)
func TestGuestSearch(t *testing.T) {
Convey("GuestSearch", t, func() {
param := &model.GuestSearchParam{
Keyword: "1",
Ps: 10,
Pn: 1,
}
res, err := s.GuestSearch(ctx, param)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}

View File

@@ -0,0 +1,561 @@
package service
import (
"context"
"encoding/json"
"strconv"
"strings"
"fmt"
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/time"
)
// Info get item info
func (s *ItemService) Info(ctx context.Context, in *item.InfoRequest) (reply *item.InfoReply, err error) {
var items map[int64]*model.Item
reply = new(item.InfoReply)
if err = v.Struct(in); err != nil {
err = ecode.RequestErr
return
}
ids := []int64{in.ID}
items, err = s.dao.Items(ctx, ids)
if err != nil {
log.Warn("service.Item Items() error(%v) or empty", err)
return
} else if len(items) == 0 {
err = ecode.NothingFound
return
}
i := items[in.ID]
reply = &item.InfoReply{
ID: i.ID,
Name: i.Name,
Status: i.Status,
Type: i.Type,
Rec: i.Recommend,
IsSale: i.IsSale,
TicketDesc: i.TicketDesc,
PromTag: i.PromoTags,
}
scs, err := s.dao.ScListByItem(ctx, ids)
if err != nil {
log.Error("service.Item ScListByItem() error(%v) or empty", err)
return
}
tks, err := s.dao.TkListByItem(ctx, ids)
if err != nil {
log.Error("service.Item TkListByItem() error(%v) or empty", err)
return
}
sctks := make(map[int64][]*model.TicketInfo)
for _, tk := range tks[in.ID] {
sctks[tk.ScreenID] = append(sctks[tk.ScreenID], tk)
}
detail, err := s.dao.ItemDetails(ctx, ids)
if err != nil {
log.Error("service.Item ItemDetails() error(%v) or empty", err)
return
}
v, err := s.dao.Venues(ctx, []int64{i.VenueID})
if err != nil {
log.Error("service.Item Venues() error(%v) or empty", err)
return
} else if len(v) == 0 {
err = ecode.NothingFound
log.Error("service.Item Venues(%v) not found", i.VenueID)
return
}
venue := v[i.VenueID]
place, err := s.dao.Place(ctx, i.PlaceID)
if err != nil {
log.Error("service.Item Place() error(%v)", err)
return
} else if place == nil {
err = ecode.NothingFound
log.Error("service.Item Place(%v) not found", i.PlaceID)
return
}
if sclist, ok := scs[in.ID]; ok {
for _, sc := range sclist {
reply.Screen = make(map[int64]*item.ScreenInfo)
tklist := make(map[int64]*item.TicketInfo)
if tkslist, ok := sctks[sc.ID]; ok {
for _, tk := range tkslist {
info := &item.TicketInfo{
ID: tk.ID,
Desc: tk.Desc,
Type: tk.Type,
SaleType: tk.SaleType,
LinkSc: tk.LinkSc,
LinkTicketID: strconv.FormatInt(tk.LinkTicketID, 10),
Symbol: tk.Symbol,
Color: tk.Color,
BuyLimit: tk.BuyLimit,
DescDetail: tk.DescDetail,
PriceList: &item.TicketPriceList{
Price: tk.Price,
OriPrice: tk.OriginPrice,
MktPrice: tk.MarketPrice,
},
StatusList: &item.TicketStatus{
IsSale: tk.IsSale,
IsVisible: tk.IsVisible,
IsRefund: tk.IsRefund,
},
Time: &item.TicketTime{
SaleStime: int64(tk.SaleStart),
SaleEtime: int64(tk.SaleEnd),
},
}
info.BuyNumLimit = new(item.TicketBuyNumLimit)
tk.FormatTicketBuyLimit(info.BuyNumLimit)
info.SaleFlag = tk.CalTkSaleFlag()
tklist[tk.ID] = info
}
}
reply.Screen[sc.ID] = &item.ScreenInfo{
ID: sc.ID,
Name: sc.Name,
Status: sc.Status,
ScTime: &item.ScreenTime{
Stime: sc.StartTime,
Etime: sc.EndTime,
},
Type: sc.Type,
TicketType: sc.TicketType,
ScreenType: sc.ScreenType,
DeliveryType: sc.DeliveryType,
PickSeat: sc.PickSeat,
Ticket: tklist,
}
}
}
reply.Img = &item.ImgList{
First: i.Img.First.URL,
Banner: i.Img.Banner.URL,
}
reply.Time = &item.ItemTime{
Stime: i.StartTime,
Etime: i.EndTime,
}
var coor model.Coor
json.Unmarshal([]byte(venue.Coordinate), &coor)
reply.Ext = &item.ItemExt{
Label: i.Label,
SpType: i.SponsorType,
VerID: i.VerID,
Detail: detail[i.ID].PerformanceDesc,
Venue: &item.VenueInfo{
ID: venue.ID,
Name: venue.Name,
Status: venue.Status,
AddrInfo: &item.VenueAddrInfo{
Province: venue.Province,
City: venue.City,
District: venue.District,
AddressDetail: venue.AddressDetail,
Traffic: venue.Traffic,
LonLatType: coor.Type,
LonLat: coor.Coor,
},
PlaceInfo: &item.PlaceInfo{
ID: place.ID,
Name: place.Name,
Status: place.Status,
BasePic: place.BasePic,
DWidth: place.DWidth,
DHeight: place.DHeight,
},
},
}
reply.BillOpt = &item.BillOpt{
BuyerInfo: i.BuyerInfo,
ExpTip: i.ExpressFee,
ExpFree: i.HasExpressFee,
VipExpFree: i.ExpressFreeFlag,
}
return reply, nil
}
// Cards get item cardlist
func (s *ItemService) Cards(ctx context.Context, in *item.CardsRequest) (reply *item.CardsReply, err error) {
var vids []int64
reply = new(item.CardsReply)
items, err := s.dao.Items(ctx, in.IDs)
if err != nil {
log.Warn("service.Item Items() error(%v)", err)
return
} else if len(items) == 0 {
err = ecode.NothingFound
return
}
cm := make(map[int64]*item.CardReply)
for id, i := range items {
cm[id] = &item.CardReply{
ID: i.ID,
Name: i.Name,
Status: i.Status,
Type: i.Type,
Rec: i.Recommend,
IsSale: i.IsSale,
TicketDesc: i.TicketDesc,
PromTag: i.PromoTags,
Img: &item.ImgList{
First: i.Img.First.URL,
Banner: i.Img.Banner.URL,
},
Time: &item.ItemTime{
Stime: i.StartTime,
Etime: i.EndTime,
},
}
vids = append(vids, i.VenueID)
}
vs, err := s.dao.Venues(ctx, model.UniqueInt64(vids))
if err != nil {
log.Error("service.Item Venues() error(%v)", err)
return
}
for id, i := range items {
venue, ok := vs[i.VenueID]
if !ok {
log.Error("venue %v not found", i.VenueID)
continue
}
var coor model.Coor
json.Unmarshal([]byte(venue.Coordinate), &coor)
cm[id].Venue = &item.VenueInfo{
ID: venue.ID,
Name: venue.Name,
Status: venue.Status,
AddrInfo: &item.VenueAddrInfo{
Province: venue.Province,
City: venue.City,
District: venue.District,
AddressDetail: venue.AddressDetail,
Traffic: venue.Traffic,
LonLatType: coor.Type,
LonLat: coor.Coor,
},
}
}
reply.Cards = cm
return
}
// BillInfo get item cardlist
func (s *ItemService) BillInfo(ctx context.Context, in *item.BillRequest) (reply *item.BillReply, err error) {
reply = new(item.BillReply)
reply.BaseInfo = make(map[int64]*item.ItemBase)
reply.BillOpt = make(map[int64]*item.BillOpt)
if err = v.Struct(in); err != nil {
err = ecode.RequestErr
return
}
if len(in.IDs) > 10 || len(in.ScIDs) > 20 || len(in.TkIDs) > 20 {
err = ecode.RequestErr
log.Error("len(in.IDs) > 10 or len(in.ScIDs) > 20 or len(in.TkIDs) > 20 ", err)
return
}
items, err := s.dao.Items(ctx, in.IDs)
if err != nil {
log.Error("service.Item Items() error(%v)", err)
return
} else if len(items) == 0 {
err = ecode.NothingFound
return
}
scs, err := s.dao.ScList(ctx, in.ScIDs)
if err != nil {
log.Error("service.Item ScList() error(%v)", err)
return
}
tks, err := s.dao.TkList(ctx, in.TkIDs)
if err != nil {
log.Error("service.Item TkList() error(%v)", err)
return
}
for id, i := range items {
reply.BaseInfo[id] = &item.ItemBase{
ID: i.ID,
Name: i.Name,
Status: i.Status,
Type: i.Type,
IsSale: i.IsSale,
PromTag: i.PromoTags,
VerID: i.VerID,
Time: &item.ItemTime{
Stime: i.StartTime,
Etime: i.EndTime,
},
Img: &item.ImgList{
First: i.Img.First.URL,
Banner: i.Img.Banner.URL,
},
}
reply.BillOpt[id] = &item.BillOpt{
BuyerInfo: i.BuyerInfo,
ExpTip: i.ExpressFee,
ExpFree: i.HasExpressFee,
VipExpFree: i.ExpressFreeFlag,
}
}
for id, sc := range scs {
if _, ok := reply.BaseInfo[sc.ProjectID]; !ok {
log.Error("screen %v not belong to any of item", id)
continue
}
if reply.BaseInfo[sc.ProjectID].Screen == nil {
reply.BaseInfo[sc.ProjectID].Screen = make(map[int64]*item.ScreenInfo)
}
reply.BaseInfo[sc.ProjectID].Screen[id] = &item.ScreenInfo{
ID: sc.ID,
Name: sc.Name,
Status: sc.Status,
ScTime: &item.ScreenTime{
Stime: sc.StartTime,
Etime: sc.EndTime,
},
Type: sc.Type,
TicketType: sc.TicketType,
ScreenType: sc.ScreenType,
DeliveryType: sc.DeliveryType,
PickSeat: sc.PickSeat,
}
}
for id, tk := range tks {
if _, ok := reply.BaseInfo[tk.ProjectID]; !ok {
log.Error("ticket %v not belong to any of item", id)
continue
}
if _, ok := reply.BaseInfo[tk.ProjectID].Screen[tk.ScreenID]; !ok {
log.Error("ticket %v not belong to any of screen", id)
continue
}
if reply.BaseInfo[tk.ProjectID].Screen[tk.ScreenID].Ticket == nil {
reply.BaseInfo[tk.ProjectID].Screen[tk.ScreenID].Ticket = make(map[int64]*item.TicketInfo)
}
reply.BaseInfo[tk.ProjectID].Screen[tk.ScreenID].Ticket[id] = &item.TicketInfo{
ID: tk.ID,
Desc: tk.Desc,
Type: tk.Type,
SaleType: tk.SaleType,
LinkSc: tk.LinkSc,
LinkTicketID: strconv.FormatInt(tk.LinkTicketID, 10),
Symbol: tk.Symbol,
Color: tk.Color,
BuyLimit: tk.BuyLimit,
DescDetail: tk.DescDetail,
PriceList: &item.TicketPriceList{
Price: tk.Price,
OriPrice: tk.OriginPrice,
MktPrice: tk.MarketPrice,
},
StatusList: &item.TicketStatus{
IsSale: tk.IsSale,
IsVisible: tk.IsVisible,
IsRefund: tk.IsRefund,
},
Time: &item.TicketTime{
SaleStime: int64(tk.SaleStart),
SaleEtime: int64(tk.SaleEnd),
},
}
reply.BaseInfo[tk.ProjectID].Screen[tk.ScreenID].Ticket[id].BuyNumLimit = new(item.TicketBuyNumLimit)
tk.FormatTicketBuyLimit(reply.BaseInfo[tk.ProjectID].Screen[tk.ScreenID].Ticket[id].BuyNumLimit)
}
return
}
// Wish 想去
func (s *ItemService) Wish(ctx context.Context, in *item.WishRequest) (reply *item.WishReply, err error) {
if in.Face == "" {
in.Face = s.c.URL.DefaultHead
}
reply = &item.WishReply{
MID: in.MID,
ItemID: in.ItemID,
}
// TODO 改进点 - 先查有没有再写入
wish := &model.UserWish{
MID: in.MID,
Face: in.Face,
ItemID: in.ItemID,
}
if err = s.dao.AddWish(ctx, wish); err != nil {
// 重复插入
if strings.Contains(err.Error(), "1062") {
log.Warn("d.AddWish(%+v) error(%v) duplicate entry", in, err)
// TODO 返回 nil 还是 ecode
err = nil
} else {
log.Error("s.Wish(%+v) error(%v)", in, err)
}
return
}
err = s.dao.WishCacheUpdate(ctx, wish)
return
}
// Fav 收藏
func (s *ItemService) Fav(ctx context.Context, in *item.FavRequest) (reply *item.FavReply, err error) {
reply = &item.FavReply{
ItemID: in.ItemID,
MID: in.MID,
Type: in.Type,
Status: in.Status,
}
if err = s.dao.FavUpdate(ctx, in.ItemID, in.MID, in.Type, in.Status); err != nil {
log.Error("s.Fav() dao.FavUpdate(%d, %d, %d) error(%v)", in.ItemID, in.MID, in.Type, err)
return
}
if err = s.dao.UserFavStateCache(ctx, in.ItemID, in.MID, in.Type, in.Status); err != nil {
log.Error("s.Fav(%+v) d.UserFavState() error(%v)", in, err)
return
}
if err = s.dao.UpdateFavListCache(ctx, in.ItemID, in.MID, in.Status); err != nil {
return
}
return
}
// Version Add or Update Project with Version
func (s *ItemService) Version(c context.Context, info *item.VersionRequest) (ret *item.VersionReply, err error) {
if paramErr := v.Struct(info); paramErr != nil {
return ret, ecode.TicketMainInfoTooLarge
}
var pid int64
var daoErr error
if info.OpType == 0 {
pid, daoErr = s.dao.AddProject(c, info.VerId)
}
return &item.VersionReply{ProjectId: pid}, daoErr
}
// BannerEdit Add or Update A Banner
func (s *ItemService) BannerEdit(c context.Context, info *item.BannerEditRequest) (ret *item.BannerEditReply, err error) {
var bannerID int64
var verID uint64
if info.VerId == 0 {
bannerID, verID, err = s.dao.AddBanner(c, info)
} else {
verID = info.VerId
verInfo, _, getErr := s.dao.GetVersion(c, verID, false)
if getErr != nil {
return nil, getErr
}
verStatus := verInfo.Status
bannerID = verInfo.TargetItem
if verStatus == model.VerStatusNotReviewed {
//草稿状态 随意编辑版本信息
err = s.dao.EditBanner(c, info)
} else if verStatus == model.VerStatusReadyForSale || verStatus == model.VerStatusOnShelf {
//审核通过或进行中 仅新增版本
var mainInfo []byte
mainInfo, err = json.Marshal(info)
if err != nil {
log.Error("jsonMarshal版本详情失败:%s", err)
return nil, ecode.TicketAddVersionFailed
}
str := fmt.Sprintf("%d%d%.2d", info.Position, info.SubPosition, info.Order)
forInt, _ := strconv.ParseInt(str, 10, 64)
err = s.dao.AddVersion(c, nil, &model.Version{
Type: model.VerTypeBanner,
Status: info.OpType,
ItemName: info.Name,
TargetItem: bannerID,
AutoPub: 1, // 自动上架
PubStart: time.Time(info.PubStart),
PubEnd: time.Time(info.PubEnd),
For: forInt,
}, &model.VersionExt{
Type: model.VerTypeBanner,
MainInfo: string(mainInfo),
})
if err != nil {
log.Error("编辑创建banner版本失败: %s", err)
return nil, ecode.TicketAddVersionFailed
}
} else {
//其他状态 不可编辑
return nil, ecode.TicketVerCannotEdit
}
}
if info.OpType == 1 {
//编辑操作为提交审核时 记入versionLog
err = s.dao.AddVersionLog(c, &model.VersionLog{
VerID: verID,
Type: 2, //用户操作记录
Log: "提交审核",
Uname: info.Uname,
})
if err != nil {
return nil, err
}
}
return &item.BannerEditReply{BannerId: bannerID}, err
}
// VersionReview Pass or Reject A Version
func (s *ItemService) VersionReview(c context.Context, info *item.VersionReviewRequest) (ret *item.VersionReviewReply, err error) {
if info.OpType == model.VerReviewPass {
//通过
switch info.VerType {
case model.VerTypeBanner:
err = s.dao.PassOrPublishBanner(c, info.VerId)
if err != nil {
return nil, err
}
default:
return nil, ecode.NothingFound
}
} else {
//驳回
_, err = s.dao.RejectVersion(c, info.VerId, info.VerType)
if err != nil {
return nil, err
}
}
//审核操作记入versionLog
err = s.dao.AddVersionLog(c, &model.VersionLog{
VerID: info.VerId,
Type: 1, //用户操作记录
Log: info.Msg,
Uname: info.Uname,
IsPass: info.OpType,
})
return &item.VersionReviewReply{VerId: info.VerId}, err
}
// VersionStatus Change A Version's Status
func (s *ItemService) VersionStatus(c context.Context, info *item.VersionStatusRequest) (ret *item.VersionStatusReply, err error) {
switch info.VerType {
case model.VerTypeBanner:
err = s.dao.CgBannerStatus(c, info)
return &item.VersionStatusReply{VerId: info.VerId}, err
default:
return nil, ecode.NothingFound
}
}

View File

@@ -0,0 +1,80 @@
package service
import (
"context"
"testing"
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
"go-common/app/service/openplatform/ticket-item/model"
. "github.com/smartystreets/goconvey/convey"
)
var (
s *ItemService
ctx = context.TODO()
)
// TestInfo
func TestInfo(t *testing.T) {
Convey("TestInfo", t, func() {
res, err := s.Info(ctx, &item.InfoRequest{ID: model.DataID})
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
So(res, ShouldNotBeEmpty)
})
Convey("TestInfo", t, func() {
res, err := s.Info(ctx, &item.InfoRequest{ID: model.NoDataID})
So(err, ShouldNotBeNil)
So(res, ShouldNotBeNil)
})
}
// Test_Cards
func TestCards(t *testing.T) {
Convey("TestCards", t, func() {
res, err := s.Cards(ctx, &item.CardsRequest{IDs: model.DataIDs})
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
So(res, ShouldNotBeEmpty)
})
Convey("TestCards", t, func() {
res, err := s.Cards(ctx, &item.CardsRequest{IDs: model.NoDataIDs})
So(err, ShouldNotBeNil)
So(res, ShouldNotBeNil)
})
}
//
func TestBillInfo(t *testing.T) {
Convey("TestBillInfo", t, func() {
res, err := s.BillInfo(ctx, &item.BillRequest{
IDs: model.DataIDs,
ScIDs: model.DataSIDs,
TkIDs: model.DataTIDs,
})
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
So(res, ShouldNotBeEmpty)
})
Convey("TestBillInfo", t, func() {
res, err := s.BillInfo(ctx, &item.BillRequest{
IDs: model.NoDataIDs,
ScIDs: model.NoDataSIDs,
TkIDs: model.NoDataTIDs,
})
So(err, ShouldNotBeNil)
So(res, ShouldNotBeNil)
})
}
func TestWish(t *testing.T) {
Convey("insert wish", t, func() {
res, err := s.Wish(ctx, &item.WishRequest{
ItemID: 1,
MID: 1,
})
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}

View File

@@ -0,0 +1,71 @@
package service
import (
"context"
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/ecode"
"github.com/jinzhu/gorm"
)
// PlaceInfo 添加/修改场地信息
func (s *ItemService) PlaceInfo(c context.Context, info *item.PlaceInfoRequest) (res *item.PlaceInfoReply, err error) {
var (
oriPlace *model.Place
tx *gorm.DB
)
oriPlace = &model.Place{
ID: info.ID,
Name: info.Name,
BasePic: info.BasePic,
Status: info.Status,
Venue: info.Venue,
DWidth: info.DWidth,
DHeight: info.DHeight,
}
if err = v.Struct(info); err != nil {
err = ecode.RequestErr
return
}
// 开启事务
if tx, err = s.dao.BeginTran(c); err != nil {
err = ecode.NotModified
return
}
if info.ID == 0 {
if err = s.dao.TxAddPlace(c, tx, oriPlace); err != nil {
tx.Rollback()
return
}
} else {
var place *model.Place
if place, err = s.dao.TxRawPlace(c, tx, info.ID); err != nil {
tx.Rollback()
return
}
if err = s.dao.TxUpdatePlace(c, tx, oriPlace); err != nil {
tx.Rollback()
return
}
if err = s.dao.TxDecPlaceNum(c, tx, place.Venue); err != nil {
tx.Rollback()
return
}
}
if err = s.dao.TxIncPlaceNum(c, tx, info.Venue); err != nil {
tx.Rollback()
return
}
// 提交事务
if err = s.dao.CommitTran(c, tx); err != nil {
err = ecode.NotModified
return
}
res = &item.PlaceInfoReply{
Success: true,
ID: oriPlace.ID,
}
return
}

View File

@@ -0,0 +1,392 @@
package service
import (
"context"
"encoding/json"
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/ecode"
"go-common/library/log"
"strings"
"github.com/jinzhu/gorm"
)
// SeatInfo 添加/修改座位信息
func (s *ItemService) SeatInfo(c context.Context, info *item.SeatInfoRequest) (res *item.SeatInfoReply, err error) {
var (
oriArea *model.Area
oriAreaSeatmap *model.AreaSeatmap
tx *gorm.DB
oriAreaSeatsMap map[int32]map[int32]int64
oriAreaSeatsArr []*model.AreaSeats
recoveryAreaSeats []int64
insertAreaSeats []*model.AreaSeats
)
oriArea = &model.Area{
ID: info.Area,
SeatsNum: info.SeatsNum,
Width: info.Width,
Height: info.Height,
RowList: info.RowList,
SeatStart: info.SeatStart,
}
if err = v.Struct(info); err != nil {
err = ecode.RequestErr
return
}
// 创建事务
if tx, err = s.dao.BeginTran(c); err != nil {
err = ecode.NotModified
return
}
// 更新area表信息
if err = s.dao.TxUpdateSeat(c, tx, oriArea); err != nil {
tx.Rollback()
return
}
// 若有seat_map字段则更新area_seatmap表
if info.SeatMap != "" {
oriAreaSeatmap = &model.AreaSeatmap{
ID: info.Area,
SeatMap: info.SeatMap,
}
if err = s.dao.TxSaveAreaSeatmap(c, tx, oriAreaSeatmap); err != nil {
tx.Rollback()
return
}
}
// 查询并记录现有area_seats表信息到oriAreaSeatsMap
if oriAreaSeatsArr, err = s.dao.TxGetAreaSeats(c, tx, info.Area); err != nil {
tx.Rollback()
return
}
oriAreaSeatsMap = make(map[int32]map[int32]int64)
for _, oriAreaSeats := range oriAreaSeatsArr {
if _, ok := oriAreaSeatsMap[oriAreaSeats.X]; !ok {
oriAreaSeatsMap[oriAreaSeats.X] = make(map[int32]int64)
}
oriAreaSeatsMap[oriAreaSeats.X][oriAreaSeats.Y] = oriAreaSeats.ID
}
// 软删除现有区域下area_seats表记录
if err = s.dao.TxBatchDeleteAreaSeats(c, tx, info.Area); err != nil {
tx.Rollback()
return
}
// 比对新旧座位信息,若重合则恢复,若不存在则添加
recoveryAreaSeats = make([]int64, 0, 100)
insertAreaSeats = make([]*model.AreaSeats, 0, 100)
for _, oriSeat := range info.Seats {
if yMap, ok := oriAreaSeatsMap[oriSeat.X]; ok {
if id, ok := yMap[oriSeat.Y]; ok {
recoveryAreaSeats = append(recoveryAreaSeats, id)
continue
}
}
insertAreaSeats = append(insertAreaSeats, &model.AreaSeats{
X: oriSeat.X,
Y: oriSeat.Y,
Label: oriSeat.Label,
Bgcolor: oriSeat.Bgcolor,
Area: info.Area,
})
}
// 批量添加待添加座位到area_seats表
if len(insertAreaSeats) > 0 {
if err = s.dao.TxBatchAddAreaSeats(c, tx, insertAreaSeats); err != nil {
tx.Rollback()
return
}
}
// 批量恢复area_seats表的存在记录
if len(recoveryAreaSeats) > 0 {
if err = s.dao.TxBatchRecoverAreaSeats(c, tx, recoveryAreaSeats); err != nil {
tx.Rollback()
return
}
}
// 提交事务
if err = s.dao.CommitTran(c, tx); err != nil {
err = ecode.NotModified
return
}
res = &item.SeatInfoReply{Success: true}
return
}
// SeatStock 设置座位库存
// 确保座位均未售出从seat_set表获取座位图不存在则取area_setmap
// 遍历请求的SeatInfo数组补足未定义的票价从票种复制生成seat_order表插入或更新seat_set座位图
func (s *ItemService) SeatStock(c context.Context, info *item.SeatStockRequest) (res *item.SeatStockReply, err error) {
var (
seatOrders []*model.SeatOrder
seatSet *model.SeatSet
seatChartRows []string
ticketPrices []*model.TicketPrice
ticketPrice *model.TicketPrice
priceSymbol map[int64]string
symbolPrice map[string]*model.TicketPrice
insertPrice []*model.TicketPrice
insertSeatOrder []*model.SeatOrder
seatmap *model.AreaSeatmap
seatChart []byte
tx *gorm.DB
)
if err = v.Struct(info); err != nil {
err = ecode.RequestErr
return
}
// 创建事务
if tx, err = s.dao.BeginTran(c); err != nil {
err = ecode.NotModified
return
}
// 获取区域不可售座位
if seatOrders, err = s.dao.TxGetUnsaleableSeatOrders(c, tx, info.Screen, info.Area); err != nil {
tx.Rollback()
err = ecode.NotModified
return
}
// 已有不可售座位则不可修改
if len(seatOrders) != 0 {
tx.Rollback()
log.Error("区域ID:%d下已有不可售座位请勿修改", info.Area)
err = ecode.NotModified
return
}
// 查找票价设置图
if seatSet, err = s.dao.TxGetSeatChart(c, tx, info.Screen, info.Area); err != nil {
tx.Rollback()
err = ecode.NotModified
return
}
if seatSet.ID == 0 {
seatSet.AreaID = info.Area
seatSet.ScreenID = info.Screen
}
if seatSet.SeatChart == "" {
if seatmap, err = s.dao.TxRawAreaSeatmap(c, tx, info.Area); err != nil {
tx.Rollback()
err = ecode.NotModified
return
}
seatSet.SeatChart = seatmap.SeatMap
}
// 没有设置图则无法生成库存
if seatSet.SeatChart == "" {
tx.Rollback()
log.Error("场次ID:%d下没有找到区域ID:%d的票价设置图", info.Screen, info.Area)
err = ecode.NotModified
return
}
// 反序列化出座位数据
if err = json.Unmarshal([]byte(seatSet.SeatChart), &seatChartRows); err != nil {
tx.Rollback()
log.Error("场次ID:%d和区域ID:%d下票价设置图数据不可用:%s", info.Screen, info.Area, err)
err = ecode.NotModified
return
}
// 获取场次下的票价,建立票种和标志映射,标志和票价映射
if ticketPrices, err = s.dao.TxGetPriceSymbols(c, tx, info.Screen); err != nil {
tx.Rollback()
err = ecode.NotModified
return
}
priceSymbol = make(map[int64]string)
symbolPrice = make(map[string]*model.TicketPrice)
for _, tp := range ticketPrices {
priceSymbol[tp.ParentID] = tp.Symbol
symbolPrice[tp.Symbol] = tp
}
// 遍历请求的SeatInfo数组补足未定义的票价修改座位图组装价格图
insertPrice = make([]*model.TicketPrice, 0)
insertSeatOrder = make([]*model.SeatOrder, 0)
alphabetTable := model.AlphabetTable()
for _, sp := range info.SeatInfo {
var _symbol string
if sp.Price == 0 {
_symbol = "#"
} else {
var ok bool
if _symbol, ok = priceSymbol[sp.Price]; !ok {
// 枚举_symbol从alphabetTable[len(priceSymbol)]逆序到alphabetTable[0]若priceSymbol没有用过这个_symbol则将其作为这个票价的symbol
for i := len(priceSymbol); i >= 0; i-- {
_symbol = alphabetTable[i]
found := false
for _, symbol := range priceSymbol {
if symbol == _symbol {
found = true
break
}
}
if !found {
var genID int64
if genID, err = model.GetTicketIDFromBase(); err != nil {
tx.Rollback()
err = ecode.NotModified
return
}
// 取票种
if ticketPrice, err = s.dao.TxGetParentTicketPrice(c, tx, sp.Price); err != nil {
tx.Rollback()
err = ecode.NotModified
return
}
ticketPrice.ID = genID
ticketPrice.ScreenID = info.Screen
ticketPrice.Symbol = _symbol
ticketPrice.ParentID = sp.Price
ticketPrice.OriginPrice = -1
ticketPrice.MarketPrice = -1
ticketPrice.IsSale = 0
ticketPrice.IsVisible = 0
ticketPrice.IsRefund = 10
// 待插入票价
insertPrice = append(insertPrice, ticketPrice)
priceSymbol[sp.Price] = _symbol
symbolPrice[_symbol] = ticketPrice
break
}
}
}
}
// 修改座位图
bs := []byte(seatChartRows[sp.X])
bs[sp.Y] = _symbol[0]
seatChartRows[sp.X] = string(bs)
// 待插入座位订单
insertSeatOrder = append(insertSeatOrder, &model.SeatOrder{
Row: sp.X,
Col: sp.Y,
PriceID: symbolPrice[_symbol].ID,
Price: symbolPrice[_symbol].Price,
ScreenID: info.Screen,
AreaID: info.Area,
})
}
// 插入票价
if err = s.dao.TxBatchAddTicketPrice(c, tx, insertPrice); err != nil {
tx.Rollback()
err = ecode.NotModified
return
}
// 插入座位订单
if err = s.dao.TxBatchAddSeatOrder(c, tx, insertSeatOrder); err != nil {
tx.Rollback()
err = ecode.NotModified
return
}
// 更新座位图PriceSet的seat_chart
if seatChart, err = json.Marshal(seatChartRows); err != nil {
tx.Rollback()
log.Error("座位图seat_chart序列化失败:%s", err)
err = ecode.NotModified
return
}
seatSet.SeatChart = string(seatChart)
if seatSet.ID == 0 {
if err = s.dao.TxAddSeatChart(c, tx, seatSet); err != nil {
tx.Rollback()
err = ecode.NotModified
return
}
} else {
if err = s.dao.TxUpdateSeatChart(c, tx, seatSet.ID, seatSet.SeatChart); err != nil {
tx.Rollback()
err = ecode.NotModified
return
}
}
// 提交事务
if err = s.dao.CommitTran(c, tx); err != nil {
err = ecode.NotModified
return
}
res = &item.SeatStockReply{Success: true}
return
}
// RemoveSeatOrders 删除坐票票价下所有座位包括seat_order和seat_set中的记录
func (s *ItemService) RemoveSeatOrders(c context.Context, info *item.RemoveSeatOrdersRequest) (res *item.RemoveSeatOrdersReply, err error) {
var (
tp *model.TicketPrice
seatOrders []*model.SeatOrder
seatSets []*model.SeatSet
delIDs []int64
areas []int64
tx *gorm.DB
)
if err = v.Struct(info); err != nil {
err = ecode.RequestErr
return
}
// 创建事务
if tx, err = s.dao.BeginTran(c); err != nil {
err = ecode.NotModified
return
}
// 查询票价
if tp, err = s.dao.TxGetTicketPrice(c, tx, info.Price); err != nil {
tx.Rollback()
err = ecode.NotModified
return
}
// 确保票价的价格标志存在
if tp.Symbol == "" {
tx.Rollback()
log.Error("票价ID:%d不存在", info.Price)
err = ecode.NotModified
return
}
// 根据场次和票价ID获取可销售座位的ID和区域ID可能场次冗余
if seatOrders, err = s.dao.TxGetSaleableSeatOrders(c, tx, tp.ScreenID, info.Price); err != nil {
tx.Rollback()
err = ecode.NotModified
return
}
// 临时mapkey为区域ID用于去重
areaMap := make(map[int64]bool)
// 统计要删除的座位订单ID和区域ID
delIDs = make([]int64, 0)
areas = make([]int64, 0)
for _, seatOrder := range seatOrders {
delIDs = append(delIDs, seatOrder.ID)
areaMap[seatOrder.AreaID] = true
}
for area := range areaMap {
areas = append(areas, area)
}
// 批量删除座位订单
if err = s.dao.TxBatchDeleteSeatOrder(c, tx, delIDs); err != nil {
tx.Rollback()
err = ecode.NotModified
return
}
// 依次更新区域的座位订单
if seatSets, err = s.dao.TxGetSeatCharts(c, tx, tp.ScreenID, areas); err != nil {
tx.Rollback()
err = ecode.NotModified
return
}
for _, seatSet := range seatSets {
seatSet.SeatChart = strings.Replace(seatSet.SeatChart, tp.Symbol, "#", -1)
if err = s.dao.TxUpdateSeatChart(c, tx, seatSet.ID, seatSet.SeatChart); err != nil {
tx.Rollback()
err = ecode.NotModified
return
}
}
// 提交事务
if err = s.dao.CommitTran(c, tx); err != nil {
err = ecode.NotModified
return
}
res = &item.RemoveSeatOrdersReply{Areas: areas}
return
}

View File

@@ -0,0 +1,38 @@
package service
import (
"testing"
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
. "github.com/smartystreets/goconvey/convey"
)
func TestSeatStock(t *testing.T) {
Convey("SeatStock", t, func() {
req := &item.SeatStockRequest{
Screen: 1633,
Area: 239,
SeatInfo: []*item.SeatPrice{
{
X: 1,
Y: 1,
Price: 13424,
},
{
X: 2,
Y: 2,
Price: 13424,
},
{
X: 3,
Y: 3,
Price: 13424,
},
},
}
res, err := s.SeatStock(ctx, req)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}

View File

@@ -0,0 +1,39 @@
package service
import (
"context"
"go-common/app/service/openplatform/ticket-item/conf"
"go-common/app/service/openplatform/ticket-item/dao"
validator "gopkg.in/go-playground/validator.v9"
)
var (
v = validator.New()
)
// ItemService Service http service
type ItemService struct {
c *conf.Config
dao *dao.Dao
}
// New init
func New(c *conf.Config) (s *ItemService) {
s = &ItemService{
c: c,
dao: dao.New(c),
}
return
}
// Ping check server ok
func (s *ItemService) Ping(c context.Context) (err error) {
return s.dao.Ping(c)
}
// Close dao
func (s *ItemService) Close() {
s.dao.Close()
}

View File

@@ -0,0 +1,18 @@
package service
import (
"flag"
"fmt"
"path/filepath"
"go-common/app/service/openplatform/ticket-item/conf"
)
func init() {
dir, _ := filepath.Abs("../cmd/item.toml")
flag.Set("conf", dir)
if err := conf.Init(); err != nil {
panic(fmt.Sprintf("conf.Init() error(%v)", err))
}
s = New(conf.Conf)
}

View File

@@ -0,0 +1,45 @@
package service
import (
"context"
item "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
"go-common/app/service/openplatform/ticket-item/model"
"go-common/library/ecode"
)
// VenueSearch 场馆搜索
func (s *ItemService) VenueSearch(c context.Context, in *model.VenueSearchParam) (venues *model.VenueSearchList, err error) {
venues, err = s.dao.VenueSearch(c, in)
return
}
// VenueInfo 添加/修改场馆信息
func (s *ItemService) VenueInfo(c context.Context, info *item.VenueInfoRequest) (res *item.VenueInfoReply, err error) {
var oriVenue = &model.Venue{
ID: info.ID,
Name: info.Name,
City: info.City,
Province: info.Province,
District: info.District,
AddressDetail: info.AddressDetail,
Status: info.Status,
Traffic: info.Traffic,
PlaceNum: 0,
}
if err = v.Struct(info); err != nil {
err = ecode.RequestErr
return
}
if info.ID == 0 {
err = s.dao.AddVenue(c, oriVenue)
} else {
err = s.dao.UpdateVenue(c, oriVenue)
}
res = &item.VenueInfoReply{
Success: true,
ID: oriVenue.ID,
}
return
}

View File

@@ -0,0 +1,24 @@
package service
import (
"testing"
"go-common/app/service/openplatform/ticket-item/model"
. "github.com/smartystreets/goconvey/convey"
)
func TestVenueSearch(t *testing.T) {
Convey("VenueSearch", t, func() {
param := &model.VenueSearchParam{
ID: 1,
PageParam: model.PageParam{
Pn: 1,
Ps: 10,
},
}
res, err := s.VenueSearch(ctx, param)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}

View File

@@ -0,0 +1,13 @@
package service
import (
"context"
"go-common/app/service/openplatform/ticket-item/model"
)
// VersionSearch 项目版本查询
func (s *ItemService) VersionSearch(c context.Context, in *model.VersionSearchParam) (versions *model.VersionSearchList, err error) {
versions, err = s.dao.VersionSearch(c, in)
return
}

View File

@@ -0,0 +1,36 @@
package service
import (
"testing"
"go-common/app/service/openplatform/ticket-item/model"
. "github.com/smartystreets/goconvey/convey"
)
func TestVersionSearch(t *testing.T) {
Convey("VersionSearch", t, func() {
params := []*model.VersionSearchParam{
{
TargetItem: 1,
PageParam: model.PageParam{
Pn: 1,
Ps: 10,
},
},
{
ItemName: "测试",
PageParam: model.PageParam{
Pn: 1,
Ps: 10,
},
},
}
for _, param := range params {
res, err := s.VersionSearch(ctx, param)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
}
})
}