diff --git a/api/err/cmb.proto b/api/err/cmb.proto new file mode 100644 index 0000000..dd8cde3 --- /dev/null +++ b/api/err/cmb.proto @@ -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]; +} \ No newline at end of file diff --git a/api/err/err.proto b/api/err/err.proto index 81d60ab..935a194 100644 --- a/api/err/err.proto +++ b/api/err/err.proto @@ -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]; -} \ No newline at end of file +} diff --git a/api/err/wechat.proto b/api/err/wechat.proto new file mode 100644 index 0000000..0f88649 --- /dev/null +++ b/api/err/wechat.proto @@ -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]; +} diff --git a/api/v1/cmb_cpn.proto b/api/v1/cmb_cpn.proto index da4c8f3..f4ceb61 100644 --- a/api/v1/cmb_cpn.proto +++ b/api/v1/cmb_cpn.proto @@ -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"]; } diff --git a/internal/data/mixrepoimpl/cmb.go b/internal/data/mixrepoimpl/cmb.go index 1e7a0cf..e615827 100644 --- a/internal/data/mixrepoimpl/cmb.go +++ b/internal/data/mixrepoimpl/cmb.go @@ -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 diff --git a/internal/data/wechat.go b/internal/data/wechat.go index ca67489..166799b 100644 --- a/internal/data/wechat.go +++ b/internal/data/wechat.go @@ -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) diff --git a/internal/data/wechatrepoimpl/cpn.go b/internal/data/wechatrepoimpl/cpn.go index 38e8543..0b2d992 100644 --- a/internal/data/wechatrepoimpl/cpn.go +++ b/internal/data/wechatrepoimpl/cpn.go @@ -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, } diff --git a/internal/pkg/helper/utils.go b/internal/pkg/helper/utils.go index fb1a38e..3864177 100644 --- a/internal/pkg/helper/utils.go +++ b/internal/pkg/helper/utils.go @@ -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() +} diff --git a/internal/service/cmb.go b/internal/service/cmb.go index 5b8035b..d35355d 100644 --- a/internal/service/cmb.go +++ b/internal/service/cmb.go @@ -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) } diff --git a/internal/service/cmb_mock.go b/internal/service/cmb_mock.go index cdcadf0..091012c 100644 --- a/internal/service/cmb_mock.go +++ b/internal/service/cmb_mock.go @@ -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 }