This commit is contained in:
李子铭 2025-03-04 14:19:55 +08:00
parent 7c764e53b7
commit 84f53cc4fc
12 changed files with 219 additions and 92 deletions

143
api/v1/cmb_cpn.proto Normal file
View File

@ -0,0 +1,143 @@
syntax = "proto3";
package api.v1;
option go_package = "voucher/api/v1;v1";
import "validate/validate.proto";
message CmbOrderRequest {
//
// ID32
string mid = 1 [json_name = "mid"];
// ID32
string aid = 2 [json_name = "aid"];
// yyyyMMddHHmmss
string date = 3 [json_name = "date"];
// 32
string random = 4 [json_name = "random"];
//
string keyAlias = 5 [json_name = "keyAlias"];
//
string cmbKeyAlias = 6 [json_name = "cmbKeyAlias"];
// API的说明文档
string encryptBody = 7 [json_name = "encryptBody"];
//
string sign = 8 [json_name = "sign"];
//
// 14
string transactionId = 9 [json_name = "transactionId", (validate.rules).string = {min_len: 1,max_len: 50}];
//
string activityId = 10 [json_name = "activityId", (validate.rules).string = {min_len: 1,max_len: 32}];
// openId
string cmbUid = 11 [json_name = "cmbUid", (validate.rules).string = {min_len: 1,max_len: 100}];
// 0-1-openId
string cmbUidType = 12 [json_name = "cmbUidType", (validate.rules).string = {min_len: 1,max_len: 10}];
// 13
string timestamp = 13 [json_name = "timestamp", (validate.rules).string = {min_len: 1,max_len: 20}];
}
message CmbOrderReply {
//
// 1000 1001
string respCode = 1 [json_name = "respCode"];
//
string respMsg = 2 [json_name = "respMsg"];
// yyyyMMddHHmmss
string date = 3 [json_name = "date"];
//
string keyAlias = 5 [json_name = "keyAlias"];
//
string cmbKeyAlias = 6 [json_name = "cmbKeyAlias"];
// API的说明文档
string encryptBody = 7 [json_name = "encryptBody"];
//
string sign = 8 [json_name = "sign"];
//
// 50
string codeNo = 9 [json_name = "codeNo"];
}
message CmbQueryProductRequest {
//
// ID32
string mid = 1 [json_name = "mid"];
// ID32
string aid = 2 [json_name = "aid"];
// yyyyMMddHHmmss
string date = 3 [json_name = "date"];
// 32
string random = 4 [json_name = "random"];
//
string keyAlias = 5 [json_name = "keyAlias"];
//
string cmbKeyAlias = 6 [json_name = "cmbKeyAlias"];
// API的说明文档
string encryptBody = 7 [json_name = "encryptBody"];
//
string sign = 8 [json_name = "sign"];
//
//
string activityId = 9 [json_name = "activityId", (validate.rules).string = {min_len: 1,max_len: 32}];
}
message CmbQueryProductReply {
//
// 1000 1001
string respCode = 1 [json_name = "respCode"];
//
string respMsg = 2 [json_name = "respMsg"];
// yyyyMMddHHmmss
string date = 3 [json_name = "date"];
//
string keyAlias = 5 [json_name = "keyAlias"];
//
string cmbKeyAlias = 6 [json_name = "cmbKeyAlias"];
// API的说明文档
string encryptBody = 7 [json_name = "encryptBody"];
//
string sign = 8 [json_name = "sign"];
//
//
string activityName = 9 [json_name = "activityName"];
//
string activityId = 10 [json_name = "activityId"];
//
string amount = 11 [json_name = "amount"];
//
string minAmount = 12 [json_name = "minAmount"];
// 01
string availableType = 13 [json_name = "availableType"];
// - yyyy-mm-dd hh:mm:ss.sss
string availableDays = 14 [json_name = "availableDays"];
// -
string startTime = 15 [json_name = "startTime"];
// -
string endTime = 16 [json_name = "endTime"];
//
string availableStock = 17 [json_name = "availableStock"];
//
string detail = 18 [json_name = "detail"];
}
message CmbNotifyRequest {
// codeNo
string ticket = 1 [json_name = "ticket"];
// 0使1使
string status = 2 [json_name = "status"];
// yyyy-mm-dd hh:mm:ss.sss
string transDate = 3 [json_name = "transDate"];
//
string orgNo = 4 [json_name = "orgNo"];
//
string ext = 5 [json_name = "ext"];
}
message CmbNotifyReply {
// 1000 1001
string respCode = 1 [json_name = "respCode"];
//
string respMsg = 2 [json_name = "respMsg"];
}

View File

@ -1,79 +0,0 @@
syntax = "proto3";
package api.v1;
option go_package = "voucher/api/v1;v1";
import "validate/validate.proto";
message CmbOrderRequest {
// 14
string transactionId = 1 [json_name = "transactionId", (validate.rules).string = {min_len: 1,max_len: 50}];
//
string activityId = 2 [json_name = "activityId", (validate.rules).string = {min_len: 1,max_len: 32}];
// openId
string cmbUid = 3 [json_name = "cmbUid", (validate.rules).string = {min_len: 1,max_len: 100}];
// 0-1-openId
string cmbUidType = 4 [json_name = "cmbUidType", (validate.rules).string = {min_len: 1,max_len: 10}];
// 13
string timestamp = 5 [json_name = "timestamp", (validate.rules).string = {min_len: 1,max_len: 20}];
}
message CmbOrderReply {
// 1000 1001
string respCode = 1 [json_name = "respCode"];
//
string respMsg = 2 [json_name = "respMsg"];
// 50
string codeNo = 3 [json_name = "codeNo"];
}
message CmbQueryProductRequest {
//
string activityId = 2 [json_name = "activityId", (validate.rules).string = {min_len: 1,max_len: 32}];
}
message CmbQueryProductReply {
// 1000 1001
string respCode = 1 [json_name = "respCode"];
//
string respMsg = 2 [json_name = "respMsg"];
//
string activityName = 3 [json_name = "activityName"];
//
string activityId = 4 [json_name = "activityId"];
//
string amount = 5 [json_name = "amount"];
//
string minAmount = 6 [json_name = "minAmount"];
// 01
string availableType = 7 [json_name = "availableType"];
// - yyyy-mm-dd hh:mm:ss.sss
string availableDays = 8 [json_name = "availableDays"];
// -
string startTime = 9 [json_name = "startTime"];
// -
string endTime = 10 [json_name = "endTime"];
//
string availableStock = 11 [json_name = "availableStock"];
//
string detail = 12 [json_name = "detail"];
}
message CmbNotifyRequest {
// codeNo
string ticket = 1 [json_name = "ticket"];
// 0使1使
string status = 2 [json_name = "status"];
// yyyy-mm-dd hh:mm:ss.sss
string transDate = 3 [json_name = "transDate"];
//
string orgNo = 4 [json_name = "orgNo"];
//
string ext = 5 [json_name = "ext"];
}
message CmbNotifyReply {
// 1000 1001
string respCode = 1 [json_name = "respCode"];
//
string respMsg = 2 [json_name = "respMsg"];
}

View File

@ -52,6 +52,10 @@ wechat:
mchID: "1605446142" # 证书所属商户 mchID: "1605446142" # 证书所属商户
mchCertificateSerialNumber: "4D081089DEB385316CBDCB55C070287E4920AC76" mchCertificateSerialNumber: "4D081089DEB385316CBDCB55C070287E4920AC76"
cmb:
mid: "d6fdd78b6fd13a808818286b9cad9687"
aid: "5efaa21263b94f669a1c90ed0279df20"
#配置日志 #配置日志
logs: logs:
business: business.log #业务日志路径:如果不写日志,则不配置或配置为空 business: business.log #业务日志路径:如果不写日志,则不配置或配置为空

View File

@ -12,6 +12,7 @@ type OrderBo struct {
OutBizNo string OutBizNo string
ProductNo string ProductNo string
Account string Account string
Type vo.OrderType
AccountType vo.OrderAccountType AccountType vo.OrderAccountType
Status vo.OrderStatus Status vo.OrderStatus
AppID string AppID string
@ -22,14 +23,10 @@ type OrderBo struct {
} }
type OrderCreateReqBo struct { type OrderCreateReqBo struct {
OrderNo string
OutBizNo string OutBizNo string
ProductNo string ProductNo string
Account string Account string
AccountType vo.OrderAccountType AccountType vo.OrderAccountType
Channel vo.Channel
AppID string
MerchantNo string
} }
type OrderCreateRepBo struct { type OrderCreateRepBo struct {

View File

@ -7,6 +7,7 @@ import (
"gorm.io/gorm" "gorm.io/gorm"
"time" "time"
"voucher/internal/biz/bo" "voucher/internal/biz/bo"
"voucher/internal/biz/vo"
"voucher/internal/pkg/lock" "voucher/internal/pkg/lock"
"voucher/internal/pkg/uid" "voucher/internal/pkg/uid"
) )
@ -25,13 +26,36 @@ func (v *VoucherBiz) CmbOrder(ctx context.Context, req *bo.OrderCreateReqBo) (re
return nil return nil
} }
product, err := v.ProductRepo.GetByPNO(ctx, req.ProductNo)
if err != nil {
return err
}
orderNo, err := v.GenerateMixRepo.GeneratorString(ctx, uid.Order) orderNo, err := v.GenerateMixRepo.GeneratorString(ctx, uid.Order)
if err != nil { if err != nil {
return err return err
} }
req.OrderNo = orderNo o := &bo.OrderBo{
v.OrderRepo.Create(ctx, req) OrderNo: orderNo,
OutBizNo: req.OutBizNo,
ProductNo: req.ProductNo,
Account: req.Account,
AppID: product.AppID,
MerchantNo: product.MerchantNo,
Channel: product.Channel,
AccountType: vo.OrderAccountTypeOpenId,
Type: vo.OrderTypeCmb,
Status: vo.OrderStatusWait,
}
order, err = v.OrderRepo.Create(ctx, o)
if err != nil {
return err
}
return nil return nil
}) })

1
internal/biz/cmb/cmb.go Normal file
View File

@ -0,0 +1 @@
package cmb

View File

@ -7,7 +7,7 @@ import (
type OrderRepo interface { type OrderRepo interface {
GetByOutBizNo(ctx context.Context, outBizNo string) (*bo.OrderBo, error) GetByOutBizNo(ctx context.Context, outBizNo string) (*bo.OrderBo, error)
Create(ctx context.Context, req *bo.OrderCreateReqBo) (*bo.OrderBo, error) Create(ctx context.Context, req *bo.OrderBo) (*bo.OrderBo, error)
GetByID(ctx context.Context, id uint64) (*bo.OrderBo, error) GetByID(ctx context.Context, id uint64) (*bo.OrderBo, error)
Ing(ctx context.Context, id uint64) error Ing(ctx context.Context, id uint64) error
Success(ctx context.Context, id uint64) error Success(ctx context.Context, id uint64) error

View File

@ -0,0 +1,26 @@
package vo
type OrderType uint8
const (
OrderTypeCmb OrderType = iota + 1
)
var OrderTypeMap = map[OrderType]string{
OrderTypeCmb: "招行",
}
func (s OrderType) GetText() string {
if t, ok := OrderTypeMap[s]; ok {
return t
}
return ""
}
func (s OrderType) GetValue() uint8 {
return uint8(s)
}
func (s OrderType) IsCmb() bool {
return s == OrderTypeCmb
}

View File

@ -11,6 +11,7 @@ import (
type VoucherBiz struct { type VoucherBiz struct {
rdb *data.Rdb rdb *data.Rdb
OrderRepo repo.OrderRepo OrderRepo repo.OrderRepo
ProductRepo repo.ProductRepo
ThirdMQSend thirdrepo.ThirdMQSend ThirdMQSend thirdrepo.ThirdMQSend
WechatCpnRepo wechatrepo.WechatCpnRepo WechatCpnRepo wechatrepo.WechatCpnRepo
GenerateMixRepo mixrepos.GenerateMixRepo GenerateMixRepo mixrepos.GenerateMixRepo
@ -19,6 +20,7 @@ type VoucherBiz struct {
func NewVoucherBiz( func NewVoucherBiz(
rdb *data.Rdb, rdb *data.Rdb,
orderRepo repo.OrderRepo, orderRepo repo.OrderRepo,
ProductRepo repo.ProductRepo,
thirdMQSend thirdrepo.ThirdMQSend, thirdMQSend thirdrepo.ThirdMQSend,
WechatCpnRepo wechatrepo.WechatCpnRepo, WechatCpnRepo wechatrepo.WechatCpnRepo,
GenerateMixRepo mixrepos.GenerateMixRepo, GenerateMixRepo mixrepos.GenerateMixRepo,
@ -26,6 +28,7 @@ func NewVoucherBiz(
return &VoucherBiz{ return &VoucherBiz{
rdb: rdb, rdb: rdb,
OrderRepo: orderRepo, OrderRepo: orderRepo,
ProductRepo: ProductRepo,
ThirdMQSend: thirdMQSend, ThirdMQSend: thirdMQSend,
WechatCpnRepo: WechatCpnRepo, WechatCpnRepo: WechatCpnRepo,
GenerateMixRepo: GenerateMixRepo, GenerateMixRepo: GenerateMixRepo,

View File

@ -18,6 +18,7 @@ type Order struct {
ProductNo string `gorm:"column:product_no;not null;comment:商品编号" json:"product_no"` // 商品编号 ProductNo string `gorm:"column:product_no;not null;comment:商品编号" json:"product_no"` // 商品编号
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"`
Status uint8 `gorm:"column:status;not null;comment:1:待发放 2:发放中 3:发放成功 4:发放失败" json:"status"` // 1:待发放 2:发放中 3:发放成功 4:发放失败 Status uint8 `gorm:"column:status;not null;comment:1:待发放 2:发放中 3:发放成功 4:发放失败" json:"status"` // 1:待发放 2:发放中 3:发放成功 4:发放失败
AppID string `gorm:"column:app_id;not null;comment:批次所属应用" json:"app_id"` // 批次所属应用 AppID string `gorm:"column:app_id;not null;comment:批次所属应用" json:"app_id"` // 批次所属应用
MerchantNo string `gorm:"column:merchant_no;not null;comment:创建批次号的商户号" json:"merchant_no"` // 创建批次号的商户号 MerchantNo string `gorm:"column:merchant_no;not null;comment:创建批次号的商户号" json:"merchant_no"` // 创建批次号的商户号

View File

@ -26,7 +26,7 @@ func (p *OrderRepoImpl) DB(ctx context.Context) *gorm.DB {
return p.db.DB(ctx).Model(model.Order{}) return p.db.DB(ctx).Model(model.Order{})
} }
func (p *OrderRepoImpl) Create(ctx context.Context, req *bo.OrderCreateReqBo) (*bo.OrderBo, error) { func (p *OrderRepoImpl) Create(ctx context.Context, req *bo.OrderBo) (*bo.OrderBo, error) {
now := time.Now() now := time.Now()
info := &model.Order{ info := &model.Order{

View File

@ -14,6 +14,10 @@ func (s *VoucherService) CmbOrder(ctx http.Context) error {
return err return err
} }
if err := req.Validate(); err != nil {
return err
}
// todo 签名验证 // todo 签名验证
boReq := &bo.OrderCreateReqBo{ boReq := &bo.OrderCreateReqBo{
@ -21,7 +25,6 @@ func (s *VoucherService) CmbOrder(ctx http.Context) error {
ProductNo: req.ActivityId, ProductNo: req.ActivityId,
Account: req.CmbUid, Account: req.CmbUid,
AccountType: vo.OrderAccountTypeOpenId, AccountType: vo.OrderAccountTypeOpenId,
Channel: vo.OrderChannelWechat,
} }
boRep, err := s.VoucherBiz.CmbOrder(ctx, boReq) boRep, err := s.VoucherBiz.CmbOrder(ctx, boReq)
@ -45,6 +48,10 @@ func (s *VoucherService) CmbProductQuery(ctx http.Context) error {
return err return err
} }
if err := req.Validate(); err != nil {
return err
}
rep := &v1.CmbQueryProductReply{} rep := &v1.CmbQueryProductReply{}
return ctx.JSON(200, rep) return ctx.JSON(200, rep)