This commit is contained in:
李子铭 2025-03-04 11:41:30 +08:00
parent 0e55f5c468
commit 7b8c29f0f8
16 changed files with 527 additions and 72 deletions

View File

@ -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 \

View File

@ -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,

View File

@ -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)

View File

@ -48,6 +48,10 @@ rocketMQ:
PerCoroutineCnt: 5 #协程数量不配置默认为20
RetryCnt: 3 #重试次数,不配置默认38
wechat:
mchID: "1605446142" # 证书所属商户
mchCertificateSerialNumber: "4D081089DEB385316CBDCB55C070287E4920AC76"
#配置日志
logs:
business: business.log #业务日志路径:如果不写日志,则不配置或配置为空

14
go.mod
View File

@ -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

28
go.sum
View File

@ -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=

View File

@ -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) {

View File

@ -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)
}

View File

@ -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,
},

View File

@ -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;

121
internal/data/wechat.go Normal file
View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -0,0 +1,10 @@
package wechatrepoimpl
import (
"github.com/google/wire"
)
// ProviderWechatReposImplSet is providers.
var ProviderWechatReposImplSet = wire.NewSet(
NewCpnRepoImpl,
)

View File

@ -0,0 +1,8 @@
package helper
import "os"
func FileExists(filePath string) bool {
_, err := os.Stat(filePath)
return err == nil || os.IsExist(err)
}

View File

@ -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.