This commit is contained in:
parent
9c62904de5
commit
ad95880eef
|
|
@ -0,0 +1,69 @@
|
|||
package biz
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"voucher/internal/biz/bo"
|
||||
"voucher/internal/biz/vo"
|
||||
"voucher/internal/pkg/lock"
|
||||
)
|
||||
|
||||
func (v *VoucherBiz) alarm(ctx context.Context, order *bo.OrderBo, errMsg string) error {
|
||||
|
||||
// 1小时 内 指定的批次号 发放 发生错误 预警
|
||||
c := vo.OrderConsumeFailAlarmKey.BuildCache([]string{order.ProductNo})
|
||||
|
||||
_, err := v.rdb.Rdb.Get(ctx, c.Key).Result()
|
||||
|
||||
if err == nil {
|
||||
// 缓存存在,直接返回
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != redis.Nil {
|
||||
return fmt.Errorf(fmt.Sprintf("alarm 获取redis缓存%s异常:%v", c.Key, err))
|
||||
}
|
||||
|
||||
cl := vo.OrderConsumeFailAlarmLockKey.BuildCache([]string{order.ProductNo})
|
||||
|
||||
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("alarm 二次获取redis缓存%s异常:%v", c.Key, err))
|
||||
}
|
||||
|
||||
if len(cacheValue) > 0 {
|
||||
return nil // 有直接返回
|
||||
}
|
||||
|
||||
// 通知
|
||||
if err = v.DingMixRepo.SendMarkdownMessage(ctx, "异常通知", v.alarmText(ctx, order, errMsg)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = v.rdb.Rdb.Set(ctx, c.Key, order.ProductNo, c.TTL).Err(); err != nil {
|
||||
return fmt.Errorf(fmt.Sprintf("设置redis缓存%s异常:%v", c.Key, err))
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (v *VoucherBiz) alarmText(_ context.Context, order *bo.OrderBo, errMsg string) string {
|
||||
|
||||
remarks := fmt.Sprintf("订单号:%s,商品编号:%s,原因:%s", order.OrderNo, order.ProductNo, errMsg)
|
||||
|
||||
msg := "# <font color='green'>" +
|
||||
"<h1>立减金发放平台报警通知</h1>" +
|
||||
"</font> \n" +
|
||||
"<font color='black'>" +
|
||||
"不好了,订单发放发生异常了" +
|
||||
"[<font color='red'>%s</font>]请尽快处理@相关人员。" +
|
||||
"</font>"
|
||||
|
||||
return fmt.Sprintf(msg, remarks)
|
||||
}
|
||||
|
|
@ -1,162 +1 @@
|
|||
package biz
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
err2 "voucher/api/err"
|
||||
v1 "voucher/api/v1"
|
||||
"voucher/internal/biz/bo"
|
||||
"voucher/internal/biz/vo"
|
||||
"voucher/internal/pkg/lock"
|
||||
)
|
||||
|
||||
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) CmbOrder(ctx context.Context, req *bo.OrderCreateReqBo) (orderNo string, err error) {
|
||||
|
||||
order, err3 := v.GetByOutBizNo(ctx, req)
|
||||
if err3 != nil {
|
||||
return orderNo, err3
|
||||
}
|
||||
|
||||
if order != nil {
|
||||
|
||||
if order.Status.IsFail() {
|
||||
|
||||
if err4 := v.orderRetry(ctx, order); err4 != nil {
|
||||
return orderNo, err4
|
||||
}
|
||||
}
|
||||
|
||||
orderNo = order.OrderNo
|
||||
return orderNo, err
|
||||
}
|
||||
|
||||
product, err3 := v.ProductRepo.GetByProductNo(ctx, req.ProductNo)
|
||||
if err3 != nil {
|
||||
return orderNo, err3
|
||||
}
|
||||
|
||||
order, err3 = v.order(ctx, req, product)
|
||||
if err3 != nil {
|
||||
return orderNo, err3
|
||||
}
|
||||
|
||||
orderNo = order.OrderNo
|
||||
|
||||
return orderNo, nil
|
||||
}
|
||||
|
||||
func (v *VoucherBiz) CmbQuery(ctx context.Context, orderNo string) (resp *v1.CmbQueryReply, err error) {
|
||||
|
||||
c := vo.CmbQueryLockKey.BuildCache([]string{orderNo})
|
||||
|
||||
err = lock.NewMutex(v.rdb.Rdb, c.TTL).Lock(ctx, c.Key, func(ctx context.Context) error {
|
||||
|
||||
order, err3 := v.OrderRepo.GetByOrderNo(ctx, orderNo)
|
||||
if err3 != nil {
|
||||
return err3
|
||||
}
|
||||
|
||||
if err = v.Query(ctx, order); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
status, err3 := order.Status.GetCmbStatusText()
|
||||
if err3 != nil {
|
||||
return err3
|
||||
}
|
||||
|
||||
resp = &v1.CmbQueryReply{
|
||||
Ticket: order.OrderNo,
|
||||
Status: status.GetValue(),
|
||||
TransDate: time.Now().Format("20060102150405"),
|
||||
OrgNo: v.bc.Cmb.OrgNo,
|
||||
Ext: "",
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (v *VoucherBiz) CmbProductQuery(ctx context.Context, productNo string) (reps *v1.CmbQueryProductReply, err error) {
|
||||
|
||||
c := vo.CmbProductQueryLockKey.BuildCache([]string{productNo})
|
||||
|
||||
err = lock.NewMutex(v.rdb.Rdb, c.TTL).Lock(ctx, c.Key, func(ctx context.Context) error {
|
||||
|
||||
product, err3 := v.ProductRepo.GetByProductNo(ctx, productNo)
|
||||
if err3 != nil {
|
||||
return err3
|
||||
}
|
||||
|
||||
if !product.Channel.IsWeChat() {
|
||||
return fmt.Errorf("只支持微信")
|
||||
}
|
||||
|
||||
wechatResp, err4 := v.WechatCpnRepo.QueryProduct(ctx, product.MchId, product.BatchNo)
|
||||
if err4 != nil {
|
||||
return err4
|
||||
}
|
||||
|
||||
reps = &v1.CmbQueryProductReply{
|
||||
RespCode: vo.CmbResponseStatusSuccess.GetValue(),
|
||||
RespMsg: "成功",
|
||||
ActivityName: product.Name,
|
||||
ActivityId: product.ProductNo,
|
||||
Amount: "",
|
||||
MinAmount: "",
|
||||
AvailableType: "",
|
||||
AvailableDays: "", // 动态有效期天数
|
||||
StartTime: "",
|
||||
EndTime: "",
|
||||
AvailableStock: "",
|
||||
Detail: *wechatResp.Description,
|
||||
}
|
||||
|
||||
inputFormat := time.RFC3339
|
||||
|
||||
if wechatResp.AvailableBeginTime != nil {
|
||||
|
||||
availableBeginTime, _ := time.Parse(inputFormat, *wechatResp.AvailableBeginTime)
|
||||
reps.StartTime = availableBeginTime.Format("2006-01-02 15:04:05.000")
|
||||
reps.SaleStartTime = reps.StartTime
|
||||
}
|
||||
|
||||
if wechatResp.AvailableEndTime != nil {
|
||||
availableEndTime, _ := time.Parse(inputFormat, *wechatResp.AvailableEndTime)
|
||||
reps.EndTime = availableEndTime.Format("2006-01-02 15:04:05.000")
|
||||
reps.SaleEndTime = reps.EndTime
|
||||
}
|
||||
|
||||
reps.Amount = fmt.Sprintf("%d", *wechatResp.StockUseRule.FixedNormalCoupon.CouponAmount)
|
||||
reps.MinAmount = fmt.Sprintf("%d", *wechatResp.StockUseRule.FixedNormalCoupon.TransactionMinimum)
|
||||
|
||||
availableStock := *wechatResp.StockUseRule.MaxCoupons - *wechatResp.DistributedCoupons
|
||||
reps.AvailableStock = fmt.Sprintf("%d", availableStock)
|
||||
|
||||
availableType, err3 := product.AvailableType.GetCmbAvailableType()
|
||||
if err3 != nil {
|
||||
return err3
|
||||
}
|
||||
|
||||
reps.AvailableType = availableType.GetValue()
|
||||
reps.AvailableDays = fmt.Sprintf("%d", product.AvailableDays)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
package kx
|
||||
|
||||
// BBToWechatRequest 蓝色兄弟请求微信发券接口数据同步Api
|
||||
type BBToWechatRequest struct {
|
||||
// 微信为每个批次分配的唯一id
|
||||
StockId string `protobuf:"bytes,9,opt,name=stockId,proto3" json:"stockId,omitempty"`
|
||||
// 商户此次发放凭据号(格式:商户id+日期+流水号)
|
||||
OutRequestNo string `protobuf:"bytes,10,opt,name=outRequestNo,proto3" json:"outRequestNo,omitempty"`
|
||||
// 微信为发券方商户分配的公众账号ID
|
||||
AppId string `protobuf:"bytes,11,opt,name=appId,proto3" json:"appId,omitempty"`
|
||||
// 批次创建方商户号
|
||||
StockCreatorMhId string `protobuf:"bytes,12,opt,name=stockCreatorMhId,json=stockCreatorMchid,proto3" json:"stockCreatorMhId,omitempty"`
|
||||
// 券面额,单位:分
|
||||
CouponValue int32 `protobuf:"bytes,13,opt,name=couponValue,proto3" json:"couponValue,omitempty"`
|
||||
// 面额发券批次门槛,单位:分
|
||||
CouponMinimum int32 `protobuf:"bytes,14,opt,name=couponMinimum,proto3" json:"couponMinimum,omitempty"`
|
||||
// 微信为代金券唯一分配的id, 在微信请求失败时可能为空
|
||||
CouponId string `protobuf:"bytes,15,opt,name=couponId,proto3" json:"couponId,omitempty"`
|
||||
// 微信返回结果
|
||||
WxRes string `protobuf:"bytes,16,opt,name=wxRes,proto3" json:"wxRes,omitempty"`
|
||||
// 招行返回结果
|
||||
CmbRes string `protobuf:"bytes,17,opt,name=cmbRes,proto3" json:"cmbRes,omitempty"`
|
||||
// 招行此次请求的数据的唯一流水号
|
||||
TransactionId string `protobuf:"bytes,18,opt,name=transactionId,proto3" json:"transactionId,omitempty"`
|
||||
}
|
||||
|
||||
func (this *BBToWechatRequest) GetSynNotice() *SynNotice {
|
||||
return &SynNotice{
|
||||
OutBizBo: this.TransactionId,
|
||||
Type: SynNoticeTypeBBToWechat,
|
||||
BizContent: this,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package kx
|
||||
|
||||
// CmbToBBRequest 招行请求蓝色兄弟发券接口数据同步Api
|
||||
type CmbToBBRequest struct {
|
||||
// 唯一流水号
|
||||
TransactionId string `protobuf:"bytes,9,opt,name=transactionId,proto3" json:"transactionId,omitempty"`
|
||||
// 外部合作方权益批次号
|
||||
ActivityId string `protobuf:"bytes,10,opt,name=activityId,proto3" json:"activityId,omitempty"`
|
||||
// 招商银行用户号 用户标识,比如手机号、支付宝openId
|
||||
CmbUid string `protobuf:"bytes,11,opt,name=cmbUid,proto3" json:"cmbUid,omitempty"`
|
||||
// 用户标识类型,0-手机号,1-支付宝openId
|
||||
CmbUidType string `protobuf:"bytes,12,opt,name=cmbUidType,proto3" json:"cmbUidType,omitempty"`
|
||||
// 时间戳,长度为13位,精度为毫秒
|
||||
Timestamp string `protobuf:"bytes,13,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
|
||||
// appId
|
||||
AppId string `protobuf:"bytes,14,opt,name=appId,proto3" json:"appId,omitempty"`
|
||||
// 补丁
|
||||
Attach string `protobuf:"bytes,15,opt,name=attach,proto3" json:"attach,omitempty"`
|
||||
}
|
||||
|
||||
func (this *CmbToBBRequest) GetSynNotice() *SynNotice {
|
||||
return &SynNotice{
|
||||
OutBizBo: this.TransactionId,
|
||||
Type: SynNoticeTypeCmbToBB,
|
||||
BizContent: this,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package kx
|
||||
|
||||
type SynNoticeType uint8
|
||||
|
||||
const (
|
||||
SynNoticeTypeCmbToBB SynNoticeType = iota + 1
|
||||
SynNoticeTypeBBToWechat
|
||||
SynNoticeTypeWechatToBB
|
||||
)
|
||||
|
||||
var SynNoticeTypeMap = map[SynNoticeType]string{
|
||||
SynNoticeTypeCmbToBB: "招行请求蓝色兄弟",
|
||||
SynNoticeTypeBBToWechat: "蓝色兄弟请求微信",
|
||||
SynNoticeTypeWechatToBB: "微信请求蓝色兄弟",
|
||||
}
|
||||
|
||||
func (s SynNoticeType) GetText() string {
|
||||
if t, ok := SynNoticeTypeMap[s]; ok {
|
||||
return t
|
||||
}
|
||||
return "未知类型"
|
||||
}
|
||||
|
||||
func (s SynNoticeType) GetValue() uint8 {
|
||||
return uint8(s)
|
||||
}
|
||||
|
||||
func (s SynNoticeType) IsCmbToBB() bool {
|
||||
return s == SynNoticeTypeCmbToBB
|
||||
}
|
||||
|
||||
func (s SynNoticeType) IsBBToWechat() bool {
|
||||
return s == SynNoticeTypeBBToWechat
|
||||
}
|
||||
|
||||
func (s SynNoticeType) IsWechatToBB() bool {
|
||||
return s == SynNoticeTypeWechatToBB
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package kx
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
var _ SynApiInterface = (*CmbToBBRequest)(nil)
|
||||
var _ SynApiInterface = (*BBToWechatRequest)(nil)
|
||||
var _ SynApiInterface = (*WechatToBBRequest)(nil)
|
||||
|
||||
type SynApiInterface interface {
|
||||
GetSynNotice() *SynNotice
|
||||
}
|
||||
|
||||
type SynNotice struct {
|
||||
OutBizBo string
|
||||
Type SynNoticeType
|
||||
BizContent SynApiInterface
|
||||
}
|
||||
|
||||
func (this *SynNotice) Marshal() ([]byte, error) {
|
||||
return json.Marshal(this)
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package kx
|
||||
|
||||
// WechatToBBRequest 微信回调蓝色兄弟接口数据同步Api
|
||||
type WechatToBBRequest struct {
|
||||
// 活动ID
|
||||
ActivityId string `protobuf:"bytes,9,opt,name=activityId,proto3" json:"activityId,omitempty"`
|
||||
// 活动名称
|
||||
ActivityName string `protobuf:"bytes,10,opt,name=activityName,proto3" json:"activityName,omitempty"`
|
||||
// 优惠券ID
|
||||
VoucherId string `protobuf:"bytes,11,opt,name=voucherId,proto3" json:"voucherId,omitempty"`
|
||||
// 领取用户ID
|
||||
UserId string `protobuf:"bytes,12,opt,name=userId,proto3" json:"userId,omitempty"`
|
||||
// 核销时间(Unix时间戳,毫秒)
|
||||
UseTime string `protobuf:"bytes,13,opt,name=useTime,proto3" json:"useTime,omitempty"`
|
||||
// 核销金额(分)
|
||||
UseAmount string `protobuf:"bytes,14,opt,name=useAmount,proto3" json:"useAmount,omitempty"`
|
||||
// 券消息类型,例如券核销(V_USE,V_REFUND)
|
||||
BizType string `protobuf:"bytes,15,opt,name=bizType,proto3" json:"bizType,omitempty"`
|
||||
// 退款时间(Unix时间戳,毫秒)
|
||||
RefundTime string `protobuf:"bytes,16,opt,name=refundTime,proto3" json:"refundTime,omitempty"`
|
||||
// 退款金额(分)
|
||||
RefundAmount string `protobuf:"bytes,17,opt,name=refundAmount,proto3" json:"refundAmount,omitempty"`
|
||||
// 券状态,可用(ENABLED)/不可用(DISABLED)
|
||||
VoucherStatus string `protobuf:"bytes,18,opt,name=voucherStatus,proto3" json:"voucherStatus,omitempty"`
|
||||
// 幂等ID
|
||||
OrderId string `protobuf:"bytes,19,opt,name=orderId,proto3" json:"orderId,omitempty"`
|
||||
// 支付宝交易号
|
||||
TradeNo string `protobuf:"bytes,20,opt,name=tradeNo,proto3" json:"tradeNo,omitempty"`
|
||||
// 券领取时间(Unix时间戳,毫秒)
|
||||
GmtVoucherCreate string `protobuf:"bytes,21,opt,name=gmtVoucherCreate,proto3" json:"gmtVoucherCreate,omitempty"`
|
||||
}
|
||||
|
||||
func (this *WechatToBBRequest) GetSynNotice() *SynNotice {
|
||||
return &SynNotice{
|
||||
OutBizBo: this.OrderId,
|
||||
Type: SynNoticeTypeBBToWechat,
|
||||
BizContent: this,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package mixrepos
|
||||
|
||||
import (
|
||||
"context"
|
||||
"voucher/internal/biz/kx"
|
||||
)
|
||||
|
||||
type KxMixRepo interface {
|
||||
Request(ctx context.Context, req *kx.SynNotice) error
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
package biz
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/redis/go-redis/v9"
|
||||
err2 "voucher/api/err"
|
||||
"voucher/internal/biz/bo"
|
||||
"voucher/internal/biz/vo"
|
||||
"voucher/internal/pkg/lock"
|
||||
)
|
||||
|
||||
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) {
|
||||
return err3
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
} 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)
|
||||
})
|
||||
}
|
||||
|
||||
func (v *VoucherBiz) createWechatNotifyRegisterTag(ctx context.Context, stockCreatorMchID, stockID string) (*bo.WechatNotifyRegisterTagBo, error) {
|
||||
return v.WechatNotifyRegisterTagRepo.Create(ctx, &bo.WechatNotifyRegisterTagBo{
|
||||
StockID: stockID,
|
||||
StockCreatorMchID: stockCreatorMchID,
|
||||
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
|
||||
}
|
||||
|
|
@ -2,22 +2,97 @@ package biz
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/go-kratos/kratos/v2/errors"
|
||||
"github.com/go-kratos/kratos/v2/log"
|
||||
"github.com/redis/go-redis/v9"
|
||||
err2 "voucher/api/err"
|
||||
v1 "voucher/api/v1"
|
||||
"voucher/internal/biz/bo"
|
||||
"voucher/internal/biz/vo"
|
||||
"voucher/internal/pkg/lock"
|
||||
)
|
||||
|
||||
func (v *VoucherBiz) order(ctx context.Context, req *bo.OrderCreateReqBo, product *bo.ProductBo) (*bo.OrderBo, error) {
|
||||
func (c *VoucherBiz) CmbOrder(ctx context.Context, request *v1.CmbRequest) (*v1.CmbReply, error) {
|
||||
|
||||
order, err := c.cmbOrder(ctx, request)
|
||||
|
||||
if err != nil {
|
||||
return c.OrderFail(ctx, err)
|
||||
}
|
||||
|
||||
return c.OrderSuccess(ctx, order.OrderNo)
|
||||
}
|
||||
|
||||
func (c *VoucherBiz) cmbOrder(ctx context.Context, request *v1.CmbRequest) (*bo.OrderBo, error) {
|
||||
|
||||
bizContent, err := c.CmbMixRepo.OrderVerify(ctx, request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx2 := context.Background()
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
order, err := c.Order(ctx2, boReq, bizContent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return order, nil
|
||||
}
|
||||
|
||||
func (v *VoucherBiz) Order(ctx context.Context, req *bo.OrderCreateReqBo, cmbReq *v1.CmbOrderRequest) (order *bo.OrderBo, err error) {
|
||||
|
||||
order, err = v.OrderRepo.GetByOutBizNo(ctx, vo.OrderTypeCmb, req.OutBizNo)
|
||||
|
||||
if err != nil && !err2.IsDbNotFound(err) {
|
||||
return order, err
|
||||
}
|
||||
|
||||
if order != nil {
|
||||
|
||||
if order.Status.IsFail() {
|
||||
|
||||
if err4 := v.orderRetry(ctx, order); err4 != nil {
|
||||
return order, err4
|
||||
}
|
||||
}
|
||||
|
||||
return order, err
|
||||
}
|
||||
|
||||
product, err3 := v.ProductRepo.GetByProductNo(ctx, req.ProductNo)
|
||||
if err3 != nil {
|
||||
return order, err3
|
||||
}
|
||||
|
||||
order, err = v.order(ctx, req, product, cmbReq)
|
||||
if err != nil {
|
||||
return order, err
|
||||
}
|
||||
|
||||
return order, nil
|
||||
}
|
||||
|
||||
func (v *VoucherBiz) order(ctx context.Context, req *bo.OrderCreateReqBo, product *bo.ProductBo, cmbReq *v1.CmbOrderRequest) (*bo.OrderBo, error) {
|
||||
|
||||
order, err := v.create(ctx, req, product)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 通知kx
|
||||
|
||||
// 注册通知标签 order.MerchantNo 批次创建商户, order.BatchNo 商品批次号
|
||||
if err = v.registerNotifyTag(ctx, order.MerchantNo, order.BatchNo); err != nil {
|
||||
return nil, err
|
||||
|
|
@ -70,91 +145,12 @@ func (v *VoucherBiz) create(ctx context.Context, req *bo.OrderCreateReqBo, produ
|
|||
return v.OrderRepo.Create(ctx, o)
|
||||
}
|
||||
|
||||
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) {
|
||||
return err3
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
} 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)
|
||||
})
|
||||
}
|
||||
|
||||
func (v *VoucherBiz) createWechatNotifyRegisterTag(ctx context.Context, stockCreatorMchID, stockID string) (*bo.WechatNotifyRegisterTagBo, error) {
|
||||
return v.WechatNotifyRegisterTagRepo.Create(ctx, &bo.WechatNotifyRegisterTagBo{
|
||||
StockID: stockID,
|
||||
StockCreatorMchID: stockCreatorMchID,
|
||||
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
|
||||
}
|
||||
|
||||
func (v *VoucherBiz) ing(ctx context.Context, id uint64) error {
|
||||
return v.OrderRepo.Ing(ctx, id)
|
||||
}
|
||||
|
||||
func (v *VoucherBiz) success(ctx context.Context, order *bo.OrderBo, voucherNo string) error {
|
||||
order.VoucherNo = voucherNo
|
||||
return v.OrderRepo.Success(ctx, order.ID, voucherNo)
|
||||
}
|
||||
|
||||
|
|
@ -171,115 +167,37 @@ func (v *VoucherBiz) fail(ctx context.Context, order *bo.OrderBo, errReq error)
|
|||
return v.alarm(ctx, order, errReq.Error())
|
||||
}
|
||||
|
||||
func (v *VoucherBiz) alarm(ctx context.Context, order *bo.OrderBo, errMsg string) error {
|
||||
func (c *VoucherBiz) OrderSuccess(ctx context.Context, orderNo string) (*v1.CmbReply, error) {
|
||||
|
||||
// 1小时 内 指定的批次号 发放 发生错误 预警
|
||||
c := vo.OrderConsumeFailAlarmKey.BuildCache([]string{order.ProductNo})
|
||||
|
||||
_, err := v.rdb.Rdb.Get(ctx, c.Key).Result()
|
||||
|
||||
if err == nil {
|
||||
// 缓存存在,直接返回
|
||||
return nil
|
||||
bizReply := &v1.CmbOrderReply{
|
||||
RespCode: vo.CmbResponseStatusSuccess.GetValue(),
|
||||
RespMsg: "成功",
|
||||
CodeNo: orderNo,
|
||||
}
|
||||
|
||||
if err != redis.Nil {
|
||||
return fmt.Errorf(fmt.Sprintf("alarm 获取redis缓存%s异常:%v", c.Key, err))
|
||||
}
|
||||
replyBizContent, _ := json.Marshal(bizReply)
|
||||
|
||||
cl := vo.OrderConsumeFailAlarmLockKey.BuildCache([]string{order.ProductNo})
|
||||
|
||||
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("alarm 二次获取redis缓存%s异常:%v", c.Key, err))
|
||||
}
|
||||
|
||||
if len(cacheValue) > 0 {
|
||||
return nil // 有直接返回
|
||||
}
|
||||
|
||||
// 通知
|
||||
if err = v.DingMixRepo.SendMarkdownMessage(ctx, "异常通知", v.alarmText(ctx, order, errMsg)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = v.rdb.Rdb.Set(ctx, c.Key, order.ProductNo, c.TTL).Err(); err != nil {
|
||||
return fmt.Errorf(fmt.Sprintf("设置redis缓存%s异常:%v", c.Key, err))
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
return c.GetResponse(ctx, replyBizContent)
|
||||
}
|
||||
|
||||
func (v *VoucherBiz) alarmText(_ context.Context, order *bo.OrderBo, errMsg string) string {
|
||||
func (c *VoucherBiz) OrderFail(ctx context.Context, err error) (*v1.CmbReply, error) {
|
||||
|
||||
remarks := fmt.Sprintf("订单号:%s,商品编号:%s,原因:%s", order.OrderNo, order.ProductNo, errMsg)
|
||||
se := errors.FromError(err)
|
||||
|
||||
msg := "# <font color='green'>" +
|
||||
"<h1>立减金发放平台报警通知</h1>" +
|
||||
"</font> \n" +
|
||||
"<font color='black'>" +
|
||||
"不好了,订单发放发生异常了" +
|
||||
"[<font color='red'>%s</font>]请尽快处理@相关人员。" +
|
||||
"</font>"
|
||||
if len(se.Reason) == 0 {
|
||||
se.Reason = err2.CmbErr_CMB_UNKNOWN.String()
|
||||
}
|
||||
|
||||
return fmt.Sprintf(msg, remarks)
|
||||
}
|
||||
|
||||
func (v *VoucherBiz) Query(ctx context.Context, order *bo.OrderBo) error {
|
||||
|
||||
status, err := v.WechatCpnRepo.Query(ctx, order)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if order.Status == status {
|
||||
log.Warnf("券状态未改变:%s,忽略不处理,orderNo:%s", order.Status.GetText(), order.OrderNo)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err = v.UpdateOrderStatus(ctx, order.ID, status); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
order.Status = status
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *VoucherBiz) UpdateOrderStatus(ctx context.Context, orderId uint64, status vo.OrderStatus) error {
|
||||
|
||||
if status.IsSuccess() {
|
||||
|
||||
return v.OrderRepo.Available(ctx, orderId)
|
||||
|
||||
} else if status.IsUse() {
|
||||
|
||||
return v.OrderRepo.Used(ctx, orderId)
|
||||
|
||||
} else if status.IsExpired() {
|
||||
|
||||
return v.OrderRepo.Expired(ctx, orderId)
|
||||
}
|
||||
|
||||
return fmt.Errorf("notice 未知券状态,orderId:%d,statuText:%s", orderId, status.GetText())
|
||||
}
|
||||
|
||||
func (v *VoucherBiz) QueryOrder(ctx context.Context, orderNo string) (string, error) {
|
||||
|
||||
order, err3 := v.OrderRepo.GetByOrderNo(ctx, orderNo)
|
||||
if err3 != nil {
|
||||
return "", err3
|
||||
}
|
||||
|
||||
status, err := v.WechatCpnRepo.Query(ctx, order)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("orderNo:%s,订单状态:%s,微信查询返回状态:%s", orderNo, order.Status.GetText(), status.GetText()), nil
|
||||
log.Errorf("order fail: %v", se)
|
||||
|
||||
bizReply := &v1.CmbOrderReply{
|
||||
RespCode: vo.CmbResponseStatusFail.GetValue(),
|
||||
RespMsg: se.Message,
|
||||
CodeNo: "",
|
||||
ThirdErrCode: se.Reason,
|
||||
}
|
||||
|
||||
replyBizContent, _ := json.Marshal(bizReply)
|
||||
|
||||
return c.GetResponse(ctx, replyBizContent)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
package biz
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
v1 "voucher/api/v1"
|
||||
"voucher/internal/biz/vo"
|
||||
"voucher/internal/pkg/lock"
|
||||
)
|
||||
|
||||
func (v *VoucherBiz) CmbProductQuery(ctx context.Context, productNo string) (reps *v1.CmbQueryProductReply, err error) {
|
||||
|
||||
c := vo.CmbProductQueryLockKey.BuildCache([]string{productNo})
|
||||
|
||||
err = lock.NewMutex(v.rdb.Rdb, c.TTL).Lock(ctx, c.Key, func(ctx context.Context) error {
|
||||
|
||||
product, err3 := v.ProductRepo.GetByProductNo(ctx, productNo)
|
||||
if err3 != nil {
|
||||
return err3
|
||||
}
|
||||
|
||||
if !product.Channel.IsWeChat() {
|
||||
return fmt.Errorf("只支持微信")
|
||||
}
|
||||
|
||||
wechatResp, err4 := v.WechatCpnRepo.QueryProduct(ctx, product.MchId, product.BatchNo)
|
||||
if err4 != nil {
|
||||
return err4
|
||||
}
|
||||
|
||||
reps = &v1.CmbQueryProductReply{
|
||||
RespCode: vo.CmbResponseStatusSuccess.GetValue(),
|
||||
RespMsg: "成功",
|
||||
ActivityName: product.Name,
|
||||
ActivityId: product.ProductNo,
|
||||
Amount: "",
|
||||
MinAmount: "",
|
||||
AvailableType: "",
|
||||
AvailableDays: "", // 动态有效期天数
|
||||
StartTime: "",
|
||||
EndTime: "",
|
||||
AvailableStock: "",
|
||||
Detail: *wechatResp.Description,
|
||||
}
|
||||
|
||||
inputFormat := time.RFC3339
|
||||
|
||||
if wechatResp.AvailableBeginTime != nil {
|
||||
|
||||
availableBeginTime, _ := time.Parse(inputFormat, *wechatResp.AvailableBeginTime)
|
||||
reps.StartTime = availableBeginTime.Format("2006-01-02 15:04:05.000")
|
||||
reps.SaleStartTime = reps.StartTime
|
||||
}
|
||||
|
||||
if wechatResp.AvailableEndTime != nil {
|
||||
availableEndTime, _ := time.Parse(inputFormat, *wechatResp.AvailableEndTime)
|
||||
reps.EndTime = availableEndTime.Format("2006-01-02 15:04:05.000")
|
||||
reps.SaleEndTime = reps.EndTime
|
||||
}
|
||||
|
||||
reps.Amount = fmt.Sprintf("%d", *wechatResp.StockUseRule.FixedNormalCoupon.CouponAmount)
|
||||
reps.MinAmount = fmt.Sprintf("%d", *wechatResp.StockUseRule.FixedNormalCoupon.TransactionMinimum)
|
||||
|
||||
availableStock := *wechatResp.StockUseRule.MaxCoupons - *wechatResp.DistributedCoupons
|
||||
reps.AvailableStock = fmt.Sprintf("%d", availableStock)
|
||||
|
||||
availableType, err3 := product.AvailableType.GetCmbAvailableType()
|
||||
if err3 != nil {
|
||||
return err3
|
||||
}
|
||||
|
||||
reps.AvailableType = availableType.GetValue()
|
||||
reps.AvailableDays = fmt.Sprintf("%d", product.AvailableDays)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
package biz
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/go-kratos/kratos/v2/log"
|
||||
"time"
|
||||
v1 "voucher/api/v1"
|
||||
"voucher/internal/biz/bo"
|
||||
"voucher/internal/biz/vo"
|
||||
"voucher/internal/pkg/lock"
|
||||
)
|
||||
|
||||
func (v *VoucherBiz) CmbQuery(ctx context.Context, orderNo string) (resp *v1.CmbQueryReply, err error) {
|
||||
|
||||
c := vo.CmbQueryLockKey.BuildCache([]string{orderNo})
|
||||
|
||||
err = lock.NewMutex(v.rdb.Rdb, c.TTL).Lock(ctx, c.Key, func(ctx context.Context) error {
|
||||
|
||||
order, err3 := v.OrderRepo.GetByOrderNo(ctx, orderNo)
|
||||
if err3 != nil {
|
||||
return err3
|
||||
}
|
||||
|
||||
if err = v.Query(ctx, order); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
status, err3 := order.Status.GetCmbStatusText()
|
||||
if err3 != nil {
|
||||
return err3
|
||||
}
|
||||
|
||||
resp = &v1.CmbQueryReply{
|
||||
Ticket: order.OrderNo,
|
||||
Status: status.GetValue(),
|
||||
TransDate: time.Now().Format("20060102150405"),
|
||||
OrgNo: v.bc.Cmb.OrgNo,
|
||||
Ext: "",
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (v *VoucherBiz) Query(ctx context.Context, order *bo.OrderBo) error {
|
||||
|
||||
status, err := v.WechatCpnRepo.Query(ctx, order)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if order.Status == status {
|
||||
log.Warnf("券状态未改变:%s,忽略不处理,orderNo:%s", order.Status.GetText(), order.OrderNo)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err = v.UpdateOrderStatus(ctx, order.ID, status); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
order.Status = status
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *VoucherBiz) UpdateOrderStatus(ctx context.Context, orderId uint64, status vo.OrderStatus) error {
|
||||
|
||||
if status.IsSuccess() {
|
||||
|
||||
return v.OrderRepo.Available(ctx, orderId)
|
||||
|
||||
} else if status.IsUse() {
|
||||
|
||||
return v.OrderRepo.Used(ctx, orderId)
|
||||
|
||||
} else if status.IsExpired() {
|
||||
|
||||
return v.OrderRepo.Expired(ctx, orderId)
|
||||
}
|
||||
|
||||
return fmt.Errorf("notice 未知券状态,orderId:%d,statuText:%s", orderId, status.GetText())
|
||||
}
|
||||
|
||||
func (v *VoucherBiz) QueryOrder(ctx context.Context, orderNo string) (string, error) {
|
||||
|
||||
order, err3 := v.OrderRepo.GetByOrderNo(ctx, orderNo)
|
||||
if err3 != nil {
|
||||
return "", err3
|
||||
}
|
||||
|
||||
status, err := v.WechatCpnRepo.Query(ctx, order)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("orderNo:%s,订单状态:%s,微信查询返回状态:%s", orderNo, order.Status.GetText(), status.GetText()), nil
|
||||
}
|
||||
|
|
@ -1,9 +1,14 @@
|
|||
package biz
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/go-kratos/kratos/v2/log"
|
||||
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"
|
||||
|
|
@ -22,6 +27,7 @@ type VoucherBiz struct {
|
|||
WechatCpnRepo wechatrepo.WechatCpnRepo
|
||||
DingMixRepo mixrepos.DingMixRepo
|
||||
CmbMixRepo mixrepos.CmbMixRepo
|
||||
KxMixRepo mixrepos.KxMixRepo
|
||||
}
|
||||
|
||||
func NewVoucherBiz(
|
||||
|
|
@ -37,6 +43,7 @@ func NewVoucherBiz(
|
|||
WechatCpnRepo wechatrepo.WechatCpnRepo,
|
||||
DingMixRepo mixrepos.DingMixRepo,
|
||||
CmbMixRepo mixrepos.CmbMixRepo,
|
||||
KxMixRepo mixrepos.KxMixRepo,
|
||||
) *VoucherBiz {
|
||||
return &VoucherBiz{
|
||||
bc: bc,
|
||||
|
|
@ -51,5 +58,23 @@ func NewVoucherBiz(
|
|||
WechatCpnRepo: WechatCpnRepo,
|
||||
DingMixRepo: DingMixRepo,
|
||||
CmbMixRepo: CmbMixRepo,
|
||||
KxMixRepo: KxMixRepo,
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
package mixrepoimpl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/go-kratos/kratos/v2/log"
|
||||
"net/http"
|
||||
"time"
|
||||
v1 "voucher/api/v1"
|
||||
"voucher/internal/biz/kx"
|
||||
"voucher/internal/biz/mixrepos"
|
||||
"voucher/internal/biz/vo"
|
||||
"voucher/internal/conf"
|
||||
"voucher/internal/pkg/request"
|
||||
)
|
||||
|
||||
type KxMixRepoImpl struct {
|
||||
bc *conf.Bootstrap
|
||||
}
|
||||
|
||||
func NewKxMixRepoImpl(bc *conf.Bootstrap) mixrepos.KxMixRepo {
|
||||
return &KxMixRepoImpl{bc: bc}
|
||||
}
|
||||
|
||||
func (s *KxMixRepoImpl) Request(ctx context.Context, req *kx.SynNotice) error {
|
||||
|
||||
body, err := req.Marshal()
|
||||
if err != nil {
|
||||
log.Errorf("请求掌上生活Marshal报错:%s", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
h := http.Header{
|
||||
"Content-Type": []string{"application/x-www-form-urlencoded"},
|
||||
}
|
||||
|
||||
url := ""
|
||||
|
||||
_, bodyBytes, err := request.Post(ctx, url, body, request.WithHeaders(h), request.WithTimeout(time.Second*20))
|
||||
if err != nil {
|
||||
log.Errorf("请求kx报错,url:%s,err:%v", url, err)
|
||||
return err
|
||||
}
|
||||
|
||||
var response *v1.CmbReply
|
||||
if err = json.Unmarshal(bodyBytes, &response); err != nil {
|
||||
log.Errorf("请求kx返回数据解析报错:%s,url:%s,bodyBytes:%s", err.Error(), url, string(bodyBytes))
|
||||
return err
|
||||
}
|
||||
|
||||
if response.RespCode != vo.CmbResponseStatusSuccess.GetValue() {
|
||||
log.Errorf("请求kx返回报错:msg:%s,url:%s,bodyBytes:%s", response.RespMsg, url, string(bodyBytes))
|
||||
return fmt.Errorf(response.RespMsg)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -10,4 +10,5 @@ var ProviderMixRepoImplSet = wire.NewSet(
|
|||
NewMQSendMixRepoImpl,
|
||||
NewCmbMixRepoImpl,
|
||||
NewDingMixRepoImpl,
|
||||
NewKxMixRepoImpl,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,85 +2,10 @@ package service
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/go-kratos/kratos/v2/errors"
|
||||
"github.com/go-kratos/kratos/v2/log"
|
||||
err2 "voucher/api/err"
|
||||
v1 "voucher/api/v1"
|
||||
"voucher/internal/biz/bo"
|
||||
"voucher/internal/biz/vo"
|
||||
)
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
log.Errorf("order fail: %v", se)
|
||||
|
||||
bizReply := &v1.CmbOrderReply{
|
||||
RespCode: vo.CmbResponseStatusFail.GetValue(),
|
||||
RespMsg: se.Message,
|
||||
CodeNo: "",
|
||||
ThirdErrCode: se.Reason,
|
||||
}
|
||||
|
||||
replyBizContent, _ := json.Marshal(bizReply)
|
||||
|
||||
return c.GetResponse(ctx, replyBizContent)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
ctx2 := context.Background()
|
||||
|
||||
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(ctx2, boReq)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return orderNo, nil
|
||||
return c.VoucherBiz.CmbOrder(ctx, request)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue