Compare commits
91 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
b5e1174402 | |
|
|
fa36755179 | |
|
|
ef2d9a92d5 | |
|
|
744e7d4169 | |
|
|
f355aa624a | |
|
|
9012f17bc0 | |
|
|
5cb45a3aaf | |
|
|
650cd52364 | |
|
|
59d7f77873 | |
|
|
a367a4530c | |
|
|
6bc3524535 | |
|
|
e5dcd3e66d | |
|
|
c92828fc41 | |
|
|
4b9c9b5652 | |
|
|
993e567eca | |
|
|
c3901c7f94 | |
|
|
6a7da03a25 | |
|
|
8d11662035 | |
|
|
2b10381a16 | |
|
|
6fd65bcdd5 | |
|
|
2f7194c945 | |
|
|
de9f99e62b | |
|
|
9c0b5b5c31 | |
|
|
eb5650a235 | |
|
|
a0e8865820 | |
|
|
05784b85fe | |
|
|
3e6e85fd82 | |
|
|
433982c75b | |
|
|
f59bf4fa15 | |
|
|
4a2e8f8307 | |
|
|
c267632672 | |
|
|
0a45f678b8 | |
|
|
7883156d26 | |
|
|
95e11c4f14 | |
|
|
29d0bc633d | |
|
|
4fb8ddfc2d | |
|
|
07641871f2 | |
|
|
9f2e438ab6 | |
|
|
8daa814b8d | |
|
|
22b0c4f6ef | |
|
|
0c7571cb7b | |
|
|
2f6b22db59 | |
|
|
304dc56bb2 | |
|
|
07c8ffc236 | |
|
|
fa66f4cca7 | |
|
|
43b0b0a5fa | |
|
|
d4e2d2d00a | |
|
|
3b29b4ef66 | |
|
|
d8279de232 | |
|
|
aa140a9627 | |
|
|
61ff2ae897 | |
|
|
e59653cdae | |
|
|
b8eb1208d0 | |
|
|
ef26d56c56 | |
|
|
ce501ce5cc | |
|
|
61da538e2f | |
|
|
7d9996e9f6 | |
|
|
059b2d30f0 | |
|
|
62ba3ef1fa | |
|
|
54e233217c | |
|
|
eb4beba9e4 | |
|
|
e0d69c5e22 | |
|
|
781de4ea02 | |
|
|
39e98122ed | |
|
|
2bdd2f7ef4 | |
|
|
d01604fd78 | |
|
|
e18ca47d93 | |
|
|
5990378b77 | |
|
|
668cc3177e | |
|
|
fee0786d68 | |
|
|
86142caad1 | |
|
|
420a6d3be3 | |
|
|
ee85d3debe | |
|
|
ddab078e1f | |
|
|
13cd99300f | |
|
|
e9a754e08a | |
|
|
62f946f520 | |
|
|
4de408c547 | |
|
|
f4872bfe74 | |
|
|
01ac62f2bc | |
|
|
12e8951c4f | |
|
|
0dd2d8d3d6 | |
|
|
07f15ce605 | |
|
|
bb5e9ee0e9 | |
|
|
6e05cf2045 | |
|
|
d8c827b59e | |
|
|
0a15c6d7b0 | |
|
|
ef81c198cf | |
|
|
6a3c0d44a6 | |
|
|
0a71346d3b | |
|
|
ad95880eef |
|
|
@ -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
|
||||
31
READEME.md
31
READEME.md
|
|
@ -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为成功,其它属于异常
|
||||
````
|
||||
|
|
|
|||
|
|
@ -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
1
go.mod
|
|
@ -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
7
go.sum
|
|
@ -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
23
gorm.sh
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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>" +
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ type OrderBo struct {
|
|||
LastUseTime *time.Time
|
||||
CreateTime *time.Time
|
||||
UpdateTime *time.Time
|
||||
|
||||
MiniMum int32
|
||||
CouponValue int32
|
||||
}
|
||||
|
||||
type OrderCreateReqBo struct {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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())
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package mixrepos
|
||||
|
||||
import (
|
||||
"context"
|
||||
"voucher/internal/biz/kog"
|
||||
)
|
||||
|
||||
type KxMixRepo interface {
|
||||
Request(ctx context.Context, req *kog.Notice) error
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
// 第一次通知失败重试入队
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ message Cmb {
|
|||
string notifyUrl = 10;
|
||||
int64 noticeStartDays = 11;
|
||||
int64 noticeEndDays = 12;
|
||||
string kxNoticeUrl = 13;
|
||||
}
|
||||
|
||||
message WechatNotifyMQ {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -10,4 +10,5 @@ var ProviderMixRepoImplSet = wire.NewSet(
|
|||
NewMQSendMixRepoImpl,
|
||||
NewCmbMixRepoImpl,
|
||||
NewDingMixRepoImpl,
|
||||
NewKxMixRepoImpl,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -10,4 +10,5 @@ var ProviderRepoImplSet = wire.NewSet(
|
|||
NewProductRepoImpl,
|
||||
NewOrderNotifyRepoImpl,
|
||||
NewWechatNotifyRegisterTagRepoImpl,
|
||||
NewUseLogRepoImpl,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue