Compare commits

...

91 Commits
pro ... kx

Author SHA1 Message Date
ziming b5e1174402 kx 2025-06-16 11:38:48 +08:00
ziming fa36755179 Merge branch 'pro' into kx
# Conflicts:
#	internal/pkg/request/request.go
2025-06-16 11:37:52 +08:00
ziming ef2d9a92d5 timeSliceQuery 2025-06-13 10:28:19 +08:00
ziming 744e7d4169 Merge branch 'pro' into kx
# Conflicts:
#	READEME.md
#	internal/biz/wechat_notify.go
#	internal/conf/conf.pb.go
2025-06-13 10:27:06 +08:00
ziming f355aa624a Merge branch 'pro' into kx 2025-06-10 10:04:27 +08:00
ziming 9012f17bc0 Merge branch 'pro' into kx
# Conflicts:
#	internal/biz/voucher.go
2025-06-10 09:58:42 +08:00
ziming 5cb45a3aaf Merge branch 'pro' into kx
# Conflicts:
#	internal/biz/wechat_notify.go
2025-06-09 15:13:46 +08:00
ziming 650cd52364 kx 2025-06-09 09:54:55 +08:00
ziming 59d7f77873 kx 2025-06-09 09:30:52 +08:00
ziming a367a4530c Merge branch 'pro' into kx 2025-06-09 09:30:33 +08:00
ziming 6bc3524535 WechatQuery 2025-06-06 09:20:42 +08:00
ziming e5dcd3e66d Merge branch 'pro' into kx
# Conflicts:
#	internal/conf/conf.pb.go
2025-06-06 09:19:19 +08:00
ziming c92828fc41 空港 2025-06-03 11:05:05 +08:00
ziming 4b9c9b5652 Merge branch 'pro' into kx
# Conflicts:
#	api/v1/cmb_cpn.proto
#	internal/biz/alarm.go
#	internal/biz/order.go
#	internal/biz/query.go
#	internal/pkg/mq_http/mq_http_test.go
#	internal/server/wechat_consumer.go
#	internal/service/cmb.go
#	internal/service/order.go
2025-06-03 09:46:41 +08:00
ziming 993e567eca mock use 2025-05-27 16:54:50 +08:00
ziming c3901c7f94 mock use 2025-05-27 16:20:27 +08:00
ziming 6a7da03a25 mock use 2025-05-27 16:15:45 +08:00
ziming 8d11662035 mock use 2025-05-27 16:11:14 +08:00
ziming 2b10381a16 mock use 2025-05-27 16:05:19 +08:00
ziming 6fd65bcdd5 mock use 2025-05-27 16:04:46 +08:00
ziming 2f7194c945 mock use 2025-05-27 13:44:58 +08:00
ziming de9f99e62b mock use 2025-05-27 11:46:28 +08:00
ziming 9c0b5b5c31 检测服务关闭~ 2025-05-27 11:22:50 +08:00
ziming eb5650a235 检测服务关闭~ 2025-05-26 18:21:42 +08:00
ziming a0e8865820 检测服务关闭~ 2025-05-26 17:39:20 +08:00
ziming 05784b85fe 检测服务关闭~ 2025-05-26 14:23:06 +08:00
ziming 3e6e85fd82 检测服务关闭~ 2025-05-26 14:17:42 +08:00
ziming 433982c75b 检测服务关闭~ 2025-05-26 14:16:27 +08:00
ziming f59bf4fa15 检测服务关闭~ 2025-05-26 14:11:13 +08:00
ziming 4a2e8f8307 add api 2025-05-26 09:23:20 +08:00
ziming c267632672 add api 2025-05-23 18:05:31 +08:00
ziming 0a45f678b8 add api 2025-05-23 17:39:42 +08:00
ziming 7883156d26 del register tag 2025-05-23 16:48:04 +08:00
ziming 95e11c4f14 del register tag 2025-05-23 14:22:49 +08:00
ziming 29d0bc633d register tag 2025-05-23 14:04:07 +08:00
ziming 4fb8ddfc2d chang code 2025-05-23 13:55:48 +08:00
ziming 07641871f2 chang code 2025-05-23 11:43:44 +08:00
ziming 9f2e438ab6 chang code 2025-05-23 10:42:40 +08:00
ziming 8daa814b8d chang code 2025-05-23 10:19:13 +08:00
ziming 22b0c4f6ef kx time out 10s add log 2025-05-22 17:42:08 +08:00
ziming 0c7571cb7b kx time out 10s add log 2025-05-22 17:29:34 +08:00
ziming 2f6b22db59 kx time out 10s 2025-05-22 16:55:28 +08:00
ziming 304dc56bb2 kx 2025-05-22 15:31:40 +08:00
ziming 07c8ffc236 kx 2025-05-22 15:06:39 +08:00
ziming fa66f4cca7 kx 2025-05-22 15:04:01 +08:00
ziming 43b0b0a5fa kx 2025-05-22 14:46:58 +08:00
ziming d4e2d2d00a kx 2025-05-22 11:39:26 +08:00
ziming 3b29b4ef66 kx 2025-05-22 11:13:52 +08:00
ziming d8279de232 kx 2025-05-22 10:19:00 +08:00
ziming aa140a9627 kx 2025-05-21 18:25:09 +08:00
ziming 61ff2ae897 kx 2025-05-21 18:22:46 +08:00
ziming e59653cdae kx 2025-05-21 18:22:23 +08:00
ziming b8eb1208d0 kx 2025-05-21 17:34:57 +08:00
ziming ef26d56c56 kx 2025-05-21 17:03:32 +08:00
ziming ce501ce5cc kx 2025-05-21 16:51:56 +08:00
ziming 61da538e2f kx 2025-05-21 16:46:06 +08:00
ziming 7d9996e9f6 kx 2025-05-21 16:39:56 +08:00
ziming 059b2d30f0 kx 2025-05-21 16:35:53 +08:00
ziming 62ba3ef1fa kg 2025-05-21 16:13:11 +08:00
ziming 54e233217c kg 2025-05-21 16:06:35 +08:00
ziming eb4beba9e4 kg 2025-05-21 15:57:15 +08:00
ziming e0d69c5e22 kg 2025-05-21 15:52:44 +08:00
ziming 781de4ea02 kg 2025-05-21 15:46:03 +08:00
ziming 39e98122ed kg 2025-05-21 15:36:56 +08:00
ziming 2bdd2f7ef4 kg 2025-05-21 15:34:15 +08:00
ziming d01604fd78 kg 2025-05-21 15:29:51 +08:00
ziming e18ca47d93 kg 2025-05-21 15:29:18 +08:00
ziming 5990378b77 kg 2025-05-21 15:28:40 +08:00
ziming 668cc3177e kg 2025-05-21 14:54:51 +08:00
ziming fee0786d68 kg 2025-05-21 14:49:38 +08:00
ziming 86142caad1 kg 2025-05-21 14:48:45 +08:00
ziming 420a6d3be3 kg 2025-05-21 14:27:43 +08:00
ziming ee85d3debe kg 2025-05-21 14:19:43 +08:00
ziming ddab078e1f kg 2025-05-21 11:54:35 +08:00
ziming 13cd99300f kg 2025-05-21 11:51:12 +08:00
ziming e9a754e08a kg 2025-05-21 11:40:36 +08:00
ziming 62f946f520 kg 回调地址是制券商户设置的回调地址,而不是发券商户设置的回调地址,除非发券商户就是制券商户 2025-05-21 11:22:01 +08:00
ziming 4de408c547 kg 2025-05-21 11:05:16 +08:00
ziming f4872bfe74 kg 2025-05-21 10:51:57 +08:00
ziming 01ac62f2bc kg 2025-05-21 10:44:35 +08:00
ziming 12e8951c4f kg 2025-05-21 10:27:52 +08:00
ziming 0dd2d8d3d6 kg 2025-05-20 17:48:45 +08:00
ziming 07f15ce605 kg 2025-05-20 17:16:56 +08:00
ziming bb5e9ee0e9 kg 2025-05-20 16:27:40 +08:00
ziming 6e05cf2045 kg 2025-05-20 15:44:49 +08:00
ziming d8c827b59e kg 2025-05-20 15:37:38 +08:00
ziming 0a15c6d7b0 kg 2025-05-20 15:36:52 +08:00
ziming ef81c198cf kx 2025-05-20 15:10:57 +08:00
ziming 6a3c0d44a6 kx 2025-05-20 14:37:43 +08:00
ziming 0a71346d3b kx 2025-05-20 14:17:04 +08:00
ziming ad95880eef kx 2025-05-20 14:16:54 +08:00
44 changed files with 963 additions and 337 deletions

2
.gitignore vendored
View File

@ -31,5 +31,5 @@ configs/config_pre2.yaml
configs/config_mock.yaml
api/**/*.go
cmd/server/wire_gen.go
/internal/conf/*.go
internal/conf/*.go
/third_party/swagger_ui/openapi.yaml

View File

@ -5,4 +5,33 @@
+ 发券API
* * *
### 压测说明
1、调用接口 POST:[http://open.cszfan.com/voucher/cmb/v1/orderMock]
+ 参数如下
````json
{
"transactionId": "每次请求生成一个唯一标识",
"activityId": "001",
"cmbUid": "oO3vO5K2nE131-9uMoeYymLhlbYk",
"cmbUidType": "1",
"timestamp": "19780107024253",
"appId": "wx9ed74283ad25bca1"
}
````
+ 返回结果如下
````json
{
"mid": "d6fdd78b6fd13a808818286b9cad9687",
"aid": "5efaa21263b94f669a1c90ed0279df20",
"date": "20250521152454",
"random": "BOIzv5O478S2Qsri",
"keyAlias": "CO_PUB_KEY_SM2",
"cmbKeyAlias": "SM2_CMBLIFE",
"encryptBody": "BDlFJjgBCJITzwf4UPpBViwFq2g+Qtiibmmen3UZqVa+Ob+GjH6O+zPXmI4nbR180PkzPUtmAzyCE61fCzcvJ1VAALjTRDrQ2vVq4bdWrv534XZQ/DD2B7AIDBIy3mehTi6DabWr8vEqPdYPoIfBSCIBX26ZNv32TzphuRHLc9D6VnxiQZlVW5DQM7u/|4E+rxnl3hSicNRnBmaq4Zu7pwB0wFKZ/6Vo+SI3HzVZSTbFWmF04pqZQqo5E4Sarqi0hA9eIDXEUPWvdbLs3IexG6l/k+NwN8h7w5Q5i0MhRvUBLiPZO1tHrNC9QBEwedy6IzUf2wfPKDSbHB+i3oDmatkp/XZA5UL5m+vI8D2aYv8CMp4BEbiF0bKVSTaS7Ws0yEOiOqi7w3HHGQE11gA==",
"sign": "MEQCID/L7XK8zr0NiErG0MbJpmakK7W9iK13PC44ye6QCecyAiBQcTv/KDVieQK/N7tReaofDnUCP8k+3R+CsNAzvCDRUw=="
}
````
2、调用接口 POST:[http://open.cszfan.com/voucher/cmb/v1/order]
````text
将接口1返回的数据作为接口2的请求参数,发起请求,http状态码200为成功,其它属于异常
````

View File

@ -68,6 +68,7 @@ cmb:
notifyUrl: "https://sandbox.cdcc.cmbchina.com/AccessGateway/transIn/updateCodeStatus.json" # 招行测试回调地址
noticeStartDays: 7
noticeEndDays: 1
kxNoticeUrl: "https://wpcallbacks.api.1688sup.com/wechatPay/register_tag"
#告警配置
alarm:

1
go.mod
View File

@ -76,6 +76,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/sirupsen/logrus v1.4.0 // indirect
github.com/stretchr/testify v1.10.0 // indirect
github.com/tidwall/gjson v1.13.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect

7
go.sum
View File

@ -239,8 +239,9 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
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/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@ -249,8 +250,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
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/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tidwall/gjson v1.13.0 h1:3TFY9yxOQShrvmjdM76K+jc66zJeT6D3/VFFYCGQf7M=
github.com/tidwall/gjson v1.13.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=

23
gorm.sh
View File

@ -112,9 +112,7 @@ import (
)
type ${table_capitalized}Repo interface {
// Create 创建 ${table_capitalized}
Create(ctx context.Context, req *bo.${table_capitalized}Bo) (*bo.${table_capitalized}Bo, error)
// GetByID 根据 ID 获取 ${table_capitalized}
GetByID(ctx context.Context,id int32) (*bo.${table_capitalized}Bo, error)
}
EOL
@ -133,6 +131,7 @@ import (
"voucher/internal/biz/repo"
"voucher/internal/biz/bo"
"voucher/internal/data"
"gorm.io/gorm"
err2 "voucher/api/err"
)
@ -143,34 +142,34 @@ type ${table_capitalized}RepoImpl struct {
}
// New${table_capitalized}RepoImpl .
func New${table_capitalized}RepoImpl() repo.${table_capitalized}Repo {
return &${table_capitalized}RepoImpl{}
func New${table_capitalized}RepoImpl(db *data.Db) repo.${table_capitalized}Repo {
return &${table_capitalized}RepoImpl{db:db}
}
func (r *${table_capitalized}RepoImpl) DB(ctx context.Context) *gorm.DB {
return p.db.DB(ctx).WithContext(ctx).Model(model.${table_capitalized}{})
func (this *${table_capitalized}RepoImpl) DB(ctx context.Context) *gorm.DB {
return this.db.DB(ctx).WithContext(ctx).Model(model.${table_capitalized}{})
}
func (r *${table_capitalized}RepoImpl) Create(ctx context.Context, req *bo.${table_capitalized}Bo) (*bo.${table_capitalized}Bo, error) {
func (this *${table_capitalized}RepoImpl) Create(ctx context.Context, req *bo.${table_capitalized}Bo) (*bo.${table_capitalized}Bo, error) {
// todo 待实现
return nil, nil
}
// GetByID 根据 ID 获取 ${table_capitalized}
func (r *${table_capitalized}RepoImpl) GetByID(ctx context.Context,id int32) (*bo.${table_capitalized}Bo, error) {
func (this *${table_capitalized}RepoImpl) GetByID(ctx context.Context,id int32) (*bo.${table_capitalized}Bo, error) {
var item model.${table_capitalized}
tx := p.DB(ctx).Where(model.${table_capitalized}{ID: id}).First(&item)
tx := this.DB(ctx).Where(model.${table_capitalized}{ID: id}).First(&item)
if tx.Error != nil {
return nil, fmt.Errorf("b fail %w", tx.Error)
return nil, tx.Error
}
if tx.RowsAffected == 0 {
return nil, err2.ErrorDbNotFound("数据不存在")
return nil, gorm.ErrRecordNotFound
}
return r.ToBo(&item), nil
return this.ToBo(&item), nil
}
EOL

View File

@ -55,7 +55,7 @@ func (v *VoucherBiz) alarm(ctx context.Context, order *bo.OrderBo, errMsg string
func (v *VoucherBiz) alarmText(_ context.Context, order *bo.OrderBo, errMsg string) string {
remarks := fmt.Sprintf("订单号:%s,商品编号:%s,原因:%s", order.OrderNo, order.ProductNo, errMsg)
remarks := fmt.Sprintf("订单号:%s,账号:%s,商品编号:%s,原因:%s", order.OrderNo, order.Account, order.ProductNo, errMsg)
msg := "# <font color='green'>" +
"<h1>立减金发放平台报警通知</h1>" +

View File

@ -28,6 +28,9 @@ type OrderBo struct {
LastUseTime *time.Time
CreateTime *time.Time
UpdateTime *time.Time
MiniMum int32
CouponValue int32
}
type OrderCreateReqBo struct {

View File

@ -13,6 +13,8 @@ type ProductBo struct {
BatchName string
BatchNo string
MchId string
MiniMum int32 // 使用券金额门槛
Amount int32
Channel vo.Channel
AvailableType vo.AvailableType
AvailableDays uint32

View File

@ -0,0 +1,16 @@
package bo
import (
"time"
"voucher/internal/biz/vo"
)
// UseLogBo 领域实体Bo结构,字段和模型字段保持一致
type UseLogBo struct {
ID uint64
OrderNo string
Amount int64
Type vo.UseLogType
OperateTime *time.Time
CreateTime *time.Time
}

View File

@ -4,9 +4,10 @@ import "voucher/internal/biz/vo"
// ConsumeInformation 定义消费信息结构体
type ConsumeInformation struct {
ConsumeTime string `json:"consume_time"`
ConsumeMchid string `json:"consume_mchid"`
TransactionID string `json:"transaction_id"`
ConsumeTime string `json:"consume_time"` // 代金券核销时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE
ConsumeMchid string `json:"consume_mchid"` // 核销代金券的商户号
TransactionID string `json:"transaction_id"` // 微信支付系统生成的订单号
ConsumeAmount int64 `json:"consume_amount,omitempty"` // 核销金额,仅有当business_type=MULTIUSE时,才会返回。单位,分
}
// PlainText 定义明文数据结构体
@ -22,6 +23,7 @@ type PlainText struct {
NoCash bool `json:"no_cash"`
Singleitem bool `json:"singleitem"`
ConsumeInformation ConsumeInformation `json:"consume_information,omitempty"`
BusinessType string `json:"business_type,omitempty"` // 枚举值 MULTIUSE:消费金,仅有当business_type=MULTIUSE时,才会返回
}
type WechatVoucherNotifyBo struct {

View File

@ -11,6 +11,7 @@ import (
"time"
"voucher/internal/biz/bo"
"voucher/internal/biz/vo"
"voucher/internal/data/wechatrepoimpl"
"voucher/internal/pkg/lock"
)
@ -178,7 +179,12 @@ func (v *VoucherBiz) ExecuteNotice(ctx context.Context, req *bo.FindInBatchesUse
func (v *VoucherBiz) notice(ctx context.Context, order *bo.OrderBo, notifyNum *int) error {
// 批量通知不做数据存储,量会很大
status, err := v.WechatCpnRepo.Query(ctx, order)
resp, err := v.WechatCpnRepo.QueryCoupon(ctx, order)
if err != nil {
return err
}
status, err := wechatrepoimpl.CpnStatus(*resp.Status).GetStatus()
if err != nil {
return err
}

View File

@ -0,0 +1,33 @@
package kog
// BBToWechatRequest 蓝色兄弟请求微信发券接口数据同步Api
type BBToWechatRequest struct {
// 微信为每个批次分配的唯一id
StockId string `json:"stockId,omitempty"`
// 商户此次发放凭据号(格式:商户id+日期+流水号)
OutRequestNo string `json:"outRequestNo,omitempty"`
// 微信为发券方商户分配的公众账号ID
AppId string `json:"appId,omitempty"`
// 批次创建方商户号
StockCreatorMhId string `json:"stockCreatorMchid,omitempty"`
// 券面额,单位:分
CouponValue int32 `json:"couponValue,omitempty"`
// 面额发券批次门槛,单位:分
CouponMinimum int32 `json:"couponMinimum,omitempty"`
// 微信为代金券唯一分配的id, 在微信请求失败时可能为空
CouponId string `json:"couponId,omitempty"`
// 微信返回结果
WxRes string `json:"wxRes,omitempty"`
// 招行返回结果
CmbRes string `json:"cmbRes,omitempty"`
// 招行此次请求的数据的唯一流水号
TransactionId string `json:"transactionId,omitempty"`
}
func (this *BBToWechatRequest) GetNotice() *Notice {
return &Notice{
OutBizBo: this.TransactionId,
Type: NoticeTypeBBToWechat,
BizContent: this,
}
}

View File

@ -0,0 +1,27 @@
package kog
// CmbToBBRequest 招行请求蓝色兄弟发券接口数据同步Api
type CmbToBBRequest struct {
// 唯一流水号
TransactionId string `json:"transactionId"`
// 外部合作方权益批次号
ActivityId string `json:"activityId"`
// 招商银行用户号 用户标识,比如手机号、支付宝openId
CmbUid string `json:"cmbUid"`
// 用户标识类型,0-手机号,1-支付宝openId
CmbUidType string `json:"cmbUidType"`
// 时间戳,长度为13位,精度为毫秒
Timestamp string `json:"timestamp"`
// appId
AppId string `json:"appId"`
// 补丁
Attach string `json:"attach"`
}
func (this *CmbToBBRequest) GetNotice() *Notice {
return &Notice{
OutBizBo: this.TransactionId,
Type: NoticeTypeCmbToBB,
BizContent: this,
}
}

38
internal/biz/kog/kog.go Normal file
View File

@ -0,0 +1,38 @@
package kog
type NoticeType uint8
const (
NoticeTypeCmbToBB NoticeType = iota + 1
NoticeTypeBBToWechat
NoticeTypeWechatToBB
)
var SynNoticeTypeMap = map[NoticeType]string{
NoticeTypeCmbToBB: "招行请求蓝色兄弟",
NoticeTypeBBToWechat: "蓝色兄弟请求微信",
NoticeTypeWechatToBB: "微信请求蓝色兄弟",
}
func (s NoticeType) GetText() string {
if t, ok := SynNoticeTypeMap[s]; ok {
return t
}
return "未知类型"
}
func (s NoticeType) GetValue() uint8 {
return uint8(s)
}
func (s NoticeType) IsCmbToBB() bool {
return s == NoticeTypeCmbToBB
}
func (s NoticeType) IsBBToWechat() bool {
return s == NoticeTypeBBToWechat
}
func (s NoticeType) IsWechatToBB() bool {
return s == NoticeTypeWechatToBB
}

View File

@ -0,0 +1,23 @@
package kog
import (
"encoding/json"
)
var _ ApiInterface = (*CmbToBBRequest)(nil)
var _ ApiInterface = (*BBToWechatRequest)(nil)
var _ ApiInterface = (*WechatToBBRequest)(nil)
type ApiInterface interface {
GetNotice() *Notice
}
type Notice struct {
OutBizBo string
Type NoticeType
BizContent ApiInterface
}
func (this *Notice) Marshal() ([]byte, error) {
return json.Marshal(this)
}

View File

@ -0,0 +1,39 @@
package kog
// WechatToBBRequest 微信回调蓝色兄弟接口数据同步Api
type WechatToBBRequest struct {
// 活动ID
ActivityId string `json:"activityId,omitempty"`
// 活动名称
ActivityName string `json:"activityName,omitempty"`
// 优惠券ID
VoucherId string `json:"voucherId,omitempty"`
// 领取用户ID
UserId string `json:"userId,omitempty"`
// 核销时间(Unix时间戳,毫秒)
UseTime string `json:"useTime,omitempty"`
// 核销金额(分)
UseAmount int64 `json:"useAmount,omitempty"`
// 券消息类型,例如券核销(V_USE,V_REFUND)
BizType string `json:"bizType,omitempty"`
// 退款时间(Unix时间戳,毫秒)
RefundTime string `json:"refundTime,omitempty"`
// 退款金额(分)
RefundAmount string `json:"refundAmount,omitempty"`
// 券状态,可用(ENABLED)/不可用(DISABLED)
VoucherStatus string `json:"voucherStatus,omitempty"`
// 幂等ID
OrderId string `json:"orderId,omitempty"`
// 支付宝交易号
TradeNo string `json:"tradeNo,omitempty"`
// 券领取时间(Unix时间戳,毫秒)
GmtVoucherCreate string `json:"gmtVoucherCreate,omitempty"`
}
func (this *WechatToBBRequest) GetNotice() *Notice {
return &Notice{
OutBizBo: this.OrderId,
Type: NoticeTypeWechatToBB,
BizContent: this,
}
}

103
internal/biz/kx.go Normal file
View File

@ -0,0 +1,103 @@
package biz
import (
"context"
"encoding/json"
"fmt"
"time"
v1 "voucher/api/v1"
"voucher/internal/biz/bo"
"voucher/internal/biz/kog"
)
func (v *VoucherBiz) cmbToBB(ctx context.Context, cmbReq *v1.CmbOrderRequest) error {
req := &kog.CmbToBBRequest{
TransactionId: cmbReq.TransactionId,
ActivityId: cmbReq.ActivityId,
CmbUid: cmbReq.CmbUid,
CmbUidType: cmbReq.CmbUidType,
Timestamp: cmbReq.Timestamp,
AppId: cmbReq.AppId,
Attach: cmbReq.Attach,
}
return v.KxMixRepo.Request(ctx, req.GetNotice())
}
func (v *VoucherBiz) bbToWx(ctx context.Context, order *bo.OrderBo, cmbReply *v1.CmbReply) error {
b, err := json.Marshal(cmbReply)
if err != nil {
return err
}
wxRes, err := json.Marshal(map[string]string{"coupon_id": order.VoucherNo})
if err != nil {
return err
}
req := &kog.BBToWechatRequest{
TransactionId: order.OutBizNo,
StockId: order.BatchNo,
OutRequestNo: order.OrderNo,
AppId: order.AppID,
StockCreatorMhId: order.MerchantNo,
CouponValue: order.CouponValue,
CouponMinimum: order.MiniMum,
CouponId: order.VoucherNo,
WxRes: string(wxRes),
CmbRes: string(b),
}
return v.KxMixRepo.Request(ctx, req.GetNotice())
}
func (v *VoucherBiz) wxToBBUse(ctx context.Context, order *bo.OrderBo, wxReq *bo.WechatVoucherNotifyBo) error {
req := &kog.WechatToBBRequest{
ActivityId: order.BatchNo,
ActivityName: wxReq.PlainText.CouponName,
VoucherId: order.VoucherNo,
UserId: order.Account,
UseTime: wxReq.PlainText.ConsumeInformation.ConsumeTime,
UseAmount: wxReq.PlainText.ConsumeInformation.ConsumeAmount,
BizType: "V_USE",
RefundTime: "",
RefundAmount: "",
VoucherStatus: "",
OrderId: order.OutBizNo,
TradeNo: order.OrderNo,
GmtVoucherCreate: fmt.Sprintf("%d", order.ReceiveSuccessTime.Unix()),
}
if wxReq.PlainText.ConsumeInformation.ConsumeTime != "" {
inputFormat := time.RFC3339
useTime, _ := time.Parse(inputFormat, wxReq.PlainText.ConsumeInformation.ConsumeTime)
timestampMs := useTime.UnixNano() / int64(time.Millisecond)
req.UseTime = fmt.Sprintf("%d", timestampMs)
}
return v.KxMixRepo.Request(ctx, req.GetNotice())
}
func (v *VoucherBiz) wxToBBRefund(ctx context.Context, order *bo.OrderBo) error {
req := &kog.WechatToBBRequest{
ActivityId: order.BatchNo,
ActivityName: "",
VoucherId: order.VoucherNo,
UserId: order.Account,
UseTime: "",
UseAmount: 0,
BizType: "V_REFUND",
RefundTime: "",
RefundAmount: "",
VoucherStatus: "",
OrderId: order.OutBizNo,
TradeNo: order.OrderNo,
GmtVoucherCreate: fmt.Sprintf("%d", order.ReceiveSuccessTime.Unix()),
}
return v.KxMixRepo.Request(ctx, req.GetNotice())
}

View File

@ -0,0 +1,10 @@
package mixrepos
import (
"context"
"voucher/internal/biz/kog"
)
type KxMixRepo interface {
Request(ctx context.Context, req *kog.Notice) error
}

View File

@ -2,17 +2,62 @@ package biz
import (
"context"
"encoding/json"
"fmt"
"github.com/go-kratos/kratos/v2/errors"
"time"
err2 "voucher/api/err"
v1 "voucher/api/v1"
"voucher/internal/biz/bo"
"voucher/internal/biz/vo"
)
func (v *VoucherBiz) CmbOrder(ctx context.Context, req *bo.OrderCreateReqBo) (orderNo string, err error) {
func (v *VoucherBiz) CmbOrder(ctx context.Context, request *v1.CmbRequest) (*v1.CmbReply, error) {
order, err3 := v.GetByOutBizNo(ctx, req)
order, err := v.cmbOrder(ctx, request)
if err != nil {
return v.OrderFail(ctx, err)
}
reply, err := v.OrderSuccess(ctx, order.OrderNo)
if err != nil {
return nil, err
}
_ = v.bbToWx(ctx, order, reply)
return reply, nil
}
func (v *VoucherBiz) cmbOrder(ctx context.Context, request *v1.CmbRequest) (*bo.OrderBo, error) {
bizContent, err := v.CmbMixRepo.OrderVerify(ctx, request)
if err != nil {
return nil, err
}
product, err3 := v.ProductRepo.GetByProductNo(ctx, bizContent.ActivityId)
if err3 != nil {
return "", err3
return nil, err
}
order, err := v.Order(ctx, product, bizContent)
if err != nil {
return nil, err
}
order.MiniMum = product.MiniMum
order.CouponValue = product.Amount
return order, nil
}
func (v *VoucherBiz) Order(ctx context.Context, product *bo.ProductBo, bizContent *v1.CmbOrderRequest) (order *bo.OrderBo, err error) {
order, err = v.OrderRepo.GetByOutBizNo(ctx, vo.OrderTypeCmb, bizContent.TransactionId)
if err != nil && !err2.IsDbNotFound(err) {
return order, err
}
if order != nil {
@ -20,43 +65,56 @@ func (v *VoucherBiz) CmbOrder(ctx context.Context, req *bo.OrderCreateReqBo) (or
if order.Status.IsFail() || order.Status.IsIng() {
if err4 := v.orderRetry(ctx, order); err4 != nil {
return "", err4
return order, err4
}
}
return order.OrderNo, err
return order, err
}
product, err3 := v.ProductRepo.GetByProductNo(ctx, req.ProductNo)
if err3 != nil {
return "", err3
order, err = v.order(ctx, product, bizContent)
if err != nil {
return nil, err
}
order, err3 = v.order(ctx, req, product)
if err3 != nil {
return "", err3
}
return order.OrderNo, nil
return order, nil
}
func (v *VoucherBiz) order(ctx context.Context, req *bo.OrderCreateReqBo, product *bo.ProductBo) (*bo.OrderBo, error) {
func (v *VoucherBiz) order(ctx context.Context, product *bo.ProductBo, bizContent *v1.CmbOrderRequest) (*bo.OrderBo, error) {
req := &bo.OrderCreateReqBo{
OutBizNo: bizContent.TransactionId,
ProductNo: bizContent.ActivityId,
Account: bizContent.CmbUid,
AppID: bizContent.AppId,
Attach: bizContent.Attach,
AccountType: vo.OrderAccountTypeOpenId,
Type: vo.OrderTypeCmb,
NotifyUrl: v.bc.Cmb.NotifyUrl,
}
order, err := v.create(ctx, req, product)
if err != nil {
return nil, err
}
voucherNo, err := v.WechatCpnRepo.Order(ctx, order)
if err != nil {
if err3 := v.fail(ctx, order, err); err3 != nil {
return nil, err3
}
return nil, err
}
_ = v.cmbToBB(ctx, bizContent)
//voucherNo, err := v.WechatCpnRepo.Order(ctx, order)
//if err != nil {
// if err3 := v.fail(ctx, order, err); err3 != nil {
// return nil, err3
// }
// return nil, err
//}
//休眠100微妙
time.Sleep(time.Millisecond * 100)
//mock发券成功,测试使用
voucherNo := order.OrderNo
if err = v.success(ctx, order, voucherNo); err != nil {
return nil, err
return order, err
}
return order, nil
@ -64,14 +122,17 @@ func (v *VoucherBiz) order(ctx context.Context, req *bo.OrderCreateReqBo, produc
func (v *VoucherBiz) orderRetry(ctx context.Context, order *bo.OrderBo) error {
voucherNo, err := v.WechatCpnRepo.Order(ctx, order)
// mock发券成功,测试使用
voucherNo := order.OrderNo
if err != nil {
if err3 := v.fail(ctx, order, err); err3 != nil {
return err3
}
return err
}
//voucherNo, err := v.WechatCpnRepo.Order(ctx, order)
//if err != nil {
// if err3 := v.fail(ctx, order, err); err3 != nil {
// return err3
// }
// return err
//}
return v.success(ctx, order, voucherNo)
}
@ -103,7 +164,7 @@ func (v *VoucherBiz) ing(ctx context.Context, id uint64) error {
}
func (v *VoucherBiz) success(ctx context.Context, order *bo.OrderBo, voucherNo string) error {
order.VoucherNo = voucherNo
return v.OrderRepo.Success(ctx, order.ID, voucherNo)
}
@ -120,17 +181,6 @@ func (v *VoucherBiz) fail(ctx context.Context, order *bo.OrderBo, errReq error)
return v.alarm(ctx, order, errReq.Error())
}
func (v *VoucherBiz) GetByOutBizNo(ctx context.Context, req *bo.OrderCreateReqBo) (*bo.OrderBo, error) {
order, err := v.OrderRepo.GetByOutBizNo(ctx, vo.OrderTypeCmb, req.OutBizNo)
if err != nil && !err2.IsDbNotFound(err) {
return nil, err
}
return order, nil
}
func (v *VoucherBiz) UpdateOrderStatus(ctx context.Context, orderId uint64, status vo.OrderStatus) error {
if status.IsSuccess() {
@ -148,3 +198,36 @@ func (v *VoucherBiz) UpdateOrderStatus(ctx context.Context, orderId uint64, stat
return fmt.Errorf("notice 未知券状态,orderId:%d,statuText:%s", orderId, status.GetText())
}
func (c *VoucherBiz) OrderSuccess(ctx context.Context, orderNo string) (*v1.CmbReply, error) {
bizReply := &v1.CmbOrderReply{
RespCode: vo.CmbResponseStatusSuccess.GetValue(),
RespMsg: "成功",
CodeNo: orderNo,
}
replyBizContent, _ := json.Marshal(bizReply)
return c.GetResponse(ctx, replyBizContent)
}
func (c *VoucherBiz) OrderFail(ctx context.Context, err error) (*v1.CmbReply, error) {
se := errors.FromError(err)
if len(se.Reason) == 0 {
se.Reason = err2.CmbErr_CMB_UNKNOWN.String()
}
bizReply := &v1.CmbOrderReply{
RespCode: vo.CmbResponseStatusFail.GetValue(),
RespMsg: se.Message,
CodeNo: "",
ThirdErrCode: se.Reason,
}
replyBizContent, _ := json.Marshal(bizReply)
return c.GetResponse(ctx, replyBizContent)
}

View File

@ -3,7 +3,6 @@ package biz
import (
"context"
"fmt"
"github.com/redis/go-redis/v9"
err2 "voucher/api/err"
"voucher/internal/biz/bo"
"voucher/internal/biz/vo"
@ -23,33 +22,9 @@ func (this *VoucherBiz) RegisterTag(ctx context.Context, productNo string) error
func (v *VoucherBiz) registerNotifyTag(ctx context.Context, stockCreatorMchID, stockID string) error {
c := vo.WechatNotifyRegisterTagCacheKey.BuildCache([]string{v.bc.WechatNotifyMQ.Tag, stockCreatorMchID, stockID})
_, err := v.rdb.Rdb.Get(ctx, c.Key).Result()
if err == nil {
// 缓存存在,直接返回
return nil
}
if err != redis.Nil {
return fmt.Errorf(fmt.Sprintf("获取redis缓存%s异常:%v", c.Key, err))
}
cl := vo.WechatNotifyRegisterTagCacheLockKey.BuildCache([]string{v.bc.WechatNotifyMQ.Tag, stockCreatorMchID, stockID})
return lock.NewMutex(v.rdb.Rdb, cl.TTL).Lock(ctx, cl.Key, func(ctx context.Context) error {
// 二次获取,判定处理,以免获取锁后又执行了一次
cacheValue, err3 := v.rdb.Rdb.Get(ctx, c.Key).Result()
if err3 != nil && err3 != redis.Nil {
return fmt.Errorf(fmt.Sprintf("二次获取redis缓存%s异常:%v", c.Key, err))
}
if cacheValue != "" {
return nil // 有直接返回
}
wechatNotifyTag, err3 := v.WechatNotifyRegisterTagRepo.GetByStockIdAndMchId(ctx, stockCreatorMchID, stockID)
if err3 != nil && !err2.IsDbNotFound(err3) {
@ -57,33 +32,36 @@ func (v *VoucherBiz) registerNotifyTag(ctx context.Context, stockCreatorMchID, s
}
if wechatNotifyTag != nil {
if wechatNotifyTag.Tag != v.bc.WechatNotifyMQ.Tag {
return fmt.Errorf("tag不一致,请检查tag配置:%s", wechatNotifyTag.Tag)
}
if wechatNotifyTag.Status.IsSuccess() {
return v.setCache(ctx, c, wechatNotifyTag)
return nil
}
} else {
wechatNotifyTag, err3 = v.createWechatNotifyRegisterTag(ctx, stockCreatorMchID, stockID)
if err3 != nil {
return err3
}
}
if err = v.WechatCpnRepo.RegisterNotifyTag(ctx, stockID); err != nil {
return v.WechatNotifyRegisterTagRepo.Fail(ctx, wechatNotifyTag.ID, err.Error())
}
if err = v.WechatNotifyRegisterTagRepo.Success(ctx, wechatNotifyTag.ID); err != nil {
return err
}
return v.setCache(ctx, c, wechatNotifyTag)
return v.registerTag(ctx, wechatNotifyTag)
})
}
func (v *VoucherBiz) registerTag(ctx context.Context, wechatNotifyTa *bo.WechatNotifyRegisterTagBo) error {
if err := v.WechatCpnRepo.RegisterNotifyTag(ctx, wechatNotifyTa.Tag); err != nil {
return v.WechatNotifyRegisterTagRepo.Fail(ctx, wechatNotifyTa.ID, err.Error())
}
return v.WechatNotifyRegisterTagRepo.Success(ctx, wechatNotifyTa.ID)
}
func (v *VoucherBiz) createWechatNotifyRegisterTag(ctx context.Context, stockCreatorMchID, stockID string) (*bo.WechatNotifyRegisterTagBo, error) {
return v.WechatNotifyRegisterTagRepo.Create(ctx, &bo.WechatNotifyRegisterTagBo{
StockID: stockID,
@ -91,12 +69,3 @@ func (v *VoucherBiz) createWechatNotifyRegisterTag(ctx context.Context, stockCre
Tag: v.bc.WechatNotifyMQ.Tag,
})
}
func (v *VoucherBiz) setCache(ctx context.Context, c *vo.Cache, wechatNotifyTag *bo.WechatNotifyRegisterTagBo) error {
if err := v.rdb.Rdb.Set(ctx, c.Key, wechatNotifyTag.Tag, c.TTL).Err(); err != nil {
return fmt.Errorf(fmt.Sprintf("设置redis缓存%s异常:%v", c.Key, err))
}
return nil
}

View File

@ -0,0 +1,13 @@
package repo
import (
"context"
"time"
"voucher/internal/biz/bo"
)
type UseLogRepo interface {
Create(ctx context.Context, req *bo.UseLogBo) (*bo.UseLogBo, error)
GetByID(ctx context.Context, id uint64) (*bo.UseLogBo, error)
GetByUseTimeOrder(ctx context.Context, orderNo string, useTime *time.Time) (*bo.UseLogBo, error)
}

View File

@ -31,19 +31,23 @@ const (
)
var CacheKeyMap = map[CacheKey]time.Duration{
CmbOrderLockKey: 30 * time.Second,
CmbQueryLockKey: 30 * time.Second,
CmbProductQueryLockKey: 30 * time.Second,
CmbBatchNoticeCacheKey: 21600 * time.Second, // 6小时
CmbBatchNoticeLockKey: 300 * time.Second,
OrderConsumeFailAlarmKey: 3 * time.Hour, // 3小时
OrderConsumeFailAlarmLockKey: 60 * time.Second,
NotifyRetryConsume: 60 * time.Second,
CmbOrderLockKey: 30 * time.Second,
CmbQueryLockKey: 30 * time.Second,
CmbProductQueryLockKey: 30 * time.Second,
CmbBatchNoticeCacheKey: 21600 * time.Second, // 6小时
CmbBatchNoticeLockKey: 300 * time.Second,
OrderConsumeFailAlarmKey: 3 * time.Hour, // 3小时
OrderConsumeFailAlarmLockKey: 60 * time.Second,
NotifyRetryConsume: 60 * time.Second,
WechatNotifyRegisterTagCacheKey: 30 * 86400 * time.Second, // 30天
WechatNotifyRegisterTagCacheLockKey: 60 * time.Second,
WechatNotifyConsumeLockKey: 30 * time.Second,
ProductQueryKey: 15 * 86400 * time.Second, // 15天
ProductQueryKey: 30 * 86400 * time.Second, // 15天
ProductQueryLockKey: 30 * time.Second,
}

View File

@ -0,0 +1,36 @@
package vo
import (
"fmt"
)
type UseLogType uint8
const (
UseLogTypeUsed UseLogType = iota + 1
UseLogTypeRefund
)
var UseLogTypeMap = map[UseLogType]string{
UseLogTypeUsed: "核销",
UseLogTypeRefund: "退款",
}
func (s UseLogType) GetText() string {
if t, ok := UseLogTypeMap[s]; ok {
return t
}
return "未知类型"
}
func (s UseLogType) String() string {
return fmt.Sprintf("%d", s)
}
func (s UseLogType) GetValue() uint8 {
return uint8(s)
}
func (s UseLogType) IsUsed() bool {
return s == UseLogTypeUsed
}

View File

@ -1,10 +1,15 @@
package biz
import (
"context"
"github.com/go-kratos/kratos/v2/log"
"sync"
v1 "voucher/api/v1"
"voucher/internal/biz/bo"
"voucher/internal/biz/cmb"
"voucher/internal/biz/mixrepos"
"voucher/internal/biz/repo"
"voucher/internal/biz/vo"
"voucher/internal/biz/wechatrepo"
"voucher/internal/conf"
"voucher/internal/data"
@ -23,6 +28,8 @@ type VoucherBiz struct {
WechatCpnRepo wechatrepo.WechatCpnRepo
DingMixRepo mixrepos.DingMixRepo
CmbMixRepo mixrepos.CmbMixRepo
KxMixRepo mixrepos.KxMixRepo
UseLogRepo repo.UseLogRepo
mu sync.RWMutex
queryMap map[string]bool
@ -41,6 +48,8 @@ func NewVoucherBiz(
WechatCpnRepo wechatrepo.WechatCpnRepo,
DingMixRepo mixrepos.DingMixRepo,
CmbMixRepo mixrepos.CmbMixRepo,
KxMixRepo mixrepos.KxMixRepo,
UseLogRepo repo.UseLogRepo,
) *VoucherBiz {
return &VoucherBiz{
bc: bc,
@ -55,7 +64,8 @@ func NewVoucherBiz(
WechatCpnRepo: WechatCpnRepo,
DingMixRepo: DingMixRepo,
CmbMixRepo: CmbMixRepo,
KxMixRepo: KxMixRepo,
UseLogRepo: UseLogRepo,
queryMap: make(map[string]bool),
}
}
@ -87,3 +97,20 @@ func (this *VoucherBiz) Remove(uid string) {
delete(this.queryMap, uid)
}
}
func (c *VoucherBiz) GetResponse(ctx context.Context, replyBizContent []byte) (*v1.CmbReply, error) {
req := &bo.CmbResponseBo{
RespCode: vo.CmbResponseStatusSuccess.GetValue(),
RespMsg: "成功",
BizContent: string(replyBizContent),
}
reply, err := c.CmbMixRepo.GetResponse(ctx, req)
if err != nil {
log.Errorf("build cmb response fail: %v", err)
return nil, err
}
return reply, nil
}

View File

@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"gorm.io/gorm"
"time"
errPb "voucher/api/err"
"voucher/internal/biz/bo"
"voucher/internal/biz/vo"
@ -40,6 +41,48 @@ func (v *VoucherBiz) WechatNotifyConsumer(ctx context.Context, tag string, req *
})
}
func (v *VoucherBiz) useLog(ctx context.Context, order *bo.OrderBo, req *bo.WechatVoucherNotifyBo) error {
if req.PlainText.ConsumeInformation.ConsumeTime == "" {
return nil
}
if req.PlainText.ConsumeInformation.ConsumeAmount > 0 {
if err := v.createUseLog(ctx, order, req); err != nil {
return err
}
}
return nil
}
func (v *VoucherBiz) createUseLog(ctx context.Context, order *bo.OrderBo, req *bo.WechatVoucherNotifyBo) error {
useTime, err2 := time.Parse(time.RFC3339, req.PlainText.ConsumeInformation.ConsumeTime)
if err2 != nil {
return err2
}
useLog, err2 := v.UseLogRepo.GetByUseTimeOrder(ctx, order.OrderNo, &useTime)
if err2 != nil && !errors.Is(err2, gorm.ErrRecordNotFound) {
return err2
}
if useLog == nil {
_, err := v.UseLogRepo.Create(ctx, &bo.UseLogBo{
OrderNo: order.OrderNo,
Amount: req.PlainText.ConsumeInformation.ConsumeAmount,
Type: vo.UseLogTypeUsed,
OperateTime: &useTime,
})
if err != nil {
return err
}
}
return nil
}
func (this *VoucherBiz) getOrder(ctx context.Context, req *bo.WechatVoucherNotifyBo) (*bo.OrderBo, error) {
order, err := this.OrderRepo.GetByCouponId(ctx, req.PlainText.StockCreatorMchid, req.PlainText.StockID, req.PlainText.CouponID)
@ -83,7 +126,17 @@ func (v *VoucherBiz) notifyUsed(ctx context.Context, order *bo.OrderBo, req *bo.
return err
}
return v.notify(ctx, order)
if err := v.notify(ctx, order); err != nil {
return err
}
if err := v.useLog(ctx, order, req); err != nil {
return err
}
_ = v.wxToBBUse(ctx, order, req)
return nil
}
func (v *VoucherBiz) available(ctx context.Context, order *bo.OrderBo) error {
@ -127,10 +180,10 @@ func (v *VoucherBiz) cmbNotify(ctx context.Context, orderId uint64) error {
return err
}
if orderNotify, err := v.Cmb.Notify(ctx, order); err != nil {
if orderNotify, err2 := v.Cmb.Notify(ctx, order); err2 != nil {
if !errPb.IsNeedRetryNotify(err) {
return err
if !errPb.IsNeedRetryNotify(err2) {
return err2
}
// 第一次通知失败重试入队

View File

@ -472,6 +472,7 @@ type Cmb struct {
NotifyUrl string `protobuf:"bytes,10,opt,name=notifyUrl,proto3" json:"notifyUrl,omitempty"`
NoticeStartDays int64 `protobuf:"varint,11,opt,name=noticeStartDays,proto3" json:"noticeStartDays,omitempty"`
NoticeEndDays int64 `protobuf:"varint,12,opt,name=noticeEndDays,proto3" json:"noticeEndDays,omitempty"`
KxNoticeUrl string `protobuf:"bytes,13,opt,name=kxNoticeUrl,proto3" json:"kxNoticeUrl,omitempty"`
}
func (x *Cmb) Reset() {
@ -590,6 +591,13 @@ func (x *Cmb) GetNoticeEndDays() int64 {
return 0
}
func (x *Cmb) GetKxNoticeUrl() string {
if x != nil {
return x.KxNoticeUrl
}
return ""
}
type WechatNotifyMQ struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -1495,7 +1503,7 @@ var file_conf_conf_proto_rawDesc = []byte{
0x65, 0x63, 0x68, 0x61, 0x74, 0x50, 0x61, 0x79, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65,
0x79, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x77, 0x65, 0x63, 0x68, 0x61,
0x74, 0x50, 0x61, 0x79, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x49, 0x44, 0x22,
0xd7, 0x02, 0x0a, 0x03, 0x43, 0x6d, 0x62, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x69, 0x64, 0x18, 0x01,
0xf9, 0x02, 0x0a, 0x03, 0x43, 0x6d, 0x62, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x69, 0x64, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x69, 0x64,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73,
0x6d, 0x32, 0x50, 0x72, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6d, 0x32,
@ -1516,81 +1524,83 @@ var file_conf_conf_proto_rawDesc = []byte{
0x28, 0x03, 0x52, 0x0f, 0x6e, 0x6f, 0x74, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x44,
0x61, 0x79, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x6f, 0x74, 0x69, 0x63, 0x65, 0x45, 0x6e, 0x64,
0x44, 0x61, 0x79, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6e, 0x6f, 0x74, 0x69,
0x63, 0x65, 0x45, 0x6e, 0x64, 0x44, 0x61, 0x79, 0x73, 0x22, 0xc6, 0x02, 0x0a, 0x0e, 0x57, 0x65,
0x63, 0x68, 0x61, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x4d, 0x51, 0x12, 0x20, 0x0a, 0x0b,
0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x28,
0x0a, 0x0f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65,
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b,
0x65, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x50,
0x6f, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x50,
0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64,
0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64,
0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x18, 0x05,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64,
0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52,
0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x07, 0x20,
0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x75,
0x70, 0x49, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70,
0x49, 0x64, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x61,
0x67, 0x55, 0x72, 0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69,
0x73, 0x74, 0x65, 0x72, 0x54, 0x61, 0x67, 0x55, 0x72, 0x6c, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x73,
0x4f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01,
0x28, 0x08, 0x52, 0x0e, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d,
0x65, 0x72, 0x22, 0x73, 0x0a, 0x05, 0x41, 0x6c, 0x61, 0x72, 0x6d, 0x12, 0x1e, 0x0a, 0x0a, 0x77,
0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x55, 0x52, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0a, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x55, 0x52, 0x4c, 0x12, 0x16, 0x0a, 0x06, 0x73,
0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x63,
0x72, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x74, 0x41, 0x6c, 0x6c, 0x18, 0x03, 0x20, 0x01,
0x28, 0x08, 0x52, 0x05, 0x61, 0x74, 0x41, 0x6c, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x74, 0x4d,
0x6f, 0x62, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x74,
0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x73, 0x22, 0x84, 0x02, 0x0a, 0x04, 0x43, 0x72, 0x6f, 0x6e,
0x12, 0x16, 0x0a, 0x06, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
0x52, 0x06, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x44, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d,
0x61, 0x6e, 0x64, 0x4d, 0x61, 0x70, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x76,
0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x43, 0x72,
0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74,
0x72, 0x79, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x61, 0x70, 0x1a, 0x3e,
0x0a, 0x0a, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x61, 0x70, 0x12, 0x16, 0x0a, 0x06,
0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73,
0x4f, 0x70, 0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x1a, 0x5e,
0x0a, 0x0f, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
0x6b, 0x65, 0x79, 0x12, 0x35, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x2e, 0x43, 0x72, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
0x4d, 0x61, 0x70, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xff,
0x02, 0x0a, 0x05, 0x52, 0x64, 0x73, 0x4d, 0x51, 0x12, 0x3d, 0x0a, 0x0b, 0x77, 0x65, 0x63, 0x68,
0x61, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e,
0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52,
0x64, 0x73, 0x4d, 0x51, 0x2e, 0x51, 0x75, 0x65, 0x75, 0x65, 0x52, 0x0b, 0x77, 0x65, 0x63, 0x68,
0x61, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x4f, 0x0a, 0x14, 0x77, 0x65, 0x63, 0x68, 0x61,
0x74, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e,
0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x64, 0x73, 0x4d, 0x51, 0x2e, 0x51, 0x75, 0x65,
0x75, 0x65, 0x52, 0x14, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x6c,
0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x3d, 0x0a, 0x0b, 0x77, 0x65, 0x63, 0x68,
0x61, 0x74, 0x52, 0x65, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e,
0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52,
0x64, 0x73, 0x4d, 0x51, 0x2e, 0x51, 0x75, 0x65, 0x75, 0x65, 0x52, 0x0b, 0x77, 0x65, 0x63, 0x68,
0x61, 0x74, 0x52, 0x65, 0x74, 0x72, 0x79, 0x1a, 0xa6, 0x01, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x75,
0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x18,
0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x1a, 0x0a,
0x08, 0x72, 0x65, 0x74, 0x72, 0x79, 0x4e, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52,
0x08, 0x72, 0x65, 0x74, 0x72, 0x79, 0x4e, 0x75, 0x6d, 0x12, 0x1e, 0x0a, 0x0a, 0x6e, 0x75, 0x6d,
0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6e,
0x75, 0x6d, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x12, 0x35, 0x0a, 0x08, 0x77, 0x61, 0x69,
0x74, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x77, 0x61, 0x69, 0x74, 0x54, 0x69, 0x6d, 0x65,
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, 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,
0x63, 0x65, 0x45, 0x6e, 0x64, 0x44, 0x61, 0x79, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x6b, 0x78, 0x4e,
0x6f, 0x74, 0x69, 0x63, 0x65, 0x55, 0x72, 0x6c, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
0x6b, 0x78, 0x4e, 0x6f, 0x74, 0x69, 0x63, 0x65, 0x55, 0x72, 0x6c, 0x22, 0xc6, 0x02, 0x0a, 0x0e,
0x57, 0x65, 0x63, 0x68, 0x61, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x4d, 0x51, 0x12, 0x20,
0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x49, 0x64,
0x12, 0x28, 0x0a, 0x0f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x53, 0x65, 0x63,
0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x61, 0x63, 0x63, 0x65, 0x73,
0x73, 0x4b, 0x65, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e,
0x64, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e,
0x64, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e,
0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e,
0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64,
0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65,
0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x06, 0x20, 0x01, 0x28,
0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18,
0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x72,
0x6f, 0x75, 0x70, 0x49, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x72, 0x6f,
0x75, 0x70, 0x49, 0x64, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,
0x54, 0x61, 0x67, 0x55, 0x72, 0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65,
0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x61, 0x67, 0x55, 0x72, 0x6c, 0x12, 0x26, 0x0a, 0x0e,
0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x18, 0x0b,
0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73,
0x75, 0x6d, 0x65, 0x72, 0x22, 0x73, 0x0a, 0x05, 0x41, 0x6c, 0x61, 0x72, 0x6d, 0x12, 0x1e, 0x0a,
0x0a, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x55, 0x52, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0a, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x55, 0x52, 0x4c, 0x12, 0x16, 0x0a,
0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73,
0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x74, 0x41, 0x6c, 0x6c, 0x18, 0x03,
0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x74, 0x41, 0x6c, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x61,
0x74, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09,
0x61, 0x74, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x73, 0x22, 0x84, 0x02, 0x0a, 0x04, 0x43, 0x72,
0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01,
0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x44, 0x0a, 0x0a, 0x63, 0x6f,
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x61, 0x70, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24,
0x2e, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
0x43, 0x72, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x61, 0x70, 0x45,
0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x61, 0x70,
0x1a, 0x3e, 0x0a, 0x0a, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x61, 0x70, 0x12, 0x16,
0x0a, 0x06, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06,
0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
0x1a, 0x5e, 0x0a, 0x0f, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x61, 0x70, 0x45, 0x6e,
0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x35, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x43, 0x72, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61,
0x6e, 0x64, 0x4d, 0x61, 0x70, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
0x22, 0xff, 0x02, 0x0a, 0x05, 0x52, 0x64, 0x73, 0x4d, 0x51, 0x12, 0x3d, 0x0a, 0x0b, 0x77, 0x65,
0x63, 0x68, 0x61, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1b, 0x2e, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x2e, 0x52, 0x64, 0x73, 0x4d, 0x51, 0x2e, 0x51, 0x75, 0x65, 0x75, 0x65, 0x52, 0x0b, 0x77, 0x65,
0x63, 0x68, 0x61, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x4f, 0x0a, 0x14, 0x77, 0x65, 0x63,
0x68, 0x61, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x72,
0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65,
0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x64, 0x73, 0x4d, 0x51, 0x2e, 0x51,
0x75, 0x65, 0x75, 0x65, 0x52, 0x14, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x54, 0x69, 0x6d, 0x65,
0x53, 0x6c, 0x69, 0x63, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x3d, 0x0a, 0x0b, 0x77, 0x65,
0x63, 0x68, 0x61, 0x74, 0x52, 0x65, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1b, 0x2e, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x2e, 0x52, 0x64, 0x73, 0x4d, 0x51, 0x2e, 0x51, 0x75, 0x65, 0x75, 0x65, 0x52, 0x0b, 0x77, 0x65,
0x63, 0x68, 0x61, 0x74, 0x52, 0x65, 0x74, 0x72, 0x79, 0x1a, 0xa6, 0x01, 0x0a, 0x05, 0x51, 0x75,
0x65, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x73, 0x4f, 0x70, 0x65,
0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x12,
0x1a, 0x0a, 0x08, 0x72, 0x65, 0x74, 0x72, 0x79, 0x4e, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28,
0x0d, 0x52, 0x08, 0x72, 0x65, 0x74, 0x72, 0x79, 0x4e, 0x75, 0x6d, 0x12, 0x1e, 0x0a, 0x0a, 0x6e,
0x75, 0x6d, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52,
0x0a, 0x6e, 0x75, 0x6d, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x12, 0x35, 0x0a, 0x08, 0x77,
0x61, 0x69, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x77, 0x61, 0x69, 0x74, 0x54, 0x69,
0x6d, 0x65, 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, 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 (

View File

@ -88,6 +88,7 @@ message Cmb {
string notifyUrl = 10;
int64 noticeStartDays = 11;
int64 noticeEndDays = 12;
string kxNoticeUrl = 13;
}
message WechatNotifyMQ {

View File

@ -287,7 +287,7 @@ func (s *CmbMixRepoImpl) Request(ctx context.Context, req *v1.CmbRequest, uri st
r := uri + "?" + uv.Encode()
_, bodyBytes, err := request.Post(ctx, r, nil, request.WithHeaders(h), request.WithTimeout(time.Second*20))
_, bodyBytes, err := request.Post(ctx, r, nil, request.WithHeaders(h))
if err != nil {
log.Errorf("请求掌上生活报错,url:%s,err:%v", r, err)
return nil, err

View File

@ -0,0 +1,62 @@
package mixrepoimpl
import (
"context"
"github.com/go-kratos/kratos/v2/log"
"net/http"
"time"
"voucher/internal/biz/kog"
"voucher/internal/biz/mixrepos"
"voucher/internal/conf"
"voucher/internal/pkg/request"
)
// KxMixRepoImpl kog 空港
type KxMixRepoImpl struct {
bc *conf.Bootstrap
// 连接池复用(优化网络开销)
options *request.Options
}
func NewKxMixRepoImpl(bc *conf.Bootstrap) mixrepos.KxMixRepo {
h := http.Header{
"Content-Type": []string{"application/json"},
}
hc := &http.Client{
Timeout: 8 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 350, // 最大空闲连接数
MaxIdleConnsPerHost: 150, // 每个主机的最大空闲连接数
IdleConnTimeout: 30 * time.Second, // 空闲连接超时时间
MaxConnsPerHost: 300, // 每个主机的最大并发连接数(默认 100,可根据需要调整)
TLSHandshakeTimeout: 3 * time.Second, // 等待TLS握手。零表示没有超时。 TLS握手超时
},
}
return &KxMixRepoImpl{
bc: bc,
options: request.NewOptions(request.WithHeaders(h), request.WithHttpClient(hc)),
}
}
func (this *KxMixRepoImpl) Request(ctx context.Context, req *kog.Notice) error {
url := this.bc.Cmb.KxNoticeUrl
if url == "" {
return nil
}
body, err := req.Marshal()
if err != nil {
return err
}
start := time.Now()
_, bodyBytes, err := request.POST(ctx, url, body, this.options)
if err != nil {
log.Errorf("请求kx发生错误,耗时:%s,url:%s,reqBody:%s,respBody:%v,err:%v",
time.Now().Sub(start).String(), url, string(body), string(bodyBytes), err)
return err
}
return nil
}

View File

@ -10,4 +10,5 @@ var ProviderMixRepoImplSet = wire.NewSet(
NewMQSendMixRepoImpl,
NewCmbMixRepoImpl,
NewDingMixRepoImpl,
NewKxMixRepoImpl,
)

View File

@ -13,14 +13,16 @@ const TableNameProduct = "product"
// Product mapped from table <product>
type Product struct {
ID int32 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
Name string `gorm:"column:name;not null;comment:商品名称" json:"name"` // 商品名称
ProductNo string `gorm:"column:product_no;not null;comment:商品编号" json:"product_no"` // 商品编号
BatchName string `gorm:"column:batch_name;not null;comment:批次名称" json:"batch_name"` // 批次名称
BatchNo string `gorm:"column:batch_no;not null;comment:立减金批次号" json:"batch_no"` // 立减金批次号
MchId string `gorm:"column:mch_id;not null;comment:商户号,创建批次的商户号" json:"mch_id"` // 商户号,创建批次的商户号
Channel uint8 `gorm:"column:channel;not null;comment:1:微信 2:支付宝" json:"channel"` // 1:微信 2:支付宝
Name string `gorm:"column:name;not null;comment:商品名称" json:"name"` // 商品名称
ProductNo string `gorm:"column:product_no;not null;comment:商品编号" json:"product_no"` // 商品编号
BatchName string `gorm:"column:batch_name;not null;comment:批次名称" json:"batch_name"` // 批次名称
BatchNo string `gorm:"column:batch_no;not null;comment:立减金批次号" json:"batch_no"` // 立减金批次号
MchId string `gorm:"column:mch_id;not null;comment:商户号,创建批次的商户号" json:"mch_id"` // 商户号,创建批次的商户号
MiniMum int32 `gorm:"column:mini_mum;not null;comment:面额发券批次门槛,单位:分" json:"mini_mum"` // 面额发券批次门槛,单位:分
Channel uint8 `gorm:"column:channel;not null;comment:1:微信 2:支付宝" json:"channel"` // 1:微信 2:支付宝
AvailableType uint8 `gorm:"column:available_type;not null;comment:1:固定有效期 2:动态有效期" json:"available_type"`
AvailableDays uint32 `gorm:"column:available_days;not null;comment:领取后多少天内" json:"available_days"`
Amount int32 `gorm:"column:amount;not null;comment:面额" json:"amount"`
CreateTime *time.Time `gorm:"column:create_time;not null" json:"create_time"`
UpdateTime *time.Time `gorm:"column:update_time" json:"update_time"`
}

View File

@ -0,0 +1,26 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
import (
"time"
)
const TableNameUseLog = "use_log"
// UseLog mapped from table <user_log>
type UseLog struct {
ID uint64 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
OrderNo string `gorm:"column:order_no;not null" json:"order_no"`
Amount int64 `gorm:"column:amount;not null;comment:核销金额" json:"amount"`
Type uint8 `gorm:"column:type;not null;comment:1:核销 2:退款" json:"type"`
OperateTime *time.Time `gorm:"column:operate_time;not null" json:"operate_time"`
CreateTime *time.Time `gorm:"column:create_time;not null" json:"create_time"`
}
// TableName UseLog's table name
func (*UseLog) TableName() string {
return TableNameUseLog
}

View File

@ -10,4 +10,5 @@ var ProviderRepoImplSet = wire.NewSet(
NewProductRepoImpl,
NewOrderNotifyRepoImpl,
NewWechatNotifyRegisterTagRepoImpl,
NewUseLogRepoImpl,
)

View File

@ -0,0 +1,76 @@
package repoimpl
import (
"context"
"gorm.io/gorm"
"time"
"voucher/internal/biz/bo"
"voucher/internal/biz/repo"
"voucher/internal/data"
"voucher/internal/data/model"
)
// UseLogRepoImpl .
type UseLogRepoImpl struct {
Base[model.UseLog, bo.UseLogBo]
db *data.Db
}
// NewUseLogRepoImpl .
func NewUseLogRepoImpl(db *data.Db) repo.UseLogRepo {
return &UseLogRepoImpl{db: db}
}
func (this *UseLogRepoImpl) DB(ctx context.Context) *gorm.DB {
return this.db.DB(ctx).WithContext(ctx).Model(model.UseLog{})
}
func (this *UseLogRepoImpl) Create(ctx context.Context, req *bo.UseLogBo) (*bo.UseLogBo, error) {
now := time.Now()
info := &model.UseLog{
OrderNo: req.OrderNo,
Type: req.Type.GetValue(),
Amount: req.Amount,
OperateTime: req.OperateTime,
CreateTime: &now,
}
if err := this.DB(ctx).Create(info).Error; err != nil {
return nil, err
}
return this.ToBo(info), nil
}
func (this *UseLogRepoImpl) GetByID(ctx context.Context, id uint64) (*bo.UseLogBo, error) {
var item model.UseLog
tx := this.DB(ctx).Where(model.UseLog{ID: id}).First(&item)
if tx.Error != nil {
return nil, tx.Error
}
if tx.RowsAffected == 0 {
return nil, gorm.ErrRecordNotFound
}
return this.ToBo(&item), nil
}
func (this *UseLogRepoImpl) GetByUseTimeOrder(ctx context.Context, orderNo string, useTime *time.Time) (*bo.UseLogBo, error) {
var item model.UseLog
tx := this.DB(ctx).Where(model.UseLog{OrderNo: orderNo, OperateTime: useTime}).First(&item)
if tx.Error != nil {
return nil, tx.Error
}
if tx.RowsAffected == 0 {
return nil, gorm.ErrRecordNotFound
}
return this.ToBo(&item), nil
}

View File

@ -9,7 +9,6 @@ import (
"github.com/wechatpay-apiv3/wechatpay-go/services/cashcoupons"
"io"
"net/http"
"time"
err2 "voucher/api/err"
"voucher/internal/biz/bo"
"voucher/internal/biz/vo"
@ -98,6 +97,30 @@ func (c *CpnRepoImpl) Order(ctx context.Context, order *bo.OrderBo) (string, err
return *resp.CouponId, nil
}
func (c *CpnRepoImpl) QueryCoupon(ctx context.Context, orderWechat *bo.OrderBo) (*cashcoupons.Coupon, error) {
req := cashcoupons.QueryCouponRequest{
CouponId: core.String(orderWechat.VoucherNo),
Appid: core.String(orderWechat.AppID),
Openid: core.String(orderWechat.Account),
}
client, err := c.GetClient(ctx)
if err != nil {
return nil, err
}
svc := cashcoupons.CouponApiService{Client: client}
resp, result, err := svc.QueryCoupon(ctx, req)
if err != nil {
return nil, c.bodyErr(ctx, result)
}
return resp, nil
}
func (c *CpnRepoImpl) Query(ctx context.Context, orderWechat *bo.OrderBo) (vo.OrderStatus, error) {
req := cashcoupons.QueryCouponRequest{
@ -126,34 +149,6 @@ func (c *CpnRepoImpl) Query(ctx context.Context, orderWechat *bo.OrderBo) (vo.Or
return CpnStatus(*resp.Status).GetStatus()
}
func (c *CpnRepoImpl) QueryCoupon(ctx context.Context, orderWechat *bo.OrderBo) (*cashcoupons.Coupon, error) {
req := cashcoupons.QueryCouponRequest{
CouponId: core.String(orderWechat.VoucherNo),
Appid: core.String(orderWechat.AppID),
Openid: core.String(orderWechat.Account),
}
client, err := c.GetClient(ctx)
if err != nil {
return nil, err
}
svc := cashcoupons.CouponApiService{Client: client}
resp, result, err := svc.QueryCoupon(ctx, req)
if err != nil {
if result.Response != nil && result.Response.Body != nil {
return nil, c.bodyErr(ctx, result)
}
return nil, err
}
return resp, nil
}
func (c *CpnRepoImpl) QueryProduct(ctx context.Context, stockCreatorMchId, stockId string) (*cashcoupons.Stock, error) {
if stockCreatorMchId == "" || stockId == "" {
@ -187,6 +182,7 @@ func (c *CpnRepoImpl) QueryProduct(ctx context.Context, stockCreatorMchId, stock
func (c *CpnRepoImpl) QueryCallback(ctx context.Context) (*cashcoupons.Callback, error) {
// 回调地址是制券商户设置的回调地址,而不是发券商户设置的回调地址,除非发券商户就是制券商户
client, err := c.GetClient(ctx)
if err != nil {
return nil, err
@ -267,7 +263,6 @@ func (c *CpnRepoImpl) RegisterNotifyTag(ctx context.Context, stockID string) err
body,
request.WithHeaders(h),
request.WithStatusCodeFunc(isSuccess),
request.WithTimeout(time.Second*20),
)
if err != nil {
return err

View File

@ -7,6 +7,7 @@ import (
)
func TestParse(t *testing.T) {
got, err := Parse("2024-10-01 10:26:57")
if err != nil {
t.Errorf("TestParse() error = %v", err)

View File

@ -3,6 +3,7 @@ package mq_http
import (
"encoding/json"
"testing"
"time"
"voucher/internal/biz/bo"
)
@ -37,7 +38,7 @@ func Test_WechatNotifyProducer(t *testing.T) {
func Test_WechatNotifyProducer2(t *testing.T) {
tag := "voucher_notify_pro"
tag := "voucher_notify_dev"
bodyStr := `{"id":"5465699d-de6a-5414-a8df-283167b577ca",
"create_time":"2025-03-07T15:57:24+08:00",
@ -66,14 +67,20 @@ func Test_WechatNotifyProducer2(t *testing.T) {
func Test_WechatNotifyProducer3(t *testing.T) {
tag := "voucher_notify_dev"
useTime := time.Now().Format(time.RFC3339)
t.Log(useTime)
bodyStr := `{"id":"8804b1d0-74e8-5975-815d-e567a761a213","create_time":"2025-03-18T09:20:50+08:00","resource_type":"encrypt-resource","event_type":"COUPON.USE","summary":"代金券核销通知","original_type":"coupon","associated_data":"coupon","plain_text":{"stock_creator_mchid":"1652465541","stock_id":"20255099","coupon_id":"97046583699","coupon_name":"招行测试滚动有效期","description":"","status":"USED","create_time":"2025-03-17T19:38:52+08:00","coupon_type":"NORMAL","no_cash":false,"singleitem":false,"consume_information":{"consume_time":"2025-03-18T09:20:50+08:00","consume_mchid":"1532524971","transaction_id":"4200002702202503180978933760"}}}`
x, _ := time.Parse(time.RFC3339, useTime)
t.Log(x.Format(time.DateTime))
if err := wechatNotifyProducer(tag, bodyStr); err != nil {
t.Errorf("入队失败 error = %v", err)
return
}
//tag := "voucher_notify_dev"
//
//bodyStr := `{"id":"8804b1d0-74e8-5975-815d-e567a761a213","create_time":"2025-03-18T09:20:50+08:00","resource_type":"encrypt-resource","event_type":"COUPON.USE","summary":"代金券核销通知","original_type":"coupon","associated_data":"coupon","plain_text":{"stock_creator_mchid":"1652465541","stock_id":"20255099","coupon_id":"97046583699","coupon_name":"招行测试滚动有效期","description":"","status":"USED","create_time":"2025-03-17T19:38:52+08:00","coupon_type":"NORMAL","no_cash":false,"singleitem":false,"consume_information":{"consume_time":"2025-03-18T09:20:50+08:00","consume_mchid":"1532524971","transaction_id":"4200002702202503180978933760"}}}`
//
//if err := wechatNotifyProducer(tag, bodyStr); err != nil {
// t.Errorf("入队失败 error = %v", err)
// return
//}
}
func Test_WechatVoucherNotifyData(t *testing.T) {

View File

@ -6,20 +6,18 @@ import (
"fmt"
"io"
"net/http"
"time"
)
type Options struct {
Headers http.Header
HttpClient *http.Client
StatusCodeFunc func(int) bool
Timeout time.Duration
HttpClient *http.Client
}
func NewOptions(options ...Option) *Options {
o := &Options{
Headers: http.Header{
"Content-Type": []string{"application/json"},
@ -29,7 +27,7 @@ func NewOptions(options ...Option) *Options {
return code == http.StatusOK
},
Timeout: 15 * time.Second,
HttpClient: http.DefaultClient,
}
for _, option := range options {
@ -41,12 +39,6 @@ func NewOptions(options ...Option) *Options {
type Option func(*Options)
func WithTimeout(timeout time.Duration) Option {
return func(options *Options) {
options.Timeout = timeout
}
}
func WithHeaders(headers http.Header) Option {
return func(options *Options) {
options.Headers = headers
@ -69,6 +61,14 @@ func POST(ctx context.Context, url string, body []byte, options *Options) (http.
return Request(ctx, http.MethodPost, url, body, options)
}
func GET(ctx context.Context, url string, options *Options) (http.Header, []byte, error) {
return Request(ctx, http.MethodGet, url, nil, options)
}
func PUT(ctx context.Context, url string, body []byte, options *Options) (http.Header, []byte, error) {
return Request(ctx, http.MethodPut, url, body, options)
}
func Post(ctx context.Context, url string, body []byte, options ...Option) (http.Header, []byte, error) {
return Request(ctx, http.MethodPost, url, body, NewOptions(options...))
}
@ -82,6 +82,7 @@ func Put(ctx context.Context, url string, body []byte, options ...Option) (http.
}
func Request(_ context.Context, method, url string, body []byte, o *Options) (http.Header, []byte, error) {
req, err := http.NewRequest(method, url, bytes.NewBuffer(body))
if err != nil {
return nil, nil, fmt.Errorf("创建HTTP请求失败: %w", err)
@ -89,13 +90,9 @@ func Request(_ context.Context, method, url string, body []byte, o *Options) (ht
req.Header = o.Headers
httpClient := &http.Client{
Timeout: o.Timeout,
}
resp, err := httpClient.Do(req)
resp, err := o.HttpClient.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("发送请求失败,timeout:%v,err:%w", o.Timeout, err)
return nil, nil, fmt.Errorf("发送请求失败,err:%w", err)
}
defer resp.Body.Close()

View File

@ -5,7 +5,6 @@ import (
"net/http"
"net/url"
"testing"
"time"
)
func Test_Get(t *testing.T) {
@ -37,7 +36,7 @@ func Test_RequestHeaders(t *testing.T) {
"Authorization": []string{"Bearer token"},
}
respHeader, respBody, err := Post(context.Background(), uri, body, WithTimeout(10*time.Second), WithHeaders(h))
respHeader, respBody, err := Post(context.Background(), uri, body, WithHeaders(h))
if err != nil {
t.Error(err)
return

View File

@ -2,80 +2,10 @@ package service
import (
"context"
"encoding/json"
"github.com/go-kratos/kratos/v2/errors"
err2 "voucher/api/err"
v1 "voucher/api/v1"
"voucher/internal/biz/bo"
"voucher/internal/biz/vo"
)
func (c *CmbService) Order(ctx context.Context, request *v1.CmbRequest) (*v1.CmbReply, error) {
orderNo, err := c.order(ctx, request)
if err != nil {
return c.OrderFail(ctx, err)
}
return c.OrderSuccess(ctx, orderNo)
}
func (c *CmbService) order(ctx context.Context, request *v1.CmbRequest) (string, error) {
bizContent, err := c.CmbMixRepo.OrderVerify(ctx, request)
if err != nil {
return "", err
}
boReq := &bo.OrderCreateReqBo{
OutBizNo: bizContent.TransactionId,
ProductNo: bizContent.ActivityId,
Account: bizContent.CmbUid,
AppID: bizContent.AppId,
Attach: bizContent.Attach,
AccountType: vo.OrderAccountTypeOpenId,
Type: vo.OrderTypeCmb,
NotifyUrl: c.bc.Cmb.NotifyUrl,
}
orderNo, err := c.VoucherBiz.CmbOrder(ctx, boReq)
if err != nil {
return "", err
}
return orderNo, nil
}
func (c *CmbService) OrderSuccess(ctx context.Context, orderNo string) (*v1.CmbReply, error) {
bizReply := &v1.CmbOrderReply{
RespCode: vo.CmbResponseStatusSuccess.GetValue(),
RespMsg: "成功",
CodeNo: orderNo,
}
replyBizContent, _ := json.Marshal(bizReply)
return c.GetResponse(ctx, replyBizContent)
}
func (c *CmbService) OrderFail(ctx context.Context, err error) (*v1.CmbReply, error) {
se := errors.FromError(err)
if len(se.Reason) == 0 {
se.Reason = err2.CmbErr_CMB_UNKNOWN.String()
}
bizReply := &v1.CmbOrderReply{
RespCode: vo.CmbResponseStatusFail.GetValue(),
RespMsg: se.Message,
CodeNo: "",
ThirdErrCode: se.Reason,
}
replyBizContent, _ := json.Marshal(bizReply)
return c.GetResponse(ctx, replyBizContent)
return c.VoucherBiz.CmbOrder(ctx, request)
}

View File

@ -34,7 +34,7 @@ func (c *CmbService) QueryProductSuccess(ctx context.Context, bizReply *v1.CmbQu
replyBizContent, _ := json.Marshal(bizReply)
return c.GetResponse(ctx, replyBizContent)
return c.VoucherBiz.GetResponse(ctx, replyBizContent)
}
func (c *CmbService) QueryProductFail(ctx context.Context, err error) (*v1.CmbReply, error) {
@ -55,5 +55,5 @@ func (c *CmbService) QueryProductFail(ctx context.Context, err error) (*v1.CmbRe
replyBizContent, _ := json.Marshal(bizReply)
return c.GetResponse(ctx, replyBizContent)
return c.VoucherBiz.GetResponse(ctx, replyBizContent)
}

View File

@ -33,7 +33,7 @@ func (c *CmbService) QuerySuccess(ctx context.Context, bizReply *v1.CmbQueryRepl
replyBizContent, _ := json.Marshal(bizReply)
return c.GetResponse(ctx, replyBizContent)
return c.VoucherBiz.GetResponse(ctx, replyBizContent)
}
func (c *CmbService) QueryFail(ctx context.Context, err error) (*v1.CmbReply, error) {
@ -48,5 +48,5 @@ func (c *CmbService) QueryFail(ctx context.Context, err error) (*v1.CmbReply, er
replyBizContent, _ := json.Marshal(bizReply)
return c.GetResponse(ctx, replyBizContent)
return c.VoucherBiz.GetResponse(ctx, replyBizContent)
}