From 7b8c29f0f881b1a1c479b081d01d669853ab8119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=AD=90=E9=93=AD?= Date: Tue, 4 Mar 2025 11:41:30 +0800 Subject: [PATCH] cmb --- Makefile | 2 +- cmd/server/wire.go | 6 +- cmd/server/wire_gen.go | 21 ++- configs/config.yaml | 4 + go.mod | 14 +- go.sum | 28 ++- internal/biz/voucher.go | 22 ++- internal/biz/wechatrepo/cpn.go | 12 ++ internal/conf/conf.pb.go | 170 ++++++++++++++----- internal/conf/conf.proto | 8 +- internal/data/wechat.go | 121 +++++++++++++ internal/data/wechatrepoimpl/cpn.go | 117 +++++++++++++ internal/data/wechatrepoimpl/cpn_status.go | 42 +++++ internal/data/wechatrepoimpl/provider_set.go | 10 ++ internal/pkg/helper/utils.go | 8 + third_party/swagger_ui/rapidoc.js | 14 +- 16 files changed, 527 insertions(+), 72 deletions(-) create mode 100644 internal/biz/wechatrepo/cpn.go create mode 100644 internal/data/wechat.go create mode 100644 internal/data/wechatrepoimpl/cpn.go create mode 100644 internal/data/wechatrepoimpl/cpn_status.go create mode 100644 internal/data/wechatrepoimpl/provider_set.go create mode 100644 internal/pkg/helper/utils.go diff --git a/Makefile b/Makefile index d30d32c..1219cf1 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ init: go install github.com/envoyproxy/protoc-gen-validate@v1.0.2 .PHONY: config -# generate internal proto +# generate cpn proto config: protoc --proto_path=./internal \ --proto_path=./third_party \ diff --git a/cmd/server/wire.go b/cmd/server/wire.go index e4ac70a..5eb6266 100644 --- a/cmd/server/wire.go +++ b/cmd/server/wire.go @@ -12,8 +12,9 @@ import ( "voucher/internal/biz" "voucher/internal/conf" "voucher/internal/data" - "voucher/internal/data/repositoryimpl" + "voucher/internal/data/repoimpl" "voucher/internal/data/thirdrepoimpl" + "voucher/internal/data/wechatrepoimpl" log2 "voucher/internal/pkg/log" "voucher/internal/server" "voucher/internal/service" @@ -25,8 +26,9 @@ func wireApp(*conf.Bootstrap, log.Logger, *log2.AccessLogger) (*kratos.App, func server.ProviderSetServer, service.ProviderSetService, biz.ProviderSetBiz, - repositoryimpl.ProviderRepoImplSet, + repoimpl.ProviderRepoImplSet, thirdrepoimpl.ProviderThirdRepositoryImplSet, + wechatrepoimpl.ProviderWechatReposImplSet, data.ProviderDataSet, log2.NewLogHelper, newApp, diff --git a/cmd/server/wire_gen.go b/cmd/server/wire_gen.go index bd255f4..1c73687 100644 --- a/cmd/server/wire_gen.go +++ b/cmd/server/wire_gen.go @@ -12,8 +12,9 @@ import ( "voucher/internal/biz" "voucher/internal/conf" "voucher/internal/data" - "voucher/internal/data/repositoryimpl" + "voucher/internal/data/repoimpl" "voucher/internal/data/thirdrepoimpl" + "voucher/internal/data/wechatrepoimpl" log2 "voucher/internal/pkg/log" "voucher/internal/server" "voucher/internal/service" @@ -28,17 +29,25 @@ import ( // wireApp init kratos application. func wireApp(bootstrap *conf.Bootstrap, logger log.Logger, accessLogger *log2.AccessLogger) (*kratos.App, func(), error) { helper := log2.NewLogHelper(logger) - gormDb, cleanup := data.NewGormDb(bootstrap) - db := data.NewDb(gormDb) - orderRepo := repositoryimpl.NewOrderRepoImpl(db) + rdb, cleanup, err := data.NewRdb(bootstrap) + if err != nil { + return nil, nil, err + } + orderRepo := repoimpl.NewOrderRepoImpl() rocketMQ, cleanup2, err := data.NewRocketMQ(bootstrap) if err != nil { cleanup() return nil, nil, err } thirdMQSend := thirdrepoimpl.NewMQSendImpl(rocketMQ) - voucherBiz := biz.NewVoucherBiz(orderRepo, thirdMQSend) - voucherService := service.NewVoucherService(voucherBiz) + wechatCpnRepo, err := wechatrepoimpl.NewCpnRepoImpl(bootstrap) + if err != nil { + cleanup2() + cleanup() + return nil, nil, err + } + voucherBiz := biz.NewVoucherBiz(rdb, orderRepo, thirdMQSend, wechatCpnRepo) + voucherService := service.NewVoucherService(bootstrap, voucherBiz) httpServer := server.NewHTTPServer(bootstrap, helper, accessLogger, voucherService) consumer := server.NewConsumer(helper, bootstrap, voucherService) app := newApp(logger, httpServer, consumer) diff --git a/configs/config.yaml b/configs/config.yaml index 9b72b96..cea7bf0 100644 --- a/configs/config.yaml +++ b/configs/config.yaml @@ -48,6 +48,10 @@ rocketMQ: PerCoroutineCnt: 5 #协程数量,不配置默认为20 RetryCnt: 3 #重试次数,不配置默认38 +wechat: + mchID: "1605446142" # 证书所属商户 + mchCertificateSerialNumber: "4D081089DEB385316CBDCB55C070287E4920AC76" + #配置日志 logs: business: business.log #业务日志路径:如果不写日志,则不配置或配置为空 diff --git a/go.mod b/go.mod index 08a20e2..b8dc5b3 100644 --- a/go.mod +++ b/go.mod @@ -9,18 +9,19 @@ require ( github.com/envoyproxy/protoc-gen-validate v1.0.4 github.com/go-kratos/kratos/contrib/config/nacos/v2 v2.0.0-20241105072421-f8b97f675b32 github.com/go-kratos/kratos/v2 v2.8.2 + github.com/go-playground/validator/v10 v10.25.0 github.com/gogf/gf v1.16.9 github.com/google/wire v0.6.0 github.com/gorilla/handlers v1.5.1 github.com/nacos-group/nacos-sdk-go v1.1.4 github.com/pkg/errors v0.9.1 github.com/redis/go-redis/v9 v9.1.0 + github.com/wechatpay-apiv3/wechatpay-go v0.2.20 go.opentelemetry.io/otel v1.28.0 go.opentelemetry.io/otel/exporters/jaeger v1.17.0 go.opentelemetry.io/otel/sdk v1.28.0 go.opentelemetry.io/otel/trace v1.28.0 go.uber.org/automaxprocs v1.5.1 - google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v2 v2.4.0 gorm.io/driver/mysql v1.5.7 @@ -35,12 +36,14 @@ require ( github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/emirpasic/gods v1.12.0 // indirect github.com/felixge/httpsnoop v1.0.1 // indirect + github.com/gabriel-vasile/mimetype v1.4.8 // indirect github.com/go-errors/errors v1.0.1 // indirect github.com/go-kratos/aegis v0.2.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-playground/assert/v2 v2.2.0 // indirect github.com/go-playground/form/v4 v4.2.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect github.com/golang/mock v1.3.1 // indirect github.com/google/uuid v1.6.0 // indirect @@ -52,6 +55,7 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/konsorten/go-windows-terminal-sequences v1.0.1 // indirect github.com/kr/text v0.2.0 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect @@ -65,13 +69,15 @@ require ( go.uber.org/atomic v1.6.0 // indirect go.uber.org/multierr v1.5.0 // indirect go.uber.org/zap v1.15.0 // indirect + golang.org/x/crypto v0.32.0 // indirect golang.org/x/exp v0.0.0-20221208152030-732eee02a75a // indirect golang.org/x/lint v0.0.0-20241112194109-818c5a804067 // indirect - golang.org/x/net v0.32.0 // indirect + golang.org/x/net v0.34.0 // indirect golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.28.0 // indirect + golang.org/x/sys v0.29.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/tools v0.28.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect google.golang.org/grpc v1.64.0 // indirect gopkg.in/ini.v1 v1.56.0 // indirect diff --git a/go.sum b/go.sum index 9dfb64a..7a1e25f 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,8 @@ dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/agiledragon/gomonkey v2.0.2+incompatible h1:eXKi9/piiC3cjJD1658mEE2o3NjkJ5vDLgYjCQu0Xlw= +github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw= github.com/aliyun/alibaba-cloud-sdk-go v1.61.18 h1:zOVTBdCKFd9JbCKz9/nt+FovbjPFmb7mUnp8nH9fQBA= github.com/aliyun/alibaba-cloud-sdk-go v1.61.18/go.mod h1:v8ESoHo4SyHmuB4b1tJqDHxfTGEciD+yhvOU/5s1Rfk= github.com/apache/rocketmq-client-go/v2 v2.1.2 h1:yt73olKe5N6894Dbm+ojRf/JPiP0cxfDNNffKwhpJVg= @@ -43,6 +45,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= +github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-kratos/aegis v0.2.0 h1:dObzCDWn3XVjUkgxyBp6ZeWtx/do0DPZ7LY3yNSJLUQ= @@ -61,6 +65,12 @@ github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lY github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/form/v4 v4.2.0 h1:N1wh+Goz61e6w66vo8vJkQt+uwZSoLz50kZPJWR8eic= github.com/go-playground/form/v4 v4.2.0/go.mod h1:q1a2BY+AQUUzhl6xA/6hBetay6dEIhMHjgvJiGo6K7U= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8= +github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= @@ -138,6 +148,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= @@ -190,6 +202,7 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -197,6 +210,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tidwall/gjson v1.13.0 h1:3TFY9yxOQShrvmjdM76K+jc66zJeT6D3/VFFYCGQf7M= @@ -205,6 +221,8 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/wechatpay-apiv3/wechatpay-go v0.2.20 h1:gS8oFn1bHGnyapR2Zb4aqTV6l4kJWgbtqjCq6k1L9DQ= +github.com/wechatpay-apiv3/wechatpay-go v0.2.20/go.mod h1:A254AUBVB6R+EqQFo3yTgeh7HtyqRRtN2w9hQSOrd4Q= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg= @@ -238,6 +256,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/exp v0.0.0-20221208152030-732eee02a75a h1:4iLhBPcpqFmylhnkbY3W0ONLUYYkDAW9xMFLfxgsvCw= golang.org/x/exp v0.0.0-20221208152030-732eee02a75a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -266,8 +286,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= -golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -301,8 +321,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= diff --git a/internal/biz/voucher.go b/internal/biz/voucher.go index 04ae355..33e5813 100644 --- a/internal/biz/voucher.go +++ b/internal/biz/voucher.go @@ -6,18 +6,30 @@ import ( "time" "voucher/internal/biz/repo" "voucher/internal/biz/thirdrepo" + "voucher/internal/biz/wechatrepo" "voucher/internal/data" "voucher/internal/pkg/lock" ) type VoucherBiz struct { - rdb *data.Rdb - OrderRepo repo.OrderRepo - ThirdMQSend thirdrepo.ThirdMQSend + rdb *data.Rdb + OrderRepo repo.OrderRepo + ThirdMQSend thirdrepo.ThirdMQSend + WechatCpnRepo wechatrepo.WechatCpnRepo } -func NewVoucherBiz(rdb *data.Rdb, orderRepo repo.OrderRepo, thirdMQSend thirdrepo.ThirdMQSend) *VoucherBiz { - return &VoucherBiz{rdb: rdb, OrderRepo: orderRepo, ThirdMQSend: thirdMQSend} +func NewVoucherBiz( + rdb *data.Rdb, + orderRepo repo.OrderRepo, + thirdMQSend thirdrepo.ThirdMQSend, + WechatCpnRepo wechatrepo.WechatCpnRepo, +) *VoucherBiz { + return &VoucherBiz{ + rdb: rdb, + OrderRepo: orderRepo, + ThirdMQSend: thirdMQSend, + WechatCpnRepo: WechatCpnRepo, + } } func (v *VoucherBiz) OrderConsume(ctx context.Context, orderNo string) (err error) { diff --git a/internal/biz/wechatrepo/cpn.go b/internal/biz/wechatrepo/cpn.go new file mode 100644 index 0000000..572992e --- /dev/null +++ b/internal/biz/wechatrepo/cpn.go @@ -0,0 +1,12 @@ +package wechatrepo + +import ( + "context" + "voucher/internal/biz/bo" + "voucher/internal/biz/vo" +) + +type WechatCpnRepo interface { + Order(ctx context.Context, orderWechat *bo.OrderWechatBo) (couponId string, err error) + Query(ctx context.Context, orderWechat *bo.OrderWechatBo) (vo.OrderWechatStatus, error) +} diff --git a/internal/conf/conf.pb.go b/internal/conf/conf.pb.go index a9e32d9..fd91124 100644 --- a/internal/conf/conf.pb.go +++ b/internal/conf/conf.pb.go @@ -30,6 +30,7 @@ type Bootstrap struct { Logs *Logs `protobuf:"bytes,2,opt,name=logs,proto3" json:"logs,omitempty"` Data *Data `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` RocketMQ *RocketMQ `protobuf:"bytes,4,opt,name=rocketMQ,proto3" json:"rocketMQ,omitempty"` + Wechat *Wechat `protobuf:"bytes,5,opt,name=wechat,proto3" json:"wechat,omitempty"` } func (x *Bootstrap) Reset() { @@ -92,6 +93,13 @@ func (x *Bootstrap) GetRocketMQ() *RocketMQ { return nil } +func (x *Bootstrap) GetWechat() *Wechat { + if x != nil { + return x.Wechat + } + return nil +} + type Server struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -344,6 +352,61 @@ func (x *EventMap) GetIsOpenConsumer() bool { return false } +type Wechat struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + MchID string `protobuf:"bytes,1,opt,name=mchID,proto3" json:"mchID,omitempty"` + MchCertificateSerialNumber string `protobuf:"bytes,2,opt,name=mchCertificateSerialNumber,proto3" json:"mchCertificateSerialNumber,omitempty"` +} + +func (x *Wechat) Reset() { + *x = Wechat{} + if protoimpl.UnsafeEnabled { + mi := &file_conf_conf_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Wechat) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Wechat) ProtoMessage() {} + +func (x *Wechat) ProtoReflect() protoreflect.Message { + mi := &file_conf_conf_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Wechat.ProtoReflect.Descriptor instead. +func (*Wechat) Descriptor() ([]byte, []int) { + return file_conf_conf_proto_rawDescGZIP(), []int{5} +} + +func (x *Wechat) GetMchID() string { + if x != nil { + return x.MchID + } + return "" +} + +func (x *Wechat) GetMchCertificateSerialNumber() string { + if x != nil { + return x.MchCertificateSerialNumber + } + return "" +} + type Logs struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -356,7 +419,7 @@ type Logs struct { func (x *Logs) Reset() { *x = Logs{} if protoimpl.UnsafeEnabled { - mi := &file_conf_conf_proto_msgTypes[5] + mi := &file_conf_conf_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -369,7 +432,7 @@ func (x *Logs) String() string { func (*Logs) ProtoMessage() {} func (x *Logs) ProtoReflect() protoreflect.Message { - mi := &file_conf_conf_proto_msgTypes[5] + mi := &file_conf_conf_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -382,7 +445,7 @@ func (x *Logs) ProtoReflect() protoreflect.Message { // Deprecated: Use Logs.ProtoReflect.Descriptor instead. func (*Logs) Descriptor() ([]byte, []int) { - return file_conf_conf_proto_rawDescGZIP(), []int{5} + return file_conf_conf_proto_rawDescGZIP(), []int{6} } func (x *Logs) GetBusiness() string { @@ -414,7 +477,7 @@ type Server_HTTP struct { func (x *Server_HTTP) Reset() { *x = Server_HTTP{} if protoimpl.UnsafeEnabled { - mi := &file_conf_conf_proto_msgTypes[6] + mi := &file_conf_conf_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -427,7 +490,7 @@ func (x *Server_HTTP) String() string { func (*Server_HTTP) ProtoMessage() {} func (x *Server_HTTP) ProtoReflect() protoreflect.Message { - mi := &file_conf_conf_proto_msgTypes[6] + mi := &file_conf_conf_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -494,7 +557,7 @@ type Data_Database struct { func (x *Data_Database) Reset() { *x = Data_Database{} if protoimpl.UnsafeEnabled { - mi := &file_conf_conf_proto_msgTypes[7] + mi := &file_conf_conf_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -507,7 +570,7 @@ func (x *Data_Database) String() string { func (*Data_Database) ProtoMessage() {} func (x *Data_Database) ProtoReflect() protoreflect.Message { - mi := &file_conf_conf_proto_msgTypes[7] + mi := &file_conf_conf_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -584,7 +647,7 @@ type Data_Redis struct { func (x *Data_Redis) Reset() { *x = Data_Redis{} if protoimpl.UnsafeEnabled { - mi := &file_conf_conf_proto_msgTypes[8] + mi := &file_conf_conf_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -597,7 +660,7 @@ func (x *Data_Redis) String() string { func (*Data_Redis) ProtoMessage() {} func (x *Data_Redis) ProtoReflect() protoreflect.Message { - mi := &file_conf_conf_proto_msgTypes[8] + mi := &file_conf_conf_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -683,7 +746,7 @@ var file_conf_conf_proto_rawDesc = []byte{ 0x6f, 0x12, 0x0e, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0xc5, 0x01, 0x0a, 0x09, 0x42, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x12, + 0x6f, 0x22, 0xf5, 0x01, 0x0a, 0x09, 0x42, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x12, 0x2e, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, @@ -695,7 +758,10 @@ var file_conf_conf_proto_rawDesc = []byte{ 0x61, 0x74, 0x61, 0x12, 0x34, 0x0a, 0x08, 0x72, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x4d, 0x51, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x4d, 0x51, 0x52, - 0x08, 0x72, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x4d, 0x51, 0x22, 0xff, 0x01, 0x0a, 0x06, 0x53, 0x65, + 0x08, 0x72, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x4d, 0x51, 0x12, 0x2e, 0x0a, 0x06, 0x77, 0x65, 0x63, + 0x68, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x76, 0x6f, 0x75, 0x63, + 0x68, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x57, 0x65, 0x63, 0x68, 0x61, + 0x74, 0x52, 0x06, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x22, 0xff, 0x01, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x2f, 0x0a, 0x04, 0x68, 0x74, 0x74, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x52, @@ -779,13 +845,19 @@ var file_conf_conf_proto_rawDesc = []byte{ 0x70, 0x65, 0x72, 0x43, 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, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x43, - 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x22, 0x3a, 0x0a, 0x04, 0x4c, 0x6f, 0x67, 0x73, 0x12, + 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x22, 0x5e, 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, 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, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 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, 0x65, 0x72, 0x22, 0x3a, 0x0a, 0x04, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x62, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x42, 0x1c, 0x5a, 0x1a, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2f, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x3b, 0x63, 0x6f, 0x6e, - 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x73, 0x73, 0x42, 0x17, 0x5a, 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 ( @@ -800,40 +872,42 @@ func file_conf_conf_proto_rawDescGZIP() []byte { return file_conf_conf_proto_rawDescData } -var file_conf_conf_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_conf_conf_proto_msgTypes = make([]protoimpl.MessageInfo, 11) var file_conf_conf_proto_goTypes = []any{ (*Bootstrap)(nil), // 0: voucher.config.Bootstrap (*Server)(nil), // 1: voucher.config.Server (*Data)(nil), // 2: voucher.config.Data (*RocketMQ)(nil), // 3: voucher.config.RocketMQ (*EventMap)(nil), // 4: voucher.config.EventMap - (*Logs)(nil), // 5: voucher.config.Logs - (*Server_HTTP)(nil), // 6: voucher.config.Server.HTTP - (*Data_Database)(nil), // 7: voucher.config.Data.Database - (*Data_Redis)(nil), // 8: voucher.config.Data.Redis - nil, // 9: voucher.config.RocketMQ.EventMapEntry - (*durationpb.Duration)(nil), // 10: google.protobuf.Duration + (*Wechat)(nil), // 5: voucher.config.Wechat + (*Logs)(nil), // 6: voucher.config.Logs + (*Server_HTTP)(nil), // 7: voucher.config.Server.HTTP + (*Data_Database)(nil), // 8: voucher.config.Data.Database + (*Data_Redis)(nil), // 9: voucher.config.Data.Redis + nil, // 10: voucher.config.RocketMQ.EventMapEntry + (*durationpb.Duration)(nil), // 11: google.protobuf.Duration } var file_conf_conf_proto_depIdxs = []int32{ 1, // 0: voucher.config.Bootstrap.server:type_name -> voucher.config.Server - 5, // 1: voucher.config.Bootstrap.logs:type_name -> voucher.config.Logs + 6, // 1: voucher.config.Bootstrap.logs:type_name -> voucher.config.Logs 2, // 2: voucher.config.Bootstrap.data:type_name -> voucher.config.Data 3, // 3: voucher.config.Bootstrap.rocketMQ:type_name -> voucher.config.RocketMQ - 6, // 4: voucher.config.Server.http:type_name -> voucher.config.Server.HTTP - 7, // 5: voucher.config.Data.db:type_name -> voucher.config.Data.Database - 8, // 6: voucher.config.Data.redis:type_name -> voucher.config.Data.Redis - 9, // 7: voucher.config.RocketMQ.eventMap:type_name -> voucher.config.RocketMQ.EventMapEntry - 10, // 8: voucher.config.Server.HTTP.timeout:type_name -> google.protobuf.Duration - 10, // 9: voucher.config.Data.Database.maxLifetime:type_name -> google.protobuf.Duration - 10, // 10: voucher.config.Data.Redis.readTimeout:type_name -> google.protobuf.Duration - 10, // 11: voucher.config.Data.Redis.writeTimeout:type_name -> google.protobuf.Duration - 10, // 12: voucher.config.Data.Redis.connMaxIdleTime:type_name -> google.protobuf.Duration - 4, // 13: voucher.config.RocketMQ.EventMapEntry.value:type_name -> voucher.config.EventMap - 14, // [14:14] is the sub-list for method output_type - 14, // [14:14] is the sub-list for method input_type - 14, // [14:14] is the sub-list for extension type_name - 14, // [14:14] is the sub-list for extension extendee - 0, // [0:14] is the sub-list for field type_name + 5, // 4: voucher.config.Bootstrap.wechat:type_name -> voucher.config.Wechat + 7, // 5: voucher.config.Server.http:type_name -> voucher.config.Server.HTTP + 8, // 6: voucher.config.Data.db:type_name -> voucher.config.Data.Database + 9, // 7: voucher.config.Data.redis:type_name -> voucher.config.Data.Redis + 10, // 8: voucher.config.RocketMQ.eventMap:type_name -> voucher.config.RocketMQ.EventMapEntry + 11, // 9: voucher.config.Server.HTTP.timeout:type_name -> google.protobuf.Duration + 11, // 10: voucher.config.Data.Database.maxLifetime:type_name -> google.protobuf.Duration + 11, // 11: voucher.config.Data.Redis.readTimeout:type_name -> google.protobuf.Duration + 11, // 12: voucher.config.Data.Redis.writeTimeout:type_name -> google.protobuf.Duration + 11, // 13: voucher.config.Data.Redis.connMaxIdleTime:type_name -> google.protobuf.Duration + 4, // 14: voucher.config.RocketMQ.EventMapEntry.value:type_name -> voucher.config.EventMap + 15, // [15:15] is the sub-list for method output_type + 15, // [15:15] is the sub-list for method input_type + 15, // [15:15] is the sub-list for extension type_name + 15, // [15:15] is the sub-list for extension extendee + 0, // [0:15] is the sub-list for field type_name } func init() { file_conf_conf_proto_init() } @@ -903,7 +977,7 @@ func file_conf_conf_proto_init() { } } file_conf_conf_proto_msgTypes[5].Exporter = func(v any, i int) any { - switch v := v.(*Logs); i { + switch v := v.(*Wechat); i { case 0: return &v.state case 1: @@ -915,7 +989,7 @@ func file_conf_conf_proto_init() { } } file_conf_conf_proto_msgTypes[6].Exporter = func(v any, i int) any { - switch v := v.(*Server_HTTP); i { + switch v := v.(*Logs); i { case 0: return &v.state case 1: @@ -927,7 +1001,7 @@ func file_conf_conf_proto_init() { } } file_conf_conf_proto_msgTypes[7].Exporter = func(v any, i int) any { - switch v := v.(*Data_Database); i { + switch v := v.(*Server_HTTP); i { case 0: return &v.state case 1: @@ -939,6 +1013,18 @@ func file_conf_conf_proto_init() { } } file_conf_conf_proto_msgTypes[8].Exporter = func(v any, i int) any { + switch v := v.(*Data_Database); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_conf_conf_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*Data_Redis); i { case 0: return &v.state @@ -957,7 +1043,7 @@ func file_conf_conf_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_conf_conf_proto_rawDesc, NumEnums: 0, - NumMessages: 10, + NumMessages: 11, NumExtensions: 0, NumServices: 0, }, diff --git a/internal/conf/conf.proto b/internal/conf/conf.proto index a13c394..207c708 100644 --- a/internal/conf/conf.proto +++ b/internal/conf/conf.proto @@ -1,7 +1,7 @@ syntax = "proto3"; package voucher.config; -option go_package = "voucher/internal/conf;conf"; +option go_package = "voucher/cpn/conf;conf"; import "google/protobuf/duration.proto"; @@ -10,6 +10,7 @@ message Bootstrap { Logs logs = 2; Data data = 3; RocketMQ rocketMQ = 4; + Wechat wechat = 5; } message Server { @@ -63,6 +64,11 @@ message EventMap { bool isOpenConsumer = 4; } +message Wechat { + string mchID = 1; + string mchCertificateSerialNumber = 2; +} + message Logs { string business = 1; string access = 2; diff --git a/internal/data/wechat.go b/internal/data/wechat.go new file mode 100644 index 0000000..44c5171 --- /dev/null +++ b/internal/data/wechat.go @@ -0,0 +1,121 @@ +package data + +import ( + "context" + "crypto/x509" + "fmt" + "github.com/go-playground/validator/v10" + "github.com/wechatpay-apiv3/wechatpay-go/core" + "github.com/wechatpay-apiv3/wechatpay-go/core/auth/verifiers" + "github.com/wechatpay-apiv3/wechatpay-go/core/option" + "github.com/wechatpay-apiv3/wechatpay-go/utils" + "os" + "sync" + "voucher/internal/pkg/helper" +) + +type Server struct { + MchID string `validate:"required" json:"mch_id"` + MchCertificateSerialNumber string `validate:"required" json:"mch_certificate_serial_number"` +} + +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) { + dir, err := os.Getwd() + if err != nil { + return nil, err + } + + filePath := fmt.Sprintf("%s/%s/%s/%s", dir, "cert", "wechat", c.MchID) + + if !helper.FileExists(filePath) { + return nil, fmt.Errorf("MchID[%s]微信密钥证书信息不存在,请联系技术人员处理", c.MchID) + } + + // 商户相关配置,商户API私钥 + mchPrivateKey, err := utils.LoadPrivateKeyWithPath(fmt.Sprintf("%s/%s", filePath, "wechat_private_key.pem")) + if err != nil { + return nil, err + } + + var client *core.Client + // 微信支付平台配置 + wechatPayCertificate, err := utils.LoadCertificateWithPath(fmt.Sprintf("%s/%s", filePath, "wechat_cert.pem")) + if err != nil { + return nil, err + } + + client, err = core.NewClient( + ctx, + option.WithMerchantCredential( + c.MchID, + c.MchCertificateSerialNumber, + mchPrivateKey, + ), + option.WithWechatPayCertificate([]*x509.Certificate{wechatPayCertificate}), + ) + if err != nil { + return nil, err + } + + return client, nil +} + +type manager struct { + once sync.Once + mutex sync.RWMutex + clients map[string]*core.Client +} + +var instance manager + +func init() { + instance = manager{ + clients: make(map[string]*core.Client), + } +} + +func GetClient(ctx context.Context, c *Server) (*core.Client, error) { + instance.mutex.Lock() + defer instance.mutex.Unlock() + + if i, ok := instance.clients[c.MchID]; ok { + return i, nil + } + + var err error + + instance.once.Do(func() { + i, err2 := newClient(ctx, c) + if err2 != nil { + err = err2 + return + } + instance.clients[c.MchID] = i + }) + + if err != nil { + return nil, err + } + + return instance.clients[c.MchID], nil +} + +func (s *Server) Verify(ctx context.Context, message, signature string) error { + + verifier := verifiers.NewSHA256WithRSAVerifier(nil) + + if err := verifier.Verify(ctx, s.MchCertificateSerialNumber, message, signature); err != nil { + return err + } + + return nil +} diff --git a/internal/data/wechatrepoimpl/cpn.go b/internal/data/wechatrepoimpl/cpn.go new file mode 100644 index 0000000..3fd2bcd --- /dev/null +++ b/internal/data/wechatrepoimpl/cpn.go @@ -0,0 +1,117 @@ +package wechatrepoimpl + +import ( + "context" + "fmt" + "github.com/wechatpay-apiv3/wechatpay-go/core" + "github.com/wechatpay-apiv3/wechatpay-go/services/cashcoupons" + "github.com/wechatpay-apiv3/wechatpay-go/services/merchantexclusivecoupon" + "voucher/internal/biz/bo" + "voucher/internal/biz/vo" + "voucher/internal/biz/wechatrepo" + "voucher/internal/conf" + "voucher/internal/data" +) + +type CpnRepoImpl struct { + Server *data.Server +} + +func NewCpnRepoImpl(bc *conf.Bootstrap) (wechatrepo.WechatCpnRepo, error) { + server := &data.Server{ + MchID: bc.Wechat.MchID, + MchCertificateSerialNumber: bc.Wechat.MchCertificateSerialNumber, + } + + if err := server.Validate(); err != nil { + return nil, err + } + + return &CpnRepoImpl{Server: server}, nil +} + +func (c *CpnRepoImpl) Order(ctx context.Context, orderWechat *bo.OrderWechatBo) (couponId string, err error) { + + req := cashcoupons.SendCouponRequest{ + Openid: core.String(orderWechat.OpenID), + StockId: core.String(orderWechat.StockID), + OutRequestNo: core.String(orderWechat.OutRequestNo), + Appid: core.String(orderWechat.AppID), + StockCreatorMchid: core.String(orderWechat.StockCreatorMchid), + } + + client, err := data.GetClient(ctx, c.Server) + if err != nil { + return + } + + svc := cashcoupons.CouponApiService{Client: client} + + resp, result, err := svc.SendCoupon(ctx, req) + if err != nil { + return + } + + if result.Response.StatusCode != CodeSuccess { + err = fmt.Errorf("Order微信返回错误StatusCode[%d]Status[%s]", result.Response.StatusCode, result.Response.Status) + return + } + + couponId = *resp.CouponId + + return +} + +func (c *CpnRepoImpl) Query(ctx context.Context, orderWechat *bo.OrderWechatBo) (vo.OrderWechatStatus, error) { + + req := cashcoupons.QueryCouponRequest{ + CouponId: core.String(orderWechat.CouponID), + Appid: core.String(orderWechat.AppID), + Openid: core.String(orderWechat.OpenID), + } + + client, err := data.GetClient(ctx, c.Server) + if err != nil { + return 0, err + } + + svc := cashcoupons.CouponApiService{Client: client} + + resp, result, err := svc.QueryCoupon(ctx, req) + if err != nil { + return 0, err + } + + if result.Response.StatusCode != CodeSuccess { + err = fmt.Errorf("Query微信返回错误StatusCode[%d]Status[%s]", result.Response.StatusCode, result.Response.Status) + return 0, err + } + + return CpnStatus(*resp.Status).GetStatus() +} + +func (c *CpnRepoImpl) QueryProduct(ctx context.Context, stockId string) error { + + client, err := data.GetClient(ctx, c.Server) + if err != nil { + return err + } + + svc := merchantexclusivecoupon.BusiFavorApiService{Client: client} + + _, result, err := svc.QueryStock(ctx, merchantexclusivecoupon.QueryStockRequest{StockId: core.String(stockId)}) + if err != nil { + return err + } + + if result.Response.StatusCode != CodeSuccess { + err = fmt.Errorf("Query微信返回错误StatusCode[%d]Status[%s]", result.Response.StatusCode, result.Response.Status) + return err + } + + return nil +} + +func (c *CpnRepoImpl) Notify(ctx context.Context) error { + return nil +} diff --git a/internal/data/wechatrepoimpl/cpn_status.go b/internal/data/wechatrepoimpl/cpn_status.go new file mode 100644 index 0000000..f2e1fc8 --- /dev/null +++ b/internal/data/wechatrepoimpl/cpn_status.go @@ -0,0 +1,42 @@ +package wechatrepoimpl + +import ( + "fmt" + "voucher/internal/biz/vo" +) + +const CodeSuccess = 200 + +type CpnStatus string + +const ( + CpnStatusAvailable = "SENDED" + CpnStatusUsed = "USED" + CpnStatusExpired = "EXPIRED" +) + +var CpnStatusTextMap = map[CpnStatus]string{ + CpnStatusAvailable: "可用", + CpnStatusUsed: "已实扣", + CpnStatusExpired: "已过期", +} + +var CpnStatusMap = map[CpnStatus]vo.OrderWechatStatus{ + CpnStatusAvailable: vo.OrderWechatStatusSuccess, + CpnStatusUsed: vo.OrderWechatStatusUse, + CpnStatusExpired: vo.OrderWechatStatusExpired, +} + +func (o CpnStatus) GetText() string { + if msg, ok := CpnStatusTextMap[o]; !ok { + return msg + } + return "" +} + +func (o CpnStatus) GetStatus() (vo.OrderWechatStatus, error) { + if resultStatus, ok := CpnStatusMap[o]; ok { + return resultStatus, nil + } + return 0, fmt.Errorf("CpnStatus[%s]未定义", o) +} diff --git a/internal/data/wechatrepoimpl/provider_set.go b/internal/data/wechatrepoimpl/provider_set.go new file mode 100644 index 0000000..5b89fe6 --- /dev/null +++ b/internal/data/wechatrepoimpl/provider_set.go @@ -0,0 +1,10 @@ +package wechatrepoimpl + +import ( + "github.com/google/wire" +) + +// ProviderWechatReposImplSet is providers. +var ProviderWechatReposImplSet = wire.NewSet( + NewCpnRepoImpl, +) diff --git a/internal/pkg/helper/utils.go b/internal/pkg/helper/utils.go new file mode 100644 index 0000000..fb1a38e --- /dev/null +++ b/internal/pkg/helper/utils.go @@ -0,0 +1,8 @@ +package helper + +import "os" + +func FileExists(filePath string) bool { + _, err := os.Stat(filePath) + return err == nil || os.IsExist(err) +} diff --git a/third_party/swagger_ui/rapidoc.js b/third_party/swagger_ui/rapidoc.js index 314582d..5ff18d1 100644 --- a/third_party/swagger_ui/rapidoc.js +++ b/third_party/swagger_ui/rapidoc.js @@ -2250,7 +2250,7 @@ class Slugger { * Convert string to unique id * @param {object} [options] * @param {boolean} [options.dryrun] Generates the next unique slug without - * updating the internal accumulator. + * updating the cpn accumulator. */ slug(value, options = {}) { const slug = this.serialize(value); @@ -14610,20 +14610,20 @@ class ApiRequest extends lit_element_s { type: String, attribute: 'fetch-credentials' }, - // properties for internal tracking + // properties for cpn tracking activeResponseTab: { type: String }, - // internal tracking of response-tab not exposed as a attribute + // cpn tracking of response-tab not exposed as a attribute selectedRequestBodyType: { type: String, attribute: 'selected-request-body-type' }, - // internal tracking of selected request-body type + // cpn tracking of selected request-body type selectedRequestBodyExample: { type: String, attribute: 'selected-request-body-example' - } // internal tracking of selected request-body example + } // cpn tracking of selected request-body example }; } @@ -23528,7 +23528,7 @@ exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { // ("var" and "dynamic" are missing because they are used like types) contextual: 'add alias and ascending async await by descending from(?=\\s*(?:\\w|$)) get global group into init(?=\\s*;) join let nameof not notnull on or orderby partial remove select set unmanaged value when where with(?=\\s*{)', // all other keywords - other: 'abstract as base break case catch checked const continue default delegate do else mq explicit extern finally fixed for foreach goto if implicit in internal is lock namespace new null operator out override params private protected public readonly ref return sealed sizeof stackalloc static switch this throw try typeof unchecked unsafe using virtual volatile while yield' + other: 'abstract as base break case catch checked const continue default delegate do else mq explicit extern finally fixed for foreach goto if implicit in cpn is lock namespace new null operator out override params private protected public readonly ref return sealed sizeof stackalloc static switch this throw try typeof unchecked unsafe using virtual volatile while yield' }; // keywords @@ -25263,7 +25263,7 @@ var Prism = (function (_self) { /** * A token stream is an array of strings and {@link Token Token} objects. * - * Token streams have to fulfill a few properties that are assumed by most functions (mostly internal ones) that process + * Token streams have to fulfill a few properties that are assumed by most functions (mostly cpn ones) that process * them. * * 1. No adjacent strings.