This commit is contained in:
李子铭 2025-03-14 16:04:37 +08:00
parent 107ed2cae0
commit bd377b5b81
10 changed files with 209 additions and 100 deletions

30
api/err/cmb.proto Normal file
View File

@ -0,0 +1,30 @@
syntax = "proto3";
package api.err;
import "errors/errors.proto";
option go_package = "voucher/api/err";
enum CmbErr{
option (errors.default_code) = 499;
// ,
CMB_UNKNOWN = 0;
// ,
CMB_PARAM_FAIL = 1 [(errors.code) = 400];
//
CMB_VERIFY_FAIL = 2 [(errors.code) = 401];
//
CMB_BIZ_CONTENT_DECRYPT_FAIL = 3 [(errors.code) = 401];
// ,
CMB_BIZ_CONTENT_CONVERT_FAIL = 4 [(errors.code) = 401];
//
CMB_BIZ_CONTENT_FAIL = 5 [(errors.code) = 401];
//
CMB_ORDER_NOT_EXIST = 6 [(errors.code) = 404];
//
CMB_PRODUCT_NOT_EXIST = 7 [(errors.code) = 404];
//
CMB_PRODUCT_NOT_AUTH = 8 [(errors.code) = 401];
//
CMB_PRODUCT_NOT_SUPPORTED = 9 [(errors.code) = 401];
}

View File

@ -10,22 +10,10 @@ enum Err {
// panic错误
SYSTEM_PANIC = 0 [(errors.code) = 599];
//
NOT_LOGIN = 1 [(errors.code) = 401];
// DB数据未找到
DB_NOT_FOUND = 2 [(errors.code) = 404];
//
PARAM = 3 [(errors.code) = 400];
//
COMMON = 4 [(errors.code) = 555];
}
enum NotifyConsumeErr{
option (errors.default_code) = 1;
//
NeedRetryNotify = 0 [(errors.code) = 500];
}
}

11
api/err/wechat.proto Normal file
View File

@ -0,0 +1,11 @@
syntax = "proto3";
package api.err;
import "errors/errors.proto";
option go_package = "voucher/api/err";
enum WechatErr{
option (errors.default_code) = 1;
//
WECHAT_FAIL = 0 [(errors.code) = 500];
}

View File

@ -68,6 +68,8 @@ message CmbOrderReply {
//
// 50
string codeNo = 9 [json_name = "codeNo"];
//
string thirdErrCode = 3 [json_name = "thirdErrCode"];
}
message CmbQueryRequest {
@ -86,6 +88,8 @@ message CmbQueryReply {
string orgNo = 12 [json_name = "orgNo"];
//
string ext = 13 [json_name = "ext"];
//
string thirdErrCode = 3 [json_name = "thirdErrCode"];
}
@ -125,6 +129,9 @@ message CmbQueryProductReply {
string saleStartTime = 19 [json_name = "saleStartTime"];
// yyyy-mm-dd hh:mm:ss.sss
string saleEndTime = 20 [json_name = "saleEndTime"];
//
string thirdErrCode = 21 [json_name = "thirdErrCode"];
}

View File

@ -9,6 +9,7 @@ import (
"net/http"
"net/url"
"time"
err2 "voucher/api/err"
v1 "voucher/api/v1"
"voucher/internal/biz/bo"
"voucher/internal/biz/mixrepos"
@ -31,38 +32,46 @@ func (s *CmbMixRepoImpl) OrderVerify(ctx context.Context, req *v1.CmbRequest) (*
bizStr, err := s.Verify(ctx, req)
if err != nil {
return nil, err
return nil, err2.ErrorCmbVerifyFail(err.Error())
}
if len(bizStr) == 0 {
return nil, errors.New("业务参数获取异常,请检查参数是否正确传递")
return nil, err2.ErrorCmbBizContentFail("业务参数获取异常,请检查参数是否正确传递")
}
var resp *v1.CmbOrderRequest
if err = json.Unmarshal([]byte(bizStr), &resp); err != nil {
return nil, err
var bizContent *v1.CmbOrderRequest
if err = json.Unmarshal([]byte(bizStr), &bizContent); err != nil {
return nil, err2.ErrorCmbBizContentFail(err.Error())
}
return resp, nil
if err = bizContent.Validate(); err != nil {
return nil, err2.ErrorCmbBizContentFail(err.Error())
}
return bizContent, nil
}
func (s *CmbMixRepoImpl) QueryVerify(ctx context.Context, req *v1.CmbRequest) (*v1.CmbQueryRequest, error) {
bizStr, err := s.Verify(ctx, req)
if err != nil {
return nil, err
return nil, err2.ErrorCmbVerifyFail(err.Error())
}
if len(bizStr) == 0 {
return nil, errors.New("业务参数获取异常,请检查参数是否正确传递")
return nil, err2.ErrorCmbBizContentFail("业务参数获取异常,请检查参数是否正确传递")
}
var resp *v1.CmbQueryRequest
if err = json.Unmarshal([]byte(bizStr), &resp); err != nil {
return nil, err
var bizContent *v1.CmbQueryRequest
if err = json.Unmarshal([]byte(bizStr), &bizContent); err != nil {
return nil, err2.ErrorCmbBizContentFail(err.Error())
}
return resp, nil
if err = bizContent.Validate(); err != nil {
return nil, err2.ErrorCmbBizContentFail(err.Error())
}
return bizContent, nil
}
func (s *CmbMixRepoImpl) ProductQueryVerify(ctx context.Context, req *v1.CmbRequest) (*v1.CmbQueryProductRequest, error) {
@ -72,12 +81,20 @@ func (s *CmbMixRepoImpl) ProductQueryVerify(ctx context.Context, req *v1.CmbRequ
return nil, err
}
var resp *v1.CmbQueryProductRequest
if err = json.Unmarshal([]byte(bizStr), &resp); err != nil {
return nil, err
if len(bizStr) == 0 {
return nil, err2.ErrorCmbBizContentFail("业务参数获取异常,请检查参数是否正确传递")
}
return resp, nil
var bizContent *v1.CmbQueryProductRequest
if err = json.Unmarshal([]byte(bizStr), &bizContent); err != nil {
return nil, err2.ErrorCmbBizContentFail(err.Error())
}
if err = bizContent.Validate(); err != nil {
return nil, err2.ErrorCmbBizContentFail(err.Error())
}
return bizContent, nil
}
func (s *CmbMixRepoImpl) Verify(_ context.Context, req *v1.CmbRequest) (string, error) {
@ -86,16 +103,16 @@ func (s *CmbMixRepoImpl) Verify(_ context.Context, req *v1.CmbRequest) (string,
b, err := cmb.Verify(s.bc.Cmb.CmbSm2Puk, str, req.Sign)
if err != nil {
return "", err
return "", err2.ErrorCmbVerifyFail(err.Error())
}
if !b {
return "", errors.New("签名验证失败")
return "", err2.ErrorCmbVerifyFail("签名验证失败")
}
bizStr, err := cmb.Decrypt(s.bc.Cmb.Sm2Prk, req.EncryptBody)
if err != nil {
return "", err
return "", err2.ErrorCmbBizContentDecryptFail(err.Error())
}
return bizStr, nil

View File

@ -22,15 +22,17 @@ type Server struct {
func (c *Server) Validate() error {
if err := validator.New().Struct(c); err != nil {
for _, err = range err.(validator.ValidationErrors) {
return err
}
}
return nil
}
func newClient(ctx context.Context, c *Server) (*core.Client, error) {
func newClient(ctx context.Context, c Server) (*core.Client, error) {
dir, err := os.Getwd()
if err != nil {
@ -86,7 +88,7 @@ func init() {
}
}
func GetClient(ctx context.Context, c *Server) (*core.Client, error) {
func GetClient(ctx context.Context, c Server) (*core.Client, error) {
instance.mutex.Lock()
defer instance.mutex.Unlock()
@ -115,7 +117,7 @@ func GetClient(ctx context.Context, c *Server) (*core.Client, error) {
return instance.clients[c.MchID], nil
}
func (s *Server) Verify(ctx context.Context, message, signature string) error {
func (s Server) Verify(ctx context.Context, message, signature string) error {
verifier := verifiers.NewSHA256WithRSAVerifier(nil)

View File

@ -19,11 +19,11 @@ import (
type CpnRepoImpl struct {
bc *conf.Bootstrap
Server *data.Server
Server data.Server
}
func NewCpnRepoImpl(bc *conf.Bootstrap) (wechatrepo.WechatCpnRepo, error) {
server := &data.Server{
server := data.Server{
MchID: bc.Wechat.MchID,
MchCertificateSerialNumber: bc.Wechat.MchCertificateSerialNumber,
}
@ -154,7 +154,7 @@ func (c *CpnRepoImpl) QueryProduct(ctx context.Context, stockCreatorMchId, stock
func (c *CpnRepoImpl) QueryCallback(ctx context.Context, mchId, mchCertNo string) (*cashcoupons.Callback, error) {
server := &data.Server{
server := data.Server{
MchID: mchId,
MchCertificateSerialNumber: mchCertNo,
}
@ -199,7 +199,7 @@ func (c *CpnRepoImpl) QueryCallback(ctx context.Context, mchId, mchCertNo string
func (c *CpnRepoImpl) SetCallback(ctx context.Context, mchId, mchCertNo, url string) (*cashcoupons.SetCallbackResponse, error) {
server := &data.Server{
server := data.Server{
MchID: mchId,
MchCertificateSerialNumber: mchCertNo,
}

View File

@ -1,8 +1,55 @@
package helper
import "os"
import (
"os"
"reflect"
)
func FileExists(filePath string) bool {
_, err := os.Stat(filePath)
return err == nil || os.IsExist(err)
}
// DeepCopy 深拷贝函数
func DeepCopy(src interface{}) interface{} {
if src == nil {
return nil
}
t := reflect.TypeOf(src)
v := reflect.ValueOf(src)
// 创建新的对象
dst := reflect.New(t.Elem()).Elem()
// 遍历结构体的所有字段
for i := 0; i < t.Elem().NumField(); i++ {
field := t.Elem().Field(i)
srcField := v.Elem().Field(i)
dstField := dst.Field(i)
// 处理不同类型的字段
switch field.Type.Kind() {
case reflect.Map:
// 处理映射类型
newMap := reflect.MakeMap(field.Type)
for _, key := range srcField.MapKeys() {
value := srcField.MapIndex(key)
newMap.SetMapIndex(key, value)
}
dstField.Set(newMap)
case reflect.Slice:
// 处理切片类型
newSlice := reflect.MakeSlice(field.Type, srcField.Len(), srcField.Cap())
reflect.Copy(newSlice, srcField)
dstField.Set(newSlice)
case reflect.Ptr:
// 处理指针类型
if !srcField.IsNil() {
newPtr := reflect.New(field.Type.Elem())
newPtr.Elem().Set(DeepCopy(srcField.Elem()).(reflect.Value))
dstField.Set(newPtr)
}
default:
// 处理其他类型
dstField.Set(srcField)
}
}
return dst.Interface()
}

View File

@ -2,9 +2,11 @@ package service
import (
"encoding/json"
"github.com/go-kratos/kratos/v2/errors"
"github.com/go-kratos/kratos/v2/log"
"github.com/go-kratos/kratos/v2/transport/http"
"io"
err2 "voucher/api/err"
v1 "voucher/api/v1"
"voucher/internal/biz/bo"
"voucher/internal/biz/vo"
@ -21,12 +23,16 @@ func (s *VoucherService) CmbOrder(ctx http.Context) error {
voucherNo, err := s.cmbOrder(ctx)
if err != nil {
log.Errorf("cmbOrder error: %v", err)
se := errors.FromError(err)
bizReply = &v1.CmbOrderReply{
RespCode: vo.CmbResponseStatusFail.GetValue(),
RespMsg: err.Error(),
CodeNo: "",
RespCode: vo.CmbResponseStatusFail.GetValue(),
RespMsg: err.Error(),
CodeNo: "",
ThirdErrCode: se.Reason,
}
log.Errorf("cmbOrder error: %v", err)
} else {
bizReply = &v1.CmbOrderReply{
RespCode: vo.CmbResponseStatusSuccess.GetValue(),
@ -58,18 +64,18 @@ func (s *VoucherService) cmbOrder(ctx http.Context) (string, error) {
bodyBytes, err := io.ReadAll(ctx.Request().Body)
if err != nil {
return "", err
return "", err2.ErrorCmbParamFail(err.Error())
}
log.Warnf("cmbOrder req: %v", string(bodyBytes))
var req *v1.CmbRequest
if err = json.Unmarshal(bodyBytes, &req); err != nil {
return "", err
return "", err2.ErrorCmbParamFail(err.Error())
}
if err = req.Validate(); err != nil {
return "", err
return "", err2.ErrorCmbParamFail(err.Error())
}
bizContent, err := s.CmbMixRepo.OrderVerify(ctx, req)
@ -77,10 +83,6 @@ func (s *VoucherService) cmbOrder(ctx http.Context) (string, error) {
return "", err
}
if err = bizContent.Validate(); err != nil {
return "", err
}
boReq := &bo.OrderCreateReqBo{
OutBizNo: bizContent.TransactionId,
ProductNo: bizContent.ActivityId,
@ -109,7 +111,13 @@ func (s *VoucherService) CmbQuery(ctx http.Context) error {
bizReply, err := s.cmbQuery(ctx)
if err != nil {
bizReply = &v1.CmbQueryReply{}
se := errors.FromError(err)
bizReply = &v1.CmbQueryReply{
ThirdErrCode: se.Reason,
}
log.Errorf("CmbQuery error: %v", err)
}
replyBizContent, _ := json.Marshal(bizReply)
@ -127,6 +135,7 @@ func (s *VoucherService) CmbQuery(ctx http.Context) error {
replyBytes, _ := json.Marshal(reply)
log.Warnf("cmbQuery reply: %v", string(replyBytes))
return ctx.JSON(200, reply)
}
@ -153,10 +162,6 @@ func (s *VoucherService) cmbQuery(ctx http.Context) (*v1.CmbQueryReply, error) {
return nil, err
}
if err = bizContent.Validate(); err != nil {
return nil, err
}
return s.VoucherBiz.CmbQuery(ctx, bizContent.CodeNo)
}
@ -170,11 +175,15 @@ func (s *VoucherService) CmbProductQuery(ctx http.Context) error {
bizReply, err := s.cmbProductQuery(ctx)
if err != nil {
log.Errorf("cmbProductQuery error: %v", err)
se := errors.FromError(err)
bizReply = &v1.CmbQueryProductReply{
RespCode: vo.CmbResponseStatusFail.GetValue(),
RespMsg: err.Error(),
RespCode: vo.CmbResponseStatusFail.GetValue(),
RespMsg: err.Error(),
ThirdErrCode: se.Reason,
}
log.Errorf("cmbProductQuery error: %v", err)
}
replyBizContent, _ := json.Marshal(bizReply)
@ -214,9 +223,5 @@ func (s *VoucherService) cmbProductQuery(ctx http.Context) (*v1.CmbQueryProductR
return nil, err
}
if err = bizContent.Validate(); err != nil {
return nil, err
}
return s.VoucherBiz.CmbProductQuery(ctx, bizContent.ActivityId)
}

View File

@ -107,45 +107,47 @@ func (s *VoucherService) DecryptBody(ctx http.Context) error {
func (s *VoucherService) QueryWechatVoucherNotifyUrl(ctx http.Context) error {
bodyBytes, err := io.ReadAll(ctx.Request().Body)
if err != nil {
return err
}
var req *v1.QueryWechatVoucherNotifyUrlRequest
if err = json.Unmarshal(bodyBytes, &req); err != nil {
return err
}
rep, err := s.VoucherBiz.WechatCpnRepo.QueryCallback(ctx, req.MchId, req.MchCertNo)
if err != nil {
return err
}
return ctx.JSON(200, &v1.QueryWechatVoucherNotifyUrlReply{
Url: *rep.NotifyUrl,
})
//bodyBytes, err := io.ReadAll(ctx.Request().Body)
//if err != nil {
// return err
//}
//
//var req *v1.QueryWechatVoucherNotifyUrlRequest
//if err = json.Unmarshal(bodyBytes, &req); err != nil {
// return err
//}
//
//rep, err := s.VoucherBiz.WechatCpnRepo.QueryCallback(ctx, req.MchId, req.MchCertNo)
//if err != nil {
// return err
//}
//
//return ctx.JSON(200, &v1.QueryWechatVoucherNotifyUrlReply{
// Url: *rep.NotifyUrl,
//})
return nil
}
func (s *VoucherService) SetWechatVoucherNotifyUrl(ctx http.Context) error {
bodyBytes, err := io.ReadAll(ctx.Request().Body)
if err != nil {
return err
}
var req *v1.SetWechatVoucherNotifyUrlRequest
if err = json.Unmarshal(bodyBytes, &req); err != nil {
return err
}
rep, err := s.VoucherBiz.WechatCpnRepo.SetCallback(ctx, req.MchId, req.MchCertNo, req.Url)
if err != nil {
return err
}
return ctx.JSON(200, &v1.SetWechatVoucherNotifyUrlReply{
MchId: req.MchId,
Url: *rep.NotifyUrl,
})
//bodyBytes, err := io.ReadAll(ctx.Request().Body)
//if err != nil {
// return err
//}
//
//var req *v1.SetWechatVoucherNotifyUrlRequest
//if err = json.Unmarshal(bodyBytes, &req); err != nil {
// return err
//}
//
//rep, err := s.VoucherBiz.WechatCpnRepo.SetCallback(ctx, req.MchId, req.MchCertNo, req.Url)
//if err != nil {
// return err
//}
//
//return ctx.JSON(200, &v1.SetWechatVoucherNotifyUrlReply{
// MchId: req.MchId,
// Url: *rep.NotifyUrl,
//})
return nil
}