426 lines
16 KiB
Go
426 lines
16 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"errors"
|
||
"fmt"
|
||
"gateway/internal/config"
|
||
"gateway/internal/otelTrace"
|
||
|
||
"gateway/internal/service/supplier"
|
||
|
||
"gateway/internal/models/merchant"
|
||
"gateway/internal/models/merchant_deploy"
|
||
"gateway/internal/models/order"
|
||
"gateway/internal/models/road"
|
||
"gateway/internal/schema/request"
|
||
"gateway/internal/schema/response"
|
||
"gateway/internal/utils"
|
||
"strconv"
|
||
"time"
|
||
|
||
"github.com/duke-git/lancet/v2/convertor"
|
||
|
||
"github.com/beego/beego/v2/core/logs"
|
||
"github.com/shopspring/decimal"
|
||
)
|
||
|
||
// ChooseRoadV2 选择通道,通过productCode选择对应的通道
|
||
func ChooseRoadV2(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
|
||
orderPrice, err := strconv.ParseFloat(convertor.ToString(c.Params["orderPrice"]), 64)
|
||
if err != nil {
|
||
c.Code = -1
|
||
c.Msg = "输入金额错误!"
|
||
return c
|
||
}
|
||
roadInfo := road.GetRoadInfoByProductCode(ctx, convertor.ToString(c.Params["productCode"]))
|
||
if roadInfo.Id == 0 {
|
||
c.Code = -1
|
||
c.Msg = "未配置支付通道!"
|
||
return c
|
||
}
|
||
if msg, ok := RoadIsValid(ctx, roadInfo, c); !ok {
|
||
c.Code = -1
|
||
c.Msg = msg
|
||
return c
|
||
}
|
||
merchantUid := c.MerchantInfo.MerchantUid
|
||
// 通道配置信息
|
||
deployInfo := merchant_deploy.GetMerchantDeployByUidAndRoadUid(ctx, merchantUid, roadInfo.RoadUid)
|
||
if deployInfo.MerchantUid == "" {
|
||
c.Code = -1
|
||
c.Msg = "该商户没有配置通道信息"
|
||
return c
|
||
}
|
||
rate, err2 := deployInfo.GetSingleRoadPlatformRateByPrice(orderPrice)
|
||
if err2 != nil {
|
||
c.Code = -1
|
||
c.Msg = "当前通道面额存在问题"
|
||
return c
|
||
}
|
||
if !deployInfo.CheckSingleRoadPlatformRate(orderPrice) {
|
||
c.Code = -1
|
||
c.Msg = "当前面额不被允许"
|
||
return c
|
||
}
|
||
c.RoadInfo = roadInfo
|
||
c.PlatformRate = rate
|
||
c.AgentRate = deployInfo.SingleRoadAgentRate
|
||
c.RoadPoolInfo = road.GetRoadPoolByRoadPoolCode(ctx, deployInfo.RollRoadCode)
|
||
return c
|
||
}
|
||
|
||
// RoadIsValid 判断通道是否是合法的
|
||
func RoadIsValid(ctx context.Context, roadInfo road.RoadInfo, c *response.PayBaseResp) (string, bool) {
|
||
if roadInfo.RoadUid == "" || len(roadInfo.RoadUid) == 0 {
|
||
return "参数缺失", false
|
||
}
|
||
FORMAT := fmt.Sprintf("该通道:%s;", roadInfo.RoadName)
|
||
if roadInfo.Status != "active" {
|
||
logs.Notice(FORMAT + "不是激活状态")
|
||
return "通道未激活", false
|
||
}
|
||
hour := time.Now().Hour()
|
||
s := roadInfo.StarHour
|
||
e := roadInfo.EndHour
|
||
if hour < s || hour > e {
|
||
logs.Notice(FORMAT)
|
||
return "当前未处在交易区间内", false
|
||
}
|
||
if roadInfo.SingleMinLimit > c.OrderAmount || roadInfo.SingleMaxLimit < c.OrderAmount {
|
||
otelTrace.Logger.WithContext(ctx).Error(FORMAT + "订单金额超限制")
|
||
return "订单金额超过交易限制", false
|
||
}
|
||
todayLimit := roadInfo.TodayLimit
|
||
totalLimit := roadInfo.TotalLimit
|
||
todayIncome := roadInfo.TodayIncome
|
||
totalIncome := roadInfo.TotalIncome
|
||
if (todayIncome + c.OrderAmount) > todayLimit {
|
||
otelTrace.Logger.WithContext(ctx).Error(FORMAT + "达到了每天金额上限")
|
||
return "订单金额超过金额限制", false
|
||
}
|
||
if (totalIncome + c.OrderAmount) > totalLimit {
|
||
otelTrace.Logger.WithContext(ctx).Error(FORMAT + "达到了总量限制")
|
||
return "订单金额达到总量限制", false
|
||
}
|
||
// 如果通道被选中,那么总请求数+1
|
||
roadInfo.RequestAll = roadInfo.RequestAll + 1
|
||
roadInfo.TodayRequestAll = roadInfo.RequestAll + 1
|
||
roadInfo.UpdateTime = time.Now()
|
||
road.UpdateRoadInfo(ctx, roadInfo)
|
||
return "", true
|
||
}
|
||
|
||
// GenerateOrderInfo 获取基本订单记录
|
||
func GenerateOrderInfo(c *response.PayBaseResp) order.OrderInfo {
|
||
// 6666是自己系统订单号
|
||
// 获取支付类型的名称,例如支付宝扫码等
|
||
orderInfo := order.OrderInfo{
|
||
MerchantUid: c.MerchantInfo.MerchantUid,
|
||
MerchantName: c.MerchantInfo.MerchantName,
|
||
MerchantOrderId: convertor.ToString(c.Params["orderNo"]),
|
||
BankOrderId: "666" + utils.GenerateId(),
|
||
OrderAmount: c.OrderAmount,
|
||
FactAmount: c.OrderAmount,
|
||
ShowAmount: c.OrderAmount,
|
||
RollPoolCode: c.RoadPoolInfo.RoadPoolCode,
|
||
RollPoolName: c.RoadPoolInfo.RoadPoolName,
|
||
RoadUid: c.RoadInfo.RoadUid,
|
||
RoadName: c.RoadInfo.RoadName,
|
||
PayProductName: c.RoadInfo.ProductName,
|
||
ShopName: convertor.ToString(c.Params["productName"]),
|
||
Freeze: config.NO,
|
||
Refund: config.NO,
|
||
Unfreeze: config.NO,
|
||
Ip: c.ClientIP,
|
||
PayProductCode: c.RoadInfo.ProductUid,
|
||
Status: config.WAIT,
|
||
NotifyUrl: convertor.ToString(c.Params["notifyUrl"]),
|
||
OrderPeriod: convertor.ToString(c.Params["orderPeriod"]),
|
||
CreateTime: time.Now(),
|
||
UpdateTime: time.Now(),
|
||
ExValue: convertor.ToString(c.Params["exValue"]),
|
||
}
|
||
|
||
if c.MerchantInfo.BelongAgentUid != "" || c.AgentRate > config.ZERO {
|
||
orderInfo.AgentUid = c.MerchantInfo.BelongAgentUid
|
||
orderInfo.AgentName = c.MerchantInfo.BelongAgentName
|
||
}
|
||
return orderInfo
|
||
}
|
||
|
||
// CreateOrderInfo 创建订单
|
||
func CreateOrderInfo(createdOrder request.CreatedOrder, info merchant.MerchantInfo, roadPoolInfo road.RoadPoolInfo, roadInfo road.RoadInfo) (orderInfo order.OrderInfo, err error) {
|
||
// 6666是自己系统订单号
|
||
// 获取支付类型的名称,例如支付宝扫码等
|
||
orderInfo = order.OrderInfo{
|
||
MerchantUid: info.MerchantUid,
|
||
MerchantName: info.MerchantName,
|
||
MerchantOrderId: createdOrder.OrderNo,
|
||
BankOrderId: "666" + utils.GenerateId(),
|
||
OrderAmount: createdOrder.OrderPrice,
|
||
FactAmount: createdOrder.OrderPrice,
|
||
ShowAmount: createdOrder.OrderPrice,
|
||
RollPoolCode: roadPoolInfo.RoadPoolCode,
|
||
RollPoolName: roadPoolInfo.RoadPoolName,
|
||
RoadUid: roadInfo.RoadUid,
|
||
RoadName: roadInfo.RoadName,
|
||
PayProductName: roadInfo.ProductName,
|
||
Freeze: config.NO,
|
||
Refund: config.NO,
|
||
Unfreeze: config.NO,
|
||
PayProductCode: roadInfo.ProductUid,
|
||
Status: config.Created,
|
||
NotifyUrl: createdOrder.NotifyUrl,
|
||
OrderPeriod: strconv.Itoa(createdOrder.OrderPeriod),
|
||
CreateTime: time.Now(),
|
||
TransactionType: roadInfo.TransactionType,
|
||
}
|
||
return
|
||
}
|
||
|
||
// GenerateOrderProfit 计算收益,平台利润,代理利润
|
||
func GenerateOrderProfit(ctx context.Context, orderInfo order.OrderInfo, c *response.PayBaseResp) order.OrderProfitInfo {
|
||
// 因为所有的手续费率都是百分率,所以需要除以100
|
||
supplierProfit := decimal.NewFromFloat(orderInfo.OrderAmount).
|
||
Div(decimal.NewFromInt(100)).
|
||
Mul(decimal.NewFromFloat(c.RoadInfo.BasicFee))
|
||
platformProfit := decimal.NewFromFloat(orderInfo.OrderAmount).
|
||
Div(decimal.NewFromInt(100)).
|
||
Mul(decimal.NewFromFloat(c.PlatformRate))
|
||
agentProfit := decimal.NewFromFloat(orderInfo.OrderAmount).
|
||
Div(decimal.NewFromInt(100)).
|
||
Mul(decimal.NewFromFloat(c.AgentRate))
|
||
|
||
// 如果用户没有设置代理,那么代理利润为0.000
|
||
if c.MerchantInfo.BelongAgentUid == "" || len(c.MerchantInfo.BelongAgentUid) == 0 {
|
||
agentProfit = decimal.NewFromFloat(config.ZERO)
|
||
}
|
||
|
||
allProfit := supplierProfit.Add(platformProfit).Add(agentProfit)
|
||
|
||
if allProfit.GreaterThanOrEqual(decimal.NewFromFloat(orderInfo.OrderAmount)) {
|
||
otelTrace.Logger.WithContext(ctx).Error(fmt.Sprintf("手续费已经超过订单金额,bankOrderId = %s", orderInfo.BankOrderId))
|
||
c.Msg = "手续费已经超过了订单金额"
|
||
c.Code = -1
|
||
}
|
||
|
||
orderProfit := order.OrderProfitInfo{
|
||
PayProductCode: c.RoadInfo.ProductUid,
|
||
PayProductName: c.RoadInfo.ProductName,
|
||
Status: config.WAIT,
|
||
MerchantOrderId: convertor.ToString(c.Params["orderNo"]),
|
||
BankOrderId: orderInfo.BankOrderId,
|
||
OrderAmount: c.OrderAmount,
|
||
FactAmount: c.OrderAmount,
|
||
ShowAmount: c.OrderAmount,
|
||
AllProfit: allProfit.InexactFloat64(),
|
||
UserInAmount: decimal.NewFromFloat(orderInfo.OrderAmount).Sub(allProfit).InexactFloat64(),
|
||
SupplierProfit: supplierProfit.InexactFloat64(),
|
||
PlatformProfit: platformProfit.InexactFloat64(),
|
||
AgentProfit: agentProfit.InexactFloat64(),
|
||
CreateTime: time.Now(),
|
||
UpdateTime: time.Now(),
|
||
MerchantUid: c.MerchantInfo.MerchantUid,
|
||
MerchantName: orderInfo.MerchantName,
|
||
SupplierRate: c.RoadInfo.BasicFee,
|
||
PlatformRate: c.PlatformRate,
|
||
AgentRate: c.AgentRate,
|
||
AgentName: orderInfo.AgentName,
|
||
AgentUid: orderInfo.AgentUid,
|
||
}
|
||
|
||
// 如果该条订单设置了代理利率,并且设置了代理
|
||
if c.MerchantInfo.BelongAgentUid != "" || c.AgentRate > config.ZERO {
|
||
orderProfit.AgentUid = c.MerchantInfo.BelongAgentUid
|
||
orderProfit.AgentName = c.MerchantInfo.BelongAgentName
|
||
}
|
||
return orderProfit
|
||
}
|
||
|
||
func CreateOrderProfitInfo(ctx context.Context, createdOrder request.CreatedOrder, merchantInfo merchant.MerchantInfo, merchantDeployInfo merchant_deploy.MerchantDeployInfo, orderInfo order.OrderInfo, roadInfo road.RoadInfo) (orderProfitInfo order.OrderProfitInfo, err error) {
|
||
// 因为所有的手续费率都是百分率,所以需要除以100
|
||
platFormRate, err := merchantDeployInfo.GetSingleRoadPlatformRateByPrice(createdOrder.OrderPrice)
|
||
if err != nil {
|
||
|
||
platFormRate = 0.0
|
||
}
|
||
|
||
supplierProfit := decimal.NewFromFloat(orderInfo.OrderAmount).
|
||
Div(decimal.NewFromInt(100)).
|
||
Mul(decimal.NewFromFloat(roadInfo.BasicFee))
|
||
platformProfit := decimal.NewFromFloat(orderInfo.OrderAmount).
|
||
Div(decimal.NewFromInt(100)).
|
||
Mul(decimal.NewFromFloat(platFormRate))
|
||
agentProfit := decimal.NewFromFloat(orderInfo.OrderAmount).
|
||
Div(decimal.NewFromInt(100)).
|
||
Mul(decimal.NewFromFloat(merchantDeployInfo.SingleRoadAgentRate))
|
||
|
||
// 如果用户没有设置代理,那么代理利润为0.000
|
||
if merchantInfo.BelongAgentUid == "" || len(merchantInfo.BelongAgentUid) == 0 {
|
||
agentProfit = decimal.NewFromFloat(config.ZERO)
|
||
}
|
||
|
||
allProfit := supplierProfit.Add(platformProfit).Add(agentProfit)
|
||
|
||
if allProfit.GreaterThanOrEqual(decimal.NewFromFloat(orderInfo.OrderAmount)) {
|
||
otelTrace.Logger.WithContext(ctx).Error(fmt.Sprintf("手续费已经超过订单金额,bankOrderId = %s", orderInfo.BankOrderId))
|
||
err = errors.New("手续费已经超过订单金额")
|
||
return
|
||
}
|
||
|
||
orderProfitInfo = order.OrderProfitInfo{
|
||
PayProductCode: roadInfo.ProductUid,
|
||
PayProductName: roadInfo.ProductName,
|
||
Status: config.Created,
|
||
MerchantOrderId: createdOrder.OrderNo,
|
||
BankOrderId: orderInfo.BankOrderId,
|
||
OrderAmount: orderInfo.OrderAmount,
|
||
FactAmount: orderInfo.FactAmount,
|
||
ShowAmount: orderInfo.ShowAmount,
|
||
AllProfit: allProfit.InexactFloat64(),
|
||
UserInAmount: decimal.NewFromFloat(orderInfo.OrderAmount).Sub(allProfit).InexactFloat64(),
|
||
SupplierProfit: supplierProfit.InexactFloat64(),
|
||
PlatformProfit: platformProfit.InexactFloat64(),
|
||
AgentProfit: agentProfit.InexactFloat64(),
|
||
CreateTime: time.Now(),
|
||
UpdateTime: time.Now(),
|
||
MerchantUid: merchantInfo.MerchantUid,
|
||
MerchantName: orderInfo.MerchantName,
|
||
SupplierRate: roadInfo.BasicFee,
|
||
PlatformRate: platFormRate,
|
||
AgentRate: merchantDeployInfo.SingleRoadAgentRate,
|
||
AgentName: orderInfo.AgentName,
|
||
AgentUid: orderInfo.AgentUid,
|
||
}
|
||
return
|
||
}
|
||
|
||
// GenerateRecord 生成订单一系列的记录
|
||
func GenerateRecord(ctx context.Context, c *response.PayBaseResp) (order.OrderInfo, order.OrderProfitInfo, error) {
|
||
// 获取订单和订单利润表
|
||
orderInfo := order.GetOrderByMerchantOrderId(ctx, convertor.ToString(c.Params["orderNo"]))
|
||
orderProfitInfo := order.GetOrderProfitByMerchantOrderId(ctx, convertor.ToString(c.Params["orderNo"]))
|
||
if orderProfitInfo.Id == 0 || orderInfo.MerchantOrderId == "" {
|
||
//生成订单记录,订单利润利润
|
||
orderInfo = GenerateOrderInfo(c)
|
||
orderProfit := GenerateOrderProfit(ctx, orderInfo, c)
|
||
if c.Code == -1 {
|
||
return orderInfo, orderProfit, errors.New("订单数据插入失败")
|
||
}
|
||
//插入订单记录和订单利润记录
|
||
if !order.InsertOrderAndOrderProfit(ctx, orderInfo, orderProfit) {
|
||
c.Code = -1
|
||
return orderInfo, orderProfit, errors.New("订单数据插入失败")
|
||
}
|
||
orderInfo = order.GetOrderByMerchantOrderId(ctx, convertor.ToString(c.Params["orderNo"]))
|
||
orderProfitInfo = order.GetOrderProfitByBankOrderId(ctx, orderProfitInfo.BankOrderId)
|
||
otelTrace.Logger.WithContext(ctx).Info("插入支付订单记录和支付利润记录成功")
|
||
return orderInfo, orderProfit, nil
|
||
}
|
||
if orderInfo.Status != config.Created {
|
||
err := errors.New("当前订单已存在,请等待处理结果或手动查询")
|
||
return orderInfo, orderProfitInfo, err
|
||
}
|
||
if !order.InsertOrderExValue(convertor.ToString(c.Params["orderNo"]), convertor.ToString(c.Params["exValue"])) {
|
||
err := errors.New("订单数据插入失败")
|
||
return orderInfo, orderProfitInfo, err
|
||
}
|
||
if !order.InsertClientIP(convertor.ToString(c.Params["orderNo"]), c.ClientIP) {
|
||
err := errors.New("订单数据插入失败")
|
||
return orderInfo, orderProfitInfo, err
|
||
}
|
||
if !order.InsertPayTime(convertor.ToString(c.Params["orderNo"])) {
|
||
err := errors.New("订单数据插入失败")
|
||
return orderInfo, orderProfitInfo, err
|
||
}
|
||
if !order.SwitchOrderAndOrderProfitStatus(ctx, convertor.ToString(c.Params["orderNo"]), config.WAIT) {
|
||
err := errors.New("订单状态转换失败")
|
||
return orderInfo, orderProfitInfo, err
|
||
}
|
||
orderInfo = order.GetOrderByMerchantOrderId(ctx, convertor.ToString(c.Params["orderNo"]))
|
||
orderProfitInfo = order.GetOrderProfitByBankOrderId(ctx, orderProfitInfo.BankOrderId)
|
||
otelTrace.Logger.WithContext(ctx).Info("插入支付订单记录和支付利润记录成功")
|
||
return orderInfo, orderProfitInfo, nil
|
||
}
|
||
|
||
func GenerateSuccessData(scanData supplier.ScanData, c *response.PayBaseResp) *response.ScanSuccessData {
|
||
params := map[string]any{
|
||
"statusCode": "00",
|
||
"orderNo": scanData.BankNo,
|
||
"orderPrice": scanData.OrderPrice,
|
||
}
|
||
sign := utils.GetMD5SignMF(params, c.MerchantInfo.MerchantSecret)
|
||
scanSuccessData := &response.ScanSuccessData{
|
||
OrderNo: scanData.OrderNo,
|
||
Sign: sign,
|
||
OrderPrice: scanData.OrderPrice,
|
||
StatusCode: "00",
|
||
Msg: "请求成功",
|
||
Code: 0,
|
||
PayUrl: scanData.PayUrl,
|
||
}
|
||
if scanSuccessData.StatusCode == "00" {
|
||
scanSuccessData.Code = 0
|
||
} else {
|
||
scanSuccessData.Code = -1
|
||
}
|
||
return scanSuccessData
|
||
}
|
||
|
||
func CreateOrderInfoAndOrderProfitInfo(ctx context.Context, createdOrder request.CreatedOrder, info merchant.MerchantInfo) (orderInfo order.OrderInfo, err error) {
|
||
roadInfo := road.GetRoadInfoByProductCode(ctx, createdOrder.ProductCode)
|
||
|
||
if roadInfo.Id == 0 {
|
||
err = errors.New("未配置支付方式")
|
||
return
|
||
}
|
||
if msg, ok := RoadIsValid(ctx, roadInfo, &response.PayBaseResp{
|
||
OrderAmount: createdOrder.OrderPrice,
|
||
}); !ok {
|
||
err = errors.New(msg)
|
||
return
|
||
}
|
||
|
||
merchantDeploy := merchant_deploy.GetMerchantDeployByUidAndRoadUid(
|
||
ctx,
|
||
info.MerchantUid,
|
||
roadInfo.RoadUid,
|
||
)
|
||
if merchantDeploy.Id == 0 {
|
||
err = errors.New("当前用户未配置支付方式")
|
||
return
|
||
}
|
||
|
||
roadPoolInfo := road.GetRoadPoolByRoadPoolCode(ctx, merchantDeploy.RollRoadCode)
|
||
if roadPoolInfo.Id == 0 {
|
||
err = errors.New("当前用户未配置支付方式")
|
||
return
|
||
}
|
||
|
||
orderInfo, err = CreateOrderInfo(createdOrder, info, roadPoolInfo, roadInfo)
|
||
if err != nil {
|
||
err = errors.Join(err, errors.New("创建订单失败"))
|
||
return
|
||
}
|
||
|
||
orderProfitInfo, err := CreateOrderProfitInfo(ctx, createdOrder, info, *merchantDeploy, orderInfo, roadInfo)
|
||
if err != nil {
|
||
err = errors.Join(err, errors.New("创建订单失败"))
|
||
return
|
||
}
|
||
|
||
if !order.InsertOrderAndOrderProfit(ctx, orderInfo, orderProfitInfo) {
|
||
err = errors.Join(err, errors.New("创建订单失败"))
|
||
return
|
||
}
|
||
|
||
return
|
||
}
|
||
|
||
func GerMerchantDeployInfoByUidAndProductCode(ctx context.Context, uid, productCode string) merchant_deploy.MerchantDeployInfo {
|
||
roadInfo := road.GetRoadInfoByProductCode(ctx, productCode)
|
||
merchantDeploy := merchant_deploy.GetMerchantDeployByUidAndRoadUid(ctx, uid, roadInfo.RoadUid)
|
||
return *merchantDeploy
|
||
}
|