Browse Source

增加系统配置接口

kobe6258 5 months ago
parent
commit
b39184a64f

+ 39 - 27
controllers/order.go

@@ -7,6 +7,7 @@ import (
 	"eta/eta_mini_crm_ht/models/response"
 	"eta/eta_mini_crm_ht/utils"
 	"fmt"
+	uuid2 "github.com/google/uuid"
 	"github.com/rdlucklib/rdluck_tools/paging"
 	"github.com/xuri/excelize/v2"
 	"math/rand"
@@ -778,35 +779,46 @@ func (this *OrderController) Refund() {
 		br.ErrMsg = "退款失败,原订单未完成支付"
 		return
 	}
-	aa := GenerateProductOrderNo()
-	refundOrder := &models.TradeOrder{
-		TransactionId:    aa,
-		OrgTransactionId: productOrder.TradeNo,
-		ProductOrderId:   productOrder.OrderId,
-		PaymentAccount:   tradeOrder.PaymentAccount,
-		PaymentWay:       tradeOrder.PaymentWay,
-		Amount:           tradeOrder.Amount,
-		Currency:         tradeOrder.Currency,
-		UserId:           tradeOrder.UserId,
-		TemplateUserId:   tradeOrder.TemplateUserId,
-		PaymentType:      models.PaymentTypeRefund,
-		PaymentStatus:    models.PaymentStatusPending,
-		CreatedTime:      time.Now(),
-	}
-	productOrder.RefundStatus = models.RefundStatusProcessing
-	productOrder.Status = models.OrderStatusRefund
-	productOrder.RefundTradeId = refundOrder.TransactionId
-	productOrder.Remark = req.Remark
-	productOrder.RefundAmount = tradeOrder.Amount
-	err = refundOrder.Refund(productOrder)
-	if err != nil {
-		br.Msg = "退款失败"
-		br.ErrMsg = "退款失败,,Err:" + err.Error()
+	uuid := uuid2.NewString()
+	key := fmt.Sprintf("refund_lock_%s", productOrder.OrderId)
+	defer func() {
+		utils.ReleaseLock(key, uuid)
+	}()
+	if utils.AcquireLock(key, 10, uuid) {
+		aa := GenerateProductOrderNo()
+		refundOrder := &models.TradeOrder{
+			TransactionId:    aa,
+			OrgTransactionId: productOrder.TradeNo,
+			ProductOrderId:   productOrder.OrderId,
+			PaymentAccount:   tradeOrder.PaymentAccount,
+			PaymentWay:       tradeOrder.PaymentWay,
+			Amount:           tradeOrder.Amount,
+			Currency:         tradeOrder.Currency,
+			UserId:           tradeOrder.UserId,
+			TemplateUserId:   tradeOrder.TemplateUserId,
+			PaymentType:      models.PaymentTypeRefund,
+			PaymentStatus:    models.PaymentStatusPending,
+			CreatedTime:      time.Now(),
+		}
+		productOrder.RefundStatus = models.RefundStatusProcessing
+		productOrder.Status = models.OrderStatusRefund
+		productOrder.RefundTradeId = refundOrder.TransactionId
+		productOrder.Remark = req.Remark
+		productOrder.RefundAmount = tradeOrder.Amount
+		err = refundOrder.Refund(productOrder)
+		if err != nil {
+			br.Msg = "退款失败"
+			br.ErrMsg = "退款失败,,Err:" + err.Error()
+			return
+		}
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "退款处理成功"
+	} else {
+		br.Msg = "退款失败,当前订单正在退款中"
+		br.ErrMsg = "退款失败,当前订单正在退款中"
 		return
 	}
-	br.Ret = 200
-	br.Success = true
-	br.Msg = "退款处理成功"
 }
 func GenerateProductOrderNo() string {
 	timestamp := time.Now().UnixNano() / 1000000 // 毫秒级时间戳

+ 1 - 0
models/db.go

@@ -55,5 +55,6 @@ func init() {
 		new(MerchantProduct),
 		new(ProductOrder),
 		new(TradeOrder),
+		new(RefundDealFlow),
 	)
 }

+ 7 - 1
models/meta_info.go

@@ -19,6 +19,7 @@ const (
 	ReportSourceType SourceType = "REPORT"
 	VideoSourceType  SourceType = "VIDEO"
 	AudioSourceType  SourceType = "AUDIO"
+	RefundSourceType SourceType = "REFUND"
 )
 
 // MetaInfo 表示 meta_infos 表的模型
@@ -28,7 +29,7 @@ type MetaInfo struct {
 	From        string     `description:"from"`
 	To          string     `description:"column:to"`
 	SourceType  SourceType `description:"source_type"`
-	MetaType    MetaType   `gorm:"column:meta_type;type:enum('USER_NOTICE')"`
+	MetaType    MetaType   `gorm:"column:meta_type;type:enum('USER_NOTICE','SYSTEM_NOTICE')"`
 	Status      StatusType `gorm:"column:status;type:enum('INIT','PENDING','FINISH','FAILED')"`
 	CreatedTime time.Time
 	UpdatedTime time.Time
@@ -40,6 +41,11 @@ type MetaData struct {
 	AuthorName    string `json:"authorName"`
 	PublishedTime string `json:"publishedTime"`
 }
+type RefundMetaData struct {
+	ProductOrderNo string
+	RealName       string
+	Result         string
+}
 
 func (m *MetaInfo) TableName() string {
 	return "meta_infos"

+ 25 - 0
models/refund_deal_flow.go

@@ -0,0 +1,25 @@
+package models
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// RefundDealFlow 表示 refund_deal_flow 表的 ORM 结构体
+type RefundDealFlow struct {
+	ID             int        `gorm:"column:id;primaryKey;autoIncrement:false"`
+	OperatorUserID *int       `gorm:"column:operator_user_id;default:null"`
+	ProductOrderNo *string    `gorm:"column:product_order_no;default:null"`
+	RefundOrderNo  *string    `gorm:"column:refund_order_no;default:null"`
+	CreatedTime    *time.Time `gorm:"column:created_time;default:null"`
+}
+
+// TableName 返回表名
+func (RefundDealFlow) TableName() string {
+	return "refund_deal_flow"
+}
+func (m *RefundDealFlow) Insert() (err error) {
+	o := orm.NewOrm()
+	_, err = o.Insert(m)
+	return
+}

+ 20 - 0
services/meta.go

@@ -35,3 +35,23 @@ func CreateMeta(authorName string, authorId int, mediaId int, publishTime string
 	id, err = metaContent.Insert()
 	return
 }
+
+func CreateRefundMeta(toUserId int) (id int64, err error) {
+	Meta := models.RefundMetaData{
+		ProductOrderNo: "",
+		RealName:       "",
+		Result:         "",
+	}
+	metaStr, _ := json.Marshal(Meta)
+	toStr := strconv.Itoa(toUserId)
+	metaContent := models.MetaInfo{
+		From:       "SYSTEM",
+		Meta:       string(metaStr),
+		MetaType:   "SYSTEM_NOTICE",
+		SourceType: models.RefundSourceType,
+		Status:     models.InitStatusType,
+		To:         toStr,
+	}
+	id, err = metaContent.Insert()
+	return
+}

+ 41 - 0
utils/distrubtLock.go

@@ -0,0 +1,41 @@
+package utils
+
+import (
+	"context"
+	"fmt"
+)
+
+const (
+	lockName = "lock:"
+)
+
+var (
+	ctx = context.Background()
+)
+
+func AcquireLock(key string, expiration int, holder string) bool {
+	script := `local key = KEYS[1]
+			local clientId = ARGV[1]
+			local expiration = tonumber(ARGV[2])
+			if redis.call("EXISTS", key) == 0 then
+				redis.call("SET", key, clientId, "EX", expiration)
+				return 1
+			else
+				return 0
+			end`
+
+	lockey := fmt.Sprintf("%s%s", lockName, key)
+	return Rc.RunLUA(script, ctx, []string{lockey}, expiration, holder)
+}
+
+func ReleaseLock(key string, holder string) bool {
+	script := `
+	   if redis.call("get", KEYS[1]) == ARGV[1] then
+	       return redis.call("del", KEYS[1])
+	   else
+	       return 0
+	   end
+	`
+	lockey := fmt.Sprintf("%s%s", lockName, key)
+	return Rc.RunLUA(script, ctx, []string{lockey}, holder)
+}

+ 2 - 0
utils/redis.go

@@ -1,6 +1,7 @@
 package utils
 
 import (
+	"context"
 	"eta/eta_mini_crm_ht/utils/redis"
 	"time"
 )
@@ -20,6 +21,7 @@ type RedisClient interface {
 	GetRedisTTL(key string) time.Duration
 	Incrby(key string, num int) (interface{}, error)
 	Do(commandName string, args ...interface{}) (reply interface{}, err error)
+	RunLUA(command string, ctx context.Context, keys []string, args ...interface{}) bool
 }
 
 func initRedis(redisType string, conf string) (redisClient RedisClient, err error) {

+ 19 - 0
utils/redis/cluster_redis.go

@@ -269,3 +269,22 @@ func (rc *ClusterRedisClient) Do(commandName string, args ...interface{}) (reply
 	newArgs = append(newArgs, args...)
 	return rc.redisClient.Do(context.TODO(), newArgs...).Result()
 }
+
+// RunLUA
+// @Description: cmd执行redis命令
+// @receiver rc
+// @param commandName
+// @param args
+// @return reply
+// @return err
+func (rc *ClusterRedisClient) RunLUA(command string, ctx context.Context, keys []string, args ...interface{}) bool {
+	script := redis.NewScript(command)
+	result, err := script.Run(ctx, rc.redisClient, keys, args).Int()
+	if err != nil {
+		return false
+	}
+	if result == 1 {
+		return true
+	}
+	return false
+}

+ 12 - 0
utils/redis/standalone_redis.go

@@ -263,3 +263,15 @@ func (rc *StandaloneRedisClient) Do(commandName string, args ...interface{}) (re
 	newArgs = append(newArgs, args...)
 	return rc.redisClient.Do(context.TODO(), newArgs...).Result()
 }
+
+func (rc *StandaloneRedisClient) RunLUA(command string, ctx context.Context, keys []string, args ...interface{}) bool {
+	script := redis.NewScript(command)
+	result, err := script.Run(ctx, rc.redisClient, keys, args).Int()
+	if err != nil {
+		return false
+	}
+	if result == 1 {
+		return true
+	}
+	return false
+}