多笔立减
This commit is contained in:
parent
e149fd412c
commit
5be1f63f04
|
|
@ -13,6 +13,7 @@ type OrderBo struct {
|
||||||
VoucherNo string
|
VoucherNo string
|
||||||
ProductNo string
|
ProductNo string
|
||||||
BatchNo string
|
BatchNo string
|
||||||
|
ActivityId string
|
||||||
Account string
|
Account string
|
||||||
Type vo.OrderType
|
Type vo.OrderType
|
||||||
AccountType vo.OrderAccountType
|
AccountType vo.OrderAccountType
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ type ProductBo struct {
|
||||||
ProductNo string
|
ProductNo string
|
||||||
BatchName string
|
BatchName string
|
||||||
BatchNo string
|
BatchNo string
|
||||||
|
ActivityId string
|
||||||
MchId string
|
MchId string
|
||||||
Channel vo.Channel
|
Channel vo.Channel
|
||||||
AvailableType vo.AvailableType
|
AvailableType vo.AvailableType
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ func (this *VoucherBiz) order(ctx context.Context, req *bo.OrderCreateReqBo, pro
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
voucherNo, err := this.WechatCpnRepo.Order(ctx, order)
|
voucherNo, err := this.send(ctx, order)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err3 := this.fail(ctx, order, err); err3 != nil {
|
if err3 := this.fail(ctx, order, err); err3 != nil {
|
||||||
return nil, err3
|
return nil, err3
|
||||||
|
|
@ -62,9 +62,18 @@ func (this *VoucherBiz) order(ctx context.Context, req *bo.OrderCreateReqBo, pro
|
||||||
return order, nil
|
return order, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *VoucherBiz) send(ctx context.Context, order *bo.OrderBo) (string, error) {
|
||||||
|
|
||||||
|
if order.ActivityId == "" {
|
||||||
|
return this.WechatCpnRepo.Order(ctx, order)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.BankMultiActivityRepo.Order(order)
|
||||||
|
}
|
||||||
|
|
||||||
func (this *VoucherBiz) orderRetry(ctx context.Context, order *bo.OrderBo) error {
|
func (this *VoucherBiz) orderRetry(ctx context.Context, order *bo.OrderBo) error {
|
||||||
|
|
||||||
voucherNo, err := this.WechatCpnRepo.Order(ctx, order)
|
voucherNo, err := this.send(ctx, order)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err3 := this.fail(ctx, order, err); err3 != nil {
|
if err3 := this.fail(ctx, order, err); err3 != nil {
|
||||||
|
|
@ -92,6 +101,8 @@ func (this *VoucherBiz) create(ctx context.Context, req *bo.OrderCreateReqBo, pr
|
||||||
Type: req.Type,
|
Type: req.Type,
|
||||||
Status: vo.OrderStatusIng, // 同步发放,状态至为发放中
|
Status: vo.OrderStatusIng, // 同步发放,状态至为发放中
|
||||||
Attach: req.Attach,
|
Attach: req.Attach,
|
||||||
|
|
||||||
|
ActivityId: product.ActivityId, // 多笔立减活动
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.OrderRepo.Create(ctx, o)
|
return this.OrderRepo.Create(ctx, o)
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ type VoucherBiz struct {
|
||||||
MqSendMixRepo mixrepos.MQSendMixRepo
|
MqSendMixRepo mixrepos.MQSendMixRepo
|
||||||
GenerateMixRepo mixrepos.GenerateMixRepo
|
GenerateMixRepo mixrepos.GenerateMixRepo
|
||||||
WechatCpnRepo wechatrepo.WechatCpnRepo
|
WechatCpnRepo wechatrepo.WechatCpnRepo
|
||||||
|
BankMultiActivityRepo wechatrepo.BankMultiActivityRepo
|
||||||
DingMixRepo mixrepos.DingMixRepo
|
DingMixRepo mixrepos.DingMixRepo
|
||||||
CmbMixRepo mixrepos.CmbMixRepo
|
CmbMixRepo mixrepos.CmbMixRepo
|
||||||
SmsMixRepo mixrepos.SmsMixRepo
|
SmsMixRepo mixrepos.SmsMixRepo
|
||||||
|
|
@ -42,6 +43,7 @@ func NewVoucherBiz(
|
||||||
MqSendMixRepo mixrepos.MQSendMixRepo,
|
MqSendMixRepo mixrepos.MQSendMixRepo,
|
||||||
GenerateMixRepo mixrepos.GenerateMixRepo,
|
GenerateMixRepo mixrepos.GenerateMixRepo,
|
||||||
WechatCpnRepo wechatrepo.WechatCpnRepo,
|
WechatCpnRepo wechatrepo.WechatCpnRepo,
|
||||||
|
BankMultiActivityRepo wechatrepo.BankMultiActivityRepo,
|
||||||
DingMixRepo mixrepos.DingMixRepo,
|
DingMixRepo mixrepos.DingMixRepo,
|
||||||
CmbMixRepo mixrepos.CmbMixRepo,
|
CmbMixRepo mixrepos.CmbMixRepo,
|
||||||
SmsMixRepo mixrepos.SmsMixRepo,
|
SmsMixRepo mixrepos.SmsMixRepo,
|
||||||
|
|
@ -58,6 +60,7 @@ func NewVoucherBiz(
|
||||||
MqSendMixRepo: MqSendMixRepo,
|
MqSendMixRepo: MqSendMixRepo,
|
||||||
GenerateMixRepo: GenerateMixRepo,
|
GenerateMixRepo: GenerateMixRepo,
|
||||||
WechatCpnRepo: WechatCpnRepo,
|
WechatCpnRepo: WechatCpnRepo,
|
||||||
|
BankMultiActivityRepo: BankMultiActivityRepo,
|
||||||
DingMixRepo: DingMixRepo,
|
DingMixRepo: DingMixRepo,
|
||||||
CmbMixRepo: CmbMixRepo,
|
CmbMixRepo: CmbMixRepo,
|
||||||
SmsMixRepo: SmsMixRepo,
|
SmsMixRepo: SmsMixRepo,
|
||||||
|
|
|
||||||
|
|
@ -127,10 +127,14 @@ func (this *VoucherBiz) cmbNotify(ctx context.Context, orderId uint64) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if orderNotify, err := this.Cmb.Notify(ctx, order); err != nil {
|
if order.ActivityId == "" {
|
||||||
|
return nil // 多笔立减活动,不做通知(?不知道有没有核销通知,多笔核销情况未知)
|
||||||
|
}
|
||||||
|
|
||||||
if !errPb.IsNeedRetryNotify(err) {
|
if orderNotify, err2 := this.Cmb.Notify(ctx, order); err != nil {
|
||||||
return err
|
|
||||||
|
if !errPb.IsNeedRetryNotify(err2) {
|
||||||
|
return err2
|
||||||
}
|
}
|
||||||
|
|
||||||
// 第一次通知失败重试入队
|
// 第一次通知失败重试入队
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package wechatrepo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"voucher/internal/biz/bo"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BankMultiActivityRepo interface {
|
||||||
|
Order(order *bo.OrderBo) (couponId string, err error)
|
||||||
|
}
|
||||||
|
|
@ -408,6 +408,7 @@ type Wechat struct {
|
||||||
MchID string `protobuf:"bytes,1,opt,name=mchID,proto3" json:"mchID,omitempty"`
|
MchID string `protobuf:"bytes,1,opt,name=mchID,proto3" json:"mchID,omitempty"`
|
||||||
MchCertificateSerialNumber string `protobuf:"bytes,2,opt,name=mchCertificateSerialNumber,proto3" json:"mchCertificateSerialNumber,omitempty"`
|
MchCertificateSerialNumber string `protobuf:"bytes,2,opt,name=mchCertificateSerialNumber,proto3" json:"mchCertificateSerialNumber,omitempty"`
|
||||||
WechatPayPublicKeyID string `protobuf:"bytes,3,opt,name=wechatPayPublicKeyID,proto3" json:"wechatPayPublicKeyID,omitempty"`
|
WechatPayPublicKeyID string `protobuf:"bytes,3,opt,name=wechatPayPublicKeyID,proto3" json:"wechatPayPublicKeyID,omitempty"`
|
||||||
|
Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Wechat) Reset() {
|
func (x *Wechat) Reset() {
|
||||||
|
|
@ -463,6 +464,13 @@ func (x *Wechat) GetWechatPayPublicKeyID() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *Wechat) GetName() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
type Cmb struct {
|
type Cmb struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
|
@ -1592,7 +1600,7 @@ var file_conf_conf_proto_rawDesc = []byte{
|
||||||
0x6f, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x65, 0x43, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x69,
|
0x6f, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x65, 0x43, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x69,
|
||||||
0x73, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x18, 0x04, 0x20,
|
0x73, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x18, 0x04, 0x20,
|
||||||
0x01, 0x28, 0x08, 0x52, 0x0e, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x75,
|
0x01, 0x28, 0x08, 0x52, 0x0e, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x75,
|
||||||
0x6d, 0x65, 0x72, 0x22, 0x92, 0x01, 0x0a, 0x06, 0x57, 0x65, 0x63, 0x68, 0x61, 0x74, 0x12, 0x14,
|
0x6d, 0x65, 0x72, 0x22, 0xa6, 0x01, 0x0a, 0x06, 0x57, 0x65, 0x63, 0x68, 0x61, 0x74, 0x12, 0x14,
|
||||||
0x0a, 0x05, 0x6d, 0x63, 0x68, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d,
|
0x0a, 0x05, 0x6d, 0x63, 0x68, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d,
|
||||||
0x63, 0x68, 0x49, 0x44, 0x12, 0x3e, 0x0a, 0x1a, 0x6d, 0x63, 0x68, 0x43, 0x65, 0x72, 0x74, 0x69,
|
0x63, 0x68, 0x49, 0x44, 0x12, 0x3e, 0x0a, 0x1a, 0x6d, 0x63, 0x68, 0x43, 0x65, 0x72, 0x74, 0x69,
|
||||||
0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x4e, 0x75, 0x6d, 0x62,
|
0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x4e, 0x75, 0x6d, 0x62,
|
||||||
|
|
@ -1601,121 +1609,122 @@ var file_conf_conf_proto_rawDesc = []byte{
|
||||||
0x6d, 0x62, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x14, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x50, 0x61,
|
0x6d, 0x62, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x14, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x50, 0x61,
|
||||||
0x79, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01,
|
0x79, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01,
|
||||||
0x28, 0x09, 0x52, 0x14, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x50, 0x61, 0x79, 0x50, 0x75, 0x62,
|
0x28, 0x09, 0x52, 0x14, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x50, 0x61, 0x79, 0x50, 0x75, 0x62,
|
||||||
0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x49, 0x44, 0x22, 0xd7, 0x02, 0x0a, 0x03, 0x43, 0x6d, 0x62,
|
0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
|
||||||
0x12, 0x10, 0x0a, 0x03, 0x6d, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d,
|
0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xd7, 0x02, 0x0a,
|
||||||
0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
|
0x03, 0x43, 0x6d, 0x62, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
0x03, 0x61, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6d, 0x32, 0x50, 0x72, 0x6b, 0x18, 0x03,
|
0x09, 0x52, 0x03, 0x6d, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x69, 0x64, 0x18, 0x02, 0x20,
|
||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6d, 0x32, 0x50, 0x72, 0x6b, 0x12, 0x16, 0x0a, 0x06,
|
0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6d, 0x32, 0x50,
|
||||||
0x73, 0x6d, 0x32, 0x50, 0x75, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6d,
|
0x72, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6d, 0x32, 0x50, 0x72, 0x6b,
|
||||||
0x32, 0x50, 0x75, 0x6b, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6d, 0x62, 0x53, 0x6d, 0x32, 0x50, 0x69,
|
0x12, 0x16, 0x0a, 0x06, 0x73, 0x6d, 0x32, 0x50, 0x75, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
|
||||||
0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6d, 0x62, 0x53, 0x6d, 0x32, 0x50,
|
0x52, 0x06, 0x73, 0x6d, 0x32, 0x50, 0x75, 0x6b, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6d, 0x62, 0x53,
|
||||||
0x69, 0x6b, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6d, 0x62, 0x53, 0x6d, 0x32, 0x50, 0x75, 0x6b, 0x18,
|
0x6d, 0x32, 0x50, 0x69, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6d, 0x62,
|
||||||
0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6d, 0x62, 0x53, 0x6d, 0x32, 0x50, 0x75, 0x6b,
|
0x53, 0x6d, 0x32, 0x50, 0x69, 0x6b, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6d, 0x62, 0x53, 0x6d, 0x32,
|
||||||
0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x07, 0x20, 0x01,
|
0x50, 0x75, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6d, 0x62, 0x53, 0x6d,
|
||||||
0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x20, 0x0a, 0x0b,
|
0x32, 0x50, 0x75, 0x6b, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x41, 0x6c, 0x69, 0x61, 0x73,
|
||||||
0x63, 0x6d, 0x62, 0x4b, 0x65, 0x79, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28,
|
0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x41, 0x6c, 0x69, 0x61, 0x73,
|
||||||
0x09, 0x52, 0x0b, 0x63, 0x6d, 0x62, 0x4b, 0x65, 0x79, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x14,
|
0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6d, 0x62, 0x4b, 0x65, 0x79, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x18,
|
||||||
0x0a, 0x05, 0x6f, 0x72, 0x67, 0x4e, 0x6f, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f,
|
0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6d, 0x62, 0x4b, 0x65, 0x79, 0x41, 0x6c, 0x69,
|
||||||
0x72, 0x67, 0x4e, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x72,
|
0x61, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x72, 0x67, 0x4e, 0x6f, 0x18, 0x09, 0x20, 0x01, 0x28,
|
||||||
0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55,
|
0x09, 0x52, 0x05, 0x6f, 0x72, 0x67, 0x4e, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x6f, 0x74, 0x69,
|
||||||
0x72, 0x6c, 0x12, 0x28, 0x0a, 0x0f, 0x6e, 0x6f, 0x74, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x72,
|
0x66, 0x79, 0x55, 0x72, 0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x6f, 0x74,
|
||||||
0x74, 0x44, 0x61, 0x79, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x6e, 0x6f, 0x74,
|
0x69, 0x66, 0x79, 0x55, 0x72, 0x6c, 0x12, 0x28, 0x0a, 0x0f, 0x6e, 0x6f, 0x74, 0x69, 0x63, 0x65,
|
||||||
0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x44, 0x61, 0x79, 0x73, 0x12, 0x24, 0x0a, 0x0d,
|
0x53, 0x74, 0x61, 0x72, 0x74, 0x44, 0x61, 0x79, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52,
|
||||||
0x6e, 0x6f, 0x74, 0x69, 0x63, 0x65, 0x45, 0x6e, 0x64, 0x44, 0x61, 0x79, 0x73, 0x18, 0x0c, 0x20,
|
0x0f, 0x6e, 0x6f, 0x74, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x44, 0x61, 0x79, 0x73,
|
||||||
0x01, 0x28, 0x03, 0x52, 0x0d, 0x6e, 0x6f, 0x74, 0x69, 0x63, 0x65, 0x45, 0x6e, 0x64, 0x44, 0x61,
|
0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x6f, 0x74, 0x69, 0x63, 0x65, 0x45, 0x6e, 0x64, 0x44, 0x61, 0x79,
|
||||||
0x79, 0x73, 0x22, 0xc6, 0x02, 0x0a, 0x0e, 0x57, 0x65, 0x63, 0x68, 0x61, 0x74, 0x4e, 0x6f, 0x74,
|
0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6e, 0x6f, 0x74, 0x69, 0x63, 0x65, 0x45,
|
||||||
0x69, 0x66, 0x79, 0x4d, 0x51, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b,
|
0x6e, 0x64, 0x44, 0x61, 0x79, 0x73, 0x22, 0xc6, 0x02, 0x0a, 0x0e, 0x57, 0x65, 0x63, 0x68, 0x61,
|
||||||
0x65, 0x79, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65,
|
0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x4d, 0x51, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x63, 0x63,
|
||||||
0x73, 0x73, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x61, 0x63, 0x63, 0x65, 0x73,
|
0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
|
||||||
0x73, 0x4b, 0x65, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x61,
|
||||||
0x52, 0x0f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65,
|
0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02,
|
||||||
0x74, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x53,
|
||||||
0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1a, 0x0a,
|
0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x50, 0x6f, 0x69, 0x6e,
|
||||||
0x08, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
|
0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x50, 0x6f, 0x69, 0x6e,
|
||||||
0x08, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x6e, 0x73,
|
0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x04, 0x20,
|
||||||
0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69,
|
0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1e, 0x0a,
|
||||||
0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70,
|
0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28,
|
||||||
0x69, 0x63, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12,
|
0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x14, 0x0a,
|
||||||
0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61,
|
0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f,
|
||||||
0x67, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x18, 0x08, 0x20, 0x01,
|
0x70, 0x69, 0x63, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09,
|
||||||
0x28, 0x09, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x26, 0x0a, 0x0e, 0x72,
|
0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64,
|
||||||
0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x61, 0x67, 0x55, 0x72, 0x6c, 0x18, 0x0a, 0x20,
|
0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12,
|
||||||
0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x61, 0x67,
|
0x26, 0x0a, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x61, 0x67, 0x55, 0x72,
|
||||||
0x55, 0x72, 0x6c, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e,
|
0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65,
|
||||||
0x73, 0x75, 0x6d, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x69, 0x73, 0x4f,
|
0x72, 0x54, 0x61, 0x67, 0x55, 0x72, 0x6c, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x73, 0x4f, 0x70, 0x65,
|
||||||
0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x22, 0x9b, 0x01, 0x0a, 0x05,
|
0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||||
0x41, 0x6c, 0x61, 0x72, 0x6d, 0x12, 0x1e, 0x0a, 0x0a, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b,
|
0x0e, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x22,
|
||||||
0x55, 0x52, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x65, 0x62, 0x68, 0x6f,
|
0x9b, 0x01, 0x0a, 0x05, 0x41, 0x6c, 0x61, 0x72, 0x6d, 0x12, 0x1e, 0x0a, 0x0a, 0x77, 0x65, 0x62,
|
||||||
0x6f, 0x6b, 0x55, 0x52, 0x4c, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18,
|
0x68, 0x6f, 0x6f, 0x6b, 0x55, 0x52, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77,
|
||||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x14, 0x0a,
|
0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x55, 0x52, 0x4c, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63,
|
||||||
0x05, 0x61, 0x74, 0x41, 0x6c, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x74,
|
0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65,
|
||||||
0x41, 0x6c, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x74, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x73,
|
0x74, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x74, 0x41, 0x6c, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08,
|
||||||
0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x74, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65,
|
0x52, 0x05, 0x61, 0x74, 0x41, 0x6c, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x74, 0x4d, 0x6f, 0x62,
|
||||||
0x73, 0x12, 0x26, 0x0a, 0x0e, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x62, 0x69,
|
0x69, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x74, 0x4d, 0x6f,
|
||||||
0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x77, 0x61, 0x72, 0x6e, 0x69,
|
0x62, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67,
|
||||||
0x6e, 0x67, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x73, 0x22, 0x84, 0x02, 0x0a, 0x04, 0x43, 0x72,
|
0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x77,
|
||||||
0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01,
|
0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x73, 0x22, 0x84, 0x02,
|
||||||
0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x44, 0x0a, 0x0a, 0x63, 0x6f,
|
0x0a, 0x04, 0x43, 0x72, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e,
|
||||||
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x61, 0x70, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24,
|
0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x44,
|
||||||
0x2e, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
|
0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x61, 0x70, 0x18, 0x02, 0x20, 0x03,
|
||||||
0x43, 0x72, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x61, 0x70, 0x45,
|
0x28, 0x0b, 0x32, 0x24, 0x2e, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e,
|
||||||
0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x61, 0x70,
|
0x66, 0x69, 0x67, 0x2e, 0x43, 0x72, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
||||||
0x1a, 0x3e, 0x0a, 0x0a, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x61, 0x70, 0x12, 0x16,
|
0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
|
||||||
0x0a, 0x06, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06,
|
0x64, 0x4d, 0x61, 0x70, 0x1a, 0x3e, 0x0a, 0x0a, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d,
|
||||||
0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
|
0x61, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01,
|
||||||
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f,
|
||||||
0x1a, 0x5e, 0x0a, 0x0f, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x61, 0x70, 0x45, 0x6e,
|
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d,
|
||||||
0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
0x6d, 0x61, 0x6e, 0x64, 0x1a, 0x5e, 0x0a, 0x0f, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d,
|
||||||
0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x35, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
|
0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
|
||||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x35, 0x0a, 0x05, 0x76, 0x61, 0x6c,
|
||||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x43, 0x72, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61,
|
0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x6f, 0x75, 0x63, 0x68,
|
||||||
0x6e, 0x64, 0x4d, 0x61, 0x70, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
|
0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x43, 0x72, 0x6f, 0x6e, 0x2e, 0x43,
|
||||||
0x22, 0xbe, 0x03, 0x0a, 0x05, 0x52, 0x64, 0x73, 0x4d, 0x51, 0x12, 0x3d, 0x0a, 0x0b, 0x77, 0x65,
|
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x61, 0x70, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
||||||
0x63, 0x68, 0x61, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
0x3a, 0x02, 0x38, 0x01, 0x22, 0xbe, 0x03, 0x0a, 0x05, 0x52, 0x64, 0x73, 0x4d, 0x51, 0x12, 0x3d,
|
||||||
0x1b, 0x2e, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
0x0a, 0x0b, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x18, 0x01, 0x20,
|
||||||
0x2e, 0x52, 0x64, 0x73, 0x4d, 0x51, 0x2e, 0x51, 0x75, 0x65, 0x75, 0x65, 0x52, 0x0b, 0x77, 0x65,
|
0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63, 0x6f,
|
||||||
0x63, 0x68, 0x61, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x4f, 0x0a, 0x14, 0x77, 0x65, 0x63,
|
0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x64, 0x73, 0x4d, 0x51, 0x2e, 0x51, 0x75, 0x65, 0x75, 0x65,
|
||||||
0x68, 0x61, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x72,
|
0x52, 0x0b, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x4f, 0x0a,
|
||||||
0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65,
|
0x14, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x6c, 0x69, 0x63, 0x65,
|
||||||
0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x64, 0x73, 0x4d, 0x51, 0x2e, 0x51,
|
0x51, 0x75, 0x65, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x76, 0x6f,
|
||||||
0x75, 0x65, 0x75, 0x65, 0x52, 0x14, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x54, 0x69, 0x6d, 0x65,
|
0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x64, 0x73,
|
||||||
0x53, 0x6c, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x3d, 0x0a, 0x0b, 0x77, 0x65,
|
0x4d, 0x51, 0x2e, 0x51, 0x75, 0x65, 0x75, 0x65, 0x52, 0x14, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74,
|
||||||
0x63, 0x68, 0x61, 0x74, 0x52, 0x65, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
0x54, 0x69, 0x6d, 0x65, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x3d,
|
||||||
0x1b, 0x2e, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
0x0a, 0x0b, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x52, 0x65, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20,
|
||||||
0x2e, 0x52, 0x64, 0x73, 0x4d, 0x51, 0x2e, 0x51, 0x75, 0x65, 0x75, 0x65, 0x52, 0x0b, 0x77, 0x65,
|
0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63, 0x6f,
|
||||||
0x63, 0x68, 0x61, 0x74, 0x52, 0x65, 0x74, 0x72, 0x79, 0x12, 0x3d, 0x0a, 0x0b, 0x72, 0x65, 0x74,
|
0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x64, 0x73, 0x4d, 0x51, 0x2e, 0x51, 0x75, 0x65, 0x75, 0x65,
|
||||||
0x72, 0x79, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b,
|
0x52, 0x0b, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x52, 0x65, 0x74, 0x72, 0x79, 0x12, 0x3d, 0x0a,
|
||||||
0x2e, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
|
0x0b, 0x72, 0x65, 0x74, 0x72, 0x79, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x18, 0x04, 0x20, 0x01,
|
||||||
0x52, 0x64, 0x73, 0x4d, 0x51, 0x2e, 0x51, 0x75, 0x65, 0x75, 0x65, 0x52, 0x0b, 0x72, 0x65, 0x74,
|
0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e,
|
||||||
0x72, 0x79, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x1a, 0xa6, 0x01, 0x0a, 0x05, 0x51, 0x75, 0x65,
|
0x66, 0x69, 0x67, 0x2e, 0x52, 0x64, 0x73, 0x4d, 0x51, 0x2e, 0x51, 0x75, 0x65, 0x75, 0x65, 0x52,
|
||||||
0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
0x0b, 0x72, 0x65, 0x74, 0x72, 0x79, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x1a, 0xa6, 0x01, 0x0a,
|
||||||
0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e,
|
0x05, 0x51, 0x75, 0x65, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
|
||||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x1a,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x73,
|
||||||
0x0a, 0x08, 0x72, 0x65, 0x74, 0x72, 0x79, 0x4e, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d,
|
0x4f, 0x70, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x4f, 0x70,
|
||||||
0x52, 0x08, 0x72, 0x65, 0x74, 0x72, 0x79, 0x4e, 0x75, 0x6d, 0x12, 0x1e, 0x0a, 0x0a, 0x6e, 0x75,
|
0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x74, 0x72, 0x79, 0x4e, 0x75, 0x6d, 0x18, 0x03,
|
||||||
0x6d, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a,
|
0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x72, 0x65, 0x74, 0x72, 0x79, 0x4e, 0x75, 0x6d, 0x12, 0x1e,
|
||||||
0x6e, 0x75, 0x6d, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x12, 0x35, 0x0a, 0x08, 0x77, 0x61,
|
0x0a, 0x0a, 0x6e, 0x75, 0x6d, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01,
|
||||||
0x69, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67,
|
0x28, 0x0d, 0x52, 0x0a, 0x6e, 0x75, 0x6d, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x12, 0x35,
|
||||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44,
|
0x0a, 0x08, 0x77, 0x61, 0x69, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b,
|
||||||
0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x77, 0x61, 0x69, 0x74, 0x54, 0x69, 0x6d,
|
0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||||
0x65, 0x22, 0xb9, 0x01, 0x0a, 0x09, 0x41, 0x6c, 0x69, 0x59, 0x75, 0x6e, 0x53, 0x6d, 0x73, 0x12,
|
0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x77, 0x61, 0x69,
|
||||||
0x20, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x18, 0x01,
|
0x74, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xb9, 0x01, 0x0a, 0x09, 0x41, 0x6c, 0x69, 0x59, 0x75, 0x6e,
|
||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x49,
|
0x53, 0x6d, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79,
|
||||||
0x64, 0x12, 0x28, 0x0a, 0x0f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x53, 0x65,
|
0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73,
|
||||||
0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x61, 0x63, 0x63, 0x65,
|
0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b,
|
||||||
0x73, 0x73, 0x4b, 0x65, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x65,
|
0x65, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f,
|
||||||
0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65,
|
0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12,
|
||||||
0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x69, 0x67, 0x6e, 0x4e,
|
0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||||
0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x69, 0x67, 0x6e, 0x4e,
|
0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73,
|
||||||
0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x57,
|
0x69, 0x67, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73,
|
||||||
0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x65,
|
0x69, 0x67, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x74, 0x65, 0x6d, 0x70, 0x6c,
|
||||||
0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x22, 0x3a, 0x0a,
|
0x61, 0x74, 0x65, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,
|
||||||
0x04, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73,
|
0x52, 0x0f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e,
|
||||||
0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x62, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73,
|
0x67, 0x22, 0x3a, 0x0a, 0x04, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x75, 0x73,
|
||||||
0x73, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28,
|
0x69, 0x6e, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x62, 0x75, 0x73,
|
||||||
0x09, 0x52, 0x06, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x42, 0x17, 0x5a, 0x15, 0x76, 0x6f, 0x75,
|
0x69, 0x6e, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18,
|
||||||
0x63, 0x68, 0x65, 0x72, 0x2f, 0x63, 0x70, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x3b, 0x63, 0x6f,
|
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x42, 0x17, 0x5a,
|
||||||
0x6e, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x15, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2f, 0x63, 0x70, 0x6e, 0x2f, 0x63, 0x6f, 0x6e,
|
||||||
|
0x66, 0x3b, 0x63, 0x6f, 0x6e, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@ message Wechat {
|
||||||
string mchID = 1;
|
string mchID = 1;
|
||||||
string mchCertificateSerialNumber = 2;
|
string mchCertificateSerialNumber = 2;
|
||||||
string wechatPayPublicKeyID = 3;
|
string wechatPayPublicKeyID = 3;
|
||||||
|
string name = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Cmb {
|
message Cmb {
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ type Order struct {
|
||||||
OutBizNo string `gorm:"column:out_biz_no;not null;comment:外部交易号" json:"out_biz_no"` // 外部交易号
|
OutBizNo string `gorm:"column:out_biz_no;not null;comment:外部交易号" json:"out_biz_no"` // 外部交易号
|
||||||
ProductNo string `gorm:"column:product_no;not null;comment:商品编号" json:"product_no"` // 商品编号
|
ProductNo string `gorm:"column:product_no;not null;comment:商品编号" json:"product_no"` // 商品编号
|
||||||
BatchNo string `gorm:"column:batch_no;not null;comment:立减金批次号" json:"batch_no"` // 立减金批次号
|
BatchNo string `gorm:"column:batch_no;not null;comment:立减金批次号" json:"batch_no"` // 立减金批次号
|
||||||
|
ActivityId string `gorm:"column:activity_id;not null;comment:activity_id" json:"activity_id"` // activity_id
|
||||||
Account string `gorm:"column:account;not null;comment:充值账号" json:"account"` // 充值账号
|
Account string `gorm:"column:account;not null;comment:充值账号" json:"account"` // 充值账号
|
||||||
AccountType uint8 `gorm:"column:account_type;not null;comment:1:oepnid/userid 2:手机号" json:"account_type"` // 1:oepnid/userid 2:手机号
|
AccountType uint8 `gorm:"column:account_type;not null;comment:1:oepnid/userid 2:手机号" json:"account_type"` // 1:oepnid/userid 2:手机号
|
||||||
Type uint8 `gorm:"column:type;not null;comment:1:招行" json:"type"`
|
Type uint8 `gorm:"column:type;not null;comment:1:招行" json:"type"`
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ type OrderBak struct {
|
||||||
OutBizNo string `gorm:"column:out_biz_no;not null;comment:外部交易号" json:"out_biz_no"` // 外部交易号
|
OutBizNo string `gorm:"column:out_biz_no;not null;comment:外部交易号" json:"out_biz_no"` // 外部交易号
|
||||||
ProductNo string `gorm:"column:product_no;not null;comment:商品编号" json:"product_no"` // 商品编号
|
ProductNo string `gorm:"column:product_no;not null;comment:商品编号" json:"product_no"` // 商品编号
|
||||||
BatchNo string `gorm:"column:batch_no;not null;comment:立减金批次号" json:"batch_no"` // 立减金批次号
|
BatchNo string `gorm:"column:batch_no;not null;comment:立减金批次号" json:"batch_no"` // 立减金批次号
|
||||||
|
ActivityId string `gorm:"column:activity_id;not null;comment:activity_id" json:"activity_id"` // activity_id
|
||||||
Account string `gorm:"column:account;not null;comment:充值账号" json:"account"` // 充值账号
|
Account string `gorm:"column:account;not null;comment:充值账号" json:"account"` // 充值账号
|
||||||
AccountType uint8 `gorm:"column:account_type;not null;comment:1:oepnid/userid 2:手机号" json:"account_type"` // 1:oepnid/userid 2:手机号
|
AccountType uint8 `gorm:"column:account_type;not null;comment:1:oepnid/userid 2:手机号" json:"account_type"` // 1:oepnid/userid 2:手机号
|
||||||
Type uint8 `gorm:"column:type;not null;comment:1:招行" json:"type"`
|
Type uint8 `gorm:"column:type;not null;comment:1:招行" json:"type"`
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,13 @@ const TableNameProduct = "product"
|
||||||
// Product mapped from table <product>
|
// Product mapped from table <product>
|
||||||
type Product struct {
|
type Product struct {
|
||||||
ID int32 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
|
ID int32 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
|
||||||
Name string `gorm:"column:name;not null;comment:商品名称" json:"name"` // 商品名称
|
Name string `gorm:"column:name;not null;comment:商品名称" json:"name"` // 商品名称
|
||||||
ProductNo string `gorm:"column:product_no;not null;comment:商品编号" json:"product_no"` // 商品编号
|
ProductNo string `gorm:"column:product_no;not null;comment:商品编号" json:"product_no"` // 商品编号
|
||||||
BatchName string `gorm:"column:batch_name;not null;comment:批次名称" json:"batch_name"` // 批次名称
|
BatchName string `gorm:"column:batch_name;not null;comment:批次名称" json:"batch_name"` // 批次名称
|
||||||
BatchNo string `gorm:"column:batch_no;not null;comment:立减金批次号" json:"batch_no"` // 立减金批次号
|
BatchNo string `gorm:"column:batch_no;not null;comment:立减金批次号" json:"batch_no"` // 立减金批次号
|
||||||
MchId string `gorm:"column:mch_id;not null;comment:商户号,创建批次的商户号" json:"mch_id"` // 商户号,创建批次的商户号
|
ActivityId string `gorm:"column:activity_id;not null;comment:activity_id" json:"activity_id"` // activity_id
|
||||||
Channel uint8 `gorm:"column:channel;not null;comment:1:微信 2:支付宝" json:"channel"` // 1:微信 2:支付宝
|
MchId string `gorm:"column:mch_id;not null;comment:商户号,创建批次的商户号" json:"mch_id"` // 商户号,创建批次的商户号
|
||||||
|
Channel uint8 `gorm:"column:channel;not null;comment:1:微信 2:支付宝" json:"channel"` // 1:微信 2:支付宝
|
||||||
AvailableType uint8 `gorm:"column:available_type;not null;comment:1:固定有效期 2:动态有效期" json:"available_type"`
|
AvailableType uint8 `gorm:"column:available_type;not null;comment:1:固定有效期 2:动态有效期" json:"available_type"`
|
||||||
AvailableDays uint32 `gorm:"column:available_days;not null;comment:领取后多少天内" json:"available_days"`
|
AvailableDays uint32 `gorm:"column:available_days;not null;comment:领取后多少天内" json:"available_days"`
|
||||||
Amount int64 `gorm:"column:amount;not null;default:0" json:"amount"`
|
Amount int64 `gorm:"column:amount;not null;default:0" json:"amount"`
|
||||||
|
|
|
||||||
|
|
@ -10,4 +10,5 @@ var ProviderDataSet = wire.NewSet(
|
||||||
NewDb,
|
NewDb,
|
||||||
NewRdb,
|
NewRdb,
|
||||||
NewRocketMQ,
|
NewRocketMQ,
|
||||||
|
NewWx,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ func (p *OrderRepoImpl) DB(ctx context.Context) *gorm.DB {
|
||||||
|
|
||||||
func (p *OrderRepoImpl) SpecifyFindInBatches(ctx context.Context, req *bo.FindInBatchesBo, fun func(ctx context.Context, rows []*bo.OrderBo) error) error {
|
func (p *OrderRepoImpl) SpecifyFindInBatches(ctx context.Context, req *bo.FindInBatchesBo, fun func(ctx context.Context, rows []*bo.OrderBo) error) error {
|
||||||
|
|
||||||
tx := p.DB(ctx)
|
tx := p.DB(ctx).Where("activity_id = ''")
|
||||||
|
|
||||||
if req.ProductNo != "" {
|
if req.ProductNo != "" {
|
||||||
tx = tx.Where("product_no = ?", req.ProductNo)
|
tx = tx.Where("product_no = ?", req.ProductNo)
|
||||||
|
|
@ -71,7 +71,7 @@ func (p *OrderRepoImpl) SpecifyFindInBatches(ctx context.Context, req *bo.FindIn
|
||||||
|
|
||||||
func (p *OrderRepoImpl) FinSucByStockIdInBatches(ctx context.Context, req *do.WechatQuery, fun func(ctx context.Context, rows []*bo.OrderBo) error) error {
|
func (p *OrderRepoImpl) FinSucByStockIdInBatches(ctx context.Context, req *do.WechatQuery, fun func(ctx context.Context, rows []*bo.OrderBo) error) error {
|
||||||
|
|
||||||
tx := p.DB(ctx).Where("status = ?", vo.OrderStatusSuccess.GetValue())
|
tx := p.DB(ctx).Where("status = ?", vo.OrderStatusSuccess.GetValue()).Where("activity_id = ''")
|
||||||
|
|
||||||
if req.ProductNo != "" {
|
if req.ProductNo != "" {
|
||||||
tx = tx.Where("product_no = ?", req.ProductNo)
|
tx = tx.Where("product_no = ?", req.ProductNo)
|
||||||
|
|
@ -144,6 +144,7 @@ func (p *OrderRepoImpl) FindInBatches(ctx context.Context, req *bo.FindInBatches
|
||||||
var results = make([]*model.Order, 0)
|
var results = make([]*model.Order, 0)
|
||||||
|
|
||||||
result := p.DB(ctx).
|
result := p.DB(ctx).
|
||||||
|
Where("activity_id = ''").
|
||||||
Where("status IN (?)", []uint8{vo.OrderStatusSuccess.GetValue(), vo.OrderStatusUse.GetValue()}).
|
Where("status IN (?)", []uint8{vo.OrderStatusSuccess.GetValue(), vo.OrderStatusUse.GetValue()}).
|
||||||
Where("receive_success_time BETWEEN ? AND ?", req.StartTime, req.EndTime).
|
Where("receive_success_time BETWEEN ? AND ?", req.StartTime, req.EndTime).
|
||||||
FindInBatches(&results, 100, func(tx *gorm.DB, batch int) error {
|
FindInBatches(&results, 100, func(tx *gorm.DB, batch int) error {
|
||||||
|
|
@ -180,6 +181,8 @@ func (p *OrderRepoImpl) Create(ctx context.Context, req *bo.OrderBo) (*bo.OrderB
|
||||||
Attach: req.Attach,
|
Attach: req.Attach,
|
||||||
CreateTime: &now,
|
CreateTime: &now,
|
||||||
UpdateTime: &now,
|
UpdateTime: &now,
|
||||||
|
|
||||||
|
ActivityId: req.ActivityId,
|
||||||
}
|
}
|
||||||
|
|
||||||
tx := p.DB(ctx).Create(info)
|
tx := p.DB(ctx).Create(info)
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ func (p *OrderBakRepoImpl) DB(ctx context.Context) *gorm.DB {
|
||||||
|
|
||||||
func (p *OrderBakRepoImpl) SpecifyFindInBatches(ctx context.Context, req *bo.FindInBatchesBo, fun func(ctx context.Context, rows []*bo.OrderBo) error) error {
|
func (p *OrderBakRepoImpl) SpecifyFindInBatches(ctx context.Context, req *bo.FindInBatchesBo, fun func(ctx context.Context, rows []*bo.OrderBo) error) error {
|
||||||
|
|
||||||
tx := p.DB(ctx)
|
tx := p.DB(ctx).Where("activity_id = ''")
|
||||||
|
|
||||||
if req.ProductNo != "" {
|
if req.ProductNo != "" {
|
||||||
tx = tx.Where("product_no = ?", req.ProductNo)
|
tx = tx.Where("product_no = ?", req.ProductNo)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
package wechatrepoimpl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/wechatpay-apiv3/wechatpay-go/core"
|
||||||
|
"voucher/internal/biz/bo"
|
||||||
|
"voucher/internal/biz/wechatrepo"
|
||||||
|
"voucher/internal/conf"
|
||||||
|
"voucher/internal/data"
|
||||||
|
"voucher/internal/pkg/wechat/srv/marketing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BankMultiActivityImpl struct {
|
||||||
|
bc *conf.Bootstrap
|
||||||
|
wx *data.Wx
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBankMultiActivityImpl(bc *conf.Bootstrap, wx *data.Wx) wechatrepo.BankMultiActivityRepo {
|
||||||
|
return &BankMultiActivityImpl{bc: bc, wx: wx}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *BankMultiActivityImpl) Order(order *bo.OrderBo) (couponId string, err error) {
|
||||||
|
|
||||||
|
req := &marketing.SendReq{
|
||||||
|
ActivityId: core.String(order.ActivityId),
|
||||||
|
StockId: core.String(order.BatchNo),
|
||||||
|
OutRequestNo: core.String(order.OrderNo),
|
||||||
|
Appid: core.String(order.AppID),
|
||||||
|
StockCreatorMchId: core.String(order.MerchantNo),
|
||||||
|
}
|
||||||
|
|
||||||
|
t, err := w.wx.Get(w.bc.Wechat.MchID)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := t.Send(order.Account, req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return *resp.CouponId, nil
|
||||||
|
}
|
||||||
|
|
@ -7,4 +7,5 @@ import (
|
||||||
// ProviderWechatReposImplSet is providers.
|
// ProviderWechatReposImplSet is providers.
|
||||||
var ProviderWechatReposImplSet = wire.NewSet(
|
var ProviderWechatReposImplSet = wire.NewSet(
|
||||||
NewCpnRepoImpl,
|
NewCpnRepoImpl,
|
||||||
|
NewBankMultiActivityImpl,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
package data
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"voucher/internal/conf"
|
||||||
|
"voucher/internal/pkg/helper"
|
||||||
|
"voucher/internal/pkg/wechat/srv/marketing"
|
||||||
|
utils2 "voucher/internal/pkg/wechat/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Wx struct {
|
||||||
|
Clients map[string]*marketing.Marketing
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWx(c *conf.Bootstrap) (*Wx, error) {
|
||||||
|
|
||||||
|
clients := make(map[string]*marketing.Marketing, 0)
|
||||||
|
|
||||||
|
client, err := buildWx(c.Wechat)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
clients[c.Wechat.MchID] = client
|
||||||
|
|
||||||
|
return &Wx{Clients: clients}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Wx) Get(mchId string) (*marketing.Marketing, error) {
|
||||||
|
|
||||||
|
if mchId == "" {
|
||||||
|
return nil, fmt.Errorf("微信商户ID不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(this.Clients) == 0 {
|
||||||
|
return nil, fmt.Errorf("微信调用client不存在")
|
||||||
|
}
|
||||||
|
|
||||||
|
if client, ok := this.Clients[mchId]; ok {
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("微信调用client不存在[%s]", mchId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildWx(wx *conf.Wechat) (*marketing.Marketing, error) {
|
||||||
|
|
||||||
|
dir, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("商户ID[%s]商户名称[%s]获取目的地址有误[%v]", wx.MchID, wx.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
filePath := fmt.Sprintf("%s/cert/wechat/%s", dir, wx.MchID)
|
||||||
|
if !helper.FileExists(filePath) {
|
||||||
|
panic(fmt.Sprintf("商户ID[%s]商户名称[%s]微信密钥证书信息不存在,请联系技术人员处理", wx.MchID, wx.Name))
|
||||||
|
}
|
||||||
|
|
||||||
|
cc, err := utils2.CreateMchConfig(
|
||||||
|
wx.MchID, // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/merchant/4013070756
|
||||||
|
wx.MchCertificateSerialNumber, // 商户API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013053053
|
||||||
|
fmt.Sprintf("%s/%s", filePath, "apiclient_key.pem"), // 商户API证书私钥文件路径,本地文件路径
|
||||||
|
wx.WechatPayPublicKeyID, // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013038816
|
||||||
|
fmt.Sprintf("%s/%s", filePath, "pub_key.pem"), // 微信支付公钥文件路径,本地文件路径
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &marketing.Marketing{MchConfig: cc}, nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
package data
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"voucher/internal/conf"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewWechat(t *testing.T) {
|
||||||
|
c := &conf.Bootstrap{
|
||||||
|
Wechat: &conf.Wechat{
|
||||||
|
MchID: "123456",
|
||||||
|
MchCertificateSerialNumber: "123456",
|
||||||
|
WechatPayPublicKeyID: "123456",
|
||||||
|
Name: "lsxd-test",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
got, err := NewWx(c)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("NewWx() error = %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.Logf("NewWx() = %v", got)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
package marketing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"voucher/internal/pkg/wechat/srv"
|
||||||
|
"voucher/internal/pkg/wechat/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
sendPath = "/v3/marketing/bank-favor/users/{openid}/bank-multi-activity"
|
||||||
|
queryPath = "/v3/marketing/bank-favor/users/{openid}/coupons/{coupon_id}"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Marketing 产品介绍 https://docs.qq.com/doc/DSUJPTEhrc0Npb2Zj?_t=1743576271598&nlc=1
|
||||||
|
type Marketing srv.Srv
|
||||||
|
|
||||||
|
// Send @link https://pay.weixin.qq.com/doc/v3/merchant/4014569793
|
||||||
|
func (srv *Marketing) Send(openId string, req *SendReq) (response *SendResp, err error) {
|
||||||
|
|
||||||
|
reqBody, err := json.Marshal(&req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
path := strings.Replace(sendPath, "{openid}", url.PathEscape(openId), -1)
|
||||||
|
|
||||||
|
respBody, err := srv.Request2(utils.Host, utils.MethodPOST, path, reqBody)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = json.Unmarshal(respBody, &response); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query @link https://pay.weixin.qq.com/doc/v3/merchant/4014569864
|
||||||
|
func (srv *Marketing) Query(appid, openId, couponId string) (response *SendResp, err error) {
|
||||||
|
|
||||||
|
path := strings.Replace(queryPath, "{openid}", url.PathEscape(openId), -1)
|
||||||
|
path = strings.Replace(path, "{coupon_id}", url.PathEscape(couponId), -1)
|
||||||
|
|
||||||
|
var uv = url.Values{}
|
||||||
|
uv.Set("appid", appid)
|
||||||
|
path += "?" + uv.Encode()
|
||||||
|
|
||||||
|
respBody, err := srv.Request2(utils.Host, utils.MethodGET, path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = json.Unmarshal(respBody, &response); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package marketing
|
||||||
|
|
||||||
|
type SendReq struct {
|
||||||
|
ActivityId *string `json:"activity_id"`
|
||||||
|
StockId *string `json:"stock_id"`
|
||||||
|
OutRequestNo *string `json:"out_request_no"`
|
||||||
|
Appid *string `json:"appid"`
|
||||||
|
StockCreatorMchId *string `json:"stock_creator_mchid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SendResp struct {
|
||||||
|
CouponId *string `json:"coupon_id"`
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package srv
|
||||||
|
|
||||||
|
import "voucher/internal/pkg/wechat/utils"
|
||||||
|
|
||||||
|
type Srv struct {
|
||||||
|
*utils.MchConfig
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,607 @@
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/sha1"
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"encoding/pem"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
Host = "https://api.mch.weixin.qq.com"
|
||||||
|
MethodGET = "GET"
|
||||||
|
MethodPOST = "POST"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MchConfig 商户信息配置,用于调用商户API
|
||||||
|
// https://pay.weixin.qq.com/doc/v3/merchant/4012716434
|
||||||
|
//
|
||||||
|
// 引用微信支付工具库 参考:https://pay.weixin.qq.com/doc/v3/merchant/4015119334
|
||||||
|
type MchConfig struct {
|
||||||
|
mchId string
|
||||||
|
certificateSerialNo string
|
||||||
|
privateKeyFilePath string
|
||||||
|
wechatPayPublicKeyId string
|
||||||
|
wechatPayPublicKeyFilePath string
|
||||||
|
privateKey *rsa.PrivateKey
|
||||||
|
wechatPayPublicKey *rsa.PublicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// MchId 商户号
|
||||||
|
func (c *MchConfig) MchId() string {
|
||||||
|
return c.mchId
|
||||||
|
}
|
||||||
|
|
||||||
|
// CertificateSerialNo 商户API证书序列号
|
||||||
|
func (c *MchConfig) CertificateSerialNo() string {
|
||||||
|
return c.certificateSerialNo
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrivateKey 商户API证书对应的私钥
|
||||||
|
func (c *MchConfig) PrivateKey() *rsa.PrivateKey {
|
||||||
|
return c.privateKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// WechatPayPublicKeyId 微信支付公钥ID
|
||||||
|
func (c *MchConfig) WechatPayPublicKeyId() string {
|
||||||
|
return c.wechatPayPublicKeyId
|
||||||
|
}
|
||||||
|
|
||||||
|
// WechatPayPublicKey 微信支付公钥
|
||||||
|
func (c *MchConfig) WechatPayPublicKey() *rsa.PublicKey {
|
||||||
|
return c.wechatPayPublicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateMchConfig MchConfig 构造函数
|
||||||
|
func CreateMchConfig(
|
||||||
|
mchId string,
|
||||||
|
certificateSerialNo string,
|
||||||
|
privateKeyFilePath string,
|
||||||
|
wechatPayPublicKeyId string,
|
||||||
|
wechatPayPublicKeyFilePath string,
|
||||||
|
) (*MchConfig, error) {
|
||||||
|
mchConfig := &MchConfig{
|
||||||
|
mchId: mchId,
|
||||||
|
certificateSerialNo: certificateSerialNo,
|
||||||
|
privateKeyFilePath: privateKeyFilePath,
|
||||||
|
wechatPayPublicKeyId: wechatPayPublicKeyId,
|
||||||
|
wechatPayPublicKeyFilePath: wechatPayPublicKeyFilePath,
|
||||||
|
}
|
||||||
|
privateKey, err := LoadPrivateKeyWithPath(mchConfig.privateKeyFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
mchConfig.privateKey = privateKey
|
||||||
|
wechatPayPublicKey, err := LoadPublicKeyWithPath(mchConfig.wechatPayPublicKeyFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
mchConfig.wechatPayPublicKey = wechatPayPublicKey
|
||||||
|
return mchConfig, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadPrivateKey 通过私钥的文本内容加载私钥
|
||||||
|
func LoadPrivateKey(privateKeyStr string) (privateKey *rsa.PrivateKey, err error) {
|
||||||
|
block, _ := pem.Decode([]byte(privateKeyStr))
|
||||||
|
if block == nil {
|
||||||
|
return nil, fmt.Errorf("decode private key err")
|
||||||
|
}
|
||||||
|
if block.Type != "PRIVATE KEY" {
|
||||||
|
return nil, fmt.Errorf("the kind of PEM should be PRVATE KEY")
|
||||||
|
}
|
||||||
|
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("parse private key err:%s", err.Error())
|
||||||
|
}
|
||||||
|
privateKey, ok := key.(*rsa.PrivateKey)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("not a RSA private key")
|
||||||
|
}
|
||||||
|
return privateKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadPublicKey 通过公钥的文本内容加载公钥
|
||||||
|
func LoadPublicKey(publicKeyStr string) (publicKey *rsa.PublicKey, err error) {
|
||||||
|
block, _ := pem.Decode([]byte(publicKeyStr))
|
||||||
|
if block == nil {
|
||||||
|
return nil, errors.New("decode public key error")
|
||||||
|
}
|
||||||
|
if block.Type != "PUBLIC KEY" {
|
||||||
|
return nil, fmt.Errorf("the kind of PEM should be PUBLIC KEY")
|
||||||
|
}
|
||||||
|
key, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("parse public key err:%s", err.Error())
|
||||||
|
}
|
||||||
|
publicKey, ok := key.(*rsa.PublicKey)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("%s is not rsa public key", publicKeyStr)
|
||||||
|
}
|
||||||
|
return publicKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadPrivateKeyWithPath 通过私钥的文件路径内容加载私钥
|
||||||
|
func LoadPrivateKeyWithPath(path string) (privateKey *rsa.PrivateKey, err error) {
|
||||||
|
privateKeyBytes, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("read private pem file err:%s", err.Error())
|
||||||
|
}
|
||||||
|
return LoadPrivateKey(string(privateKeyBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadPublicKeyWithPath 通过公钥的文件路径加载公钥
|
||||||
|
func LoadPublicKeyWithPath(path string) (publicKey *rsa.PublicKey, err error) {
|
||||||
|
publicKeyBytes, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("read certificate pem file err:%s", err.Error())
|
||||||
|
}
|
||||||
|
return LoadPublicKey(string(publicKeyBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptOAEPWithPublicKey 使用 OAEP padding方式用公钥进行加密
|
||||||
|
func EncryptOAEPWithPublicKey(message string, publicKey *rsa.PublicKey) (ciphertext string, err error) {
|
||||||
|
if publicKey == nil {
|
||||||
|
return "", fmt.Errorf("you should input *rsa.PublicKey")
|
||||||
|
}
|
||||||
|
ciphertextByte, err := rsa.EncryptOAEP(sha1.New(), rand.Reader, publicKey, []byte(message), nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("encrypt message with public key err:%s", err.Error())
|
||||||
|
}
|
||||||
|
ciphertext = base64.StdEncoding.EncodeToString(ciphertextByte)
|
||||||
|
return ciphertext, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignSHA256WithRSA 通过私钥对字符串以 SHA256WithRSA 算法生成签名信息
|
||||||
|
func SignSHA256WithRSA(source string, privateKey *rsa.PrivateKey) (signature string, err error) {
|
||||||
|
if privateKey == nil {
|
||||||
|
return "", fmt.Errorf("private key should not be nil")
|
||||||
|
}
|
||||||
|
h := crypto.Hash.New(crypto.SHA256)
|
||||||
|
_, err = h.Write([]byte(source))
|
||||||
|
if err != nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
hashed := h.Sum(nil)
|
||||||
|
signatureByte, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hashed)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return base64.StdEncoding.EncodeToString(signatureByte), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifySHA256WithRSA 通过公钥对字符串和签名结果以 SHA256WithRSA 验证签名有效性
|
||||||
|
func VerifySHA256WithRSA(source string, signature string, publicKey *rsa.PublicKey) error {
|
||||||
|
if publicKey == nil {
|
||||||
|
return fmt.Errorf("public key should not be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
sigBytes, err := base64.StdEncoding.DecodeString(signature)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("verify failed: signature is not base64 encoded")
|
||||||
|
}
|
||||||
|
hashed := sha256.Sum256([]byte(source))
|
||||||
|
err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, hashed[:], sigBytes)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("verify signature with public key error:%s", err.Error())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateNonce 生成一个长度为 NonceLength 的随机字符串(只包含大小写字母与数字)
|
||||||
|
func GenerateNonce() (string, error) {
|
||||||
|
const (
|
||||||
|
// NonceSymbols 随机字符串可用字符集
|
||||||
|
NonceSymbols = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
// NonceLength 随机字符串的长度
|
||||||
|
NonceLength = 32
|
||||||
|
)
|
||||||
|
|
||||||
|
bs := make([]byte, NonceLength)
|
||||||
|
_, err := rand.Read(bs)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
symbolsByteLength := byte(len(NonceSymbols))
|
||||||
|
for i, b := range bs {
|
||||||
|
bs[i] = NonceSymbols[b%symbolsByteLength]
|
||||||
|
}
|
||||||
|
return string(bs), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildAuthorization 构建请求头中的 Authorization 信息
|
||||||
|
func BuildAuthorization(
|
||||||
|
mchid string,
|
||||||
|
certificateSerialNo string,
|
||||||
|
privateKey *rsa.PrivateKey,
|
||||||
|
method string,
|
||||||
|
canonicalURL string,
|
||||||
|
body []byte,
|
||||||
|
) (string, error) {
|
||||||
|
const (
|
||||||
|
SignatureMessageFormat = "%s\n%s\n%d\n%s\n%s\n" // 数字签名原文格式
|
||||||
|
// HeaderAuthorizationFormat 请求头中的 Authorization 拼接格式
|
||||||
|
HeaderAuthorizationFormat = "WECHATPAY2-SHA256-RSA2048 mchid=\"%s\",nonce_str=\"%s\",timestamp=\"%d\",serial_no=\"%s\",signature=\"%s\""
|
||||||
|
)
|
||||||
|
|
||||||
|
nonce, err := GenerateNonce()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
timestamp := time.Now().Unix()
|
||||||
|
message := fmt.Sprintf(SignatureMessageFormat, method, canonicalURL, timestamp, nonce, body)
|
||||||
|
signature, err := SignSHA256WithRSA(message, privateKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
authorization := fmt.Sprintf(
|
||||||
|
HeaderAuthorizationFormat,
|
||||||
|
mchid, nonce, timestamp, certificateSerialNo, signature,
|
||||||
|
)
|
||||||
|
return authorization, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractResponseBody 提取应答报文的 Body
|
||||||
|
func ExtractResponseBody(response *http.Response) ([]byte, error) {
|
||||||
|
if response.Body == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := io.ReadAll(response.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("read response HttpBody err:[%s]", err.Error())
|
||||||
|
}
|
||||||
|
response.Body = io.NopCloser(bytes.NewBuffer(body))
|
||||||
|
return body, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
WechatPayTimestamp = "Wechatpay-Timestamp" // 微信支付回包时间戳
|
||||||
|
WechatPayNonce = "Wechatpay-Nonce" // 微信支付回包随机字符串
|
||||||
|
WechatPaySignature = "Wechatpay-Signature" // 微信支付回包签名信息
|
||||||
|
WechatPaySerial = "Wechatpay-Serial" // 微信支付回包平台序列号
|
||||||
|
RequestID = "Request-Id" // 微信支付回包请求ID
|
||||||
|
)
|
||||||
|
|
||||||
|
// ValidateResponse 验证微信支付回包的签名信息
|
||||||
|
func ValidateResponse(
|
||||||
|
wechatpayPublicKeyId string,
|
||||||
|
wechatpayPublicKey *rsa.PublicKey,
|
||||||
|
headers *http.Header,
|
||||||
|
body []byte,
|
||||||
|
) error {
|
||||||
|
requestID := headers.Get(RequestID)
|
||||||
|
timestampStr := headers.Get(WechatPayTimestamp)
|
||||||
|
serialNo := headers.Get(WechatPaySerial)
|
||||||
|
signature := headers.Get(WechatPaySignature)
|
||||||
|
nonce := headers.Get(WechatPayNonce)
|
||||||
|
|
||||||
|
// 拒绝过期请求
|
||||||
|
timestamp, err := strconv.ParseInt(timestampStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid timestamp: %v", err)
|
||||||
|
}
|
||||||
|
if time.Now().Sub(time.Unix(timestamp, 0)) > 5*time.Minute {
|
||||||
|
return errors.New("invalid timestamp")
|
||||||
|
}
|
||||||
|
|
||||||
|
if serialNo != wechatpayPublicKeyId {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"serial-no mismatch: got %s, expected %s, request-id: %s",
|
||||||
|
serialNo,
|
||||||
|
wechatpayPublicKeyId,
|
||||||
|
requestID,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
message := fmt.Sprintf("%s\n%s\n%s\n", timestampStr, nonce, body)
|
||||||
|
if err := VerifySHA256WithRSA(message, signature, wechatpayPublicKey); err != nil {
|
||||||
|
return fmt.Errorf("invalid signature: %v, request-id: %s", err, requestID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApiException 微信支付API错误异常,发送HTTP请求成功,但返回状态码不是 2XX 时抛出本异常
|
||||||
|
type ApiException struct {
|
||||||
|
HttpStatusCode int // 应答报文的 HTTP 状态码
|
||||||
|
HttpHeader http.Header // 应答报文的 Header 信息
|
||||||
|
HttpBody []byte // 应答报文的 Body 原文
|
||||||
|
ErrCode string // 微信支付回包的错误码
|
||||||
|
ErrMessage string // 微信支付回包的错误信息
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiException) Error() string {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
buf.WriteString(fmt.Sprintf("srv error:[StatusCode: %d, Body: %s", c.HttpStatusCode, string(c.HttpBody)))
|
||||||
|
if len(c.HttpHeader) > 0 {
|
||||||
|
buf.WriteString(" Header: ")
|
||||||
|
for key, value := range c.HttpHeader {
|
||||||
|
buf.WriteString(fmt.Sprintf("\n - %v=%v", key, value))
|
||||||
|
}
|
||||||
|
buf.WriteString("\n")
|
||||||
|
}
|
||||||
|
buf.WriteString("]")
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiException) StatusCode() int {
|
||||||
|
return c.HttpStatusCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiException) Header() http.Header {
|
||||||
|
return c.HttpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiException) Body() []byte {
|
||||||
|
return c.HttpBody
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiException) ErrorCode() string {
|
||||||
|
return c.ErrCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiException) ErrorMessage() string {
|
||||||
|
return c.ErrMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewApiException(statusCode int, header http.Header, body []byte) error {
|
||||||
|
ret := &ApiException{
|
||||||
|
HttpStatusCode: statusCode,
|
||||||
|
HttpHeader: header,
|
||||||
|
HttpBody: body,
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyObject := map[string]interface{}{}
|
||||||
|
if err := json.Unmarshal(body, &bodyObject); err == nil {
|
||||||
|
if val, ok := bodyObject["code"]; ok {
|
||||||
|
ret.ErrCode = val.(string)
|
||||||
|
}
|
||||||
|
if val, ok := bodyObject["message"]; ok {
|
||||||
|
ret.ErrMessage = val.(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time 复制 time.Time 对象,并返回复制体的指针
|
||||||
|
func Time(t time.Time) *time.Time {
|
||||||
|
return &t
|
||||||
|
}
|
||||||
|
|
||||||
|
// String 复制 string 对象,并返回复制体的指针
|
||||||
|
func String(s string) *string {
|
||||||
|
return &s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bool 复制 bool 对象,并返回复制体的指针
|
||||||
|
func Bool(b bool) *bool {
|
||||||
|
return &b
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64 复制 float64 对象,并返回复制体的指针
|
||||||
|
func Float64(f float64) *float64 {
|
||||||
|
return &f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float32 复制 float32 对象,并返回复制体的指针
|
||||||
|
func Float32(f float32) *float32 {
|
||||||
|
return &f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64 复制 int64 对象,并返回复制体的指针
|
||||||
|
func Int64(i int64) *int64 {
|
||||||
|
return &i
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int32 复制 int64 对象,并返回复制体的指针
|
||||||
|
func Int32(i int32) *int32 {
|
||||||
|
return &i
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *MchConfig) Request(host, method, path string, reqBody []byte) (response []byte, err error) {
|
||||||
|
|
||||||
|
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Print(reqUrl.Path)
|
||||||
|
|
||||||
|
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//httpRequest.Header.Set("mchid", srv.mchId)
|
||||||
|
httpRequest.Header.Set("Accept", "application/json")
|
||||||
|
httpRequest.Header.Set("Wechatpay-Serial", srv.WechatPayPublicKeyId())
|
||||||
|
httpRequest.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
authorization, err := BuildAuthorization(
|
||||||
|
srv.MchId(),
|
||||||
|
srv.CertificateSerialNo(),
|
||||||
|
srv.PrivateKey(),
|
||||||
|
method,
|
||||||
|
reqUrl.Path,
|
||||||
|
reqBody,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
httpRequest.Header.Set("Authorization", authorization)
|
||||||
|
|
||||||
|
client := &http.Client{}
|
||||||
|
httpResponse, err := client.Do(httpRequest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
respBody, err := ExtractResponseBody(httpResponse)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
|
||||||
|
// 2XX 成功,验证应答签名
|
||||||
|
err = ValidateResponse(
|
||||||
|
srv.WechatPayPublicKeyId(),
|
||||||
|
srv.WechatPayPublicKey(),
|
||||||
|
&httpResponse.Header,
|
||||||
|
respBody,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return respBody, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, &ApiException{
|
||||||
|
HttpStatusCode: httpResponse.StatusCode,
|
||||||
|
HttpHeader: httpResponse.Header,
|
||||||
|
HttpBody: respBody,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *MchConfig) Request2(host, method, path string, reqBody []byte) (response []byte, err error) {
|
||||||
|
|
||||||
|
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
httpRequest.Header.Set("Accept", "application/json")
|
||||||
|
httpRequest.Header.Set("Wechatpay-Serial", srv.WechatPayPublicKeyId())
|
||||||
|
httpRequest.Header.Set("Content-Type", "application/json")
|
||||||
|
httpRequest.Header.Set("mchid", "application/json")
|
||||||
|
|
||||||
|
authorization, err := BuildAuthorization(
|
||||||
|
srv.MchId(),
|
||||||
|
srv.CertificateSerialNo(),
|
||||||
|
srv.PrivateKey(),
|
||||||
|
method,
|
||||||
|
path,
|
||||||
|
reqBody,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
httpRequest.Header.Set("Authorization", authorization)
|
||||||
|
|
||||||
|
hs, _ := json.Marshal(httpRequest.Header)
|
||||||
|
fmt.Printf("\npath=%s\nreqBody=%s\nheaders=%s\n", path, string(reqBody), string(hs))
|
||||||
|
|
||||||
|
client := &http.Client{}
|
||||||
|
httpResponse, err := client.Do(httpRequest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
respBody, err := ExtractResponseBody(httpResponse)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
|
||||||
|
// 2XX 成功,验证应答签名
|
||||||
|
err = ValidateResponse(
|
||||||
|
srv.WechatPayPublicKeyId(),
|
||||||
|
srv.WechatPayPublicKey(),
|
||||||
|
&httpResponse.Header,
|
||||||
|
respBody,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return respBody, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, &ApiException{
|
||||||
|
HttpStatusCode: httpResponse.StatusCode,
|
||||||
|
HttpHeader: httpResponse.Header,
|
||||||
|
HttpBody: respBody,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *MchConfig) Verify(request *http.Request) (string, error) {
|
||||||
|
|
||||||
|
respBody, err := io.ReadAll(request.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("read request HttpBody err:[%s]", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ValidateResponse(
|
||||||
|
srv.WechatPayPublicKeyId(),
|
||||||
|
srv.WechatPayPublicKey(),
|
||||||
|
&request.Header,
|
||||||
|
respBody,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return EncryptOAEPWithPublicKey(string(respBody), srv.wechatPayPublicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildSortedQueryString 函数接受一个 map,返回按照字段名排序后的 URL 键值对格式字符串
|
||||||
|
func BuildSortedQueryString(params map[string]any) string {
|
||||||
|
// 创建一个字符串切片,用于保存所有的键名
|
||||||
|
var keys []string
|
||||||
|
for key := range params {
|
||||||
|
keys = append(keys, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对键名进行 ASCII 字典顺序排序
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
// 构建一个 URL 键值对字符串
|
||||||
|
var queryStrings []string
|
||||||
|
for _, key := range keys {
|
||||||
|
// 拼接 key=value
|
||||||
|
queryStrings = append(queryStrings, fmt.Sprintf("%s=%v", key, params[key]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 & 连接所有的 key=value 对
|
||||||
|
return strings.Join(queryStrings, "&")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Sha1(data string) string {
|
||||||
|
// 创建一个 SHA-1 哈希对象
|
||||||
|
hash := sha1.New()
|
||||||
|
// 写入数据
|
||||||
|
hash.Write([]byte(data))
|
||||||
|
// 计算并获取加密后的结果
|
||||||
|
hashBytes := hash.Sum(nil)
|
||||||
|
// 将结果转换为十六进制字符串
|
||||||
|
hashString := hex.EncodeToString(hashBytes)
|
||||||
|
// 打印加密后的 SHA-1 值
|
||||||
|
return hashString
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue