Initial commit

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

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,25 @@
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-sales/api/grpc/type:all-srcs",
"//app/service/openplatform/ticket-sales/api/grpc/v1:all-srcs",
"//app/service/openplatform/ticket-sales/cmd:all-srcs",
"//app/service/openplatform/ticket-sales/conf:all-srcs",
"//app/service/openplatform/ticket-sales/dao:all-srcs",
"//app/service/openplatform/ticket-sales/model:all-srcs",
"//app/service/openplatform/ticket-sales/server/grpc:all-srcs",
"//app/service/openplatform/ticket-sales/server/http:all-srcs",
"//app/service/openplatform/ticket-sales/service:all-srcs",
],
tags = ["automanaged"],
)

View File

@@ -0,0 +1,46 @@
### Version 0.0.15
1. 增加结算稽核的接口
### Version 0.0.14
1. ipv6的兼容
### Version 0.0.13
1. 修正重复声明service的问题
### Version 0.0.12
1. 订单结构调整,支持订单号批量查询
### Version 0.0.11
1. 增加订单日志功能
### Version 0.0.10
1. 缩短票的缓存时间
### Version 0.0.9
1. recv_tel 字段类型修改
#### Version 0.0.8
1. 修正修改拼团订单时未删除对应的缓存
#### Version 0.0.7
1. 修正订单列表不返回express_type的bug
#### Version 0.0.6
1. 调用其他服务增加日志
#### Version 0.0.5
1. 修正一些int类型的不规范使用
#### Version 0.0.4
1. 拼团接口
1. 订单查询接口
#### Version 0.0.3
1. 规范开放平台的code说明
#### Version 0.0.2
1. 修改退款赋值
#### Version 0.0.1
1. 初始化服务结构
1. 分销部分grpc接口尝试

View File

@@ -0,0 +1,8 @@
# Owner
liuzhan
yangyucheng
# Author
# Reviewer
qiuliang

View File

@@ -0,0 +1,13 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- liuzhan
- yangyucheng
labels:
- openplatform
- service
- service/openplatform/ticket-sales
options:
no_parent_owners: true
reviewers:
- qiuliang

View File

@@ -0,0 +1,13 @@
#### account-service
`ticket-service`主要是为开放平台票务各个业务提供一个综合的grpc接口。
* 聚合了票务多个模块(`项目` `销售` `促销` `ES`)的服务接口
* 提供了rpc服务
1. 为分销业务(`distrib`)封装grpc接口
##### 依赖环境
Go 1.7.5或更高版本
##### API文档
TODO example code api

View File

@@ -0,0 +1,59 @@
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
proto_library(
name = "_type_proto",
srcs = ["order.proto"],
tags = ["automanaged"],
deps = ["@gogo_special_proto//github.com/gogo/protobuf/gogoproto"],
)
go_proto_library(
name = "_type_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogofast_proto"],
importpath = "go-common/app/service/openplatform/ticket-sales/api/grpc/type",
proto = ":_type_proto",
tags = ["automanaged"],
deps = [
"//library/time:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [],
embed = [":_type_go_proto"],
importpath = "go-common/app/service/openplatform/ticket-sales/api/grpc/type",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/time:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@com_github_gogo_protobuf//sortkeys: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,85 @@
//存放订单内部的数据表结构
syntax = "proto3";
package ticket.service.sales.v1;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option go_package = "_type";
option (gogoproto.goproto_getters_all) = false;
option (gogoproto.goproto_stringer_all) = false;
option (gogoproto.stringer_all) = true;
//OrderSKU 订单包含的sku信息
message OrderSKU {
int64 order_id = 1 [(gogoproto.jsontag) = "order_id", (gogoproto.customname) = "OrderID"];
int64 sku_id = 2 [(gogoproto.jsontag) = "sku_id", (gogoproto.customname) = "SKUID"];
int64 count = 3 [(gogoproto.jsontag) = "count"];
int64 origin_price = 4 [(gogoproto.jsontag) = "origin_price"];
int64 price = 5 [(gogoproto.jsontag) = "price"];
repeated int64 seat_ids = 6 [(gogoproto.jsontag) = "seat_ids", (gogoproto.customname) = "SeatIDs"];
int32 ticket_type = 7 [(gogoproto.jsontag) = "ticket_type", (gogoproto.casttype) = "int16"];
OrderSKUDiscounts discounts = 8 [(gogoproto.jsontag) = "discounts"];
int64 ctime = 9 [(gogoproto.jsontag) = "-", (gogoproto.customname) = "CTime", (gogoproto.casttype) = "go-common/library/time.Time"];
int64 mtime = 10 [(gogoproto.jsontag) = "-", (gogoproto.customname) = "MTime", (gogoproto.casttype) = "go-common/library/time.Time"];
}
//OrderPayCharge 订单支付信息
message OrderPayCharge {
int64 order_id = 1 [(gogoproto.jsontag) = "order_id", (gogoproto.customname) = "OrderID"];
string charge_id = 2 [(gogoproto.jsontag) = "charge_id", (gogoproto.customname) = "ChargeID"];
int32 channel = 3 [(gogoproto.jsontag) = "channel", (gogoproto.casttype) = "int16"];
int32 paid = 4 [(gogoproto.jsontag) = "paid", (gogoproto.casttype) = "int16"];
int32 refunded = 5 [(gogoproto.jsontag) = "refunded", (gogoproto.casttype) = "int16"];
int64 pay_time = 6 [(gogoproto.jsontag) = "-"];
int64 ctime = 7 [(gogoproto.jsontag) = "-", (gogoproto.customname) = "CTime", (gogoproto.casttype) = "go-common/library/time.Time"];
int64 mtime = 8 [(gogoproto.jsontag) = "-", (gogoproto.customname) = "MTime", (gogoproto.casttype) = "go-common/library/time.Time"];
}
//OrderItemInfo 订单中的商品快照
message OrderItemInfo {
string name = 1 [(gogoproto.jsontag) = "name"];
string img = 2 [(gogoproto.jsontag) = "img"];
int64 screen_id = 3 [(gogoproto.jsontag) = "screen_id", (gogoproto.customname) = "ScreenID"];
string screen_name = 4 [(gogoproto.jsontag) = "screen_name"];
int32 screen_type = 5 [(gogoproto.jsontag) = "screen_type", (gogoproto.casttype) = "int16"];
int32 deliver_type = 6 [(gogoproto.jsontag) = "deliver_type", (gogoproto.casttype) = "int16"];
int64 express_fee = 7 [(gogoproto.jsontag) = "express_fee"];
int32 vip_express_free = 8 [(gogoproto.jsontag) = "express_free_flag", (gogoproto.casttype) = "int16", (gogoproto.customname) = "VIPExpressFree"];
int64 ver_id = 9 [(gogoproto.jsontag) = "project_ver_id", (gogoproto.customname) = "VerID"];
}
//OrderSKUDiscounts 订单分摊到sku上的折扣信息
message OrderSKUDiscounts {
map<int32, int64> platform = 1 [(gogoproto.jsontag) = "1"];
map<int32, int64> merchant = 2 [(gogoproto.jsontag) = "2"];
}
//OrderBuyer 订单购买人快照
message OrderBuyer {
int64 id = 1 [(gogoproto.jsontag) = "id", (gogoproto.customname) = "ID"];
string name = 2 [(gogoproto.jsontag) = "name"];
string tel = 3 [(gogoproto.jsontag) = "tel"];
string personal_id = 4 [(gogoproto.jsontag) = "personal_id", (gogoproto.customname) = "PersonalID"];
}
//OrderDeliver 订单配送信息快照
message OrderDeliver {
int64 addr_id = 1 [(gogoproto.jsontag) = "addr_id", (gogoproto.customname) = "AddrID"];
string name = 2 [(gogoproto.jsontag) = "name"];
string tel = 3 [(gogoproto.jsontag) = "tel"];
string addr = 4 [(gogoproto.jsontag) = "addr"];
}
//OrderExtra 订单额外信息
message OrderExtra {
int64 auto_recv_time = 1 [(gogoproto.jsontag) = "AutoRecvTime"];
int64 delay_recv_times = 2 [(gogoproto.jsontag) = "DelayRecvTimes"];
}
//OrderCoupon 订单优惠券信息
message OrderCoupon {
string code = 1 [(gogoproto.jsontag) = "code"];
string name = 2 [(gogoproto.jsontag) = "name"];
int64 money = 3 [(gogoproto.jsontag) = "money"];
}

View File

@@ -0,0 +1,69 @@
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["client.go"],
embed = [":v1_go_proto"],
importpath = "go-common/app/service/openplatform/ticket-sales/api/grpc/v1",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/openplatform/ticket-sales/api/grpc/type:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/time: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",
],
)
proto_library(
name = "v1_proto",
srcs = [
"order.proto",
"pay.proto",
"promotion.proto",
"promotion_mis.proto",
"ticket.proto",
],
tags = ["manual"],
deps = [
"//app/service/openplatform/ticket-sales/api/grpc/type:_type_proto",
"@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-sales/api/grpc/v1",
proto = ":v1_proto",
tags = ["manual"],
deps = [
"//app/service/openplatform/ticket-sales/api/grpc/type:_type_go_proto",
"//library/time:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,35 @@
package v1
import (
"context"
"fmt"
"go-common/library/net/rpc/warden"
"google.golang.org/grpc"
)
// AppID 本服务的discoveryID
const AppID = "ticket.service.sales"
// TradeSalesClient .
type TradeSalesClient interface {
TradeClient
PromotionClient
}
var _ TradeSalesClient = client{}
type client struct {
TradeClient
PromotionClient
}
// NewClient include TradeClient adn SalesClient
func NewClient(cfg *warden.ClientConfig, opts ...grpc.DialOption) (TradeSalesClient, error) {
cc, err := warden.NewClient(cfg, opts...).Dial(context.Background(), fmt.Sprintf("discovery://default/%s", AppID))
if err != nil {
return nil, err
}
return client{TradeClient: NewTradeClient(cc), PromotionClient: NewPromotionClient(cc)}, nil
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,187 @@
//存放api使用的模型
syntax = "proto3";
package ticket.service.sales.v1;
import "app/service/openplatform/ticket-sales/api/grpc/type/order.proto";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option go_package = "v1";
option (gogoproto.goproto_getters_all) = false;
option (gogoproto.goproto_stringer_all) = false;
option (gogoproto.stringer_all) = true;
//ListOrdersRequest 用户订单列表请求参数
message ListOrdersRequest {
string uid = 1 [(gogoproto.customname) = "UID"];
repeated int64 order_id = 2 [(gogoproto.customname) = "OrderID"];
int64 item_id = 3 [(gogoproto.customname) = "ItemID"];
repeated int32 status = 4 [(gogoproto.casttype) = "int16"];
repeated int32 sub_status = 5 [(gogoproto.casttype) = "int16"];
repeated int32 refund_status = 6 [(gogoproto.casttype) = "int16"];
int64 limit = 7;
int64 offset = 8;
string order_by = 9;
}
//ListOrdersResponse 用户订单列表返回
message ListOrdersResponse {
repeated OrderResponse list = 1;
int64 count = 2;
int64 next_offset = 3;
}
//OrderResponse 单个订单响应
message OrderResponse {
int64 order_id = 1 [(gogoproto.jsontag) = "order_id", (gogoproto.customname) = "OrderID"];
string uid = 2 [(gogoproto.jsontag) = "uid", (gogoproto.customname) = "UID"];
int32 order_type = 3 [(gogoproto.jsontag) = "order_type", (gogoproto.casttype) = "int16"];
int64 item_id = 4 [(gogoproto.jsontag) = "item_id", (gogoproto.customname) = "ItemID"];
OrderItemInfo item_info = 5 [(gogoproto.jsontag) = "item_info"];
int64 count = 6 [(gogoproto.jsontag) = "count"];
int64 total_money = 7 [(gogoproto.jsontag) = "total_money"];
int64 pay_money = 8 [(gogoproto.jsontag) = "pay_money"];
int64 express_fee = 9 [(gogoproto.jsontag) = "express_fee"];
int32 status = 10 [(gogoproto.jsontag) = "status", (gogoproto.casttype) = "int16"];
int32 sub_status = 11 [(gogoproto.jsontag) = "sub_status", (gogoproto.casttype) = "int16"];
int32 refund_status = 12 [(gogoproto.jsontag) = "refund_status", (gogoproto.casttype) = "int16"];
string source = 13 [(gogoproto.jsontag) = "source"];
int32 is_deleted = 14 [(gogoproto.jsontag) = "is_deleted", (gogoproto.casttype) = "int16"];
repeated OrderSKU skus = 15 [(gogoproto.jsontag) = "order_sku", (gogoproto.customname) = "SKUs"];
OrderResponseMore detail = 16 [(gogoproto.jsontag) = "detail"];
OrderPayCharge pay_charge = 17 [(gogoproto.jsontag) = "pay_charge"];
int64 ctime = 18 [(gogoproto.jsontag) = "ctime", (gogoproto.customname) = "CTime", (gogoproto.casttype) = "go-common/library/time.Time"];
int64 mtime = 19 [(gogoproto.jsontag) = "mtime", (gogoproto.customname) = "MTime", (gogoproto.casttype) = "go-common/library/time.Time"];
}
//OrderResponseMore 更详细的订单响应信息
message OrderResponseMore {
OrderCoupon coupon = 1 [(gogoproto.jsontag) = "coupon"];
repeated OrderBuyer buyers = 2 [(gogoproto.jsontag) = "buyers"];
OrderExtra extra = 3 [(gogoproto.jsontag) = "extra"];
OrderDeliver deliver = 4 [(gogoproto.jsontag) = "deliver"];
string remark = 5 [(gogoproto.jsontag) = "remark"];
int32 device_type = 6 [(gogoproto.jsontag) = "device_type", (gogoproto.casttype) = "int16"];
uint32 ip = 7 [(gogoproto.jsontag) = "ip", (gogoproto.customname) = "IP"];
string msource = 8 [(gogoproto.jsontag) = "msource", (gogoproto.customname) = "MSource"];
string express_co = 9 [(gogoproto.jsontag) = "-", (gogoproto.customname) = "ExpressCO"];
string express_no = 10 [(gogoproto.jsontag) = "-", (gogoproto.customname) = "ExpressNO"];
int32 express_type = 11 [(gogoproto.jsontag) = "-", (gogoproto.casttype) = "int16"];
}
//CreateOrderSKU 创建订单的sku请求
message CreateOrderSKU {
int64 sku_id = 1 [(gogoproto.customname) = "SKUID"];
int64 count = 2;
}
//CreateOrderRequest 单个订单创建请求
message CreateOrderRequest {
int64 project_id = 1 [(gogoproto.customname) = "ProjectID"];
int64 screen_id = 2 [(gogoproto.customname) = "ScreenID"];
repeated CreateOrderSKU skus = 3 [(gogoproto.customname) = "SKUs"];
int64 uid = 4 [(gogoproto.customname) = "UID"];
int64 pay_money = 5;
int32 order_type = 6 [(gogoproto.casttype) = "int16"];
int64 ts = 7 [(gogoproto.customname) = "TS"];
int64 promo_id = 8 [(gogoproto.customname) = "PromoID"];
int64 promo_group_id = 9 [(gogoproto.customname) = "PromoGroupID"];
repeated .ticket.service.sales.v1.OrderBuyer buyers = 10;
.ticket.service.sales.v1.OrderDeliver deliver_detail = 11;
repeated uint64 seats = 12;
repeated string coupons = 13;
int64 lock_id = 14 [(gogoproto.customname) = "LockID"];
string source = 15;
int32 is_deleted = 16 [(gogoproto.casttype) = "int16"];
int32 device_type = 17 [(gogoproto.casttype) = "int16"];
}
//CreateOrdersRequest 创建订单请求
message CreateOrdersRequest {
repeated CreateOrderRequest orders = 1;
}
//CreateOrderResult 创建订单结果
message CreateOrderResult {
int64 order_id = 1 [(gogoproto.customname) = "OrderID"];
int32 code = 2 [(gogoproto.casttype) = "int"];
string message = 3;
}
//CreateOrdersResponse 创建订单响应
message CreateOrdersResponse {
uint32 count = 1;
repeated CreateOrderResult result = 2;
}
//UpBuyerRequest 更新购买人信息
message UpBuyerRequest{
int64 order_id = 1 [(gogoproto.customname) = "OrderID"];
.ticket.service.sales.v1.OrderBuyer buyers = 2;
}
//UpDeliveryRequest 更新配送信息
message UpDeliveryRequest{
int64 order_id = 1 [(gogoproto.customname) = "OrderID"];
OrderDeliver deliver_detail = 2 [(gogoproto.jsontag) = "deliver_detail"];
}
//UpDetailResponse 更新返回数据
message UpDetailResponse{
int64 order_id = 1 [(gogoproto.customname) = "OrderID"];
int32 is_update= 2 [(gogoproto.customname) = "IsUpdate",(gogoproto.jsontag) = "update",(gogoproto.casttype) = "int16"];
}
//OrderLog 订单日志
message OrderLog {
int64 id = 1 [(gogoproto.customname) = "ID"];
string uid = 2 [(gogoproto.customname) = "UID"];
int64 order_id = 3 [(gogoproto.customname) = "OID"];
string ip = 4 [(gogoproto.customname) = "IP"];
string op_data = 5 [(gogoproto.customname) = "OpData"];
string remark = 6 [(gogoproto.customname) = "Remark"];
string op_object = 7 [(gogoproto.customname) = "OpObject"];
string op_name = 8 [(gogoproto.customname) = "OpName"];
int64 ctime = 9 [(gogoproto.customname) = "CTime", (gogoproto.casttype) = "go-common/library/time.Time"];
int64 mtime = 10 [(gogoproto.customname) = "MTime", (gogoproto.casttype) = "go-common/library/time.Time"];
}
//ListOrdersLogRequest 订单日志
message ListOrderLogRequest {
int64 order_id = 1 [(gogoproto.customname) = "OrderID"];
int64 limit = 2;
int64 offset = 3;
string order_by = 4;
}
//ListOrderLogResponse 订单日志相应
message ListOrderLogResponse {
repeated OrderLog list = 1;
int64 cnt = 2;
}
//AddOrderLogRequest 订单日志插入
message AddOrderLogRequest {
OrderLog data = 1;
}
//AddOrderLogResponse 订单日志插入相应
message AddOrderLogResponse {
int64 id = 1;
}
service Trade {
rpc ListOrders (ListOrdersRequest) returns (ListOrdersResponse);
rpc CreateOrders (CreateOrdersRequest) returns (CreateOrdersResponse);
rpc UpdateBuyer (UpBuyerRequest) returns (UpDetailResponse);
rpc UpdateDelivery (UpDeliveryRequest) returns (UpDetailResponse);
rpc ListOrderLogs (ListOrderLogRequest) returns (ListOrderLogResponse);
rpc AddOrderLogs (AddOrderLogRequest) returns (AddOrderLogResponse);
}

View File

@@ -0,0 +1,557 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: app/service/openplatform/ticket-sales/api/grpc/v1/pay.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 strings "strings"
import reflect "reflect"
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
type PayNotifyRequest struct {
MsgID string `protobuf:"bytes,1,opt,name=msgID,proto3" json:"msgID,omitempty"`
MsgContent string `protobuf:"bytes,2,opt,name=msgContent,proto3" json:"msgContent,omitempty"`
TestMode bool `protobuf:"varint,3,opt,name=testMode,proto3" json:"testMode,omitempty"`
}
func (m *PayNotifyRequest) Reset() { *m = PayNotifyRequest{} }
func (*PayNotifyRequest) ProtoMessage() {}
func (*PayNotifyRequest) Descriptor() ([]byte, []int) { return fileDescriptorPay, []int{0} }
type PayNotifyResponse struct {
}
func (m *PayNotifyResponse) Reset() { *m = PayNotifyResponse{} }
func (*PayNotifyResponse) ProtoMessage() {}
func (*PayNotifyResponse) Descriptor() ([]byte, []int) { return fileDescriptorPay, []int{1} }
func init() {
proto.RegisterType((*PayNotifyRequest)(nil), "ticket.service.sales.v1.PayNotifyRequest")
proto.RegisterType((*PayNotifyResponse)(nil), "ticket.service.sales.v1.PayNotifyResponse")
}
// 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 Pay service
type PayClient interface {
PayNotify(ctx context.Context, in *PayNotifyRequest, opts ...grpc.CallOption) (*PayNotifyResponse, error)
}
type payClient struct {
cc *grpc.ClientConn
}
func NewPayClient(cc *grpc.ClientConn) PayClient {
return &payClient{cc}
}
func (c *payClient) PayNotify(ctx context.Context, in *PayNotifyRequest, opts ...grpc.CallOption) (*PayNotifyResponse, error) {
out := new(PayNotifyResponse)
err := grpc.Invoke(ctx, "/ticket.service.sales.v1.Pay/PayNotify", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Pay service
type PayServer interface {
PayNotify(context.Context, *PayNotifyRequest) (*PayNotifyResponse, error)
}
func RegisterPayServer(s *grpc.Server, srv PayServer) {
s.RegisterService(&_Pay_serviceDesc, srv)
}
func _Pay_PayNotify_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(PayNotifyRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(PayServer).PayNotify(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/ticket.service.sales.v1.Pay/PayNotify",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(PayServer).PayNotify(ctx, req.(*PayNotifyRequest))
}
return interceptor(ctx, in, info, handler)
}
var _Pay_serviceDesc = grpc.ServiceDesc{
ServiceName: "ticket.service.sales.v1.Pay",
HandlerType: (*PayServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "PayNotify",
Handler: _Pay_PayNotify_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "app/service/openplatform/ticket-sales/api/grpc/v1/pay.proto",
}
func (m *PayNotifyRequest) 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 *PayNotifyRequest) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.MsgID) > 0 {
dAtA[i] = 0xa
i++
i = encodeVarintPay(dAtA, i, uint64(len(m.MsgID)))
i += copy(dAtA[i:], m.MsgID)
}
if len(m.MsgContent) > 0 {
dAtA[i] = 0x12
i++
i = encodeVarintPay(dAtA, i, uint64(len(m.MsgContent)))
i += copy(dAtA[i:], m.MsgContent)
}
if m.TestMode {
dAtA[i] = 0x18
i++
if m.TestMode {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i++
}
return i, nil
}
func (m *PayNotifyResponse) 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 *PayNotifyResponse) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
return i, nil
}
func encodeVarintPay(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 *PayNotifyRequest) Size() (n int) {
var l int
_ = l
l = len(m.MsgID)
if l > 0 {
n += 1 + l + sovPay(uint64(l))
}
l = len(m.MsgContent)
if l > 0 {
n += 1 + l + sovPay(uint64(l))
}
if m.TestMode {
n += 2
}
return n
}
func (m *PayNotifyResponse) Size() (n int) {
var l int
_ = l
return n
}
func sovPay(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
func sozPay(x uint64) (n int) {
return sovPay(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (this *PayNotifyRequest) String() string {
if this == nil {
return "nil"
}
s := strings.Join([]string{`&PayNotifyRequest{`,
`MsgID:` + fmt.Sprintf("%v", this.MsgID) + `,`,
`MsgContent:` + fmt.Sprintf("%v", this.MsgContent) + `,`,
`TestMode:` + fmt.Sprintf("%v", this.TestMode) + `,`,
`}`,
}, "")
return s
}
func (this *PayNotifyResponse) String() string {
if this == nil {
return "nil"
}
s := strings.Join([]string{`&PayNotifyResponse{`,
`}`,
}, "")
return s
}
func valueToStringPay(v interface{}) string {
rv := reflect.ValueOf(v)
if rv.IsNil() {
return "nil"
}
pv := reflect.Indirect(rv).Interface()
return fmt.Sprintf("*%v", pv)
}
func (m *PayNotifyRequest) 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 ErrIntOverflowPay
}
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: PayNotifyRequest: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: PayNotifyRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field MsgID", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPay
}
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 ErrInvalidLengthPay
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.MsgID = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field MsgContent", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPay
}
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 ErrInvalidLengthPay
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.MsgContent = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field TestMode", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPay
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.TestMode = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := skipPay(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthPay
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *PayNotifyResponse) 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 ErrIntOverflowPay
}
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: PayNotifyResponse: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: PayNotifyResponse: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
default:
iNdEx = preIndex
skippy, err := skipPay(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthPay
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipPay(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, ErrIntOverflowPay
}
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, ErrIntOverflowPay
}
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, ErrIntOverflowPay
}
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, ErrInvalidLengthPay
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowPay
}
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 := skipPay(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 (
ErrInvalidLengthPay = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowPay = fmt.Errorf("proto: integer overflow")
)
func init() {
proto.RegisterFile("app/service/openplatform/ticket-sales/api/grpc/v1/pay.proto", fileDescriptorPay)
}
var fileDescriptorPay = []byte{
// 287 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x90, 0x31, 0x4f, 0xc3, 0x30,
0x10, 0x85, 0xeb, 0x56, 0x45, 0xad, 0x27, 0x30, 0x03, 0x55, 0x84, 0xdc, 0xaa, 0x53, 0x41, 0xaa,
0xad, 0xc0, 0xc8, 0x56, 0x58, 0x18, 0x8a, 0xaa, 0x8c, 0x6c, 0x4e, 0x70, 0x8c, 0x45, 0x93, 0x33,
0xb1, 0x13, 0x29, 0x1b, 0x3f, 0xaf, 0x23, 0x23, 0x13, 0xa2, 0xf9, 0x25, 0xa8, 0x0e, 0xaa, 0x2a,
0x24, 0x24, 0x36, 0xbf, 0xe7, 0xef, 0xee, 0xdd, 0x1d, 0xbe, 0x11, 0xc6, 0x70, 0x2b, 0x8b, 0x4a,
0x27, 0x92, 0x83, 0x91, 0xb9, 0x59, 0x0b, 0x97, 0x42, 0x91, 0x71, 0xa7, 0x93, 0x17, 0xe9, 0xe6,
0x56, 0xac, 0xa5, 0xe5, 0xc2, 0x68, 0xae, 0x0a, 0x93, 0xf0, 0x2a, 0xe4, 0x46, 0xd4, 0xcc, 0x14,
0xe0, 0x80, 0x9c, 0xb5, 0x0c, 0xfb, 0xa9, 0x67, 0x9e, 0x65, 0x55, 0x18, 0xcc, 0x95, 0x76, 0xcf,
0x65, 0xcc, 0x12, 0xc8, 0xb8, 0x02, 0x05, 0xdc, 0xf3, 0x71, 0x99, 0x7a, 0xe5, 0x85, 0x7f, 0xb5,
0x7d, 0xa6, 0x80, 0x8f, 0x57, 0xa2, 0x7e, 0x00, 0xa7, 0xd3, 0x3a, 0x92, 0xaf, 0xa5, 0xb4, 0x8e,
0x8c, 0x71, 0x3f, 0xb3, 0xea, 0xfe, 0x6e, 0x84, 0x26, 0x68, 0x36, 0x5c, 0x0c, 0x9b, 0xcf, 0x71,
0x7f, 0xb9, 0x33, 0xa2, 0xd6, 0x27, 0x14, 0xe3, 0xcc, 0xaa, 0x5b, 0xc8, 0x9d, 0xcc, 0xdd, 0xa8,
0xbb, 0xa3, 0xa2, 0x03, 0x87, 0x04, 0x78, 0xe0, 0xa4, 0x75, 0x4b, 0x78, 0x92, 0xa3, 0xde, 0x04,
0xcd, 0x06, 0xd1, 0x5e, 0x4f, 0x4f, 0xf1, 0xc9, 0x41, 0xa0, 0x35, 0x90, 0x5b, 0x79, 0xa5, 0x71,
0x6f, 0x25, 0x6a, 0x12, 0xe3, 0xe1, 0xfe, 0x8f, 0x5c, 0xb0, 0x3f, 0x56, 0x64, 0xbf, 0x07, 0x0e,
0x2e, 0xff, 0x83, 0xb6, 0x51, 0x8b, 0xf3, 0xcd, 0x96, 0x76, 0x3e, 0xb6, 0xb4, 0xf3, 0xd6, 0x50,
0xb4, 0x69, 0x28, 0x7a, 0x6f, 0x28, 0xfa, 0x6a, 0x28, 0x7a, 0xec, 0x56, 0x61, 0x7c, 0xe4, 0xaf,
0x72, 0xfd, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x7d, 0x78, 0x04, 0x37, 0x9c, 0x01, 0x00, 0x00,
}

View File

@@ -0,0 +1,25 @@
// 支付相关接口
syntax = "proto3";
package ticket.service.sales.v1;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option go_package = "v1";
option (gogoproto.goproto_getters_all) = false;
option (gogoproto.goproto_stringer_all) = false;
option (gogoproto.stringer_all) = true;
service Pay {
rpc PayNotify (PayNotifyRequest) returns (PayNotifyResponse);
}
message PayNotifyRequest {
string msgID = 1 [(gogoproto.customname) = "MsgID"];
string msgContent = 2;
bool testMode = 3;
}
message PayNotifyResponse {
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,180 @@
syntax = "proto3";
package ticket.service.sales.v1;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option go_package = "v1";
option (gogoproto.goproto_getters_all) = false;
option (gogoproto.goproto_stringer_all) = false;
option (gogoproto.stringer_all) = true;
message Promo{
int64 promo_id = 1 [(gogoproto.jsontag) = "promo_id", (gogoproto.customname)= "PromoID"];
int32 type = 2 [(gogoproto.jsontag) = "type", (gogoproto.casttype) = "int16"];
int64 item_id = 3 [(gogoproto.jsontag) = "item_id", (gogoproto.customname)= "ItemID"];
int64 sku_id = 4 [(gogoproto.jsontag) = "sku_id", (gogoproto.customname)= "SKUID"];
int64 extra = 5 [(gogoproto.jsontag) = "extra"];
int64 expire_sec = 6 [(gogoproto.jsontag) = "expire_sec"];
int64 sku_count = 7 [(gogoproto.jsontag) = "sku_count", (gogoproto.customname)= "SKUCount"];
int64 amount = 8 [(gogoproto.jsontag) = "amount"];
int64 buyer_count = 9 [(gogoproto.jsontag) = "buyer_count"];
int64 begin_time = 10 [(gogoproto.jsontag) = "begin_time"];
int64 end_time = 11 [(gogoproto.jsontag) = "end_time"];
int32 status = 12 [(gogoproto.jsontag) = "status", (gogoproto.casttype) = "int16"];
int64 ctime = 13 [(gogoproto.jsontag) = "ctime"];
int64 mtime = 14 [(gogoproto.jsontag) = "mtime"];
int64 priv_sku_id = 15 [(gogoproto.jsontag) = "priv_sku_id", (gogoproto.customname)= "PrivSKUID"];
string usable_coupons = 16 [(gogoproto.jsontag) = "usable_coupons"];
}
message PromoGroup {
int64 promo_id = 1 [(gogoproto.jsontag) = "promo_id", (gogoproto.customname)= "PromoID"];
int64 group_id = 2 [(gogoproto.jsontag) = "group_id", (gogoproto.customname)= "GroupID"];
int64 uid = 3 [(gogoproto.jsontag) = "uid", (gogoproto.customname)= "UID"];
int64 order_count = 4 [(gogoproto.jsontag) = "order_count"];
int32 status =5 [(gogoproto.jsontag) = "status", (gogoproto.casttype) = "int16"];
int64 expire_at = 6 [(gogoproto.jsontag) = "expire_at"];
int64 ctime = 7 [(gogoproto.jsontag) = "ctime"];
int64 mtime = 8 [(gogoproto.jsontag) = "mtime"];
}
message PromoOrder {
int64 promo_id = 1 [(gogoproto.jsontag) = "promo_id", (gogoproto.customname)= "PromoID"];
int64 group_id = 2 [(gogoproto.jsontag) = "group_id", (gogoproto.customname)= "GroupID"];
int64 order_id = 3 [(gogoproto.jsontag) = "order_id", (gogoproto.customname)= "OrderID"];
int32 is_master = 4 [(gogoproto.jsontag) = "is_master", (gogoproto.casttype) = "int16"];
int64 uid = 5 [(gogoproto.jsontag) = "uid", (gogoproto.customname)= "UID"];
int32 status = 6 [(gogoproto.jsontag) = "status", (gogoproto.casttype) = "int16"];
int64 ctime = 7 [(gogoproto.jsontag) = "ctime"];
int64 mtime = 8 [(gogoproto.jsontag) = "mtime"];
int64 sku_id = 9 [(gogoproto.jsontag) = "sku_id", (gogoproto.customname)= "SKUID"];
}
message CreatePromoRequest{
int64 promo_id = 1 [(gogoproto.jsontag) = "promo_id",(gogoproto.moretags) = "form:\"promo_id\" validate:\"required\"", (gogoproto.customname)= "PromoID"];
int32 type = 2 [(gogoproto.jsontag) = "type",(gogoproto.moretags) = "form:\"type\"", (gogoproto.casttype) = "int16"];
int64 item_id = 3 [(gogoproto.jsontag) = "item_id",(gogoproto.moretags) = "form:\"item_id\" validate:\"required\"", (gogoproto.customname)= "ItemID"];
int64 sku_id = 4 [(gogoproto.jsontag) = "sku_id",(gogoproto.moretags) = "form:\"sku_id\" validate:\"required\"", (gogoproto.customname)= "SKUID"];
int64 extra = 5 [(gogoproto.jsontag) = "extra",(gogoproto.moretags) = "form:\"extra\" validate:\"required\""];
int64 expire_sec = 6 [(gogoproto.jsontag) = "expire_sec",(gogoproto.moretags) = "form:\"expire_sec\" validate:\"required\""];
int64 sku_count = 7 [(gogoproto.jsontag) = "sku_count",(gogoproto.moretags) = "form:\"sku_count\" validate:\"required\"", (gogoproto.customname)= "SKUCount"];
int64 amount = 8 [(gogoproto.jsontag) = "amount",(gogoproto.moretags) = "form:\"amount\" validate:\"required\""];
int64 buyer_count = 9 [(gogoproto.jsontag) = "buyer_count",(gogoproto.moretags) = "form:\"buyer_count\" validate:\"required\""];
int64 begin_time = 10 [(gogoproto.jsontag) = "begin_time",(gogoproto.moretags) = "form:\"begin_time\" validate:\"required\""];
int64 end_time = 11 [(gogoproto.jsontag) = "end_time",(gogoproto.moretags) = "form:\"end_time\" validate:\"required\""];
int64 priv_sku_id = 12 [(gogoproto.jsontag) = "priv_sku_id",(gogoproto.moretags) = "form:\"priv_sku_id\"", (gogoproto.customname)= "PrivSKUID"];
string usable_coupons = 13 [(gogoproto.jsontag) = "usable_coupons",(gogoproto.moretags) = "form:\"usable_coupons\""];
}
message OperatePromoRequest{
int64 promo_id = 1 [(gogoproto.jsontag) = "promo_id",(gogoproto.moretags) = "form:\"promo_id\" validate:\"required\"", (gogoproto.customname)= "PromoID"];
int32 operate_type = 2 [(gogoproto.jsontag) = "operate_type",(gogoproto.moretags) = "form:\"operate_type\" validate:\"required\"", (gogoproto.casttype) = "int16"];
}
message CheckCreatePromoOrderRequest{
int64 uid = 1 [(gogoproto.jsontag) = "uid",(gogoproto.moretags) = "form:\"uid\" validate:\"required\"", (gogoproto.customname)= "UID"];
int64 sku_id = 2 [(gogoproto.jsontag) = "sku_id",(gogoproto.moretags) = "form:\"sku_id\" validate:\"required\"", (gogoproto.customname)= "SKUID"];
int64 promo_id = 3 [(gogoproto.jsontag) = "promo_id",(gogoproto.moretags) = "form:\"promo_id\" validate:\"required\"", (gogoproto.customname)= "PromoID"];
int64 group_id = 4 [(gogoproto.jsontag) = "group_id",(gogoproto.moretags) = "form:\"group_id\"", (gogoproto.customname)= "GroupID"];
}
message RepeatOrder{
int64 order_id = 1 [(gogoproto.jsontag) = "order_id", (gogoproto.customname)= "OrderID"];
int32 is_master = 2 [(gogoproto.jsontag) = "is_master", (gogoproto.casttype) = "int16"];
int32 status = 3 [(gogoproto.jsontag) = "status", (gogoproto.casttype) = "int16"];
}
message CheckCreatePromoOrderResponse{
int64 amount = 1 [(gogoproto.jsontag) = "amount"];
int64 sku_id = 2 [(gogoproto.jsontag) = "sku_id", (gogoproto.customname)= "SKUID"];
int64 priv_sku_id = 3 [(gogoproto.jsontag) = "priv_sku_id", (gogoproto.customname)= "PrivSKUID"];
string usable_coupons = 4 [(gogoproto.jsontag) = "usable_coupons"];
RepeatOrder repeat_order = 5 [(gogoproto.jsontag) = "repeat_order"];
}
message CreatePromoOrderRequest{
int64 promo_id = 1 [(gogoproto.jsontag) = "promo_id",(gogoproto.moretags) = "form:\"promo_id\" validate:\"required\"", (gogoproto.customname)= "PromoID"];
int64 order_id = 2 [(gogoproto.jsontag) = "order_id",(gogoproto.moretags) = "form:\"order_id\" validate:\"required\"", (gogoproto.customname)= "OrderID"];
int64 group_id = 3 [(gogoproto.jsontag) = "group_id",(gogoproto.moretags) = "form:\"group_id\"", (gogoproto.customname)= "GroupID"];
int64 uid = 4 [(gogoproto.jsontag) = "uid",(gogoproto.moretags) = "form:\"uid\" validate:\"required\"", (gogoproto.customname)= "UID"];
int64 promo_sku_id = 5 [(gogoproto.jsontag) = "promo_sku_id",(gogoproto.moretags) = "form:\"promo_sku_id\" validate:\"required\"", (gogoproto.customname)= "PromoSKUID"];
int64 ctime = 6 [(gogoproto.jsontag) = "ctime",(gogoproto.moretags) = "form:\"ctime\" validate:\"required\""];
int64 pay_money = 7 [(gogoproto.jsontag) = "pay_money",(gogoproto.moretags) = "form:\"pay_money\""];
}
message CommonResponse {
int64 res = 1 [(gogoproto.jsontag) = "res"];
}
message PromoID{
int64 promo_id = 1 [(gogoproto.jsontag) = "promo_id",(gogoproto.moretags) = "form:\"promo_id\" validate:\"required\"", (gogoproto.customname)= "PromoID"];
}
message OrderID{
int64 order_id = 1 [(gogoproto.jsontag) = "order_id",(gogoproto.moretags) = "form:\"order_id\" validate:\"required\"", (gogoproto.customname)= "OrderID"];
}
message GroupID{
int64 group_id = 1 [(gogoproto.jsontag) = "group_id",(gogoproto.moretags) = "form:\"group_id\" validate:\"required\"", (gogoproto.customname)= "GroupID"];
}
message GetPromoGroupInfoRequest{
int64 order_id = 1 [(gogoproto.jsontag) = "order_id",(gogoproto.moretags) = "form:\"order_id\" validate:\"required\"", (gogoproto.customname)= "OrderID"];
}
message GetPromoGroupInfoResponse {
int64 promo_id = 1 [(gogoproto.jsontag) = "promo_id", (gogoproto.customname)= "PromoID"];
int64 sku_count = 2 [(gogoproto.jsontag) = "sku_count", (gogoproto.customname)= "SKUCount"];
int64 amount = 3 [(gogoproto.jsontag) = "amount"];
int64 group_id = 4 [(gogoproto.jsontag) = "group_id", (gogoproto.customname)= "GroupID"];
int64 order_count = 5 [(gogoproto.jsontag) = "order_count"];
int64 expire_at = 6 [(gogoproto.jsontag) = "expire_at"];
int32 status = 7 [(gogoproto.jsontag) = "status", (gogoproto.casttype) = "int16"];
int64 ctime = 8 [(gogoproto.jsontag) = "ctime"];
}
message CheckIssueResponse {
int64 promo_id = 1 [(gogoproto.jsontag) = "promo_id", (gogoproto.customname)= "PromoID"];
int64 group_id = 2 [(gogoproto.jsontag) = "group_id", (gogoproto.customname)= "GroupID"];
repeated OrderID paid_orders = 3 [(gogoproto.jsontag) = "paid_orders"];
}
message FinishIssueRequest {
int64 promo_id = 1 [(gogoproto.jsontag) = "promo_id",(gogoproto.moretags) = "form:\"promo_id\" validate:\"required\"", (gogoproto.customname)= "PromoID"];
int64 group_id = 2 [(gogoproto.jsontag) = "group_id",(gogoproto.moretags) = "form:\"group_id\" validate:\"required\"", (gogoproto.customname)= "GroupID"];
}
message GroupFailedRequest {
int64 group_id = 1 [(gogoproto.jsontag) = "group_id",(gogoproto.moretags) = "form:\"group_id\" validate:\"required\"", (gogoproto.customname)= "GroupID"];
int64 cancel_num = 2 [(gogoproto.jsontag) = "cancel_num",(gogoproto.moretags) = "form:\"cancel_num\" validate:\"required\""];
}
message EditPromoRequest {
int64 promo_id = 1 [(gogoproto.jsontag) = "promo_id",(gogoproto.moretags) = "form:\"promo_id\" validate:\"required\"", (gogoproto.customname)= "PromoID"];
int64 amount = 2 [(gogoproto.jsontag) = "amount",(gogoproto.moretags) = "form:\"amount\""];
int64 expire_sec = 3 [(gogoproto.jsontag) = "expire_sec",(gogoproto.moretags) = "form:\"expire_sec\""];
int64 begin_time = 4 [(gogoproto.jsontag) = "begin_time",(gogoproto.moretags) = "form:\"begin_time\""];
int64 end_time = 5 [(gogoproto.jsontag) = "end_time",(gogoproto.moretags) = "form:\"end_time\""];
int64 priv_sku_id = 6 [(gogoproto.jsontag) = "priv_sku_id",(gogoproto.moretags) = "form:\"priv_sku_id\"", (gogoproto.customname)= "PrivSKUID"];
string usable_coupons = 7 [(gogoproto.jsontag) = "usable_coupons",(gogoproto.moretags) = "form:\"usable_coupons\""];
int64 sku_count = 8 [(gogoproto.jsontag) = "sku_count",(gogoproto.moretags) = "form:\"sku_count\"", (gogoproto.customname)= "SKUCount"];
}
service Promotion{
rpc CreatePromo(CreatePromoRequest) returns(PromoID){};
rpc GetPromo(PromoID) returns(Promo){};
rpc OperatePromo(OperatePromoRequest) returns(CommonResponse){};
rpc EditPromo(EditPromoRequest) returns(CommonResponse){};
rpc GetPromoGroupInfo(GetPromoGroupInfoRequest) returns(GetPromoGroupInfoResponse){};
rpc GroupFailed(GroupFailedRequest) returns(GroupID){};
rpc CheckCreateStatus(CheckCreatePromoOrderRequest) returns (CheckCreatePromoOrderResponse){};
rpc CreatePromoOrder(CreatePromoOrderRequest) returns(OrderID){};
rpc PromoPayNotify(OrderID) returns(OrderID){};
rpc CancelOrder(OrderID) returns(OrderID){};
rpc CheckIssue(OrderID) returns(CheckIssueResponse){};
rpc FinishIssue(FinishIssueRequest) returns(GroupID){};
rpc PromoRefundNotify(OrderID) returns(OrderID){};
}

View File

@@ -0,0 +1,922 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: app/service/openplatform/ticket-sales/api/grpc/v1/promotion_mis.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 strings "strings"
import reflect "reflect"
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
type PromoOrderMis struct {
PromoID int64 `protobuf:"varint,1,opt,name=promo_id,json=promoId,proto3" json:"promo_id"`
GroupID int64 `protobuf:"varint,2,opt,name=group_id,json=groupId,proto3" json:"group_id"`
OrderID int64 `protobuf:"varint,3,opt,name=order_id,json=orderId,proto3" json:"order_id"`
IsMaster int16 `protobuf:"varint,4,opt,name=is_master,json=isMaster,proto3,casttype=int16" json:"is_master"`
UID int64 `protobuf:"varint,5,opt,name=uid,proto3" json:"uid"`
Status int16 `protobuf:"varint,6,opt,name=status,proto3,casttype=int16" json:"status"`
PayTime int64 `protobuf:"varint,7,opt,name=pay_time,json=payTime,proto3" json:"pay_time"`
Ctime int64 `protobuf:"varint,8,opt,name=ctime,proto3" json:"ctime"`
SKUID int64 `protobuf:"varint,9,opt,name=sku_id,json=skuId,proto3" json:"sku_id"`
}
func (m *PromoOrderMis) Reset() { *m = PromoOrderMis{} }
func (*PromoOrderMis) ProtoMessage() {}
func (*PromoOrderMis) Descriptor() ([]byte, []int) { return fileDescriptorPromotionMis, []int{0} }
type GetGroupOrdersMisRequest struct {
OrderID int64 `protobuf:"varint,1,opt,name=order_id,json=orderId,proto3" json:"order_id" form:"order_id"`
GroupID int64 `protobuf:"varint,2,opt,name=group_id,json=groupId,proto3" json:"group_id" form:"group_id"`
}
func (m *GetGroupOrdersMisRequest) Reset() { *m = GetGroupOrdersMisRequest{} }
func (*GetGroupOrdersMisRequest) ProtoMessage() {}
func (*GetGroupOrdersMisRequest) Descriptor() ([]byte, []int) {
return fileDescriptorPromotionMis, []int{1}
}
type GetGroupOrdersMisResponse struct {
Orders []*PromoOrderMis `protobuf:"bytes,2,rep,name=orders" json:"orders"`
}
func (m *GetGroupOrdersMisResponse) Reset() { *m = GetGroupOrdersMisResponse{} }
func (*GetGroupOrdersMisResponse) ProtoMessage() {}
func (*GetGroupOrdersMisResponse) Descriptor() ([]byte, []int) {
return fileDescriptorPromotionMis, []int{2}
}
func init() {
proto.RegisterType((*PromoOrderMis)(nil), "ticket.service.sales.v1.PromoOrderMis")
proto.RegisterType((*GetGroupOrdersMisRequest)(nil), "ticket.service.sales.v1.GetGroupOrdersMisRequest")
proto.RegisterType((*GetGroupOrdersMisResponse)(nil), "ticket.service.sales.v1.GetGroupOrdersMisResponse")
}
// 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 PromotionMis service
type PromotionMisClient interface {
GetGroupOrdersMis(ctx context.Context, in *GetGroupOrdersMisRequest, opts ...grpc.CallOption) (*GetGroupOrdersMisResponse, error)
}
type promotionMisClient struct {
cc *grpc.ClientConn
}
func NewPromotionMisClient(cc *grpc.ClientConn) PromotionMisClient {
return &promotionMisClient{cc}
}
func (c *promotionMisClient) GetGroupOrdersMis(ctx context.Context, in *GetGroupOrdersMisRequest, opts ...grpc.CallOption) (*GetGroupOrdersMisResponse, error) {
out := new(GetGroupOrdersMisResponse)
err := grpc.Invoke(ctx, "/ticket.service.sales.v1.PromotionMis/GetGroupOrdersMis", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for PromotionMis service
type PromotionMisServer interface {
GetGroupOrdersMis(context.Context, *GetGroupOrdersMisRequest) (*GetGroupOrdersMisResponse, error)
}
func RegisterPromotionMisServer(s *grpc.Server, srv PromotionMisServer) {
s.RegisterService(&_PromotionMis_serviceDesc, srv)
}
func _PromotionMis_GetGroupOrdersMis_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetGroupOrdersMisRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(PromotionMisServer).GetGroupOrdersMis(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/ticket.service.sales.v1.PromotionMis/GetGroupOrdersMis",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(PromotionMisServer).GetGroupOrdersMis(ctx, req.(*GetGroupOrdersMisRequest))
}
return interceptor(ctx, in, info, handler)
}
var _PromotionMis_serviceDesc = grpc.ServiceDesc{
ServiceName: "ticket.service.sales.v1.PromotionMis",
HandlerType: (*PromotionMisServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetGroupOrdersMis",
Handler: _PromotionMis_GetGroupOrdersMis_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "app/service/openplatform/ticket-sales/api/grpc/v1/promotion_mis.proto",
}
func (m *PromoOrderMis) 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 *PromoOrderMis) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.PromoID != 0 {
dAtA[i] = 0x8
i++
i = encodeVarintPromotionMis(dAtA, i, uint64(m.PromoID))
}
if m.GroupID != 0 {
dAtA[i] = 0x10
i++
i = encodeVarintPromotionMis(dAtA, i, uint64(m.GroupID))
}
if m.OrderID != 0 {
dAtA[i] = 0x18
i++
i = encodeVarintPromotionMis(dAtA, i, uint64(m.OrderID))
}
if m.IsMaster != 0 {
dAtA[i] = 0x20
i++
i = encodeVarintPromotionMis(dAtA, i, uint64(m.IsMaster))
}
if m.UID != 0 {
dAtA[i] = 0x28
i++
i = encodeVarintPromotionMis(dAtA, i, uint64(m.UID))
}
if m.Status != 0 {
dAtA[i] = 0x30
i++
i = encodeVarintPromotionMis(dAtA, i, uint64(m.Status))
}
if m.PayTime != 0 {
dAtA[i] = 0x38
i++
i = encodeVarintPromotionMis(dAtA, i, uint64(m.PayTime))
}
if m.Ctime != 0 {
dAtA[i] = 0x40
i++
i = encodeVarintPromotionMis(dAtA, i, uint64(m.Ctime))
}
if m.SKUID != 0 {
dAtA[i] = 0x48
i++
i = encodeVarintPromotionMis(dAtA, i, uint64(m.SKUID))
}
return i, nil
}
func (m *GetGroupOrdersMisRequest) 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 *GetGroupOrdersMisRequest) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.OrderID != 0 {
dAtA[i] = 0x8
i++
i = encodeVarintPromotionMis(dAtA, i, uint64(m.OrderID))
}
if m.GroupID != 0 {
dAtA[i] = 0x10
i++
i = encodeVarintPromotionMis(dAtA, i, uint64(m.GroupID))
}
return i, nil
}
func (m *GetGroupOrdersMisResponse) 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 *GetGroupOrdersMisResponse) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.Orders) > 0 {
for _, msg := range m.Orders {
dAtA[i] = 0x12
i++
i = encodeVarintPromotionMis(dAtA, i, uint64(msg.Size()))
n, err := msg.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n
}
}
return i, nil
}
func encodeVarintPromotionMis(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 *PromoOrderMis) Size() (n int) {
var l int
_ = l
if m.PromoID != 0 {
n += 1 + sovPromotionMis(uint64(m.PromoID))
}
if m.GroupID != 0 {
n += 1 + sovPromotionMis(uint64(m.GroupID))
}
if m.OrderID != 0 {
n += 1 + sovPromotionMis(uint64(m.OrderID))
}
if m.IsMaster != 0 {
n += 1 + sovPromotionMis(uint64(m.IsMaster))
}
if m.UID != 0 {
n += 1 + sovPromotionMis(uint64(m.UID))
}
if m.Status != 0 {
n += 1 + sovPromotionMis(uint64(m.Status))
}
if m.PayTime != 0 {
n += 1 + sovPromotionMis(uint64(m.PayTime))
}
if m.Ctime != 0 {
n += 1 + sovPromotionMis(uint64(m.Ctime))
}
if m.SKUID != 0 {
n += 1 + sovPromotionMis(uint64(m.SKUID))
}
return n
}
func (m *GetGroupOrdersMisRequest) Size() (n int) {
var l int
_ = l
if m.OrderID != 0 {
n += 1 + sovPromotionMis(uint64(m.OrderID))
}
if m.GroupID != 0 {
n += 1 + sovPromotionMis(uint64(m.GroupID))
}
return n
}
func (m *GetGroupOrdersMisResponse) Size() (n int) {
var l int
_ = l
if len(m.Orders) > 0 {
for _, e := range m.Orders {
l = e.Size()
n += 1 + l + sovPromotionMis(uint64(l))
}
}
return n
}
func sovPromotionMis(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
func sozPromotionMis(x uint64) (n int) {
return sovPromotionMis(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (this *PromoOrderMis) String() string {
if this == nil {
return "nil"
}
s := strings.Join([]string{`&PromoOrderMis{`,
`PromoID:` + fmt.Sprintf("%v", this.PromoID) + `,`,
`GroupID:` + fmt.Sprintf("%v", this.GroupID) + `,`,
`OrderID:` + fmt.Sprintf("%v", this.OrderID) + `,`,
`IsMaster:` + fmt.Sprintf("%v", this.IsMaster) + `,`,
`UID:` + fmt.Sprintf("%v", this.UID) + `,`,
`Status:` + fmt.Sprintf("%v", this.Status) + `,`,
`PayTime:` + fmt.Sprintf("%v", this.PayTime) + `,`,
`Ctime:` + fmt.Sprintf("%v", this.Ctime) + `,`,
`SKUID:` + fmt.Sprintf("%v", this.SKUID) + `,`,
`}`,
}, "")
return s
}
func (this *GetGroupOrdersMisRequest) String() string {
if this == nil {
return "nil"
}
s := strings.Join([]string{`&GetGroupOrdersMisRequest{`,
`OrderID:` + fmt.Sprintf("%v", this.OrderID) + `,`,
`GroupID:` + fmt.Sprintf("%v", this.GroupID) + `,`,
`}`,
}, "")
return s
}
func (this *GetGroupOrdersMisResponse) String() string {
if this == nil {
return "nil"
}
s := strings.Join([]string{`&GetGroupOrdersMisResponse{`,
`Orders:` + strings.Replace(fmt.Sprintf("%v", this.Orders), "PromoOrderMis", "PromoOrderMis", 1) + `,`,
`}`,
}, "")
return s
}
func valueToStringPromotionMis(v interface{}) string {
rv := reflect.ValueOf(v)
if rv.IsNil() {
return "nil"
}
pv := reflect.Indirect(rv).Interface()
return fmt.Sprintf("*%v", pv)
}
func (m *PromoOrderMis) 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 ErrIntOverflowPromotionMis
}
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: PromoOrderMis: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: PromoOrderMis: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field PromoID", wireType)
}
m.PromoID = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPromotionMis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.PromoID |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field GroupID", wireType)
}
m.GroupID = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPromotionMis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.GroupID |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field OrderID", wireType)
}
m.OrderID = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPromotionMis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.OrderID |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 4:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field IsMaster", wireType)
}
m.IsMaster = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPromotionMis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.IsMaster |= (int16(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 5:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field UID", wireType)
}
m.UID = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPromotionMis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.UID |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 6:
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 ErrIntOverflowPromotionMis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Status |= (int16(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 7:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field PayTime", wireType)
}
m.PayTime = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPromotionMis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.PayTime |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 8:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Ctime", wireType)
}
m.Ctime = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPromotionMis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Ctime |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 9:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field SKUID", wireType)
}
m.SKUID = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPromotionMis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.SKUID |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipPromotionMis(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthPromotionMis
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *GetGroupOrdersMisRequest) 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 ErrIntOverflowPromotionMis
}
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: GetGroupOrdersMisRequest: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: GetGroupOrdersMisRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field OrderID", wireType)
}
m.OrderID = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPromotionMis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.OrderID |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field GroupID", wireType)
}
m.GroupID = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPromotionMis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.GroupID |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipPromotionMis(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthPromotionMis
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *GetGroupOrdersMisResponse) 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 ErrIntOverflowPromotionMis
}
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: GetGroupOrdersMisResponse: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: GetGroupOrdersMisResponse: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Orders", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPromotionMis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthPromotionMis
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Orders = append(m.Orders, &PromoOrderMis{})
if err := m.Orders[len(m.Orders)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipPromotionMis(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthPromotionMis
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipPromotionMis(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, ErrIntOverflowPromotionMis
}
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, ErrIntOverflowPromotionMis
}
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, ErrIntOverflowPromotionMis
}
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, ErrInvalidLengthPromotionMis
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowPromotionMis
}
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 := skipPromotionMis(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 (
ErrInvalidLengthPromotionMis = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowPromotionMis = fmt.Errorf("proto: integer overflow")
)
func init() {
proto.RegisterFile("app/service/openplatform/ticket-sales/api/grpc/v1/promotion_mis.proto", fileDescriptorPromotionMis)
}
var fileDescriptorPromotionMis = []byte{
// 552 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0x31, 0x8f, 0xd3, 0x4c,
0x10, 0x8d, 0xe3, 0xcf, 0x71, 0xb2, 0xdf, 0x01, 0xc2, 0x27, 0x71, 0xe6, 0x84, 0xec, 0xc8, 0x05,
0x44, 0x41, 0x67, 0x2b, 0x39, 0x89, 0x82, 0x32, 0x22, 0x3a, 0x05, 0x14, 0x71, 0x32, 0xd0, 0xd0,
0x44, 0x4e, 0xbc, 0x67, 0x56, 0x39, 0x67, 0x17, 0xef, 0x3a, 0xd2, 0x49, 0x14, 0xfc, 0x00, 0xfe,
0x06, 0x12, 0x3f, 0xe5, 0x4a, 0x4a, 0x2a, 0x8b, 0x73, 0x99, 0x92, 0x92, 0x0a, 0xed, 0xac, 0x73,
0x06, 0x1d, 0x29, 0x68, 0xec, 0xf1, 0x9b, 0x79, 0x6f, 0xd6, 0x6f, 0x66, 0xd1, 0x38, 0x62, 0x2c,
0xe0, 0x38, 0x5b, 0x93, 0x05, 0x0e, 0x28, 0xc3, 0x2b, 0x76, 0x1e, 0x89, 0x33, 0x9a, 0xa5, 0x81,
0x20, 0x8b, 0x25, 0x16, 0x47, 0x3c, 0x3a, 0xc7, 0x3c, 0x88, 0x18, 0x09, 0x92, 0x8c, 0x2d, 0x82,
0xf5, 0x20, 0x60, 0x19, 0x4d, 0xa9, 0x20, 0x74, 0x35, 0x4b, 0x09, 0xf7, 0x59, 0x46, 0x05, 0xb5,
0x0e, 0x54, 0xb5, 0x5f, 0x29, 0xf9, 0xc0, 0xf2, 0xd7, 0x83, 0xc3, 0xa3, 0x84, 0x88, 0x77, 0xf9,
0xdc, 0x5f, 0xd0, 0x34, 0x48, 0x68, 0x42, 0x03, 0xa8, 0x9f, 0xe7, 0x67, 0xf0, 0x05, 0x1f, 0x10,
0x29, 0x1d, 0xef, 0xb3, 0x8e, 0x6e, 0x9d, 0x4a, 0xfd, 0x97, 0x59, 0x8c, 0xb3, 0x29, 0xe1, 0xd6,
0x10, 0xb5, 0xa1, 0xe1, 0x8c, 0xc4, 0xb6, 0xd6, 0xd5, 0x7a, 0xfa, 0xe8, 0xa0, 0x2c, 0x5c, 0x13,
0x8a, 0x26, 0xcf, 0x36, 0x85, 0x7b, 0x9d, 0x0e, 0x4d, 0x88, 0x26, 0xb1, 0xe4, 0x24, 0x19, 0xcd,
0x99, 0xe4, 0x34, 0x6b, 0xce, 0x89, 0xc4, 0x14, 0x67, 0x9b, 0x0e, 0x4d, 0x88, 0x14, 0x87, 0xca,
0x9e, 0x92, 0xa3, 0xd7, 0x1c, 0x38, 0x87, 0xe2, 0x6c, 0xd3, 0xa1, 0x09, 0xd1, 0x24, 0xb6, 0x8e,
0x51, 0x87, 0xf0, 0x59, 0x1a, 0x71, 0x81, 0x33, 0xfb, 0xbf, 0xae, 0xd6, 0x33, 0x46, 0xf7, 0x36,
0x85, 0x5b, 0x83, 0x3f, 0x0b, 0xd7, 0x20, 0x2b, 0x31, 0x78, 0x12, 0xb6, 0x09, 0x9f, 0x02, 0x64,
0x75, 0x91, 0x9e, 0x93, 0xd8, 0x36, 0xa0, 0xc7, 0xed, 0xb2, 0x70, 0xf5, 0x37, 0xa0, 0x2f, 0xd1,
0x50, 0x3e, 0xac, 0xc7, 0xa8, 0xc5, 0x45, 0x24, 0x72, 0x6e, 0xb7, 0x40, 0x73, 0x7f, 0x53, 0xb8,
0x15, 0x52, 0x0b, 0x56, 0x80, 0xf5, 0x08, 0xb5, 0x59, 0x74, 0x31, 0x13, 0x24, 0xc5, 0xb6, 0x09,
0x9a, 0x7b, 0x60, 0x4a, 0x85, 0x85, 0x26, 0x8b, 0x2e, 0x5e, 0x93, 0x14, 0x5b, 0x2e, 0x32, 0x16,
0x50, 0xd5, 0x86, 0xaa, 0xce, 0xa6, 0x70, 0x15, 0x10, 0xaa, 0x97, 0xd5, 0x47, 0x2d, 0xbe, 0xcc,
0xe5, 0xff, 0x77, 0xa0, 0x62, 0xbf, 0x2c, 0x5c, 0xe3, 0xd5, 0x0b, 0x75, 0xba, 0x2a, 0x15, 0x1a,
0x7c, 0x99, 0x4f, 0x62, 0xef, 0x8b, 0x86, 0xec, 0x13, 0x2c, 0xc0, 0x51, 0xb0, 0x88, 0x4f, 0x09,
0x0f, 0xf1, 0xfb, 0x1c, 0x73, 0x61, 0x8d, 0x7f, 0xb3, 0x52, 0x8d, 0xac, 0xbf, 0xc3, 0xca, 0x1f,
0x85, 0x7b, 0x47, 0x2e, 0xdb, 0x53, 0x6f, 0x8b, 0x78, 0xb5, 0xbb, 0xe3, 0x1b, 0x53, 0xec, 0xef,
0x98, 0x62, 0x2d, 0xb3, 0x45, 0xbc, 0xeb, 0xc1, 0x7a, 0x09, 0xba, 0xff, 0x97, 0x93, 0x72, 0x46,
0x57, 0x1c, 0x5b, 0xcf, 0x51, 0x0b, 0xda, 0x71, 0xbb, 0xd9, 0xd5, 0x7b, 0xff, 0x0f, 0x1f, 0xfa,
0x3b, 0x16, 0xd9, 0xff, 0x63, 0x2b, 0x47, 0x48, 0x5a, 0xa2, 0x98, 0x61, 0xf5, 0x1e, 0x7e, 0xd2,
0xd0, 0xde, 0xe9, 0xf6, 0x6e, 0xc8, 0xd5, 0xfd, 0x80, 0xee, 0xde, 0xe8, 0x6c, 0x0d, 0x76, 0x76,
0xd8, 0xe5, 0xe7, 0xe1, 0xf0, 0x5f, 0x28, 0xea, 0xc7, 0xbc, 0xc6, 0xe8, 0xc1, 0xe5, 0x95, 0xd3,
0xf8, 0x76, 0xe5, 0x34, 0x3e, 0x96, 0x8e, 0x76, 0x59, 0x3a, 0xda, 0xd7, 0xd2, 0xd1, 0xbe, 0x97,
0x8e, 0xf6, 0xb6, 0xb9, 0x1e, 0xcc, 0x5b, 0x70, 0xdf, 0x8e, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff,
0x5a, 0xdf, 0xa3, 0x84, 0x00, 0x04, 0x00, 0x00,
}

View File

@@ -0,0 +1,36 @@
syntax = "proto3";
package ticket.service.sales.v1;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option go_package = "v1";
option (gogoproto.goproto_getters_all) = false;
option (gogoproto.goproto_stringer_all) = false;
option (gogoproto.stringer_all) = true;
message PromoOrderMis {
int64 promo_id = 1 [(gogoproto.jsontag) = "promo_id", (gogoproto.customname)= "PromoID"];
int64 group_id = 2 [(gogoproto.jsontag) = "group_id", (gogoproto.customname)= "GroupID"];
int64 order_id = 3 [(gogoproto.jsontag) = "order_id", (gogoproto.customname)= "OrderID"];
int32 is_master = 4 [(gogoproto.jsontag) = "is_master", (gogoproto.casttype) = "int16"];
int64 uid = 5 [(gogoproto.jsontag) = "uid", (gogoproto.customname)= "UID"];
int32 status = 6 [(gogoproto.jsontag) = "status", (gogoproto.casttype) = "int16"];
int64 pay_time = 7 [(gogoproto.jsontag) = "pay_time"];
int64 ctime = 8 [(gogoproto.jsontag) = "ctime"];
int64 sku_id = 9 [(gogoproto.jsontag) = "sku_id", (gogoproto.customname)= "SKUID"];
}
message GetGroupOrdersMisRequest{
int64 order_id = 1 [(gogoproto.jsontag) = "order_id",(gogoproto.moretags) = "form:\"order_id\"", (gogoproto.customname)= "OrderID"];
int64 group_id = 2 [(gogoproto.jsontag) = "group_id",(gogoproto.moretags) = "form:\"group_id\"", (gogoproto.customname)= "GroupID"];
}
message GetGroupOrdersMisResponse {
repeated PromoOrderMis orders = 2 [(gogoproto.jsontag) = "orders"];
}
service PromotionMis{
rpc GetGroupOrdersMis(GetGroupOrdersMisRequest) returns(GetGroupOrdersMisResponse){}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,71 @@
//存放api使用的模型
syntax = "proto3";
package ticket.service.sales.v1;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option go_package = "v1";
option (gogoproto.goproto_getters_all) = false;
option (gogoproto.goproto_stringer_all) = false;
option (gogoproto.stringer_all) = true;
service Ticket {
// 查询电子票详情 - 支持根据订单号查询、场次 + uid 查询、票 id 查询
rpc TicketView(TicketViewRequest) returns (TicketViewResponse);
// 查询赠票信息
rpc TicketSend(TicketSendRequest) returns (TicketSendResponse);
}
message TicketViewRequest {
int64 order_id = 1 [(gogoproto.customname) = "OrderID"];
int64 uid = 2 [(gogoproto.customname) = "UID"];
int64 screen_id = 3 [(gogoproto.customname) = "ScreenID"];
repeated int64 id = 4 [(gogoproto.customname) = "ID"];
}
message TicketViewResponse {
repeated TicketItem tickets = 1;
}
message TicketItem {
int64 id = 1 [(gogoproto.customname) = "ID"];
int64 uid = 2 [(gogoproto.customname) = "UID"];
int64 oid = 3 [(gogoproto.customname) = "OID"];
int64 sid = 4 [(gogoproto.customname) = "SID"];
int64 price = 5;
int64 src = 6 [(gogoproto.casttype) = "int16"];
int64 type = 7 [(gogoproto.casttype) = "int16"];
int64 status = 8 [(gogoproto.casttype) = "int16"];
string qr = 9;
int64 ref_id = 10 [(gogoproto.customname) = "RefID"];
int64 sku_id = 11 [(gogoproto.customname) = "SkuID"];
int64 seat_id = 12 [(gogoproto.customname) = "SeatID"];
string seat = 13;
int64 refund_apply_time = 14 [(gogoproto.casttype) = "go-common/library/time.Time"];
int64 etime = 15 [(gogoproto.customname) = "ETime", (gogoproto.casttype) = "go-common/library/time.Time"];
int64 ctime = 16 [(gogoproto.customname) = "CTime", (gogoproto.casttype) = "go-common/library/time.Time"];
int64 mtime = 17 [(gogoproto.customname) = "MTime", (gogoproto.casttype) = "go-common/library/time.Time"];
}
message TicketSendRequest {
repeated int64 send_tid = 1 [(gogoproto.customname) = "SendTID"];
repeated int64 recv_tid = 2 [(gogoproto.customname) = "RecvTID"];
}
message TicketSendResponse {
repeated TicketSendItem ticket_sends = 1;
}
message TicketSendItem {
int64 id = 1 [(gogoproto.customname) = "ID"];
int64 sid = 2 [(gogoproto.customname) = "SID"];
int64 send_tid = 3 [(gogoproto.customname) = "SendTID"];
int64 recv_tid = 4 [(gogoproto.customname) = "RecvTID"];
int64 send_uid = 5 [(gogoproto.customname) = "SendUID"];
int64 recv_uid = 6 [(gogoproto.customname) = "RecvUID"];
string recv_tel = 7 [(gogoproto.customname) = "RecvTel"];
int32 status = 8 [(gogoproto.casttype) = "int16"];
int64 ctime = 9 [(gogoproto.customname) = "CTime", (gogoproto.casttype) = "go-common/library/time.Time"];
int64 mtime = 10 [(gogoproto.customname) = "MTime", (gogoproto.casttype) = "go-common/library/time.Time"];
int64 oid = 11 [(gogoproto.customname) = "OID"];
}

View File

@@ -0,0 +1,45 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_binary",
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
data = ["ticket-sales.toml"],
importpath = "go-common/app/service/openplatform/ticket-sales/cmd",
tags = ["automanaged"],
visibility = ["//visibility:private"],
deps = [
"//app/service/openplatform/ticket-sales/conf:go_default_library",
"//app/service/openplatform/ticket-sales/server/grpc:go_default_library",
"//app/service/openplatform/ticket-sales/server/http:go_default_library",
"//app/service/openplatform/ticket-sales/service:go_default_library",
"//app/service/openplatform/ticket-sales/service/mis:go_default_library",
"//library/conf/paladin:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/net/trace:go_default_library",
],
)
go_binary(
name = "cmd",
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)
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,59 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/service/openplatform/ticket-sales/conf"
"go-common/app/service/openplatform/ticket-sales/server/grpc"
"go-common/app/service/openplatform/ticket-sales/server/http"
"go-common/app/service/openplatform/ticket-sales/service"
"go-common/app/service/openplatform/ticket-sales/service/mis"
"go-common/library/conf/paladin"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
"go-common/library/net/trace"
)
func main() {
flag.Parse()
if err := paladin.Init(); err != nil {
panic(err)
}
if err := paladin.Watch("ticket-sales.toml", conf.Conf); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
defer log.Close()
trace.Init(conf.Conf.Tracer)
defer trace.Close()
log.Info("ticket-sales start")
ecode.Init(nil)
// service init
srv := service.New(conf.Conf)
misSrv := mis.New(srv.Get())
grpc.New(srv, misSrv)
http.Init(conf.Conf, srv)
log.Info("ready to serv")
// signal handler
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("ticket-sales get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGSTOP, syscall.SIGINT:
// rpcSvr.Close()
time.Sleep(time.Second * 2)
log.Info("ticket-sales exit")
return
case syscall.SIGHUP:
// TODO reload
default:
return
}
}
}

View File

@@ -0,0 +1,191 @@
# This is a TOML document. Boom.
version = "0.0.2"
user = "nobody"
pid = "/tmp/ticket-sales.pid"
dir = "/data/log"
perf = "0.0.0.0:3013"
family = "ticket-sales"
address = "127.0.0.1"
env = "dev"
[log]
dir = "/tmp/log/ticket-sales"
v = 3
[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"
#dsn = "test_3310:Lb1XsyqV6ZjY34tPKcAdHGapuxi9vowr@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 = "172.16.33.203:9379"
idle = 10
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "10s"
[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"}
[ut]
distPrefix = "http://localhost:8801/x/internal/ticket/sales"
[encrypt]
key = "bilibili_key_GYl"
iv = "biliBiliIv123456"
[urls]
basecenter = "http://uat-show.bilibili.co/api/basecenter"
[basecenter]
appId = "nBF6jpB7"
token = "XZUGqmAf1rRmu7l0dhogFIPPvveHOgSy2WtQ957JPeE="
[grpcClient]
[grpcClient.item]
dial = "1000ms"
timeout = "5000ms"
[grpcClient.account]
dial = "1000ms"
timeout = "5000ms"
[auth]
managerHost = "http://uat-manager.bilibili.co"
dashboardHost = "http://uat-dashboard-mng.bilibili.co"
dashboardCaller = "manager-go"
[auth.DsHTTPClient]
key = "manager-go"
secret = "949bbb2dd3178252638c2407578bc7ad"
dial = "1s"
timeout = "1s"
keepAlive = "60s"
[auth.DsHTTPClient.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[auth.MaHTTPClient]
key = "f6433799dbd88751"
secret = "36f8ddb1806207fe07013ab6a77a3935"
dial = "1s"
timeout = "1s"
keepAlive = "60s"
[auth.MaHTTPClient.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[auth.session]
sessionIDLength = 32
cookieLifeTime = 1800
cookieName = "mng-go"
domain = ".bilibili.co"
[auth.session.Memcache]
name = "go-business/auth"
proto = "tcp"
addr = "172.16.33.54:11211"
active = 5
idle = 5
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "80s"
[testProject]
ids = [10005, 10001, 425]
# querystring需要带这个参数才可以访问到
check_query = "1e1a4e8ca5a787226ce7a50535764651"
[databus]
[databus.update]
key = "39143bf7b888273e"
secret= "0766c43df93a9204d81c46caf2231ee1"
group= "TicketItemUpdate-OpenTicket-P"
topic= "TicketItemUpdate-T"
action="pub"
name = "databus/update"
proto = "tcp"
addr = "172.16.38.154:6205"
idle = 100
active = 100
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"

View File

@@ -0,0 +1,38 @@
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-sales/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/common/openplatform/encoding:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/net/trace:go_default_library",
"//library/queue/databus: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,96 @@
package conf
import (
"go-common/app/common/openplatform/encoding"
"go-common/library/cache/redis"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/net/http/blademaster"
"go-common/library/net/rpc/warden"
"go-common/library/net/trace"
"go-common/library/queue/databus"
"go-common/library/time"
"github.com/BurntSushi/toml"
)
var (
// Conf common conf
Conf = &Config{}
)
//Config config struct
type Config struct {
//数据库配置
DB *DB
// redis
Redis *Redis
// http client
HTTPClient HTTPClient
// http
BM *blademaster.ServerConfig
// tracer
Tracer *trace.Config
// log
Log *log.Config
// UT
UT *UT
GRPCClient map[string]*warden.ClientConfig
Encrypt *encoding.EncryptConfig
URLs map[string]string
//basecenter配置
BaseCenter *BaseCenter
Databus map[string]*databus.Config
TestProject *TestProject
}
// HTTPClient config
type HTTPClient struct {
Read *blademaster.ClientConfig
Write *blademaster.ClientConfig
}
// HTTPServers Http Servers
type HTTPServers struct {
Inner *blademaster.ServerConfig
Local *blademaster.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
}
//BaseCenter 的配置
type BaseCenter struct {
AppID string
Token string
}
// TestProject 测试项目配置
type TestProject struct {
IDs []int64
CheckQuery string
}
// Set set config and decode.
func (c *Config) Set(text string) error {
var tmp Config
if _, err := toml.Decode(text, &tmp); err != nil {
return err
}
*c = tmp
return nil
}

View File

@@ -0,0 +1,98 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"account_test.go",
"dao_test.go",
"distrib_test.go",
"item_test.go",
"order_detail_test.go",
"order_log_test.go",
"order_test.go",
"promotion_group_test.go",
"promotion_order_test.go",
"promotion_test.go",
"stock_test.go",
"ticket_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/openplatform/ticket-sales/api/grpc/type:go_default_library",
"//app/service/openplatform/ticket-sales/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-sales/conf:go_default_library",
"//app/service/openplatform/ticket-sales/model:go_default_library",
"//app/service/openplatform/ticket-sales/model/consts:go_default_library",
"//library/conf/paladin:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"account.go",
"dao.cache.go",
"dao.go",
"distrib.go",
"item.go",
"order.go",
"order_detail.go",
"order_log.go",
"promotion.go",
"promotion_group.go",
"promotion_order.go",
"redis.go",
"stock.go",
"ticket.go",
],
importpath = "go-common/app/service/openplatform/ticket-sales/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/common/openplatform/encoding:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/openplatform/ticket-item/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-sales/api/grpc/type:go_default_library",
"//app/service/openplatform/ticket-sales/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-sales/conf:go_default_library",
"//app/service/openplatform/ticket-sales/model:go_default_library",
"//app/service/openplatform/ticket-sales/model/consts:go_default_library",
"//library/cache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/naming/discovery:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/metadata:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/net/rpc/warden/resolver:go_default_library",
"//library/queue/databus:go_default_library",
"//library/stat/prom:go_default_library",
"//library/time:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"@com_github_gogo_protobuf//types:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,17 @@
package dao
import (
"context"
acc "go-common/app/service/main/account/api"
"go-common/library/net/metadata"
)
//GetUserCards 获取用户卡片信息
func (d *Dao) GetUserCards(ctx context.Context, mids []int64) (*acc.CardsReply, error) {
req := &acc.MidsReq{
Mids: mids,
RealIp: metadata.String(ctx, metadata.RemoteIP),
}
return d.accClient.Cards3(ctx, req)
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,54 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
package(default_visibility = ["//visibility:public"])
go_library(
name = "go_default_library",
srcs = [
"cache.go",
"distrib.go",
"model.go",
"order.go",
"pay.go",
"promo.go",
"stock.go",
"ticket.go",
],
importpath = "go-common/app/service/openplatform/ticket-sales/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/common/openplatform/encoding:go_default_library",
"//app/service/openplatform/ticket-sales/api/grpc/type:go_default_library",
"//app/service/openplatform/ticket-sales/api/grpc/v1:go_default_library",
"//library/log:go_default_library",
"//library/time:go_default_library",
"@com_github_gogo_protobuf//types:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/openplatform/ticket-sales/model/consts:all-srcs",
"//app/service/openplatform/ticket-sales/model/order_checker/account:all-srcs",
"//app/service/openplatform/ticket-sales/model/order_checker/item:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,47 @@
package model
//缓存key的常量
const (
CacheKeyOrderList = "order_ls" //订单列表缓存
CacheKeyOrderMn = "order_mn" //order_main缓存
CacheKeyOrderCnt = "order_cnt" //订单数缓存
CacheKeyOrderDt = "order_dt" //order_detail缓存
CacheKeyOrderSKU = "order_sku" //order_sku缓存
CacheKeyOrderPayCh = "order_ch" //order_pay_charge缓存
CacheKeyStock = "stock:%d" // 库存数 redis key 前缀
CacheKeyStockL = "locked:%d" // 锁定库存数 redisKey 前缀
CacheKeySku = "sku:%d" // skuId => sku redis key 前缀
CacheKeyItemSku = "sku.item:%d" // itemId => sku redis key 前缀
// 票相关 key
CacheKeyScreenSales = "ticket:screen.sales" // hash {sid:cnt} 各场次总的出票数
CacheKeyScreenDailySales = "ticket:screen.daily" // hash {sid:cnt} 各场次的当日销量
CacheKeyUserBuyScreen = "ticket:user.screen:%d" // hash {sid:cnt} 用户购买各场次票数量
CacheKeyOrderTickets = "ticket:order.tks:%d" // 一笔订单下所有电子票信息
CacheKeyScreenTickets = "ticket:screens.tks:%d:%d" // 一个场次下用户电子票信息
CacheKeyTicketQr = "ticket:qr.tk:%s" // 一个二维码对应电子票信息
CacheKeyTicket = "ticket:tk:%d" // 单张电子票信息
CacheKeyTicketPool = "ticket:pool:%d" // sku票池
CacheKeyTicketSend = "ticket:send:%d" // 票的赠送信息 send_tid => ticket_send
CacheKeyTicketRecv = "ticket:recv:%d" // 票的赠送信息 recv_tid => ticket_send
RedisExpireStock = 120 // 库存量缓存过期时间
RedisExpireStockTmp = 2 // 库存量缓存过期时间
RedisExpireSku = 1800 // SKU信息缓存过期时间
RedisExpireSkuTmp = 2 // SKU信息缓存过期时间
RedisExpireTenMin = 600 // 过期时间 10 分钟
RedisExpireTenMinTmp = 2 // 过期时间 10 分钟
RedisExpireOneDay = 86400 // 过期时间 1 天
RedisExpireOneDayTmp = 2 // 过期时间 1 天 兼容版
CacheKeyPromo = "%d:promotion:sales" //拼团活动缓存
CacheKeyPromoGroup = "%d:promotion:group:sales" //团缓存
CacheKeyPromoOrder = "%d:promotion:order:sales" //拼团订单缓存
CacheKeyPromoOrders = "%d:promotion:orders:sales" //拼团团订单缓存
RedisExpirePromo = 1 // 过期时间5分钟 to do
RedisExpirePromoGroup = 1 // 过期时间5分钟 to do
RedisExpirePromoOrder = 1 // 过期时间5分钟 to do
RedisExpirePromoOrders = 1 // 过期时间5分钟 to do
)

View File

@@ -0,0 +1,35 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"order.go",
"pay.go",
"project.go",
"promo.go",
"stock.go",
"ticket.go",
],
importpath = "go-common/app/service/openplatform/ticket-sales/model/consts",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
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,41 @@
package consts
//订单常量
const (
OrderTypeNormal = 1 //普通订单
OrderTypeGroup = 2 //拼团订单
OrderTypeDistrib = 4 //分销订单(已废弃)
OrderStatusUnpaid = 1 //未付款
OrderStatusPaid = 2 //已付款
OrderStatusRefunded = 3 //已退款
OrderStatusCancel = 4 //已取消
SubStatusUnpaid = 1 //未付款
SubStatusClose = 2 //已取消-系统关闭
SubStatusPaid = 3 //已付款-待出票
//4-6为退款状态已拆出为refundStatus7-8为已废弃付款子状态
SubStatusCompleted = 9 //已完成
SubStatusUnshipped = 10 //已待发货
SubStatusShipped = 11 //已付款-待收货
SubStatusCancel = 12 //已取消-用户取消(待启用)
RefundStatusNone = 0 //无退款
RefundStatusPtRefunding = 1 //部分退款中
RefundStatusPtRefunded = 2 //部分已退款
RefundStatusRefunding = 3 //退款中
RefundStatusRefunded = 4 //已退款
RefundTxStatusCreated = 1 //退款流水创建
RefundTxStatusSucc = 2 //退款流水处理成功
)
var (
//OrderTypes 订单类型
OrderTypes = map[int16]string{
OrderTypeNormal: "普通",
OrderTypeGroup: "拼团",
//Deprecated
OrderTypeDistrib: "分销",
}
)

View File

@@ -0,0 +1,11 @@
package consts
// 支付状态
const (
PayStatusPaying = "PAYING" // 待支付
PayStatusOverdue = "OVERDUE" // 已过期
PayStatusClose = "CLOSED" // 支付关闭
PayStatusFail = "FAIL" // 支付失败
PayStatusSuccess = "SUCCESS" // 支付成功
PayStatusFinished = "FINISHED" // 交易成功
)

View File

@@ -0,0 +1,22 @@
package consts
//项目相关状态
const (
DefaultBuyNumLimit = 8 //默认单张订单购买限制
BuyerInfoTel = 1 //需要手机号
BuyerInfoPerID = 2 //需要身份证号
BuyerInfoPerPic = 3 //需要身份证图片(未实现)
DeliverTypeNone = 1 //不配送
DeliverTypeSelf = 2 //自取
DeliverTypeExpress = 3 //快递配送
TicketTypePaper = 1 //纸质票
TicketTypeElec = 2 //电子票
TicketTypeExt = 3 //外部票(电子票)
TicketTypeExch = 12 //兑换票(未实现,实为纸质票+自取)
PickSeatYes = 1 //选座项目
PickSeatNo = 0 //不选座项目
)

View File

@@ -0,0 +1,21 @@
package consts
//拼团常量
const (
PromoWaitShelf int16 = 1 //待上架
PromoUpShelf int16 = 2 //已上架
PromoDelShelf int16 = 3 //废弃
PromoFinishShelf int16 = 4 //已结束
DoUpShelf int16 = 1 //上架
DoDelShelf int16 = 2 //废弃
GroupDoing int16 = 0 //拼团中
GroupSuccess int16 = 1 //拼团成功
GroupFailed int16 = 2 //拼团失败
PromoOrderUnpaid int16 = 1 //待支付
PromoOrderPaid int16 = 2 //已支付
PromoOrderRefund int16 = 3 //已退款
PromoOrderCancel int16 = 4 //已取消
)

View File

@@ -0,0 +1,16 @@
package consts
// 库存操作日志 opType 常量
const (
OpTypeOrder int16 = 0 // 0 下单减库存
OpTypePaid int16 = 1 // 1 订单支付解锁库存
OpTypeRefund int16 = 2 // 退票补充库存(3为退 voucher 减库存,已弃用)
OpTypeReserve int16 = 4 // 预留扣库存
OpTypeConfirm int16 = 5 // 确认预留解锁库存
OpTypeActive int16 = 7 // 场次激活重置库存
OpTypeBaseDecr int16 = 10 // 基础库存减少
OpTypeBaseIncr int16 = 11 // 基础库存增加
OpTypePrivDecr int16 = 12 // 活动库存减少
OpTypePrivIncr int16 = 13 // 活动库存增加
OpTypePrivInit int16 = 14 // 活动库存初始化
)

View File

@@ -0,0 +1,26 @@
package consts
//票状态常量
const (
TkStatusUnchecked = 0 //未检票
TkStatusChecked = 1 //已检票
TkStatusExpired = 2 //已过期
TkStatusRefunded = 3 //已退票
TkStatusRefunding = 4 //退票中
TkStatusRefundFail = 5 //退票失败
TkStatusSended = 6 //已转赠
)
// 票类型: 0-订单出票, 1-系统赠票, 2-用户赠票, 3-票代分销'
const (
TkTypeOrder = 0 // 订单出票
TkTypeSystemSend = 1 // 系统赠票
TkTypeUserSend = 2 // 用户赠票
TkTypeDistrib = 3 // 票代分销
)
// ticket_id 类型
const (
TIDTypeSend = "send"
TIDTypeRecv = "recv"
)

View File

@@ -0,0 +1,23 @@
package model
//DistOrderArg 分销订单同步入参
type DistOrderArg struct {
Oid uint64 `form:"oid" validate:"required"`
CmAmount uint64 `form:"cm_amount" validate:"min=1,required"`
CmMethod int64 `form:"cm_method" validate:"min=1,required"`
CmPrice uint64 `form:"cm_price" validate:"min=1,required"`
Duid uint64 `form:"dist_user" validate:"min=0"`
Stat int64 `form:"status" validate:"min=0"`
Pid uint64 `form:"pid" validate:"min=0"`
Count uint64 `form:"count" validate:"min=1,required"`
Sid uint64 `form:"sid" validate:"min=0"`
Type int64 `form:"type" validate:"min=0"`
RefStat int64 `form:"refund_status" validate:"min=0"`
PayAmount uint64 `form:"payment_amount" validate:"min=0"`
Serial string `form:"serial" validate:"required"`
}
//DistOrderGetArg 分销订单查询入参
type DistOrderGetArg struct {
Oid uint64 `form:"oid" validate:"required"`
}

View File

@@ -0,0 +1,87 @@
package model
import (
"fmt"
"strings"
"go-common/library/time"
)
//Order...主订单表状态
const (
OrderPaid = 2
OrderRefunded = 3
OrderRefundPartly = 2
OrderRefundedAll = 4
)
//DistOrder...分销订单表状态
const (
DistOrderNormal = 1
DistOrderRefunded = 2
DistOrderPartlyRefunded = 3
)
// SpecsSeparator sku 规格分隔符
const SpecsSeparator = "_"
//OrderInfo 订单同步字段
type OrderInfo struct {
Oid uint64 `json:"oid"`
CmAmount uint64 `json:"cm_amount"`
CmMethod int64 `json:"cm_method"`
CmPrice uint64 `json:"cm_price"`
Duid uint64 `json:"duid"`
Stat int64 `json:"status"`
Pid uint64 `json:"pid"`
Count uint64 `json:"count"`
Sid uint64 `json:"sid"`
Type int64 `json:"type"`
PayAmount uint64 `json:"pay_amount"`
Serial string `json:"serial_num"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
//OrderStockCnt 订单库存
type OrderStockCnt struct {
OrderID int64
Count int64
}
//SkuCnt sku库存
type SkuCnt struct {
SkuID int64
Count int64
}
//Batch 批量库存操作
type Batch struct {
ScreenID int64 // 场次 ID
TicketPriceID int64 // 票价 ID 就是 sku_stock SKUID
SkAlert int64 // 库存预警数
TotalStock int64 // 总库存数
}
//Specs 生成库存规格
func (b *Batch) Specs() (s string) {
s = fmt.Sprintf("%d%s%d", b.ScreenID, SpecsSeparator, b.TicketPriceID)
return
}
//InsPlHlds insert语句占位符
func InsPlHlds(colCnt int, rowCnt int) string {
hLen := colCnt*2 + 2
h := make([]byte, hLen)
h[0] = '('
h[hLen-2] = ')'
h[hLen-1] = ','
copy(h[1:], []byte(strings.Repeat(",?", colCnt)[1:]))
bPlHlds := make([]byte, hLen*rowCnt-1)
j := 0
for i := 0; i < rowCnt; i++ {
copy(bPlHlds[j:], h)
j += hLen
}
return string(bPlHlds)
}

View File

@@ -0,0 +1,469 @@
package model
import (
"encoding/json"
"go-common/app/common/openplatform/encoding"
"go-common/app/service/openplatform/ticket-sales/api/grpc/type"
"go-common/app/service/openplatform/ticket-sales/api/grpc/v1"
"go-common/library/time"
"github.com/gogo/protobuf/types"
)
//OrderMain 订单主表结构
type OrderMain struct {
OrderID int64 `json:"order_id"`
UID string `json:"uid"`
OrderType int16 `json:"order_type"`
ItemID int64 `json:"item_id"`
ItemInfo *_type.OrderItemInfo `json:"item_info"`
Count int64 `json:"count"`
TotalMoney int64 `json:"total_money"`
PayMoney int64 `json:"pay_money"`
ExpressFee int64 `json:"express_fee"`
PayChannel int16 `json:"pay_channel"`
PayTime int64 `json:"pay_time"`
Source string `json:"source"`
Status int16 `json:"status"`
SubStatus int16 `json:"sub_status"`
RefundStatus int16 `json:"refund_status"`
IsDeleted int16 `json:"is_deleted"`
CTime time.Time `json:"ctime"`
MTime time.Time `json:"mtime"`
}
//OrderMainQuerier 订单表查询参数
type OrderMainQuerier v1.ListOrdersRequest
// OrderDetail 订单详情表信息
type OrderDetail struct {
OrderID int64 `json:"order_id"`
Buyer string `json:"buyer"`
Tel string `json:"tel"`
PersonalID string `json:"personal_id"`
ExpressCO string `json:"express_co"`
ExpressNO string `json:"express_no"`
ExpressType int16 `json:"express_type"`
Remark string `json:"remark"`
DeviceType int16 `json:"device_type"`
IP []byte `json:"ip"`
Coupon *_type.OrderCoupon `json:"coupon"`
DeliverDetail *_type.OrderDeliver `json:"deliver_detail"`
Detail *_type.OrderExtra `json:"detail"`
MSource string `json:"msource"`
CTime time.Time `json:"-"`
MTime time.Time `json:"-"`
}
//OrderSKU order_sku表结构
type OrderSKU _type.OrderSKU
//OrderPayCharge 订单支付表结构
type OrderPayCharge _type.OrderPayCharge
//GetFields 获取order_main表所有字段,参数是需要排除的字段
func (o *OrderMain) GetFields(except *types.FieldMask) []string {
fields := []string{
"order_id", "uid", "order_type", "item_id", "item_info",
"count", "total_money", "express_fee", "pay_money", "pay_channel",
"pay_time", "source", "status", "sub_status", "refund_status",
"is_deleted", "ctime", "mtime",
}
if except != nil {
lp := len(except.Paths)
mExcept := make(map[string]bool, lp)
for _, v := range except.Paths {
mExcept[v] = true
}
res := make([]string, len(fields)-lp)
i := 0
for _, v := range fields {
if ok := mExcept[v]; !ok {
res[i] = v
i++
}
}
return res
}
return fields
}
//GetFields 获取order_detail字段名称
func (o *OrderDetail) GetFields(except *types.FieldMask) []string {
fields := []string{
"order_id", "buyer", "tel", "personal_id", "express_co",
"express_no", "express_type", "remark", "device_type", "ip",
"coupon", "deliver_detail", "detail", "msource", "ctime",
"mtime",
}
if except != nil {
lp := len(except.Paths)
mExcept := make(map[string]bool, lp)
for _, v := range except.Paths {
mExcept[v] = true
}
res := make([]string, len(fields)-lp)
i := 0
for _, v := range fields {
if ok := mExcept[v]; !ok {
res[i] = v
i++
}
}
return res
}
return fields
}
//GetFields 获取order_sku对象的字段名
func (o *OrderSKU) GetFields(except *types.FieldMask) []string {
fields := []string{
"order_id", "sku_id", "count", "origin_price", "price",
"seat_ids", "ticket_type", "discounts", "ctime", "mtime",
}
if except != nil {
lp := len(except.Paths)
mExcept := make(map[string]bool, lp)
for _, v := range except.Paths {
mExcept[v] = true
}
res := make([]string, len(fields)-lp)
i := 0
for _, v := range fields {
if ok := mExcept[v]; !ok {
res[i] = v
i++
}
}
return res
}
return fields
}
//GetFields 获取order_pay_charge对象的字段名
func (o *OrderPayCharge) GetFields(except *types.FieldMask) []string {
fields := []string{
"order_id", "charge_id", "channel", "paid", "refunded",
"ctime", "mtime",
}
if except != nil {
lp := len(except.Paths)
mExcept := make(map[string]bool, lp)
for _, v := range except.Paths {
mExcept[v] = true
}
res := make([]string, len(fields)-lp)
i := 0
for _, v := range fields {
if ok := mExcept[v]; !ok {
res[i] = v
i++
}
}
return res
}
return fields
}
//GetPtrs 获取order_main对象指针
// 如果设置vptr参数,会把struct指针替换成string指针,并在vptr保存原struct指针(as value)和它在返回数组中的下标(as key)
func (o *OrderMain) GetPtrs(fields *types.FieldMask, vptr map[int]interface{}) []interface{} {
ptrs := map[string]interface{}{
"order_id": &o.OrderID,
"uid": &o.UID,
"order_type": &o.OrderType,
"item_id": &o.ItemID,
"item_info": &o.ItemInfo,
"count": &o.Count,
"total_money": &o.TotalMoney,
"express_fee": &o.ExpressFee,
"pay_money": &o.PayMoney,
"pay_channel": &o.PayChannel,
"pay_time": &o.PayTime,
"source": &o.Source,
"status": &o.Status,
"sub_status": &o.SubStatus,
"refund_status": &o.RefundStatus,
"is_deleted": &o.IsDeleted,
"ctime": &o.CTime,
"mtime": &o.MTime,
}
if fields == nil {
fields = &types.FieldMask{Paths: o.GetFields(nil)}
}
ret := make([]interface{}, len(fields.Paths))
i := 0
for _, f := range fields.Paths {
if vptr != nil && f == "item_info" {
var s string
ret[i] = &s
vptr[i] = ptrs[f]
} else {
ret[i] = ptrs[f]
}
i++
}
return ret
}
//GetPtrs 获取order_detail对象指针
func (o *OrderDetail) GetPtrs(fields *types.FieldMask, vptr map[int]interface{}) []interface{} {
ptrs := map[string]interface{}{
"order_id": &o.OrderID,
"buyer": &o.Buyer,
"tel": &o.Tel,
"personal_id": &o.PersonalID,
"express_co": &o.ExpressCO,
"express_no": &o.ExpressNO,
"express_type": &o.ExpressType,
"remark": &o.Remark,
"device_type": &o.DeviceType,
"ip": &o.IP,
"coupon": &o.Coupon,
"deliver_detail": &o.DeliverDetail,
"detail": &o.Detail,
"msource": &o.MSource,
"ctime": &o.CTime,
"mtime": &o.MTime,
}
if fields == nil {
fields = &types.FieldMask{Paths: o.GetFields(nil)}
}
ret := make([]interface{}, len(fields.Paths))
i := 0
for _, f := range fields.Paths {
if vptr != nil && (f == "coupon" || f == "deliver_detail" || f == "detail") {
var s string
ret[i] = &s
vptr[i] = ptrs[f]
} else {
ret[i] = ptrs[f]
}
i++
}
return ret
}
//GetPtrs 获取order_sku对象的字段指针
func (o *OrderSKU) GetPtrs(fields *types.FieldMask, vptr map[int]interface{}) []interface{} {
ptrs := map[string]interface{}{
"order_id": &o.OrderID,
"sku_id": &o.SKUID,
"count": &o.Count,
"origin_price": &o.OriginPrice,
"price": &o.Price,
"seat_ids": &o.SeatIDs,
"ticket_type": &o.TicketType,
"discounts": &o.Discounts,
"ctime": &o.CTime,
"mtime": &o.MTime,
}
if fields == nil {
fields = &types.FieldMask{Paths: o.GetFields(nil)}
}
ret := make([]interface{}, len(fields.Paths))
i := 0
for _, f := range fields.Paths {
if vptr != nil && (f == "discounts" || f == "seat_ids") {
var s string
ret[i] = &s
vptr[i] = ptrs[f]
} else {
ret[i] = ptrs[f]
}
i++
}
return ret
}
//GetPtrs 获取order_pay_charge对象的字段指针
func (o *OrderPayCharge) GetPtrs(fields *types.FieldMask, vptr map[int]interface{}) []interface{} {
ptrs := map[string]interface{}{
"order_id": &o.OrderID,
"charge_id": &o.ChargeID,
"channel": &o.Channel,
"paid": &o.Paid,
"refunded": &o.Refunded,
"ctime": &o.CTime,
"mtime": &o.MTime,
}
if fields == nil {
fields = &types.FieldMask{Paths: o.GetFields(nil)}
}
ret := make([]interface{}, len(fields.Paths))
i := 0
for _, f := range fields.Paths {
if vptr != nil && f == "discounts" {
var s string
ret[i] = &s
vptr[i] = ptrs[f]
} else {
ret[i] = ptrs[f]
}
i++
}
return ret
}
//GetVals 获取order_main对象里的值
func (o *OrderMain) GetVals(fields *types.FieldMask, asString bool) []interface{} {
vals := map[string]interface{}{
"order_id": o.OrderID,
"uid": o.UID,
"order_type": o.OrderType,
"item_id": o.ItemID,
"item_info": o.ItemInfo,
"count": o.Count,
"total_money": o.TotalMoney,
"express_fee": o.ExpressFee,
"pay_money": o.PayMoney,
"pay_channel": o.PayChannel,
"pay_time": o.PayTime,
"source": o.Source,
"status": o.Status,
"sub_status": o.SubStatus,
"refund_status": o.RefundStatus,
"is_deleted": o.IsDeleted,
"ctime": o.CTime,
"mtime": o.MTime,
}
if fields == nil {
fields = &types.FieldMask{Paths: o.GetFields(nil)}
}
ret := make([]interface{}, len(fields.Paths))
i := 0
for _, f := range fields.Paths {
if asString && f == "item_info" {
if b, err := json.Marshal(vals[f]); err == nil {
ret[i] = string(b)
}
} else {
ret[i] = vals[f]
}
i++
}
return ret
}
//GetVals 获取order_detail对象字段的值
func (o *OrderDetail) GetVals(fields *types.FieldMask, asString bool) []interface{} {
vals := map[string]interface{}{
"order_id": o.OrderID,
"buyer": o.Buyer,
"tel": o.Tel,
"personal_id": o.PersonalID,
"express_co": o.ExpressCO,
"express_no": o.ExpressNO,
"express_type": o.ExpressType,
"remark": o.Remark,
"device_type": o.DeviceType,
"ip": o.IP,
"coupon": o.Coupon,
"deliver_detail": o.DeliverDetail,
"detail": o.Detail,
"msource": o.MSource,
"ctime": o.CTime,
"mtime": o.MTime,
}
if fields == nil {
fields = &types.FieldMask{Paths: o.GetFields(nil)}
}
ret := make([]interface{}, len(fields.Paths))
i := 0
for _, f := range fields.Paths {
if asString && (f == "coupon" || f == "deliver_detail" || f == "detail") {
if b, err := json.Marshal(vals[f]); err == nil {
ret[i] = string(b)
}
} else {
ret[i] = vals[f]
}
i++
}
return ret
}
//GetVals 获取order_sku字段的值
func (o *OrderSKU) GetVals(fields *types.FieldMask, asString bool) []interface{} {
vals := map[string]interface{}{
"order_id": o.OrderID,
"sku_id": o.SKUID,
"count": o.Count,
"origin_price": o.OriginPrice,
"price": o.Price,
"seat_ids": o.SeatIDs,
"ticket_type": o.TicketType,
"discounts": o.Discounts,
"ctime": o.CTime,
"mtime": o.MTime,
}
if fields == nil {
fields = &types.FieldMask{Paths: o.GetFields(nil)}
}
ret := make([]interface{}, len(fields.Paths))
i := 0
for _, f := range fields.Paths {
if asString && (f == "discounts" || f == "seat_ids") {
if b, err := json.Marshal(vals[f]); err == nil {
ret[i] = string(b)
}
} else {
ret[i] = vals[f]
}
i++
}
return ret
}
func (o *OrderDetail) getEncryptPtrs() []*string {
res := make([]*string, 3)
res[0] = &o.Tel
res[1] = &o.PersonalID
if o.DeliverDetail != nil {
res[2] = &o.DeliverDetail.Tel
}
return res
}
//Encrypt 加密order_detail的字段
func (o *OrderDetail) Encrypt(c *encoding.EncryptConfig) {
for _, p := range o.getEncryptPtrs() {
if p != nil {
s, _ := encoding.Encrypt(*p, c)
*p = s
}
}
}
//Decrypt 解密order_detail字段
func (o *OrderDetail) Decrypt(c *encoding.EncryptConfig) {
for _, p := range o.getEncryptPtrs() {
if p != nil {
s, _ := encoding.Decrypt(*p, c)
*p = s
}
}
}
//GetSettleOrdersRequest 获取结算订单请求
type GetSettleOrdersRequest struct {
Date string `form:"date" validate:"required"`
Ref byte `form:"ref"`
ExtParams string `form:"extParams" validate:"omitempty,numeric"`
PageSize int `form:"pagesize"`
}
//SettleOrder 获取结算订单返回
type SettleOrder struct {
ID int64 `json:"-"`
OrderID int64 `json:"order_id"`
RefID int64 `json:"ref_id"`
RefundApplyTime time.Time `json:"-"`
}
//SettleOrders 获取结算订单返回
type SettleOrders struct {
Data []*SettleOrder `json:"data"`
ExtParams string `json:"extParams"`
}

View File

@@ -0,0 +1,36 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["account.go"],
importpath = "go-common/app/service/openplatform/ticket-sales/model/order_checker/account",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/account/api:go_default_library",
"//app/service/main/account/model:go_default_library",
"//app/service/main/vip/model:go_default_library",
"//app/service/openplatform/ticket-sales/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-sales/dao:go_default_library",
"//library/ecode: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,68 @@
package account
import (
"context"
"time"
acc "go-common/app/service/main/account/api"
mAcc "go-common/app/service/main/account/model"
vip "go-common/app/service/main/vip/model"
rpc "go-common/app/service/openplatform/ticket-sales/api/grpc/v1"
"go-common/app/service/openplatform/ticket-sales/dao"
"go-common/library/ecode"
)
//Checker 检查用户信息
type Checker struct {
dao *dao.Dao
Users *acc.CardsReply
}
//New 新建一个用户检查类
func New(d *dao.Dao) *Checker {
return &Checker{
dao: d,
}
}
//Check 检查用户条件
func (ac *Checker) Check(ctx context.Context, req *rpc.CreateOrdersRequest) (ee []ecode.Codes, err error) {
l := len(req.Orders)
ee = make([]ecode.Codes, l)
uids := make([]int64, l)
uidMap := make(map[int64]bool, l)
i := 0
for _, v := range req.Orders {
if ok := uidMap[v.UID]; !ok {
uids[i] = v.UID
uidMap[v.UID] = true
i++
}
}
uids = uids[:i]
if ac.Users, err = ac.dao.GetUserCards(ctx, uids); err != nil {
return
}
begin:
for k, v := range req.Orders {
if _, ok := ac.Users.Cards[v.UID]; !ok {
ee[k] = ecode.TicketInvalidUser
continue begin
}
}
return
}
//GetUser 获取用户信息
func (ac *Checker) GetUser(mid int64) *mAcc.Card {
u, ok := ac.Users.Cards[mid]
if !ok {
return nil
}
v := u.Vip
if v.Type != vip.NotVip && v.Status != vip.VipStatusNotOverTime && v.DueDate <= time.Now().Unix() {
return u
}
u.Vip.Type = vip.NotVip
return u
}

View File

@@ -0,0 +1,38 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["item.go"],
importpath = "go-common/app/service/openplatform/ticket-sales/model/order_checker/item",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/account/model:go_default_library",
"//app/service/main/vip/model:go_default_library",
"//app/service/openplatform/ticket-item/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-sales/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-sales/dao:go_default_library",
"//app/service/openplatform/ticket-sales/model/consts:go_default_library",
"//app/service/openplatform/ticket-sales/model/order_checker/account:go_default_library",
"//library/ecode: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,238 @@
package item
import (
"context"
"strconv"
"strings"
"time"
acc "go-common/app/service/main/account/model"
vip "go-common/app/service/main/vip/model"
itm "go-common/app/service/openplatform/ticket-item/api/grpc/v1"
rpc "go-common/app/service/openplatform/ticket-sales/api/grpc/v1"
"go-common/app/service/openplatform/ticket-sales/dao"
"go-common/app/service/openplatform/ticket-sales/model/consts"
"go-common/app/service/openplatform/ticket-sales/model/order_checker/account"
"go-common/library/ecode"
)
//Checker 检查商品信息
type Checker struct {
dao *dao.Dao
ItemInfos *itm.BillReply
ac *account.Checker
Prices []Prices
}
//Prices 输出订单商品价格
type Prices struct {
Total int64
Pay int64
ExpFee int64
}
//New 新建一个检查类
func New(d *dao.Dao, ac *account.Checker) *Checker {
return &Checker{
dao: d,
ac: ac,
}
}
//Check 检查商品信息
func (ic *Checker) Check(ctx context.Context, req *rpc.CreateOrdersRequest) (ee []ecode.Codes, err error) {
itemIDs, scIDs, tkIDs := getItemIds(req.Orders)
ic.ItemInfos, err = ic.dao.ItemBillInfo(ctx, itemIDs, scIDs, tkIDs)
if err != nil {
return
}
ee = make([]ecode.Codes, len(req.Orders))
ic.Prices = make([]Prices, len(req.Orders))
begin:
for k, v := range req.Orders {
//检查订单类型
if _, ok := consts.OrderTypes[v.OrderType]; !ok {
ee[k] = ecode.TicketParamInvalid
continue begin
}
//检查项目
if e := ic.checkItem(v); e != nil {
ee[k] = e
continue begin
}
//检查购买人信息
if e := ic.checkBuyer(v); e != nil {
ee[k] = e
continue begin
}
user := ic.ac.GetUser(v.UID)
//检查票种
cnt, skuIDs, e := ic.checkSKU(v, user)
if e != nil {
ee[k] = e
continue begin
}
//检查剩余可购数
boughtCnt, _ := ic.dao.RawBoughtCount(ctx, strconv.FormatInt(v.UID, 10), v.ProjectID, skuIDs)
if e = ic.buyLimit(v, user, boughtCnt, cnt); e != nil {
ee[k] = e
continue begin
}
//检查商品价格
ic.Prices[k], e = ic.checkPrice(v, user)
if e != nil {
ee[k] = e
continue begin
}
}
return
}
//getItemIds 依次返回订单请求中的商品ID、场次ID、票价ID
func getItemIds(orders []*rpc.CreateOrderRequest) ([]int64, []int64, []int64) {
l := len(orders)
itemIDsMp, scIDsMp, tkIDsMp := make(map[int64]bool, l), make(map[int64]bool, l), make(map[int64]bool, l)
itemIDs, scIDs, tkIDs := make([]int64, l), make([]int64, l), make([]int64, l)
var i1, i2, i3 int
for _, o := range orders {
if _, ok := itemIDsMp[o.ProjectID]; !ok {
itemIDsMp[o.ProjectID] = true
itemIDs[i1] = o.ProjectID
i1++
}
if _, ok := scIDsMp[o.ScreenID]; !ok {
scIDsMp[o.ScreenID] = true
scIDs[i2] = o.ScreenID
i2++
}
for _, sku := range o.SKUs {
if _, ok := tkIDsMp[sku.SKUID]; !ok {
tkIDsMp[sku.SKUID] = true
tkIDs[i3] = sku.SKUID
i3++
}
}
}
return itemIDs[:i1], scIDs[:i2], tkIDs[:i3]
}
func (ic *Checker) checkItem(o *rpc.CreateOrderRequest) ecode.Codes {
//检查项目是否存在
if _, ok := ic.ItemInfos.BaseInfo[o.ProjectID]; !ok {
return ecode.TicketRecordLost
}
//todo 检查项目状态
if _, ok := ic.ItemInfos.BillOpt[o.ProjectID]; !ok {
ic.ItemInfos.BillOpt[o.ProjectID] = &itm.BillOpt{}
}
//检查场次是否存在
scr, ok := ic.ItemInfos.BaseInfo[o.ProjectID].Screen[o.ScreenID]
if !ok {
return ecode.TicketRecordLost
}
//不选座场次必传sku
if scr.PickSeat == consts.PickSeatNo && len(o.SKUs) == 0 {
return ecode.TicketMissData
}
//检查必填配送信息
if scr.DeliveryType == consts.DeliverTypeExpress && (o.DeliverDetail.Tel == "" || o.DeliverDetail.Addr == "" || o.DeliverDetail.Name == "") {
return ecode.TicketMissData
}
return nil
}
func (ic *Checker) checkBuyer(o *rpc.CreateOrderRequest) ecode.Codes {
sBuyer := ic.ItemInfos.BillOpt[o.ProjectID].BuyerInfo
if sBuyer != "" && len(o.Buyers) == 0 {
return ecode.TicketMissData
}
aBuyer := strings.Split(sBuyer, ",")
for _, v := range aBuyer {
f, _ := strconv.Atoi(v)
if (f == consts.BuyerInfoTel && o.Buyers[0].Tel == "") ||
(f == consts.BuyerInfoPerID && o.Buyers[0].PersonalID == "") {
return ecode.TicketMissData
}
}
return nil
}
func (ic *Checker) checkSKU(o *rpc.CreateOrderRequest, user *acc.Card) (cnt int64, skuIDs []int64, e ecode.Codes) {
skuIDs = make([]int64, len(o.SKUs))
now := time.Now().Unix()
//检查每个sku可售态
for k, sku := range o.SKUs {
skuIDs[k] = sku.SKUID
tk, ok := ic.ItemInfos.BaseInfo[o.ProjectID].Screen[o.ScreenID].Ticket[skuIDs[k]]
if sku.Count <= 0 || !ok {
e = ecode.TicketParamInvalid
return
}
if tk.Time.SaleStime > now {
e = ecode.TicketSaleNotStart
return
}
if tk.Time.SaleEtime < now {
e = ecode.TicketSaleEnd
return
}
if user.Vip.Type < tk.BuyLimit {
e = ecode.TicketNoPriv
return
}
cnt += sku.Count
}
return
}
//buyLimit 检查订单可购买数,返回单用户可购买数与单笔订单可购买数
func (ic *Checker) buyLimit(o *rpc.CreateOrderRequest, user *acc.Card, boughtCnt int64, buyCnt int64) ecode.Codes {
var lvLimits []*itm.BnlLevel
var vipLimits map[int32]*itm.BnlLevel
var oLimit, uLimit int64
if opt, ok := ic.ItemInfos.BillOpt[o.ProjectID]; ok && opt.BuyLimit != nil {
lvLimits = opt.BuyLimit.Level
vipLimits = opt.BuyLimit.VIP
oLimit = int64(opt.BuyLimit.Per)
}
uLevel, vipTyp := user.Level, user.Vip.Type
if int(uLevel) >= len(lvLimits) {
uLevel = 0
}
if uLimit == 0 {
oLimit = consts.DefaultBuyNumLimit
}
if vipTyp == vip.NotVip || lvLimits[uLevel].ApplyToVip == 1 {
uLimit = int64(lvLimits[uLevel].Max)
} else {
uLimit = int64(vipLimits[vipTyp].Max)
}
if buyCnt > oLimit {
return ecode.TicketExceedLimit
}
if uLimit-boughtCnt-buyCnt <= 0 {
return ecode.TicketExceedLimit
}
return nil
}
func (ic *Checker) checkPrice(o *rpc.CreateOrderRequest, user *acc.Card) (p Prices, e ecode.Codes) {
opt := ic.ItemInfos.BillOpt[o.ProjectID]
//非大会员不免邮
if user == nil || user.Vip.Type != vip.AnnualVip || opt.VipExpFree == 0 {
p.ExpFee = int64(opt.ExpTip)
if p.ExpFee < 0 {
p.ExpFee = 0
}
}
p.Total = p.ExpFee
for _, s := range o.SKUs {
tk := ic.ItemInfos.BaseInfo[o.ProjectID].Screen[o.ScreenID].Ticket[int64(s.SKUID)]
p.Total += int64(tk.PriceList.Price) * s.Count
}
p.Pay = p.Total
if p.Pay != o.PayMoney {
e = ecode.TicketPriceChanged
}
return
}

View File

@@ -0,0 +1,96 @@
package model
import (
"bytes"
"crypto/md5"
"fmt"
"sort"
"strconv"
"go-common/library/log"
xtime "go-common/library/time"
)
// MsgContent 支付回调 msgContent 字段的结构
// 由于 MsgContent 可能增/减字段故使用 map 兼容
type MsgContent map[string]string
// Charge 支付回调结构体
type Charge struct {
ID string
Paid bool
Refunded bool
OrderID int64
DeviceType int64
Channel int64
Amount int64
TimePaid xtime.Time
}
// ValidSign 签名校验
func (m MsgContent) ValidSign() (ok bool) {
sign := m["sign"]
delete(m, "sign")
var keys []string
for key := range m {
keys = append(keys, key)
}
sort.Strings(keys)
buf := bytes.Buffer{}
for _, k := range keys {
if buf.Len() > 0 {
buf.WriteByte('&')
}
buf.WriteString(k)
buf.WriteString("=")
buf.WriteString(m[k])
}
fmt.Println(buf.String())
h := md5.New()
ok = string(h.Sum(buf.Bytes())) == sign
return
}
// ToCharge 生成 charge 结构
func (m MsgContent) ToCharge() (charge *Charge, err error) {
charge = &Charge{}
charge.ID = m["txId"]
charge.Paid = true
charge.Refunded = false
orderID, err := strconv.ParseInt(m["orderId"], 10, 64)
if err != nil {
log.Error("MsgContent.ToCharge() strconv.ParseInt(orderId: %s) error(%v)", m["orderId"], err)
return
}
charge.OrderID = orderID
deviceType, err := strconv.ParseInt(m["deviceType"], 10, 64)
if err != nil {
log.Error("MsgContent.ToCharge() strconv.ParseInt(deviceType: %s) error(%v)", m["deviceType"], err)
return
}
charge.DeviceType = deviceType
payChannel, err := strconv.ParseInt(m["payChannel"], 10, 64)
if err != nil {
log.Error("MsgContent.ToCharge() strconv.ParseInt(payChannel: %s) error(%v)", m["payChannel"], err)
return
}
charge.Channel = payChannel
amount, err := strconv.ParseInt(m["amount"], 10, 64)
if err != nil {
log.Error("MsgContent.ToCharge() strconv.ParseInt(amount: %s) error(%v)", m["amount"], err)
return
}
charge.Amount = amount
if err = charge.TimePaid.Scan(m["orderPayTime"]); err != nil {
log.Error("MsgContent.ToCharge() TimePaid.Scan(%v) error(%v)", m["orderPayTime"], err)
return
}
return
}

View File

@@ -0,0 +1,48 @@
package model
import "go-common/library/time"
//Promotion 活动表
type Promotion struct {
PromoID int64 `json:"promo_id"`
Type int16 `json:"type"`
ItemID int64 `json:"item_id"`
SKUID int64 `json:"sku_id"`
Extra int64 `json:"extra"`
ExpireSec int64 `json:"expire_sec"`
SKUCount int64 `json:"sku_count"`
Amount int64 `json:"amount"`
BuyerCount int64 `json:"buyer_count"`
BeginTime int64 `json:"begin_time"`
EndTime int64 `json:"end_time"`
Status int16 `json:"status"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
PrivSKUID int64 `json:"priv_sku_id"`
UsableCoupons string `json:"usable_coupons"`
}
//PromotionGroup 拼团表
type PromotionGroup struct {
PromoID int64 `json:"promo_id"`
GroupID int64 `json:"group_id"`
UID int64 `json:"uid"`
OrderCount int64 `json:"order_count"`
Status int16 `json:"status"`
ExpireAt int64 `json:"expire_at"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
//PromotionOrder 拼团订单表
type PromotionOrder struct {
PromoID int64 `json:"promo_id"`
GroupID int64 `json:"group_id"`
OrderID int64 `json:"order_id"`
IsMaster int16 `json:"is_master"`
UID int64 `json:"uid"`
Status int16 `json:"status"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
SKUID int64 `json:"sku_id"`
}

View File

@@ -0,0 +1,29 @@
package model
import "go-common/library/time"
// SKUStockLog sku 库存操作日志
type SKUStockLog struct {
ID int64 `db:"id"`
SKUID int64 `db:"sku_id"`
OpType int16 `db:"op_type"`
SrcID int64 `db:"src_id"`
Stock int64 `db:"stock"`
CanceledAt time.Time `db:"canceled_at"`
Ctime time.Time `db:"ctime,autogen"`
Mtime time.Time `db:"mtime,autogen"`
}
// SKUStock sku 库存
type SKUStock struct {
SKUID int64 `db:"sku_id"`
ParentSKUID int64 `db:"parent_sku_id"`
ItemID int64 `db:"item_id"`
Specs string `db:"specs"`
TotalStock int64 `db:"total_stock"`
Stock int64 `db:"stock"`
LockedStock int64 `db:"locked_stock"`
SkAlert int64 `db:"sk_alert"`
Ctime time.Time `db:"ctime,autogen"`
Mtime time.Time `db:"mtime,autogen"`
}

View File

@@ -0,0 +1,41 @@
package model
import (
xtime "go-common/library/time"
)
// Ticket ticket 表结构
type Ticket struct {
ID int64 `json:"id"`
UID int64 `json:"uid"`
OID int64 `json:"oid"`
SID int64 `json:"sid"`
Price int64 `json:"price"`
Src int16 `json:"src"`
Type int16 `json:"type"`
Status int16 `json:"status"`
Qr string `json:"qr"`
RefID int64 `json:"ref_id"`
SkuID int64 `json:"sku_id"`
SeatID int64 `json:"seat_id"`
Seat string `json:"seat"`
RefundApplyTime xtime.Time `json:"refund_apply_time"`
ETime xtime.Time `json:"etime"`
CTime xtime.Time `json:"ctime"`
MTime xtime.Time `json:"mtime"`
}
// TicketSend ticket_send 表结构
type TicketSend struct {
ID int64 `json:"id"`
SID int64 `son:"sid"`
SendTID int64 `json:"send_tid"`
RecvTID int64 `json:"recv_tid"`
SendUID int64 `json:"send_uid"`
RecvUID int64 `json:"recv_uid"`
RecvTel string `json:"recv_tel"`
Status int16 `json:"status"`
CTime xtime.Time `json:"ctime"`
MTime xtime.Time `json:"mtime"`
OID int64 `json:"oid"`
}

View File

@@ -0,0 +1,52 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = ["server.go"],
importpath = "go-common/app/service/openplatform/ticket-sales/server/grpc",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/openplatform/ticket-sales/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-sales/service:go_default_library",
"//app/service/openplatform/ticket-sales/service/mis: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"],
)
go_test(
name = "go_default_test",
srcs = ["server_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/openplatform/ticket-sales/api/grpc/type:go_default_library",
"//app/service/openplatform/ticket-sales/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-sales/conf:go_default_library",
"//app/service/openplatform/ticket-sales/service:go_default_library",
"//library/conf/paladin:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,34 @@
package grpc
import (
"context"
rpc "go-common/app/service/openplatform/ticket-sales/api/grpc/v1"
"go-common/app/service/openplatform/ticket-sales/service"
"go-common/library/net/rpc/warden"
"go-common/app/service/openplatform/ticket-sales/service/mis"
"google.golang.org/grpc"
)
//New 生成rpc服务
func New(srv *service.Service, misSrv *mis.Mis) *warden.Server {
s := warden.NewServer(nil)
s.Use(middleware())
rpc.RegisterTradeServer(s.Server(), srv)
rpc.RegisterPromotionServer(s.Server(), srv)
rpc.RegisterPromotionMisServer(s.Server(), misSrv)
rpc.RegisterTicketServer(s.Server(), srv)
_, err := s.Start()
if err != nil {
panic("run server failed!" + err.Error())
}
return s
}
func middleware() grpc.UnaryServerInterceptor {
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
//call chain
resp, err = handler(ctx, req)
return
}
}

View File

@@ -0,0 +1,56 @@
package grpc
import (
"context"
"flag"
"fmt"
"path/filepath"
"testing"
sales "go-common/app/service/openplatform/ticket-sales/api/grpc/v1"
"go-common/app/service/openplatform/ticket-sales/conf"
"go-common/app/service/openplatform/ticket-sales/service"
"go-common/app/service/openplatform/ticket-sales/api/grpc/type"
"go-common/library/conf/paladin"
. "github.com/smartystreets/goconvey/convey"
)
var (
s *service.Service
)
func init() {
dir, _ := filepath.Abs("../../cmd/ticket-sales.toml")
flag.Set("conf", dir)
if err := paladin.Init(); err != nil {
panic(err)
}
if err := paladin.Watch("ticket-sales.toml", conf.Conf); err != nil {
panic(err)
}
s = service.New(conf.Conf)
}
//Test_Info
func TestInfo(t *testing.T) {
Convey("get data", t, func() {
data := &sales.UpBuyerRequest{}
data.OrderID = 10000012002571
data.Buyers = &_type.OrderBuyer{
ID: 1,
Name: "wlt",
Tel: "1388888888",
PersonalID: "360822199207227275",
}
res, err := s.UpdateBuyer(context.TODO(), data)
fmt.Println(res)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
So(res, ShouldNotBeEmpty)
})
}

View File

@@ -0,0 +1,60 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"distrib.go",
"http.go",
"promotion.go",
"promotion_group.go",
"promotion_order.go",
"settle.go",
],
importpath = "go-common/app/service/openplatform/ticket-sales/server/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/openplatform/ticket-sales/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-sales/conf:go_default_library",
"//app/service/openplatform/ticket-sales/model:go_default_library",
"//app/service/openplatform/ticket-sales/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",
"//library/net/http/blademaster/render:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["http_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/openplatform/ticket-sales/conf:go_default_library",
"//app/service/openplatform/ticket-sales/service:go_default_library",
"//library/conf/paladin:go_default_library",
"//library/net/http/blademaster:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,49 @@
package http
import (
"github.com/pkg/errors"
"go-common/app/service/openplatform/ticket-sales/model"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
)
func syncOrder(c *bm.Context) {
orderStatusMap := make(map[int64]string)
orderStatusMap[model.OrderPaid] = "已付款"
orderStatusMap[model.OrderRefunded] = "已退款"
arg := new(model.DistOrderArg)
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
_, ok := orderStatusMap[arg.Stat]
if !ok {
c.JSON("stat", ecode.TicketParamInvalid)
return
}
if arg.Serial == "" {
c.JSON("serial_num is empty", ecode.TicketParamInvalid)
return
}
switch arg.Stat {
case model.OrderPaid:
arg.Stat = model.DistOrderNormal
if arg.RefStat == model.OrderRefundPartly {
arg.Stat = model.DistOrderRefunded
}
case model.OrderRefunded:
arg.Stat = model.DistOrderRefunded
}
c.JSON(svc.SyncOrder(c, arg))
}
func getOrder(c *bm.Context) {
arg := new(model.DistOrderGetArg)
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
c.JSON(svc.GetOrder(c, arg.Oid))
}

View File

@@ -0,0 +1,71 @@
package http
import (
"net/http"
"go-common/app/service/openplatform/ticket-sales/conf"
"go-common/app/service/openplatform/ticket-sales/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
var (
svc *service.Service
)
// Init init ticket service.
func Init(c *conf.Config, s *service.Service) {
svc = s
// init router
engine := bm.DefaultServer(c.BM)
initRouter(engine)
outerRouter(engine)
if err := engine.Start(); err != nil {
log.Error("engine.Start error(%v)", err)
panic(err)
}
}
// initRouter init inner router.
func initRouter(e *bm.Engine) {
e.Ping(ping)
// 等依赖方修改后,再删除
group := e.Group("/x/internal/ticket/sales")
{
group.POST("/distrib/syncorder", syncOrder)
group.GET("/distrib/getorder", getOrder)
}
//ticket
group = e.Group("/openplatform/internal/ticket/sales")
{
group.POST("/distrib/syncorder", syncOrder)
group.GET("/distrib/getorder", getOrder)
group.POST("/promo/order/check", checkCreatePromoOrder)
group.POST("/promo/order/create", createPromoOrder)
group.GET("/promo/order/pay", payNotify)
group.GET("/promo/order/cancel", cancelOrder)
group.GET("/promo/order/check/issue", checkIssue)
group.POST("/promo/order/finish/issue", finishIssue)
group.GET("/promo/get", getPromo)
group.POST("promo/create", createPromo)
group.POST("promo/operate", operatePromo)
group.POST("promo/edit", editPromo)
group.POST("/settle/compare", settleCompare)
group.POST("/settle/repush", settleRepush)
}
}
// outerRouter init inner router.
func outerRouter(e *bm.Engine) {
}
// ping check server ok.
func ping(c *bm.Context) {
if err := svc.Ping(c); err != nil {
log.Error("ticket http service ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}

View File

@@ -0,0 +1,59 @@
package http
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
"sync"
"testing"
"go-common/app/service/openplatform/ticket-sales/conf"
"go-common/app/service/openplatform/ticket-sales/service"
"go-common/library/conf/paladin"
httpx "go-common/library/net/http/blademaster"
)
var (
once sync.Once
client *httpx.Client
syncOrderURL string
)
func startHTTP() {
if err := paladin.Init(); err != nil {
panic(err)
}
if err := paladin.Watch("ticket-sales.toml", conf.Conf); err != nil {
panic(err)
}
client = httpx.NewClient(conf.Conf.HTTPClient.Read)
Init(conf.Conf, service.New(conf.Conf))
}
func TestGetOrder(t *testing.T) {
syncOrderURL = conf.Conf.UT.DistPrefix + "/distrib/getorder"
fmt.Println(syncOrderURL)
once.Do(startHTTP)
params := url.Values{}
params.Set("oid", "100000004421700")
var err error
var req *http.Request
if req, err = client.NewRequest("GET", syncOrderURL, "127.0.0.1", params); err != nil {
t.Errorf("http.NewRequest(GET, %s) error(%v)", syncOrderURL, err)
t.FailNow()
}
reqURI := req.URL.String()
t.Logf("req uri: %s\n", reqURI)
var res struct {
Code int `json:"code"`
Data string `json:"data"`
}
if err = client.Do(context.TODO(), req, &res); err != nil {
t.Errorf("client.Do() error(%v)", err)
t.FailNow()
}
str, _ := json.Marshal(res)
t.Logf("res: %+v", string(str))
}

View File

@@ -0,0 +1,46 @@
package http
import (
rpcV1 "go-common/app/service/openplatform/ticket-sales/api/grpc/v1"
bm "go-common/library/net/http/blademaster"
)
func getPromo(c *bm.Context) {
arg := new(rpcV1.PromoID)
if err := c.Bind(arg); err != nil {
return
}
c.JSON(svc.GetPromo(c, arg))
}
func createPromo(c *bm.Context) {
arg := new(rpcV1.CreatePromoRequest)
if err := c.Bind(arg); err != nil {
return
}
c.JSON(svc.CreatePromo(c, arg))
}
func operatePromo(c *bm.Context) {
arg := new(rpcV1.OperatePromoRequest)
if err := c.Bind(arg); err != nil {
return
}
c.JSON(svc.OperatePromo(c, arg))
}
func editPromo(c *bm.Context) {
arg := new(rpcV1.EditPromoRequest)
if err := c.Bind(arg); err != nil {
return
}
c.JSON(svc.EditPromo(c, arg))
}

View File

@@ -0,0 +1 @@
package http

View File

@@ -0,0 +1,66 @@
package http
import (
rpcV1 "go-common/app/service/openplatform/ticket-sales/api/grpc/v1"
bm "go-common/library/net/http/blademaster"
)
func checkCreatePromoOrder(c *bm.Context) {
arg := new(rpcV1.CheckCreatePromoOrderRequest)
if err := c.Bind(arg); err != nil {
return
}
c.JSON(svc.CheckCreateStatus(c, arg))
}
func createPromoOrder(c *bm.Context) {
arg := new(rpcV1.CreatePromoOrderRequest)
if err := c.Bind(arg); err != nil {
return
}
c.JSON(svc.CreatePromoOrder(c, arg))
}
func payNotify(c *bm.Context) {
arg := new(rpcV1.OrderID)
if err := c.Bind(arg); err != nil {
return
}
c.JSON(svc.PromoPayNotify(c, arg))
}
func cancelOrder(c *bm.Context) {
arg := new(rpcV1.OrderID)
if err := c.Bind(arg); err != nil {
return
}
c.JSON(svc.CancelOrder(c, arg))
}
func checkIssue(c *bm.Context) {
arg := new(rpcV1.OrderID)
if err := c.Bind(arg); err != nil {
return
}
c.JSON(svc.CheckIssue(c, arg))
}
func finishIssue(c *bm.Context) {
arg := new(rpcV1.FinishIssueRequest)
if err := c.Bind(arg); err != nil {
return
}
c.JSON(svc.FinishIssue(c, arg))
}

View File

@@ -0,0 +1,59 @@
package http
import (
"encoding/json"
"go-common/app/service/openplatform/ticket-sales/model"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/render"
"net/http"
"go-common/library/net/http/blademaster/binding"
)
func settleCompare(c *bm.Context) {
req := &model.GetSettleOrdersRequest{}
err := json.NewDecoder(c.Request.Body).Decode(&req)
if err != nil {
c.Status(http.StatusBadRequest)
return
}
if err = binding.Form.Bind(c.Request, req); err != nil {
c.Render(http.StatusOK, render.MapJSON{
"errno": 1,
"msg": err.Error(),
})
return
}
data, err := svc.GetSettleOrders(c, req.Date, req.Ref == 1, req.ExtParams, req.PageSize)
if err != nil {
c.Render(http.StatusOK, render.MapJSON{
"errno": 1,
"msg": err.Error(),
})
return
}
c.Render(http.StatusOK, render.MapJSON{
"errno": 0,
"data": data,
})
}
func settleRepush(c *bm.Context) {
var req interface{}
err := json.NewDecoder(c.Request.Body).Decode(&req)
if err != nil {
c.Status(http.StatusBadRequest)
return
}
err = svc.RepushSettleOrders(c, req)
if err != nil {
c.Render(http.StatusOK, render.MapJSON{
"errno": 1,
"msg": err.Error(),
})
}
c.Render(http.StatusOK, render.MapJSON{
"errno": 0,
"msg": "将在5分钟内重推",
})
}

View File

@@ -0,0 +1,85 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"distrib.go",
"order.go",
"order_detail.go",
"pay.go",
"promotion.go",
"promotion_group.go",
"promotion_order.go",
"service.go",
"stock.go",
"ticket.go",
],
importpath = "go-common/app/service/openplatform/ticket-sales/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/common/openplatform/random:go_default_library",
"//app/service/openplatform/ticket-sales/api/grpc/type:go_default_library",
"//app/service/openplatform/ticket-sales/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-sales/conf:go_default_library",
"//app/service/openplatform/ticket-sales/dao:go_default_library",
"//app/service/openplatform/ticket-sales/model:go_default_library",
"//app/service/openplatform/ticket-sales/model/consts:go_default_library",
"//app/service/openplatform/ticket-sales/model/order_checker/account:go_default_library",
"//app/service/openplatform/ticket-sales/model/order_checker/item:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/metadata:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"distrib_test.go",
"order_test.go",
"promotion_group_test.go",
"promotion_order_test.go",
"promotion_test.go",
"service_test.go",
"stock_test.go",
"ticket_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/openplatform/ticket-sales/api/grpc/type:go_default_library",
"//app/service/openplatform/ticket-sales/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-sales/conf:go_default_library",
"//app/service/openplatform/ticket-sales/model:go_default_library",
"//app/service/openplatform/ticket-sales/model/consts:go_default_library",
"//library/conf/paladin:go_default_library",
"//library/ecode:go_default_library",
"//vendor/github.com/davecgh/go-spew/spew:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/openplatform/ticket-sales/service/mis:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,46 @@
package service
import (
"context"
"fmt"
"github.com/pkg/errors"
"go-common/app/service/openplatform/ticket-sales/model"
"go-common/library/ecode"
)
// SyncOrder 同步订单方法
func (s *Service) SyncOrder(c context.Context, oi *model.DistOrderArg) (affect int64, err error) {
if oi.Stat == model.DistOrderNormal {
has, _ := s.dao.HasOrder(c, oi)
if has {
err = ecode.TicketRecordDupli
errors.Wrap(err, fmt.Sprintf("重复的正向订单:%v", oi.Oid))
return
}
}
if oi.Stat == model.DistOrderRefunded {
roi := &model.DistOrderArg{}
roi.Stat = model.DistOrderNormal
roi.Oid = oi.Oid
has, _ := s.dao.HasOrder(c, roi)
if !has {
err = ecode.TicketRecordLost
errors.Wrap(err, fmt.Sprintf("缺少正向订单:%v", oi.Oid))
return
}
}
affect, err = s.dao.InsertOrder(c, oi)
return
}
//GetOrder 获取分销订单方法
func (s *Service) GetOrder(c context.Context, oid uint64) (oi []*model.OrderInfo, err error) {
oi, err = s.dao.GetOrder(c, oid)
if err != nil {
errors.Wrap(err, fmt.Sprintf("查询订单失败:%v", oid))
return
}
return
}

View File

@@ -0,0 +1,18 @@
package service
import (
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
func TestGetOrder(t *testing.T) {
Convey("GetOrder", t, func() {
time.Sleep(time.Second)
oi, err := svr.GetOrder(ctx, 10001)
So(err, ShouldBeNil)
t.Logf("order:%v", oi)
})
}

View File

@@ -0,0 +1,38 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"promotion_group.go",
"service.go",
],
importpath = "go-common/app/service/openplatform/ticket-sales/service/mis",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/openplatform/ticket-sales/api/grpc/v1:go_default_library",
"//app/service/openplatform/ticket-sales/conf:go_default_library",
"//app/service/openplatform/ticket-sales/dao:go_default_library",
"//app/service/openplatform/ticket-sales/model:go_default_library",
"//library/ecode: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,52 @@
package mis
import (
"context"
rpcV1 "go-common/app/service/openplatform/ticket-sales/api/grpc/v1"
"go-common/app/service/openplatform/ticket-sales/model"
"go-common/library/ecode"
)
//GetGroupOrdersMis 获取拼团订单
func (m *Mis) GetGroupOrdersMis(c context.Context, arg *rpcV1.GetGroupOrdersMisRequest) (res *rpcV1.GetGroupOrdersMisResponse, err error) {
var groupID int64
if arg.GroupID != 0 {
groupID = arg.GroupID
} else if arg.OrderID != 0 {
var promoOrder *model.PromotionOrder
if promoOrder, err = m.dao.PromoOrder(c, arg.OrderID); err != nil || promoOrder == nil {
err = ecode.TicketPromotionOrderLost
return
}
groupID = promoOrder.GroupID
}
if groupID == 0 {
err = ecode.TicketPromotionGroupLost
return
}
var orders []*model.PromotionOrder
if orders, err = m.dao.PromoOrders(c, groupID); err != nil || orders == nil {
err = ecode.TicketPromotionOrderLost
return
}
res = new(rpcV1.GetGroupOrdersMisResponse)
for _, order := range orders {
tempOrder, _ := m.dao.Orders(c, &model.OrderMainQuerier{OrderID: []int64{order.OrderID}})
r := &rpcV1.PromoOrderMis{
PromoID: order.PromoID,
GroupID: order.GroupID,
OrderID: order.OrderID,
IsMaster: order.IsMaster,
UID: order.UID,
Status: order.Status,
Ctime: int64(order.Ctime),
PayTime: tempOrder[0].PayTime,
SKUID: order.SKUID,
}
res.Orders = append(res.Orders, r)
}
return
}

View File

@@ -0,0 +1,21 @@
package mis
import (
"go-common/app/service/openplatform/ticket-sales/conf"
"go-common/app/service/openplatform/ticket-sales/dao"
)
//Mis http server
type Mis struct {
c *conf.Config
dao *dao.Dao
}
// New for new mis obj
func New(c *conf.Config, d *dao.Dao) *Mis {
m := &Mis{
c: c,
dao: d,
}
return m
}

View File

@@ -0,0 +1,346 @@
package service
import (
"context"
"errors"
"fmt"
"net"
"strconv"
"time"
"go-common/app/service/openplatform/ticket-sales/api/grpc/type"
rpc "go-common/app/service/openplatform/ticket-sales/api/grpc/v1"
"go-common/app/service/openplatform/ticket-sales/dao"
"go-common/app/service/openplatform/ticket-sales/model"
"go-common/app/service/openplatform/ticket-sales/model/consts"
oca "go-common/app/service/openplatform/ticket-sales/model/order_checker/account"
oci "go-common/app/service/openplatform/ticket-sales/model/order_checker/item"
"go-common/library/ecode"
"go-common/library/net/metadata"
)
//OrderChecker 下单前置检查器每个检查器需要有个Check方法接收下单请求做为参数返回和下单请求数一样多且顺序也一样的ecode.Codeserrcode不为0的在后续流程中拦截
type OrderChecker interface {
Check(context.Context, *rpc.CreateOrdersRequest) ([]ecode.Codes, error)
}
//OrderLocker 下单前置锁
type OrderLocker interface {
Lock(context.Context, *rpc.CreateOrdersRequest) ([]ecode.Codes, error)
}
//OrderProcesser 下单处理器
type OrderProcesser struct {
}
//useChecker 使用检查器
func (p *OrderProcesser) useChecker(ctx context.Context, req *rpc.CreateOrdersRequest, rules ...OrderChecker) (ee []ecode.Codes, err error) {
if len(rules) == 0 {
return
}
ee, err = rules[0].Check(ctx, req)
if err != nil {
return
}
l := len(req.Orders)
if len(ee) != l {
return nil, errors.New("ecode length must be equal with order length")
}
if len(rules) == 1 {
return
}
l1 := 0
for i := 0; i < l; i++ {
if ee[i] == nil {
l1++
}
}
req1 := &rpc.CreateOrdersRequest{
Orders: make([]*rpc.CreateOrderRequest, l1),
}
//m key:成功的ecode在原数组中的下标, val:去掉失败记录后的下标
m := make(map[int]int, l1)
j := 0
for i := 0; i < l; i++ {
if ee[i] == nil {
req1.Orders[j] = req.Orders[i]
m[i] = j
j++
}
}
ec1, err := p.useChecker(ctx, req1, rules[1:]...)
if err != nil {
return
}
if ec1 != nil {
for k, v := range m {
if ec1[v] != nil {
ee[k] = ec1[v]
}
}
}
return
}
//ListOrders 订单列表
func (s *Service) ListOrders(ctx context.Context, req *rpc.ListOrdersRequest) (res *rpc.ListOrdersResponse, err error) {
query := (*model.OrderMainQuerier)(req)
cnt, err := s.dao.OrderCount(ctx, query)
if err != nil {
return
}
res = &rpc.ListOrdersResponse{}
res.Count = cnt
if query.Limit == 0 {
query.Limit = dao.DefaultOrderPSize
}
if query.OrderBy == "" {
query.OrderBy = dao.DefaultOrderOrderBy
}
list, err := s.dao.Orders(ctx, query)
if err != nil {
return
}
ll := len(list)
if res.Count == 0 && ll > 0 {
res.Count = int64(ll)
}
oids := make([]int64, ll)
for k, v := range list {
oids[k] = v.OrderID
}
dts, err := s.dao.OrderDetails(ctx, oids)
if err != nil {
return
}
skus, err := s.dao.OrderSKUs(ctx, oids)
if err != nil {
return
}
chs, err := s.dao.OrderPayCharges(ctx, oids)
if err != nil {
return
}
res.List = make([]*rpc.OrderResponse, ll)
for k, v := range list {
o := &rpc.OrderResponse{}
o.OrderID = v.OrderID
o.UID = v.UID
o.OrderType = v.OrderType
o.ItemID = v.ItemID
o.ItemInfo = v.ItemInfo
o.Count = v.Count
o.TotalMoney = v.TotalMoney
o.PayMoney = v.PayMoney
o.ExpressFee = v.ExpressFee
o.Status = v.Status
o.SubStatus = v.SubStatus
o.RefundStatus = v.RefundStatus
o.CTime = v.CTime
o.MTime = v.MTime
o.Source = v.Source
o.IsDeleted = v.IsDeleted
if dt, ok := dts[v.OrderID]; ok {
o.Detail = &rpc.OrderResponseMore{}
o.Detail.Coupon = dt.Coupon
o.Detail.Deliver = dt.DeliverDetail
o.Detail.Extra = dt.Detail
o.Detail.ExpressCO = dt.ExpressCO
o.Detail.ExpressNO = dt.ExpressNO
o.Detail.ExpressType = dt.ExpressType
o.Detail.Remark = dt.Remark
o.Detail.DeviceType = dt.DeviceType
o.Detail.IP = 0
o.Detail.MSource = dt.MSource
o.Detail.Buyers = []*_type.OrderBuyer{
{
Name: dt.Buyer,
Tel: dt.Tel,
PersonalID: dt.PersonalID,
},
}
}
if ss, ok := skus[v.OrderID]; ok {
o.SKUs = make([]*_type.OrderSKU, len(ss))
for k, v := range ss {
o.SKUs[k] = (*_type.OrderSKU)(v)
}
}
if ch, ok := chs[v.OrderID]; ok {
o.PayCharge = (*_type.OrderPayCharge)(ch)
o.PayCharge.PayTime = v.PayTime
}
res.List[k] = o
}
return
}
//CreateOrders 创建订单
func (s *Service) CreateOrders(ctx context.Context, req *rpc.CreateOrdersRequest) (res *rpc.CreateOrdersResponse, err error) {
p := &OrderProcesser{}
ac := oca.New(s.dao)
ic := oci.New(s.dao, ac)
ee, err := p.useChecker(ctx, req, ac, ic)
if err != nil {
return
}
res = &rpc.CreateOrdersResponse{
Result: make([]*rpc.CreateOrderResult, len(req.Orders)),
}
var n, i, j int
var skuN int64
for k, v := range req.Orders {
if ee[k] == nil {
n++
for _, s := range v.SKUs {
skuN += s.Count
}
} else {
res.Result[k] = &rpc.CreateOrderResult{
Code: ee[k].Code(),
Message: ee[k].Message(),
}
}
}
if n == 0 {
return
}
oids, err := s.dao.OrderID(ctx, n)
if err != nil {
return
}
orders := make([]*model.OrderMain, n)
dts := make([]*model.OrderDetail, n)
skus := make([]*model.OrderSKU, skuN)
if err != nil {
return
}
for k, v := range req.Orders {
if ee[k] != nil {
continue
}
item := ic.ItemInfos.BaseInfo[v.ProjectID]
opt := ic.ItemInfos.BillOpt[v.ProjectID]
scr := item.Screen[v.ScreenID]
orders[i] = &model.OrderMain{
OrderID: oids[i],
UID: fmt.Sprintf("%d", v.UID),
OrderType: v.OrderType,
ItemID: v.ProjectID,
ItemInfo: &_type.OrderItemInfo{
Name: item.Name,
Img: item.Img.First,
ScreenID: v.ScreenID,
ScreenType: int16(scr.Type),
DeliverType: int16(scr.DeliveryType),
ExpressFee: int64(opt.ExpTip),
VIPExpressFree: int16(opt.VipExpFree),
VerID: 0, //todo 补充ver_id
},
TotalMoney: ic.Prices[k].Total,
PayMoney: ic.Prices[k].Pay,
ExpressFee: ic.Prices[k].ExpFee,
Source: v.Source,
IsDeleted: v.IsDeleted,
}
//非大会员不免邮
for _, s := range v.SKUs {
tk := scr.Ticket[int64(s.SKUID)]
orders[i].Count += s.Count
skus[j] = &model.OrderSKU{
OrderID: orders[i].OrderID,
SKUID: s.SKUID,
Count: s.Count,
OriginPrice: int64(tk.PriceList.OriPrice),
Price: int64(tk.PriceList.Price),
TicketType: int16(tk.Type),
}
j++
}
if orders[i].PayMoney == 0 {
orders[i].Status = consts.OrderStatusPaid
orders[i].SubStatus = consts.SubStatusPaid
} else {
orders[i].Status = consts.OrderStatusUnpaid
orders[i].SubStatus = consts.SubStatusUnpaid
}
dts[i] = &model.OrderDetail{
OrderID: orders[i].OrderID,
IP: net.ParseIP(metadata.String(ctx, metadata.RemoteIP)),
DeviceType: v.DeviceType,
DeliverDetail: v.DeliverDetail,
}
if len(v.Buyers) > 0 {
dts[i].Buyer = v.Buyers[0].Name
dts[i].Tel = v.Buyers[0].Tel
dts[i].PersonalID = v.Buyers[0].PersonalID
}
i++
}
tx, err := s.dao.BeginTx(ctx)
if err != nil {
return
}
s.dao.TxInsertOrders(tx, orders)
s.dao.TxInsertOrderDetails(tx, dts)
s.dao.TxInsertOrderSKUs(tx, skus)
tx.Rollback()
return
}
//ListOrderLogs 日志列表
func (s *Service) ListOrderLogs(ctx context.Context, req *rpc.ListOrderLogRequest) (res *rpc.ListOrderLogResponse, err error) {
res = new(rpc.ListOrderLogResponse)
orderLogs, err := s.dao.GetOrderLogList(ctx, req.OrderID, req.Offset, req.Limit, req.OrderBy)
if err != nil {
return
}
res.List = append(res.List, orderLogs...)
cnt, err := s.dao.GetOrderLogCnt(ctx, req.OrderID)
if err != nil {
return
}
res.Cnt = cnt
return
}
//AddOrderLogs 日志添加
func (s *Service) AddOrderLogs(ctx context.Context, req *rpc.AddOrderLogRequest) (res *rpc.AddOrderLogResponse, err error) {
res = new(rpc.AddOrderLogResponse)
insertID, err := s.dao.AddOrderLog(ctx, req.Data)
if err != nil {
return
}
res.Id = insertID
return
}
//GetSettleOrders 获取结算订单
func (s *Service) GetSettleOrders(ctx context.Context, dt string, ref bool, ext string, size int) (res *model.SettleOrders, err error) {
t, err := time.Parse("2006-01-02", dt)
if err != nil {
return
}
var id int64
if ext != "" {
id, err = strconv.ParseInt(ext, 10, 64)
if err != nil {
return
}
}
var offset int64
if ref {
res, offset, err = s.dao.RawGetSettleRefunds(ctx, t, t.Add(time.Hour*24), id, size)
} else {
res, offset, err = s.dao.RawGetSettleOrders(ctx, t, t.Add(time.Hour*24), id, size)
}
if offset > 0 {
res.ExtParams = strconv.FormatInt(offset, 10)
}
return
}
//RepushSettleOrders 重推结算订单
func (s *Service) RepushSettleOrders(ctx context.Context, req interface{}) error {
return s.dao.DatabusPub(ctx, "settle_repush", req)
}

View File

@@ -0,0 +1,54 @@
package service
import (
"context"
"fmt"
"go-common/app/service/openplatform/ticket-sales/api/grpc/type"
rpc "go-common/app/service/openplatform/ticket-sales/api/grpc/v1"
"go-common/app/service/openplatform/ticket-sales/model"
"go-common/library/log"
)
// UpdateBuyer 更新购买信息
func (s *Service) UpdateBuyer(c context.Context, req *rpc.UpBuyerRequest) (res *rpc.UpDetailResponse, err error) {
var oi int16 = 1
res = &rpc.UpDetailResponse{}
res.OrderID = req.OrderID
_, err = s.dao.UpdateDetailBuyer(c, req)
if err != nil {
log.Warn("更新订单详情%d失败", req.OrderID)
res.IsUpdate = 0
return
}
key := fmt.Sprintf("%s:%d", model.CacheKeyOrderDt, req.OrderID)
s.dao.RedisDel(c, key)
res.IsUpdate = oi
return
}
// UpdateDelivery 更新delivery 信息
func (s *Service) UpdateDelivery(c context.Context, req *rpc.UpDeliveryRequest) (res *rpc.UpDetailResponse, err error) {
var oi int16 = 1
res = &rpc.UpDetailResponse{}
res.OrderID = req.OrderID
deli := req.DeliverDetail
delivery := &_type.OrderDeliver{
AddrID: deli.AddrID,
Name: deli.Name,
Addr: deli.Addr,
Tel: deli.Tel,
}
_, err = s.dao.UpdateDetailDelivery(c, delivery, req.OrderID)
if err != nil {
log.Warn("更新订单详情配送信息%d失败", req.OrderID)
res.IsUpdate = 0
return
}
key := fmt.Sprintf("%s:%d", model.CacheKeyOrderDt, req.OrderID)
s.dao.RedisDel(c, key)
res.IsUpdate = oi
return
}

View File

@@ -0,0 +1,91 @@
package service
import (
"context"
"fmt"
"testing"
"time"
rpc "go-common/app/service/openplatform/ticket-sales/api/grpc/v1"
"go-common/app/service/openplatform/ticket-sales/api/grpc/type"
"github.com/davecgh/go-spew/spew"
"github.com/smartystreets/goconvey/convey"
)
func TestListOrders(t *testing.T) {
convey.Convey("ListOrders", t, func() {
req := &rpc.ListOrdersRequest{
OrderID: []int64{100000003240240},
}
res, _ := svr.ListOrders(context.TODO(), req)
convey.So(res.Count, convey.ShouldEqual, 1)
o := res.List[0]
convey.So(o.ItemInfo.Name, convey.ShouldEqual, "小凡の订单流程")
convey.So(len(o.SKUs[0].SeatIDs), convey.ShouldBeGreaterThan, 1)
convey.So(o.PayCharge.ChargeID, convey.ShouldEqual, "2946652108982083584")
convey.So(o.Detail.Buyers[0].Tel, convey.ShouldEqual, "13524568885")
req = &rpc.ListOrdersRequest{
UID: "27515328",
ItemID: 662,
Status: []int16{2},
}
res, _ = svr.ListOrders(context.TODO(), req)
o = res.List[0]
convey.So(o.Detail.Deliver.Tel, convey.ShouldEqual, "15129075612")
})
}
func TestCreateOrders(t *testing.T) {
convey.Convey("CreateOrders", t, func() {
req := &rpc.CreateOrdersRequest{
Orders: []*rpc.CreateOrderRequest{
{
ProjectID: 1191,
ScreenID: 1738,
SKUs: []*rpc.CreateOrderSKU{
{
SKUID: 13760,
Count: 1,
},
},
UID: 27515305,
PayMoney: 30,
OrderType: 1,
TS: time.Now().Unix(),
Buyers: []*_type.OrderBuyer{
{
Name: "Lisi",
Tel: "13800138000",
PersonalID: "123456",
},
},
DeliverDetail: &_type.OrderDeliver{
Name: "Lisi",
Addr: "Beijing",
Tel: "13800138000",
},
},
},
}
res, err := svr.CreateOrders(context.TODO(), req)
spew.Dump(res, err)
})
}
func TestListOrderLogs(t *testing.T) {
convey.Convey("ListOrders", t, func() {
req := &rpc.ListOrderLogRequest{
OrderID: 15198751542471,
Limit: 0,
Offset: 10,
OrderBy: "",
}
res, _ := svr.ListOrderLogs(context.TODO(), req)
fmt.Println(res)
})
}

View File

@@ -0,0 +1,88 @@
package service
import (
"context"
"encoding/json"
"net/url"
"go-common/app/service/openplatform/ticket-sales/api/grpc/v1"
"go-common/app/service/openplatform/ticket-sales/model"
"go-common/app/service/openplatform/ticket-sales/model/consts"
"go-common/library/ecode"
"go-common/library/log"
)
// PayNotify 支付回调通知接口
func (s *Service) PayNotify(c context.Context, req v1.PayNotifyRequest) (resp v1.PayNotifyResponse, err error) {
log.Info("s.PayNotify(%s)", req.String())
if req.MsgID == "" || req.MsgContent == "" {
err = ecode.ParamInvalid
return
}
msgContent, err := url.QueryUnescape(req.MsgContent)
if err != nil {
log.Error("s.PayNotify() MsgContent=%s error(%v)", req.MsgContent, err)
return
}
mc := model.MsgContent{}
if err = json.Unmarshal([]byte(msgContent), &mc); err != nil {
log.Error("s.PayNotify() msgContent=%s error(%v)", msgContent, err)
return
}
// 不是测试模式要验证签名
if !req.TestMode && !mc.ValidSign() {
err = ecode.SignCheckErr
return
}
if mc["payStatus"] == consts.PayStatusSuccess {
var charge *model.Charge
if charge, err = mc.ToCharge(); err != nil {
log.Error("s.PayNotify() mc.ToCharge(%v) error(%v)", mc, err)
return
}
s.chargeCallback(c, charge, req.TestMode)
}
return
}
// chargeCallback 支付回调处理
func (s *Service) chargeCallback(c context.Context, charge *model.Charge, testMode bool) (err error) {
orders, err := s.dao.RawOrders(c, &model.OrderMainQuerier{OrderID: []int64{charge.OrderID}})
if err != nil {
log.Error("s.chargeCallback() s.dao.RawUserOrders(%d) error(%v)", charge.OrderID, err)
return
}
if len(orders) == 0 {
log.Error("s.chargeCallback() s.dao.RawUserOrders() 订单 ID %d 未找到", charge.OrderID)
return
}
order := orders[0]
// 测试模式却不是测试项目
if testMode && !s.isTestProject(order.ItemID) {
err = ecode.ParamInvalid
log.Warn("testMode %t but not test project", testMode)
return
}
if order.PayMoney != charge.Amount {
log.Warn("订单金额不匹配 order: %d, charge: %d", order.PayMoney, charge.Amount)
return
}
return
}
func (s *Service) isTestProject(itemID int64) bool {
for _, ID := range s.c.TestProject.IDs {
if ID == itemID {
return true
}
}
return false
}

View File

@@ -0,0 +1,206 @@
package service
import (
"context"
rpcV1 "go-common/app/service/openplatform/ticket-sales/api/grpc/v1"
"go-common/app/service/openplatform/ticket-sales/model"
"go-common/app/service/openplatform/ticket-sales/model/consts"
"go-common/library/ecode"
"time"
)
//GetPromo 获取拼团详情
func (s *Service) GetPromo(c context.Context, arg *rpcV1.PromoID) (res *rpcV1.Promo, err error) {
var promo *model.Promotion
if promo, err = s.dao.Promo(c, arg.PromoID); err != nil || promo == nil {
err = ecode.TicketPromotionLost
return
}
res = &rpcV1.Promo{
PromoID: promo.PromoID,
Type: promo.Type,
ItemID: promo.ItemID,
SKUID: promo.SKUID,
Extra: promo.Extra,
ExpireSec: promo.ExpireSec,
SKUCount: promo.SKUCount,
Amount: promo.Amount,
BuyerCount: promo.BuyerCount,
BeginTime: promo.BeginTime,
EndTime: promo.EndTime,
Status: promo.Status,
Ctime: int64(promo.Ctime),
Mtime: int64(promo.Mtime),
PrivSKUID: promo.PrivSKUID,
UsableCoupons: promo.UsableCoupons,
}
return
}
//CreatePromo 创建拼团
func (s *Service) CreatePromo(c context.Context, arg *rpcV1.CreatePromoRequest) (res *rpcV1.PromoID, err error) {
var promo *model.Promotion
if promo, err = s.dao.Promo(c, arg.PromoID); err != nil {
err = ecode.TicketUnKnown
return
}
if promo != nil {
err = ecode.PromoExists
return
}
res = new(rpcV1.PromoID)
promo = &model.Promotion{
PromoID: arg.PromoID,
Type: arg.Type,
ItemID: arg.ItemID,
SKUID: arg.SKUID,
Extra: arg.Extra,
ExpireSec: arg.ExpireSec,
SKUCount: arg.SKUCount,
Amount: arg.Amount,
BuyerCount: arg.BuyerCount,
BeginTime: arg.BeginTime,
EndTime: arg.EndTime,
PrivSKUID: arg.PrivSKUID,
UsableCoupons: arg.UsableCoupons,
}
if res.PromoID, err = s.dao.CreatePromo(c, promo); err != nil {
err = ecode.TicketUnKnown
return
}
return
}
//HasPromoOfSKU 判断是否有相同sku已上架的活动
func (s *Service) HasPromoOfSKU(c context.Context, skuID int64, beginTime int64, endTime int64) (num int64, err error) {
if num, err = s.dao.HasPromoOfSKU(c, skuID, beginTime, endTime); err != nil {
err = ecode.TicketUnKnown
return
}
return
}
//OperatePromo 修改活动状态
func (s *Service) OperatePromo(c context.Context, arg *rpcV1.OperatePromoRequest) (res *rpcV1.CommonResponse, err error) {
var promo *model.Promotion
if promo, err = s.dao.Promo(c, arg.PromoID); err != nil || promo == nil {
err = ecode.TicketPromotionLost
return
}
var fromStatus, toStatus int16
if arg.OperateType == consts.DoUpShelf {
var hasPromo int64
if hasPromo, err = s.HasPromoOfSKU(c, promo.SKUID, promo.BeginTime, promo.EndTime); err != nil {
return
}
if 0 != hasPromo {
err = ecode.TicketPromoExistSameTime
return
}
fromStatus = consts.PromoWaitShelf
toStatus = consts.PromoUpShelf
} else if arg.OperateType == consts.DoDelShelf {
fromStatus = consts.PromoUpShelf
toStatus = consts.PromoDelShelf
} else {
err = ecode.IllegalPromoOperate
return
}
if fromStatus != promo.Status {
err = ecode.PromoStatusChanged
return
}
res = new(rpcV1.CommonResponse)
if res.Res, err = s.dao.OperatePromo(c, arg.PromoID, fromStatus, toStatus); err != nil {
err = ecode.TicketUnKnown
return
}
s.dao.DelCachePromo(c, arg.PromoID)
return
}
//CheckPromoStatus 检测拼团状态skuID可为0为0则不检测skuID是否一致
func (s *Service) CheckPromoStatus(c context.Context, promoID int64, skuID int64) (res *model.Promotion, err error) {
if res, err = s.dao.Promo(c, promoID); err != nil || res == nil {
err = ecode.TicketPromotionLost
return
}
if skuID != 0 && res.SKUID != skuID {
err = ecode.TicketPromotionLost
return
}
currentTime := time.Now().Unix()
if res.Status != consts.PromoUpShelf || res.BeginTime > currentTime || res.EndTime < currentTime {
err = ecode.TicketPromotionEnd
return
}
return
}
//EditPromo 编辑Promo to do
func (s *Service) EditPromo(c context.Context, arg *rpcV1.EditPromoRequest) (res *rpcV1.CommonResponse, err error) {
res = new(rpcV1.CommonResponse)
var promo *model.Promotion
currentTime := time.Now().Unix()
if promo, err = s.dao.Promo(c, arg.PromoID); err != nil || promo == nil {
err = ecode.TicketPromotionLost
return
}
if promo.BeginTime < currentTime {
switch promo.Status {
case consts.PromoFinishShelf, consts.PromoDelShelf:
err = ecode.PromoEditFieldNotALlowed
return
case consts.PromoWaitShelf:
return
case consts.PromoUpShelf:
if promo.EndTime < currentTime {
err = ecode.PromoEditFieldNotALlowed
return
}
if promo.EndTime > currentTime && (arg.ExpireSec != 0 || arg.EndTime != 0 || arg.BeginTime != 0 || arg.SKUCount != 0 || arg.PrivSKUID != 0 || arg.Amount != 0 || arg.UsableCoupons == "") {
err = ecode.PromoEditFieldNotALlowed
return
}
}
}
if arg.ExpireSec != 0 {
promo.ExpireSec = arg.ExpireSec
}
//if arg.SKUCount != 0 {
// promo.SKUCount = arg.SKUCount
//}
//if arg.BeginTime != 0 {
// promo.BeginTime = arg.BeginTime
//}
//if arg.EndTime != 0 {
// promo.EndTime = arg.EndTime
//}
//if arg.Amount != 0 {
// arg.Amount = promo.Amount
//}
//if arg.PrivSKUID != 0 {
// promo.PrivSKUID = arg.PrivSKUID
//}
//
//if arg.UsableCoupons != "" {
// promo.UsableCoupons = arg.UsableCoupons
//}
if res.Res, err = s.dao.UpdatePromo(c, promo); err != nil {
return
}
s.dao.DelCachePromo(c, arg.PromoID)
return
}

View File

@@ -0,0 +1,55 @@
package service
import (
"context"
rpcV1 "go-common/app/service/openplatform/ticket-sales/api/grpc/v1"
"go-common/app/service/openplatform/ticket-sales/model"
"go-common/app/service/openplatform/ticket-sales/model/consts"
"go-common/library/ecode"
"time"
)
//GetPromoGroupInfo 获取拼团详情,同时检测当前团状态
func (s *Service) GetPromoGroupInfo(c context.Context, arg *rpcV1.GetPromoGroupInfoRequest) (res *rpcV1.GetPromoGroupInfoResponse, err error) {
var promoOrder *model.PromotionOrder
if promoOrder, err = s.dao.PromoOrder(c, arg.OrderID); err != nil || promoOrder == nil {
err = ecode.TicketPromotionOrderLost
return
}
var promoGroup *model.PromotionGroup
if promoGroup, err = s.dao.PromoGroup(c, promoOrder.GroupID); err != nil || promoGroup == nil {
err = ecode.TicketPromotionGroupLost
return
}
var promo *model.Promotion
if promo, err = s.dao.Promo(c, promoOrder.PromoID); err != nil || promo == nil {
err = ecode.TicketPromotionLost
return
}
if promoGroup.Status == consts.GroupDoing && promoGroup.ExpireAt <= time.Now().Unix() {
promoGroup.Status = consts.GroupFailed
}
res = &rpcV1.GetPromoGroupInfoResponse{
PromoID: promo.PromoID,
SKUCount: promo.SKUCount,
Amount: promo.Amount,
GroupID: promoGroup.GroupID,
OrderCount: promoGroup.OrderCount,
ExpireAt: promoGroup.ExpireAt,
Status: promoGroup.Status,
Ctime: int64(promoGroup.Ctime),
}
return
}
//GroupFailed 拼团失败
func (s *Service) GroupFailed(c context.Context, arg *rpcV1.GroupFailedRequest) (res *rpcV1.GroupID, err error) {
if _, err = s.dao.UpdateGroupStatusAndOrderCount(c, arg.GroupID, arg.CancelNum, consts.GroupDoing, consts.GroupFailed); err != nil {
err = ecode.TicketUpdatePromoGroupFail
return
}
s.dao.DelCachePromoGroup(c, arg.GroupID)
s.dao.DelCachePromoOrders(c, arg.GroupID)
res = &rpcV1.GroupID{GroupID: arg.GroupID}
return
}

View File

@@ -0,0 +1,25 @@
package service
import (
"context"
rpcV1 "go-common/app/service/openplatform/ticket-sales/api/grpc/v1"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_GetPromoGroupInfo(t *testing.T) {
Convey("GetPromoGroupInfo", t, func() {
res, err := svr.GetPromoGroupInfo(context.TODO(), &rpcV1.GetPromoGroupInfoRequest{OrderID: 123})
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestService_GroupFailed(t *testing.T) {
Convey("GroupFailed", t, func() {
res, err := svr.GroupFailed(context.TODO(), &rpcV1.GroupFailedRequest{GroupID: 1, CancelNum: 1})
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}

View File

@@ -0,0 +1,407 @@
package service
import (
"context"
"go-common/app/common/openplatform/random"
rpcV1 "go-common/app/service/openplatform/ticket-sales/api/grpc/v1"
"go-common/app/service/openplatform/ticket-sales/model"
"go-common/app/service/openplatform/ticket-sales/model/consts"
"go-common/library/database/sql"
"go-common/library/ecode"
"go-common/library/log"
"math"
"time"
)
//GetPromoOrder 获取拼团订单详情
func (s *Service) GetPromoOrder(c context.Context, orderID int64) (res *rpcV1.PromoOrder, err error) {
var promoOrder *model.PromotionOrder
if promoOrder, err = s.dao.PromoOrder(c, orderID); err != nil || promoOrder == nil {
err = ecode.TicketPromotionOrderLost
return
}
res = &rpcV1.PromoOrder{
PromoID: promoOrder.PromoID,
GroupID: promoOrder.GroupID,
OrderID: promoOrder.OrderID,
IsMaster: promoOrder.IsMaster,
UID: promoOrder.UID,
Status: promoOrder.Status,
Ctime: int64(promoOrder.Ctime),
Mtime: int64(promoOrder.Mtime),
SKUID: promoOrder.SKUID,
}
return
}
//CheckCreateStatus 检测用户是否满足创单条件
func (s *Service) CheckCreateStatus(c context.Context, arg *rpcV1.CheckCreatePromoOrderRequest) (res *rpcV1.CheckCreatePromoOrderResponse, err error) {
var promo *model.Promotion
if promo, err = s.CheckPromoStatus(c, arg.PromoID, arg.SKUID); err != nil {
return
}
var promoOrderInfo *model.PromotionOrder
if promoOrderInfo, err = s.GetUserJoinPromoOrder(c, arg.PromoID, promo.SKUCount, arg.GroupID, arg.UID); err != nil && err != ecode.TicketPromotionRepeatJoin {
return
}
res = &rpcV1.CheckCreatePromoOrderResponse{
Amount: promo.Amount,
SKUID: promo.SKUID,
PrivSKUID: promo.PrivSKUID,
UsableCoupons: promo.UsableCoupons,
}
if err == ecode.TicketPromotionRepeatJoin {
err = nil
res.RepeatOrder = &rpcV1.RepeatOrder{
OrderID: promoOrderInfo.OrderID,
IsMaster: promoOrderInfo.IsMaster,
Status: promoOrderInfo.Status,
}
}
return
}
//GetUserJoinPromoOrder 获取用户正在参与该活动的订单
func (s *Service) GetUserJoinPromoOrder(c context.Context, promoID int64, skuCount int64, groupID int64, uid int64) (res *model.PromotionOrder, err error) {
currentTime := time.Now().Unix()
res = new(model.PromotionOrder)
if groupID == 0 {
//1.1找出该活动正在拼团中且未过期的拼团
if _, err = s.dao.GetUserGroupDoing(c, promoID, uid, consts.GroupDoing); err != nil && err != sql.ErrNoRows {
log.Warn(err.Error())
return
}
if err == sql.ErrNoRows {
//1.2该活动没有正在拼的团,找到用户发起未支付的拼团
if res, err = s.dao.PromoOrderByStatus(c, promoID, groupID, uid, consts.PromoOrderUnpaid); err != nil && err != sql.ErrNoRows {
log.Warn(err.Error())
return
}
if err == sql.ErrNoRows {
//未找到
err = nil
return
}
//找到,重复参加
err = ecode.TicketPromotionRepeatJoin
return
}
//1.3该活动有正在拼的团,查看该用户的拼团订单信息 to do
if res, err = s.dao.PromoOrderByStatus(c, promoID, groupID, uid, consts.PromoOrderPaid); err != nil && err != sql.ErrNoRows {
log.Warn(err.Error())
return
}
err = ecode.TicketPromotionRepeatJoin
return
}
var promoGroup *model.PromotionGroup
//2.1检查该拼团的状态
if promoGroup, err = s.dao.PromoGroup(c, groupID); err != nil || promoGroup == nil {
err = ecode.TicketPromotionGroupLost
return
}
if promoGroup.Status != consts.GroupDoing || promoGroup.ExpireAt < currentTime {
err = ecode.TicketPromotionGroupLost
return
}
if promoGroup.OrderCount >= skuCount {
err = ecode.TicketPromotionGroupFull
return
}
//2.2检查用户是否参与过该拼团
if res, err = s.dao.PromoOrderDoing(c, promoID, groupID, uid); err != nil && err != sql.ErrNoRows {
log.Warn(err.Error())
return
}
if err == sql.ErrNoRows {
err = nil
return
}
err = ecode.TicketPromotionRepeatJoin
return
}
//CreatePromoOrder 创建活动订单
func (s *Service) CreatePromoOrder(c context.Context, arg *rpcV1.CreatePromoOrderRequest) (res *rpcV1.OrderID, err error) {
var (
number int64
status = consts.PromoOrderUnpaid
)
if arg.PayMoney == 0 {
status = consts.PromoOrderPaid
}
if arg.GroupID == 0 {
//团长订单
if status == consts.PromoOrderUnpaid {
//非0元单
if number, err = s.dao.AddPromoOrder(c, arg.PromoID, 0, arg.OrderID, 1, arg.UID, status, arg.PromoSKUID, arg.Ctime); err != nil || number == 0 {
err = ecode.TicketAddPromoOrderFail
return
}
res = &rpcV1.OrderID{OrderID: arg.OrderID}
return
}
//0元单
var conn *sql.Tx
if conn, err = s.dao.BeginTx(c); err != nil {
err = ecode.TicketUnKnown
return
}
var groupID = random.Uniqid(15)
if number, err = s.dao.TxAddPromoOrder(c, conn, arg.PromoID, groupID, arg.OrderID, 1, arg.UID, status, arg.PromoSKUID, arg.Ctime); err != nil || number == 0 {
err = ecode.TicketAddPromoOrderFail
conn.Rollback()
return
}
var promo *model.Promotion
if promo, err = s.dao.Promo(c, arg.PromoID); err != nil || promo == nil {
err = ecode.TicketPromotionLost
conn.Rollback()
return
}
currentTime := time.Now().Unix()
expireAt := int64(math.Max(math.Min(float64(promo.EndTime), float64(promo.ExpireSec+currentTime)), float64(currentTime)))
if number, err = s.dao.TxAddPromoGroup(c, conn, arg.PromoID, groupID, arg.UID, 1, status, expireAt); err != nil || number == 0 {
err = ecode.TicketAddPromoGroupFail
conn.Rollback()
return
}
conn.Commit()
res = &rpcV1.OrderID{OrderID: arg.OrderID}
return
}
//非团长订单
var conn *sql.Tx
if conn, err = s.dao.BeginTx(c); err != nil {
err = ecode.TicketUnKnown
return
}
if number, err = s.dao.TxAddPromoOrder(c, conn, arg.PromoID, arg.GroupID, arg.OrderID, 0, arg.UID, status, arg.PromoSKUID, arg.Ctime); err != nil || number == 0 {
err = ecode.TicketAddPromoOrderFail
conn.Rollback()
return
}
var promo *model.Promotion
if promo, err = s.dao.Promo(c, arg.PromoID); err != nil || promo == nil {
err = ecode.TicketPromotionLost
conn.Rollback()
return
}
if number, err = s.dao.TxUpdateGroupOrderCount(c, conn, 1, arg.GroupID, promo.SKUCount); err != nil || number == 0 {
err = ecode.TicketUpdatePromoGroupFail
conn.Rollback()
return
}
conn.Commit()
s.dao.DelCachePromoGroup(c, arg.GroupID)
s.dao.DelCachePromoOrders(c, arg.GroupID)
res = &rpcV1.OrderID{OrderID: arg.OrderID}
return
}
//CancelOrder 取消订单
func (s *Service) CancelOrder(c context.Context, arg *rpcV1.OrderID) (res *rpcV1.OrderID, err error) {
var promoOrder *model.PromotionOrder
if promoOrder, err = s.dao.PromoOrder(c, arg.OrderID); err != nil || promoOrder == nil {
err = ecode.TicketPromotionOrderLost
return
}
var conn *sql.Tx
if conn, err = s.dao.BeginTx(c); err != nil {
err = ecode.TicketUnKnown
return
}
var number int64
if number, err = s.dao.TxUpdatePromoOrderStatus(c, conn, arg.OrderID, consts.PromoOrderCancel); err != nil {
err = ecode.TicketUpdatePromoOrderFail
conn.Rollback()
return
}
if number == 0 {
conn.Rollback()
res = &rpcV1.OrderID{OrderID: 0}
return
}
if promoOrder.GroupID == 0 {
conn.Commit()
s.dao.DelCachePromoOrder(c, arg.OrderID)
res = arg
return
}
if number, err = s.dao.TxUpdateGroupOrderCount(c, conn, -1, promoOrder.GroupID, 100000); err != nil || number == 0 {
err = ecode.TicketUpdatePromoGroupFail
conn.Rollback()
return
}
conn.Commit()
s.dao.DelCachePromoOrder(c, arg.OrderID)
s.dao.DelCachePromoGroup(c, promoOrder.GroupID)
s.dao.DelCachePromoOrders(c, promoOrder.GroupID)
res = arg
return
}
// PromoPayNotify 支付通知
func (s *Service) PromoPayNotify(c context.Context, arg *rpcV1.OrderID) (res *rpcV1.OrderID, err error) {
var promoOrder *model.PromotionOrder
if promoOrder, err = s.dao.PromoOrder(c, arg.OrderID); err != nil || promoOrder == nil {
err = ecode.TicketPromotionOrderLost
return
}
var promo *model.Promotion
if promo, err = s.dao.Promo(c, promoOrder.PromoID); err != nil || promo == nil {
err = ecode.TicketPromotionLost
return
}
if promo.Status != consts.PromoUpShelf {
err = ecode.TicketPromotionEnd
}
if promoOrder.GroupID != 0 {
//非团长订单
if _, err = s.dao.UpdatePromoOrderStatus(c, arg.OrderID, consts.PromoOrderPaid); err != nil {
err = ecode.TicketUpdatePromoOrderFail
return
}
s.dao.DelCachePromoOrder(c, arg.OrderID)
s.dao.DelCachePromoOrders(c, promoOrder.GroupID)
res = arg
return
}
//团长订单
var (
conn *sql.Tx
number int64
)
if conn, err = s.dao.BeginTx(c); err != nil {
err = ecode.TicketUnKnown
return
}
currentTime := time.Now().Unix()
groupID := random.Uniqid(15)
expireAt := int64(math.Max(math.Min(float64(promo.EndTime), float64(promo.ExpireSec+currentTime)), float64(currentTime)))
if number, err = s.dao.TxAddPromoGroup(c, conn, promoOrder.PromoID, groupID, promoOrder.UID, 1, consts.GroupDoing, expireAt); err != nil || number == 0 {
err = ecode.TicketAddPromoGroupFail
conn.Rollback()
return
}
if number, err = s.dao.TxUpdatePromoOrderGroupIDAndStatus(c, conn, arg.OrderID, groupID, consts.PromoOrderPaid); err != nil || number == 0 {
err = ecode.TicketUpdatePromoOrderFail
conn.Rollback()
return
}
conn.Commit()
s.dao.DelCachePromoOrder(c, arg.OrderID)
res = arg
return
}
//CheckIssue 出票检查
func (s *Service) CheckIssue(c context.Context, arg *rpcV1.OrderID) (res *rpcV1.CheckIssueResponse, err error) {
var promoOrder *model.PromotionOrder
if promoOrder, err = s.dao.PromoOrder(c, arg.OrderID); err != nil || promoOrder == nil {
err = ecode.TicketPromotionOrderLost
return
}
if promoOrder.IsMaster == 0 || promoOrder.Status != consts.PromoOrderPaid {
err = ecode.TicketPromoOrderTypeErr
return
}
var promoGroup *model.PromotionGroup
if promoGroup, err = s.dao.PromoGroup(c, promoOrder.GroupID); err != nil || promoGroup == nil {
err = ecode.TicketPromotionGroupLost
return
}
if promoGroup.Status != consts.GroupDoing {
err = ecode.TicketPromoGroupStatusErr
return
}
var groupOrders []*model.PromotionOrder
if groupOrders, err = s.dao.GroupOrdersByStatus(c, promoOrder.GroupID, consts.PromoOrderPaid); err != nil {
err = ecode.TicketUnKnown
return
}
var promo *model.Promotion
if promo, err = s.dao.RawPromo(c, promoGroup.PromoID); err != nil {
err = ecode.TicketPromotionLost
return
}
stock := int64(len(groupOrders))
if stock < promo.SKUCount {
err = ecode.TicketPromotionGroupNotFull
return
}
res = new(rpcV1.CheckIssueResponse)
res.PromoID = promoOrder.PromoID
res.GroupID = promoOrder.GroupID
for _, v := range groupOrders {
temp := &rpcV1.OrderID{OrderID: v.OrderID}
res.PaidOrders = append(res.PaidOrders, temp)
}
return
}
//FinishIssue 完成出票
func (s *Service) FinishIssue(c context.Context, arg *rpcV1.FinishIssueRequest) (res *rpcV1.GroupID, err error) {
var (
number int64
promo *model.Promotion
conn *sql.Tx
)
if promo, err = s.dao.Promo(c, arg.PromoID); err != nil || promo == nil {
err = ecode.TicketPromotionLost
return
}
if conn, err = s.dao.BeginTx(c); err != nil {
err = ecode.TicketUnKnown
return
}
if number, err = s.dao.TxUpdateGroupStatus(c, conn, arg.GroupID, consts.GroupDoing, consts.GroupSuccess); err != nil {
conn.Rollback()
err = ecode.TicketUpdatePromoGroupFail
return
}
if number == 0 {
res = &rpcV1.GroupID{GroupID: arg.GroupID}
return
}
if number, err = s.dao.TxUpdatePromoBuyerCount(c, conn, arg.GroupID, promo.SKUCount); err != nil || number == 0 {
conn.Rollback()
err = ecode.TicketUpdatePromoGroupFail
return
}
conn.Commit()
s.dao.DelCachePromo(c, arg.PromoID)
s.dao.DelCachePromoGroup(c, arg.GroupID)
s.dao.DelCachePromoOrders(c, arg.GroupID)
res = &rpcV1.GroupID{GroupID: arg.GroupID}
return
}
// PromoRefundNotify 退款通知
func (s *Service) PromoRefundNotify(c context.Context, arg *rpcV1.OrderID) (res *rpcV1.OrderID, err error) {
var promoOrder *model.PromotionOrder
if promoOrder, err = s.dao.PromoOrder(c, arg.OrderID); err != nil || promoOrder == nil {
err = ecode.TicketPromotionOrderLost
return
}
if _, err = s.dao.UpdatePromoOrderStatus(c, arg.OrderID, consts.PromoOrderRefund); err != nil {
err = ecode.TicketUpdatePromoOrderFail
return
}
s.dao.DelCachePromoGroup(c, promoOrder.GroupID)
s.dao.DelCachePromoOrder(c, promoOrder.OrderID)
s.dao.DelCachePromoOrders(c, promoOrder.GroupID)
res = &rpcV1.OrderID{OrderID: promoOrder.OrderID}
return
}

View File

@@ -0,0 +1,90 @@
package service
import (
"context"
rpcV1 "go-common/app/service/openplatform/ticket-sales/api/grpc/v1"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_GetPromoOrder(t *testing.T) {
Convey("GetPromoOrder", t, func() {
res, err := svr.GetPromoOrder(context.TODO(), 1)
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestService_CheckCreateStatus(t *testing.T) {
Convey("CheckCreateStatus", t, func() {
res, err := svr.CheckCreateStatus(context.TODO(), &rpcV1.CheckCreatePromoOrderRequest{UID: 112, SKUID: 23, PromoID: 1})
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestService_GetUserJoinPromoOrder(t *testing.T) {
Convey("GetUserJoinPromoOrder", t, func() {
res, err := svr.GetUserJoinPromoOrder(context.TODO(), 1, 2, 0, 1112)
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestService_CreatePromoOrder(t *testing.T) {
Convey("CreatePromoOrder", t, func() {
res, err := svr.CreatePromoOrder(context.TODO(),
&rpcV1.CreatePromoOrderRequest{
PromoID: 1,
OrderID: 1,
GroupID: 0,
UID: 1,
PromoSKUID: 1,
Ctime: 1,
PayMoney: 1,
})
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestService_CancelOrder(t *testing.T) {
Convey("CancelOrder", t, func() {
res, err := svr.CancelOrder(context.TODO(), &rpcV1.OrderID{OrderID: 1})
So(err, ShouldNotBeNil)
t.Logf("res:%v", res)
})
}
func TestService_PromoPayNotify(t *testing.T) {
Convey("PromoPayNotify", t, func() {
res, err := svr.PromoPayNotify(context.TODO(), &rpcV1.OrderID{OrderID: 1})
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestService_CheckIssue(t *testing.T) {
Convey("CheckIssue", t, func() {
res, err := svr.CheckIssue(context.TODO(), &rpcV1.OrderID{OrderID: 1})
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestService_FinishIssue(t *testing.T) {
Convey("FinishIssue", t, func() {
res, err := svr.FinishIssue(context.TODO(), &rpcV1.FinishIssueRequest{PromoID: 1, GroupID: 1})
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestService_PromoRefundNotify(t *testing.T) {
Convey("PromoRefundNotify", t, func() {
res, err := svr.PromoRefundNotify(context.TODO(), &rpcV1.OrderID{OrderID: 1})
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}

View File

@@ -0,0 +1,57 @@
package service
import (
"context"
rpcV1 "go-common/app/service/openplatform/ticket-sales/api/grpc/v1"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_GetPromo(t *testing.T) {
Convey("GetPromo", t, func() {
res, err := svr.GetPromo(context.TODO(), &rpcV1.PromoID{PromoID: 1})
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestService_CreatePromo(t *testing.T) {
Convey("CreatePromo", t, func() {
res, err := svr.CreatePromo(context.TODO(), &rpcV1.CreatePromoRequest{PromoID: 1})
So(err, ShouldNotBeNil)
t.Logf("res:%v", res)
})
}
func TestService_HasPromoOfSKU(t *testing.T) {
Convey("HasPromoOfSKU", t, func() {
res, err := svr.HasPromoOfSKU(context.TODO(), 1, 1, 1)
So(err, ShouldBeNil)
t.Logf("res:%v", res)
})
}
func TestService_OperatePromo(t *testing.T) {
Convey("OperatePromo", t, func() {
res, err := svr.OperatePromo(context.TODO(), &rpcV1.OperatePromoRequest{PromoID: 1, OperateType: 1})
So(err, ShouldNotBeNil)
t.Logf("res:%v", res)
})
}
func TestService_CheckPromoStatus(t *testing.T) {
Convey("CheckPromoStatus", t, func() {
res, err := svr.CheckPromoStatus(context.TODO(), 1, 1)
So(err, ShouldNotBeNil)
t.Logf("res:%v", res)
})
}
func TestService_EditPromo(t *testing.T) {
Convey("EditPromo", t, func() {
res, err := svr.EditPromo(context.TODO(), &rpcV1.EditPromoRequest{PromoID: 1, Amount: 100})
So(err, ShouldNotBeNil)
t.Logf("res:%v", res)
})
}

Some files were not shown because too many files have changed in this diff Show More