修改网关代码的结构,调整了逻辑,删除了许多无用的代码

This commit is contained in:
kongyuebin
2021-09-16 14:57:23 +08:00
parent 706a95317d
commit 2a98cbd9ac
58 changed files with 6137 additions and 744 deletions

View File

@@ -0,0 +1,193 @@
package service
import (
"context"
"gateway/conf"
"gateway/models/merchant"
"gateway/models/order"
"gateway/response"
"github.com/beego/beego/v2/client/orm"
"github.com/beego/beego/v2/core/logs"
"strconv"
"strings"
)
//获取商户信息
func GetMerchantInfo(params map[string]string) *response.PayBaseResp {
c := new(response.PayBaseResp)
c.Params = make(map[string]string)
c.Params = params
merchantInfo := merchant.GetMerchantByPaykey(params["payKey"])
if merchantInfo.MerchantUid == "" || len(merchantInfo.MerchantUid) == 0 {
c.Code = -1
c.Msg = "商户不存在或者paykey有误请联系管理员"
} else if merchantInfo.Status != conf.ACTIVE {
c.Code = -1
c.Msg = "商户状态已经被冻结或者被删除,请联系管理员!"
} else {
c.MerchantInfo = merchantInfo
}
return c
}
func JudgeParams(c *response.PayBaseResp) *response.PayBaseResp {
//c.ReturnUrlIsValid()
c = OrderIsValid(c)
c = NotifyUrlIsValid(c)
c = OsTypeIsValid(c)
c = PayWayCodeIsValid(c)
c = ProductIsValid(c)
c = OrderPeriodIsValid(c)
//c = IpIsWhite()
c = OrderPriceIsValid(c)
return c
}
/*
* 插入支付订单记录和订单利润记录,保证一致性
*/
func InsertOrderAndOrderProfit(orderInfo order.OrderInfo, orderProfitInfo order.OrderProfitInfo) bool {
o := orm.NewOrm()
if err := o.DoTx(func(ctx context.Context, txOrm orm.TxOrmer) error {
if _, err := txOrm.Insert(&orderInfo); err != nil {
logs.Error("insert orderInfo fail: ", err)
return err
}
if _, err := txOrm.Insert(&orderProfitInfo); err != nil {
logs.Error("insert orderProfit fail: ", err)
return err
}
return nil
}); err != nil {
return false
}
return true
}
/**
** 判断跳转地址是否符合规则
*/
func ReturnUrlIsValid(c *response.PayBaseResp) *response.PayBaseResp {
if c.Params["returnUrl"] == "" || len(c.Params["returnUrl"]) == 0 {
c.Code = -1
c.Msg = "支付成功后跳转地址不能为空"
}
return c
}
/**
** 判断回调地址是否符合规则
*/
func NotifyUrlIsValid(c *response.PayBaseResp) *response.PayBaseResp {
if c.Params["notifyUrl"] == "" || len(c.Params["notifyUrl"]) == 0 {
c.Code = -1
c.Msg = "支付成功订单回调地址不能空位"
}
return c
}
/**
** 判断设备类型是否符合规则
*/
func OsTypeIsValid(c *response.PayBaseResp) *response.PayBaseResp {
if c.Params["osType"] == "" || len(c.Params["osType"]) == 0 {
c.Code = -1
c.Msg = "支付设备系统类型不能为空,默认填写\"1\"即可"
}
return c
}
/**
** 判断支付类型字段是否符合规则
*/
func PayWayCodeIsValid(c *response.PayBaseResp) *response.PayBaseResp {
if c.Params["payWayCode"] == "" || len(c.Params["payWayCode"]) == 0 {
c.Code = -1
c.Msg = "支付类型字段不能为空"
return c
}
if !strings.Contains(c.Params["payWayCode"], "SCAN") {
c.Code = -1
c.Msg = "扫码支付不支持这种支付类型"
} else {
scanPayWayCodes := conf.GetScanPayWayCodes()
for _, v := range scanPayWayCodes {
if c.Params["payWayCode"] == v {
c.PayWayCode = strings.Replace(c.Params["payWayCode"], "-", "_", -1)
return c
}
}
c.Code = -1
c.Msg = "不存在这种支付类型,请仔细阅读对接文档"
}
return c
}
func ProductIsValid(c *response.PayBaseResp) *response.PayBaseResp {
if c.Params["productName"] == "" || len(c.Params["productName"]) == 0 {
c.Code = -1
c.Msg = "商品描述信息字段不能为空"
}
return c
}
func OrderPeriodIsValid(c *response.PayBaseResp) *response.PayBaseResp {
if c.Params["orderPeriod"] == "" || len(c.Params["orderPeriod"]) == 0 {
c.Code = -1
c.Msg = "订单过期时间不能为空,默认填写\"1\"即可"
}
return c
}
//判断订单金额
func OrderPriceIsValid(c *response.PayBaseResp) *response.PayBaseResp {
if c.Params["orderPrice"] == "" || len(c.Params["orderPrice"]) == 0 {
c.Code = -1
c.Msg = "订单金额不能为空"
return c
}
a, err := strconv.ParseFloat(c.Params["orderPrice"], 64)
if err != nil {
logs.Error("order price is invalid ", c.Params["orderPrice"])
c.Code = -1
c.Msg = "订单金额非法"
}
c.OrderAmount = a
return c
}
//判断金额订单号是否为空或者有重复
func OrderIsValid(c *response.PayBaseResp) *response.PayBaseResp {
if c.Params["orderNo"] == "" || len(c.Params["orderNo"]) == 0 {
c.Code = -1
c.Msg = "商户订单号不能为空"
return c
}
if order.OrderNoIsEixst(c.Params["orderNo"]) {
c.Code = -1
c.Msg = "商户订单号重复"
}
return c
}
//判断ip是否在白名单中
func IpIsWhite() bool {
//TODO
return true
}

View File

@@ -0,0 +1,249 @@
/***************************************************
** @Desc : 处理网关模块的一些需要操作数据库的功能
** @Time : 2019/12/7 16:40
** @Author : yuebin
** @File : gateway_solve
** @Last Modified by : yuebin
** @Last Modified time: 2019/12/7 16:40
** @Software: GoLand
****************************************************/
package service
import (
"fmt"
"gateway/conf"
"gateway/models/merchant"
"gateway/models/order"
"gateway/models/road"
"gateway/response"
"gateway/supplier"
"gateway/utils"
"github.com/beego/beego/v2/core/logs"
"github.com/rs/xid"
"strings"
"time"
)
//选择通道
func ChooseRoad(c *response.PayBaseResp) *response.PayBaseResp {
payWayCode := c.Params["payWayCode"]
merchantUid := c.MerchantInfo.MerchantUid
//通道配置信息
deployInfo := merchant.GetMerchantDeployByUidAndPayType(merchantUid, payWayCode)
if deployInfo.MerchantUid == "" {
c.Code = -1
c.Msg = "该商户没有配置通道信息"
return c
}
singleRoad := road.GetRoadInfoByRoadUid(deployInfo.SingleRoadUid)
c.RoadPoolInfo = road.GetRoadPoolByRoadPoolCode(deployInfo.RollRoadCode)
if RoadIsValid(singleRoad, c) {
c.RoadInfo = singleRoad
c.PlatformRate = deployInfo.SingleRoadPlatformRate
c.AgentRate = deployInfo.SingleRoadAgentRate
return c
}
//如果单通道没有有效的,那么寻找通道池里面的通道
if c.RoadPoolInfo.RoadPoolCode == "" {
c.Code = -1
c.Msg = "该商户没有配置通道"
return c
}
roadUids := strings.Split(c.RoadPoolInfo.RoadUidPool, "||")
roadInfos := road.GetRoadInfosByRoadUids(roadUids)
for _, roadInfo := range roadInfos {
if RoadIsValid(roadInfo, c) {
c.RoadInfo = roadInfo
c.PlatformRate = deployInfo.RollRoadPlatformRate
c.AgentRate = deployInfo.RollRoadAgentRate
return c
}
}
if c.RoadInfo.RoadUid == "" {
c.Code = -1
c.Msg = "该商户没有配置通道或者通道不可用"
}
return c
}
//判断通道是否是合法的
func RoadIsValid(roadInfo road.RoadInfo, c *response.PayBaseResp) 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
}
minAmount := roadInfo.SingleMinLimit
maxAmount := roadInfo.SingleMaxLimit
if minAmount > c.OrderAmount || maxAmount < c.OrderAmount {
logs.Error(FORMAT + "订单金额超限制")
return false
}
todayLimit := roadInfo.TodayLimit
totalLimit := roadInfo.TotalLimit
todayIncome := roadInfo.TodayIncome
totalIncome := roadInfo.TotalIncome
if (todayIncome + c.OrderAmount) > todayLimit {
logs.Error(FORMAT + "达到了每天金额上限")
return false
}
if (totalIncome + c.OrderAmount) > totalLimit {
logs.Error(FORMAT + "达到了总量限制")
return false
}
//如果通道被选中,那么总请求数+1
roadInfo.RequestAll = roadInfo.RequestAll + 1
roadInfo.UpdateTime = utils.GetBasicDateTime()
road.UpdateRoadInfo(roadInfo)
return true
}
//获取基本订单记录
func GenerateOrderInfo(c *response.PayBaseResp) order.OrderInfo {
//6666是自己系统订单号
bankOrderNo := "6666" + xid.New().String()
//获取支付类型的名称,例如支付宝扫码等
payTypeName := conf.GetNameByPayWayCode(c.Params["payWayCode"])
orderInfo := order.OrderInfo{
MerchantUid: c.MerchantInfo.MerchantUid,
MerchantName: c.MerchantInfo.MerchantName,
MerchantOrderId: c.Params["orderNo"],
BankOrderId: bankOrderNo,
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: c.Params["productName"],
Freeze: conf.NO,
Refund: conf.NO,
Unfreeze: conf.NO,
PayProductCode: c.RoadInfo.ProductUid,
PayTypeCode: c.PayWayCode,
PayTypeName: payTypeName,
OsType: c.Params["osType"],
Status: conf.WAIT,
NotifyUrl: c.Params["notifyUrl"],
ReturnUrl: c.Params["returnUrl"],
OrderPeriod: c.Params["orderPeriod"],
UpdateTime: utils.GetBasicDateTime(),
CreateTime: utils.GetBasicDateTime(),
}
if c.MerchantInfo.BelongAgentUid != "" || c.AgentRate > conf.ZERO {
orderInfo.AgentUid = c.MerchantInfo.BelongAgentUid
orderInfo.AgentName = c.MerchantInfo.BelongAgentName
}
return orderInfo
}
//计算收益,平台利润,代理利润
func GenerateOrderProfit(orderInfo order.OrderInfo, c *response.PayBaseResp) order.OrderProfitInfo {
//因为所有的手续费率都是百分率所以需要除以100
payTypeName := conf.GetNameByPayWayCode(c.PayWayCode)
supplierProfit := c.OrderAmount / 100 * c.RoadInfo.BasicFee
platformProfit := c.OrderAmount / 100 * c.PlatformRate
agentProfit := c.OrderAmount / 100 * c.AgentRate
//如果用户没有设置代理那么代理利润为0.000
if c.MerchantInfo.BelongAgentUid == "" || len(c.MerchantInfo.BelongAgentUid) == 0 {
agentProfit = conf.ZERO
}
allProfit := supplierProfit + platformProfit + agentProfit
if allProfit >= c.OrderAmount {
logs.Error("手续费已经超过订单金额bankOrderId = %s", orderInfo.BankOrderId)
c.Msg = "手续费已经超过了订单金额"
c.Code = -1
}
orderProfit := order.OrderProfitInfo{
PayProductCode: c.RoadInfo.ProductUid,
PayProductName: c.RoadInfo.ProductName,
PayTypeCode: c.PayWayCode,
PayTypeName: payTypeName,
Status: conf.WAIT,
MerchantOrderId: c.Params["orderNo"],
BankOrderId: orderInfo.BankOrderId,
OrderAmount: c.OrderAmount,
FactAmount: c.OrderAmount,
ShowAmount: c.OrderAmount,
AllProfit: allProfit,
UserInAmount: c.OrderAmount - allProfit,
SupplierProfit: supplierProfit,
PlatformProfit: platformProfit,
AgentProfit: agentProfit,
UpdateTime: utils.GetBasicDateTime(),
CreateTime: utils.GetBasicDateTime(),
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 > conf.ZERO {
orderProfit.AgentUid = c.MerchantInfo.BelongAgentUid
orderProfit.AgentName = c.MerchantInfo.BelongAgentName
}
return orderProfit
}
/*
* 生成订单一系列的记录
*/
func GenerateRecord(c *response.PayBaseResp) (order.OrderInfo, order.OrderProfitInfo) {
//生成订单记录,订单利润利润
orderInfo := GenerateOrderInfo(c)
orderProfit := GenerateOrderProfit(orderInfo, c)
if c.Code == -1 {
return orderInfo, orderProfit
}
if !InsertOrderAndOrderProfit(orderInfo, orderProfit) {
c.Code = -1
return orderInfo, orderProfit
}
logs.Info("插入支付订单记录和支付利润记录成功")
return orderInfo, orderProfit
}
func GenerateSuccessData(scanData supplier.ScanData, c *response.PayBaseResp) *response.ScanSuccessData {
params := make(map[string]string)
params["orderNo"] = scanData.OrderNo
params["orderPrice"] = scanData.OrderPrice
params["payKey"] = c.MerchantInfo.MerchantKey
params["payURL"] = scanData.PayUrl
params["statusCode"] = "00"
keys := utils.SortMap(params)
sign := utils.GetMD5Sign(params, keys, c.MerchantInfo.MerchantSecret)
scanSuccessData := new(response.ScanSuccessData)
scanSuccessData.StatusCode = "00"
scanSuccessData.PayKey = c.MerchantInfo.MerchantKey
scanSuccessData.OrderNo = scanData.OrderNo
scanSuccessData.OrderPrice = scanData.OrderPrice
scanSuccessData.PayUrl = scanData.PayUrl
scanSuccessData.PayKey = c.MerchantInfo.MerchantKey
scanSuccessData.Msg = "请求成功"
scanSuccessData.Sign = sign
return scanSuccessData
}

View File

@@ -0,0 +1,503 @@
package service
import (
"context"
"errors"
"fmt"
"gateway/conf"
"gateway/message"
"gateway/models/accounts"
"gateway/models/merchant"
"gateway/models/notify"
"gateway/models/order"
"gateway/models/road"
"gateway/utils"
"github.com/beego/beego/v2/client/orm"
"github.com/beego/beego/v2/core/logs"
"net/url"
"strconv"
)
//处理支付成功的加款等各项操作
func SolvePaySuccess(bankOrderId string, factAmount float64, trxNo string) bool {
o := orm.NewOrm()
err := o.DoTx(func(ctx context.Context, txOrm orm.TxOrmer) error {
var orderInfo order.OrderInfo
if err := txOrm.Raw("select * from order_info where bank_order_id = ? for update", bankOrderId).QueryRow(&orderInfo); err != nil || orderInfo.BankOrderId == "" {
logs.Error("不存在该订单或者select for update出错")
return err
}
if orderInfo.Status != "wait" {
logs.Error("该订单已经处理,订单号=", bankOrderId)
return errors.New(fmt.Sprintf("该订单已经处理,订单号= %s", bankOrderId))
}
if factAmount <= conf.ZERO {
factAmount = orderInfo.OrderAmount
}
var orderProfitInfo order.OrderProfitInfo
if err := txOrm.Raw("select * from order_profit_info where bank_order_id = ? for update", bankOrderId).QueryRow(&orderProfitInfo); err != nil || orderProfitInfo.BankOrderId == "" {
logs.Error("select order_profit_info for update fail: ", err)
return err
}
if orderProfitInfo.BankOrderId == "" {
logs.Error("solve pay success, get orderProfit fail, bankOrderId = ", bankOrderId)
return errors.New(fmt.Sprintf("solve pay success, get orderProfit fail, bankOrderId = %s", bankOrderId))
}
orderInfo.Status = conf.SUCCESS
orderInfo.BankTransId = trxNo
orderInfo.UpdateTime = utils.GetBasicDateTime()
if _, err := txOrm.Update(&orderInfo); err != nil || orderInfo.BankOrderId == "" {
logs.Error(fmt.Sprintf("solve pay success, update order info fail: %s, bankOrderId = %s", err, bankOrderId))
return err
}
orderSettleInfo := order.OrderSettleInfo{
PayTypeCode: orderInfo.PayTypeCode,
PayProductCode: orderInfo.PayProductCode,
RoadUid: orderInfo.RoadUid,
PayProductName: orderInfo.PayProductName,
PayTypeName: orderInfo.PayTypeName,
MerchantUid: orderInfo.MerchantUid,
MerchantOrderId: orderInfo.MerchantOrderId,
MerchantName: orderInfo.MerchantName,
BankOrderId: bankOrderId,
SettleAmount: orderProfitInfo.UserInAmount,
IsAllowSettle: conf.YES,
IsCompleteSettle: conf.NO,
UpdateTime: utils.GetBasicDateTime(),
CreateTime: utils.GetBasicDateTime(),
}
if _, err := txOrm.Insert(&orderSettleInfo); err != nil {
logs.Error(fmt.Sprintf("solve pay successinsert order settle info fail: %s, bankOrderId = %s", err, bankOrderId))
return err
}
//做账户的加款操作,最重要的一部
var accountInfo accounts.AccountInfo
if err := txOrm.Raw("select * from account_info where account_uid = ? for update", orderInfo.MerchantUid).QueryRow(&accountInfo); err != nil || accountInfo.AccountUid == "" {
logs.Error(fmt.Sprintf("solve pay success, raw account info fail: %s, bankOrderId = %s", err, bankOrderId))
return err
}
if _, err := txOrm.QueryTable(accounts.ACCOUNT_INFO).Filter("account_uid", orderInfo.MerchantUid).
Update((orm.Params{"balance": accountInfo.Balance + orderProfitInfo.UserInAmount, "wait_amount": accountInfo.WaitAmount + orderProfitInfo.UserInAmount})); err != nil {
logs.Error(fmt.Sprintf("solve pay success, update account info fail: %s, bankOrderId = %s", err, bankOrderId))
return err
}
//添加一条动账记录
accountHistory := accounts.AccountHistoryInfo{
AccountUid: orderInfo.MerchantUid,
AccountName: orderInfo.MerchantName,
Type: conf.PLUS_AMOUNT,
Amount: orderProfitInfo.UserInAmount,
Balance: accountInfo.Balance + orderProfitInfo.UserInAmount,
UpdateTime: utils.GetBasicDateTime(),
CreateTime: utils.GetBasicDateTime(),
}
if _, err := txOrm.Insert(&accountHistory); err != nil {
logs.Error(fmt.Sprintf("solve pay successinsert account history fail%s, bankOrderId = %s", err, bankOrderId))
return err
}
//更新通道信息
roadInfo := road.GetRoadInfoByRoadUid(orderInfo.RoadUid)
roadInfo.UpdateTime = utils.GetBasicDateTime()
roadInfo.RequestSuccess += 1
roadInfo.TotalIncome += orderInfo.FactAmount
roadInfo.TodayIncome += orderInfo.FactAmount
roadInfo.TodayProfit += orderProfitInfo.PlatformProfit + orderProfitInfo.AgentProfit
roadInfo.TotalProfit += orderProfitInfo.PlatformProfit + orderProfitInfo.AgentProfit
roadInfo.UpdateTime = utils.GetBasicDateTime()
if _, err := txOrm.Update(&roadInfo); err != nil {
logs.Error(fmt.Sprintf("solve pay success, update road info fail: %s, bankOrderId = %s", err, bankOrderId))
return err
}
//更新订单利润表
orderProfitInfo.Status = conf.SUCCESS
orderProfitInfo.UpdateTime = utils.GetBasicDateTime()
if _, err := txOrm.Update(&orderProfitInfo); err != nil {
logs.Error(fmt.Sprintf("solve pay success, update order profit info fail: %s, bankOrderId = %s", err, bankOrderId))
return err
}
// 给下游发送回调通知
go CreateOrderNotifyInfo(orderInfo, conf.SUCCESS)
return nil
})
if err != nil {
logs.Error("SolvePaySuccess失败", err)
return false
}
logs.Info("SolvePaySuccess处理成功")
return true
}
//处理支付失败
func SolvePayFail(bankOrderId, transId string) bool {
o := orm.NewOrm()
err := o.DoTx(func(ctx context.Context, txOrm orm.TxOrmer) error {
var orderTmp order.OrderInfo
//bankOrderId := orderInfo.BankOrderId
if err := txOrm.Raw("select * from order_info where bank_order_id = ?", bankOrderId).QueryRow(&orderTmp); err != nil || orderTmp.BankOrderId == "" {
return err
}
if orderTmp.Status != "wait" {
return errors.New("订单已经处理,不要重复加款")
}
if _, err := txOrm.QueryTable(order.ORDER_INFO).Filter("bank_order_id", bankOrderId).Update(orm.Params{"status": conf.FAIL, "bank_trans_id": transId}); err != nil {
logs.Error("更改订单状态失败:", err)
return err
}
if _, err := txOrm.QueryTable(order.ORDER_PROFIT_INFO).Filter("bank_order_id", bankOrderId).Update(orm.Params{"status": conf.FAIL, "bank_trans_id": transId}); err != nil {
logs.Error("更改订单状态失败:", err)
return err
}
go CreateOrderNotifyInfo(orderTmp, conf.FAIL)
return nil
})
if err != nil {
logs.Error("SolvePayFail", err)
return false
}
logs.Info("SolvePayFail成功")
return true
}
//处理订单冻结
func SolveOrderFreeze(bankOrderId string) bool {
o := orm.NewOrm()
err := o.DoTx(func(ctx context.Context, txOrm orm.TxOrmer) error {
var orderInfo order.OrderInfo
if err := txOrm.Raw("select * from order_info where bank_order_id = ? for update", bankOrderId).QueryRow(&orderInfo); err != nil || orderInfo.BankOrderId == "" {
logs.Error("solve order freeze 不存在这样的订单记录bankOrderId = ", bankOrderId)
return err
}
if orderInfo.Status != conf.SUCCESS {
logs.Error("非成功订单不能进行冻结")
return errors.New("非成功订单不能进行冻结")
}
orderInfo.Freeze = conf.YES
orderInfo.FreezeTime = utils.GetBasicDateTime()
orderInfo.UpdateTime = utils.GetBasicDateTime()
if _, err := txOrm.Update(&orderInfo); err != nil {
logs.Error("solve order freeze fail: ", err)
return err
}
//账户的冻结金额里面加入相应的金额
orderProfitInfo := order.GetOrderProfitByBankOrderId(bankOrderId)
var accountInfo accounts.AccountInfo
if err := txOrm.Raw("select * from account_info where account_uid = ? for update", orderInfo.MerchantUid).QueryRow(&accountInfo); err != nil || accountInfo.AccountUid == "" {
logs.Error(fmt.Sprintf("solve pay fail select acount fail%s", err))
return err
}
accountInfo.UpdateTime = utils.GetBasicDateTime()
accountInfo.FreezeAmount = accountInfo.FreezeAmount + orderProfitInfo.UserInAmount
if _, err := txOrm.Update(&accountInfo); err != nil {
logs.Error("solve order freeze fail: ", err)
return err
}
//插入一条动账记录
accountHistoryInfo := accounts.AccountHistoryInfo{
AccountName: accountInfo.AccountName,
AccountUid: accountInfo.AccountUid,
Type: conf.FREEZE_AMOUNT,
Amount: orderProfitInfo.UserInAmount,
Balance: accountInfo.Balance,
UpdateTime: utils.GetBasicDateTime(),
CreateTime: utils.GetBasicDateTime(),
}
if _, err := txOrm.Insert(&accountHistoryInfo); err != nil {
logs.Error("solve order freeze fail: ", err)
return err
}
return nil
})
if err != nil {
logs.Error("SolveOrderFreeze", err)
return false
}
logs.Info("SolveOrderFreeze")
return true
}
//订单解冻
func SolveOrderUnfreeze(bankOrderId string) bool {
o := orm.NewOrm()
if err := o.DoTx(func(ctx context.Context, txOrm orm.TxOrmer) error {
orderInfo := new(order.OrderInfo)
if err := txOrm.Raw("select * from order_info where bank_order_id = ? for update", bankOrderId).QueryRow(orderInfo); err != nil || orderInfo.BankOrderId == "" {
logs.Error("solve order unfreeze 不存在这样的订单记录bankOrderId = ", bankOrderId)
return err
}
orderInfo.Freeze = ""
orderInfo.Unfreeze = conf.YES
orderInfo.UnfreezeTime = utils.GetBasicDateTime()
orderInfo.UpdateTime = utils.GetBasicDateTime()
if _, err := txOrm.Update(orderInfo); err != nil {
logs.Error("solve order unfreeze fail: ", err)
return err
}
orderProfitInfo := order.GetOrderProfitByBankOrderId(bankOrderId)
accountInfo := new(accounts.AccountInfo)
if err := txOrm.Raw("select * from account_info where account_uid = ? for update", orderInfo.MerchantUid).QueryRow(accountInfo); err != nil || accountInfo.AccountUid == "" {
logs.Error(fmt.Sprintf("unfreeze select account fail: %s", err))
return err
}
accountInfo.UpdateTime = utils.GetBasicDateTime()
accountInfo.FreezeAmount = accountInfo.FreezeAmount - orderProfitInfo.UserInAmount
if _, err := txOrm.Update(accountInfo); err != nil {
logs.Error("solve order unfreeze fail: ", err)
return err
}
accountHistoryInfo := accounts.AccountHistoryInfo{
AccountUid: accountInfo.AccountUid,
AccountName: accountInfo.AccountName,
Type: conf.UNFREEZE_AMOUNT,
Amount: orderProfitInfo.UserInAmount,
Balance: accountInfo.Balance,
UpdateTime: utils.GetBasicDateTime(),
CreateTime: utils.GetBasicDateTime(),
}
if _, err := txOrm.Insert(&accountHistoryInfo); err != nil {
return err
}
return nil
}); err != nil {
logs.Error("SolveOrderUnfreeze失败", err)
return false
}
return true
}
func SolveRefund(bankOrderId string) bool {
o := orm.NewOrm()
if err := o.DoTx(func(ctx context.Context, txOrm orm.TxOrmer) error {
orderInfo := new(order.OrderInfo)
if err := txOrm.Raw("select * from order_info where bank_order_id = ? for update", bankOrderId).QueryRow(orderInfo); err != nil || orderInfo.BankOrderId == "" {
logs.Error("solve refund 不存在这样的订单bankOrderId = " + bankOrderId)
return err
}
orderInfo.UpdateTime = utils.GetBasicDateTime()
orderInfo.Refund = conf.YES
orderInfo.RefundTime = utils.GetBasicDateTime()
orderProfitInfo := order.GetOrderProfitByBankOrderId(bankOrderId)
account := new(accounts.AccountInfo)
if err := txOrm.Raw("select * from account_info where account_uid = ? for update", orderInfo.MerchantUid).QueryRow(account); err != nil || account.AccountUid == "" {
return err
}
account.UpdateTime = utils.GetBasicDateTime()
account.SettleAmount = account.SettleAmount - orderProfitInfo.UserInAmount
account.Balance = account.Balance - orderProfitInfo.UserInAmount
if orderInfo.Freeze == conf.YES {
account.FreezeAmount = account.FreezeAmount - orderProfitInfo.UserInAmount
if account.FreezeAmount < 0 {
account.FreezeAmount = conf.ZERO
}
orderInfo.Freeze = ""
}
if _, err := txOrm.Update(orderInfo); err != nil {
logs.Error("solve order refund update order info fail: ", err)
return err
}
if _, err := txOrm.Update(account); err != nil {
logs.Error("solve order refund update account fail: ", err)
return err
}
accountHistoryInfo := accounts.AccountHistoryInfo{
AccountName: account.AccountName,
AccountUid: account.AccountUid,
Type: conf.REFUND,
Amount: orderProfitInfo.UserInAmount,
Balance: account.Balance,
UpdateTime: utils.GetBasicDateTime(),
CreateTime: utils.GetBasicDateTime(),
}
if _, err := txOrm.Insert(&accountHistoryInfo); err != nil {
logs.Error("solve order refund insert account history fail: ", err)
return err
}
return nil
}); err != nil {
logs.Error("SolveRefund 成功:", err)
return false
}
return true
}
func SolveOrderRoll(bankOrderId string) bool {
o := orm.NewOrm()
if err := o.DoTx(func(ctx context.Context, txOrm orm.TxOrmer) error {
orderInfo := new(order.OrderInfo)
if err := txOrm.Raw("select * from order_info where bank_order_id = ? for update", bankOrderId).QueryRow(orderInfo); err != nil {
logs.Error("solve order roll fail ", err)
return err
}
if orderInfo.Status != conf.SUCCESS {
logs.Error("solve order roll 订单不存在或者订单状态不是success, bankOrderId=", bankOrderId)
return errors.New("solve order roll failed")
}
orderInfo.UpdateTime = utils.GetBasicDateTime()
orderProfitInfo := order.GetOrderProfitByBankOrderId(bankOrderId)
account := new(accounts.AccountInfo)
if err := txOrm.Raw("select * from account_info where account_uid = ? for update", orderInfo.MerchantUid).QueryRow(account); err != nil || account.AccountUid == "" {
return err
}
account.UpdateTime = utils.GetBasicDateTime()
if orderInfo.Refund == conf.YES {
account.Balance = account.Balance + orderProfitInfo.UserInAmount
account.SettleAmount = account.SettleAmount + orderProfitInfo.UserInAmount
orderInfo.Refund = conf.NO
}
if _, err := txOrm.Update(orderInfo); err != nil {
logs.Error("solve order roll fail update order info fail: ", err)
return err
}
if _, err := txOrm.Update(account); err != nil {
logs.Error("solve order roll update account fail: ", err)
return err
}
accountHistoryInfo := accounts.AccountHistoryInfo{
AccountUid: account.AccountUid,
AccountName: account.AccountName,
Type: conf.PLUS_AMOUNT,
Amount: orderProfitInfo.UserInAmount,
Balance: account.Balance,
UpdateTime: utils.GetBasicDateTime(),
CreateTime: utils.GetBasicDateTime(),
}
if _, err := txOrm.Insert(&accountHistoryInfo); err != nil {
logs.Error("solve order roll insert account history fail: ", err)
return err
}
return nil
}); err != nil {
logs.Error("SolveOrderRoll处理失败", err)
return false
}
return true
}
//比较订单金额和实际支付金额的大小
func CompareOrderAndFactAmount(factAmount float64, orderInfo order.OrderInfo) int {
orderAmount := orderInfo.OrderAmount
//将金额放大1000倍
oa := int64(orderAmount * 1000)
fa := int64(factAmount * 1000)
if oa > fa {
//如果实际金额大返回1
return 1
} else if oa == fa {
return 0
} else {
return 2
}
}
//支付完成后,处理给商户的回调信息
func CreateOrderNotifyInfo(orderInfo order.OrderInfo, tradeStatus string) {
notifyInfo := new(notify.NotifyInfo)
notifyInfo.Type = "order"
notifyInfo.BankOrderId = orderInfo.BankOrderId
notifyInfo.MerchantOrderId = orderInfo.MerchantOrderId
notifyInfo.Status = "wait"
notifyInfo.Times = 0
notifyInfo.UpdateTime = utils.GetBasicDateTime()
notifyInfo.CreateTime = utils.GetBasicDateTime()
merchantInfo := merchant.GetMerchantByUid(orderInfo.MerchantUid)
params := make(map[string]string)
params["orderNo"] = orderInfo.MerchantOrderId
params["orderPrice"] = strconv.FormatFloat(orderInfo.OrderAmount, 'f', 2, 64)
params["factPrice"] = strconv.FormatFloat(orderInfo.FactAmount, 'f', 2, 64)
params["orderTime"] = utils.GetDateTimeNot()
if orderInfo.BankTransId != "" {
params["trxNo"] = orderInfo.BankTransId
} else {
params["trxNo"] = orderInfo.BankOrderId
}
params["statusCode"] = "00"
params["tradeStatus"] = tradeStatus
params["payKey"] = merchantInfo.MerchantKey
params["sign"] = utils.GetMD5Sign(params, utils.SortMap(params), merchantInfo.MerchantSecret)
u := url.Values{}
for k, v := range params {
u.Add(k, v)
}
notifyInfo.Url = orderInfo.NotifyUrl + "?" + u.Encode()
if notify.InsertNotifyInfo(*notifyInfo) {
logs.Info(fmt.Sprintf("订单bankOrderId=%s已经将回调地址插入数据库", orderInfo.BankOrderId))
} else {
logs.Error(fmt.Sprintf("订单bankOrderId=%s插入回调数据库失败", orderInfo.BankOrderId))
}
//将订单发送到消息队列,给下面的商户进行回调
go message.SendMessage(conf.MqOrderNotify, orderInfo.BankOrderId)
}

View File

@@ -0,0 +1,234 @@
/***************************************************
** @Desc : 订单结算,将订单上面的钱加入到账户余额中
** @Time : 2019/11/22 11:34
** @Author : yuebin
** @File : order_settle
** @Last Modified by : yuebin
** @Last Modified time: 2019/11/22 11:34
** @Software: GoLand
****************************************************/
package service
import (
"context"
"errors"
"fmt"
"gateway/conf"
"gateway/models/accounts"
"gateway/models/merchant"
"gateway/models/order"
"gateway/utils"
"github.com/beego/beego/v2/client/orm"
"github.com/beego/beego/v2/core/logs"
"time"
)
const (
Interval = 2 //隔多少分钟进行结算
Minutes = 1 //每隔15分钟进行扫码看有没有隔天押款金额
)
/**
* 订单结算,将那些支付成功的订单金额加入到商户账户的结算金额中
*/
func OrderSettle() {
params := make(map[string]string)
params["is_allow_settle"] = conf.YES
params["is_complete_settle"] = conf.NO
orderSettleList := order.GetOrderSettleListByParams(params)
for _, orderSettle := range orderSettleList {
orderProfitInfo := order.GetOrderProfitByBankOrderId(orderSettle.BankOrderId)
if !settle(orderSettle, orderProfitInfo) {
logs.Error(fmt.Sprintf("结算订单bankOrderId = #{orderSettle.BankOrderId} 执行失败"))
} else {
logs.Info(fmt.Sprintf("结算订单bankOrderId= #{orderSettle.BankOrderId},执行成功"))
}
}
}
func settle(orderSettle order.OrderSettleInfo, orderProfit order.OrderProfitInfo) bool {
o := orm.NewOrm()
if err := o.DoTx(func(ctx context.Context, txOrm orm.TxOrmer) error {
tmpSettle := new(order.OrderSettleInfo)
if err := txOrm.Raw("select * from order_settle_info where bank_order_id=? for update", orderSettle.BankOrderId).QueryRow(tmpSettle); err != nil || tmpSettle.BankOrderId == "" {
logs.Error("获取tmpSettle失败bankOrderId=%s", orderSettle.BankOrderId)
return err
}
tmpSettle.UpdateTime = utils.GetBasicDateTime()
tmpSettle.IsCompleteSettle = conf.YES
if _, err := txOrm.Update(tmpSettle); err != nil {
logs.Error("更新tmpSettle失败错误", err)
return err
}
accountInfo := new(accounts.AccountInfo)
if err := txOrm.Raw("select * from account_info where account_uid=? for update", orderSettle.MerchantUid).QueryRow(accountInfo); err != nil || accountInfo.UpdateTime == "" {
logs.Error("结算select account info失败错误信息", err)
return err
}
accountInfo.UpdateTime = utils.GetBasicDateTime()
// 商户有押款操作
loadAmount := 0.0
merchantDeployInfo := merchant.GetMerchantDeployByUidAndPayType(accountInfo.AccountUid, orderSettle.PayTypeCode)
if merchantDeployInfo.IsLoan == conf.YES {
loadAmount = merchantDeployInfo.LoanRate * 0.01 * orderProfit.FactAmount
date := utils.GetDate()
params := make(map[string]string)
params["merchant_uid"] = tmpSettle.MerchantUid
params["road_uid"] = tmpSettle.RoadUid
params["load_date"] = date
if !merchant.IsExistMerchantLoadByParams(params) {
tmp := merchant.MerchantLoadInfo{Status: conf.NO, MerchantUid: orderSettle.MerchantUid, RoadUid: orderSettle.RoadUid,
LoadDate: utils.GetDateAfterDays(merchantDeployInfo.LoanDays), LoadAmount: loadAmount,
UpdateTime: utils.GetBasicDateTime(), CreateTime: utils.GetBasicDateTime()}
if _, err := txOrm.Insert(&tmp); err != nil {
logs.Error("結算插入merchantLoad失敗失败信息", err)
return err
} else {
logs.Info("结算插入新的merchantLoad信息成功")
}
} else {
merchantLoad := new(merchant.MerchantLoadInfo)
if err := txOrm.Raw("select * from merchant_load_info where merchant_uid=? and road_uid=? and load_date=? for update").
QueryRow(merchantLoad); err != nil || merchantLoad.UpdateTime == "" {
logs.Error(fmt.Sprintf("结算过程select merchant load info失败错误信息#{err}"))
return err
} else {
merchantLoad.UpdateTime = utils.GetBasicDateTime()
merchantLoad.LoadAmount += loadAmount
if _, err := txOrm.Update(merchantLoad); err != nil {
logs.Error(fmt.Sprintf("结算过程update merchant load info失败失败信息#{err}"))
return err
}
}
}
} else {
logs.Info(fmt.Sprintf("结算过程中,该商户不需要押款,全款结算"))
}
if accountInfo.WaitAmount < orderProfit.UserInAmount {
logs.Error("系统出现严重故障,账户的带结算金额小于订单结算金额")
return errors.New("系统出现严重故障,账户的带结算金额小于订单结算金额, 账户 = " + accountInfo.AccountName + "订单id = " + orderProfit.BankOrderId)
}
needAmount := orderProfit.UserInAmount - loadAmount
accountInfo.SettleAmount = accountInfo.SettleAmount + needAmount
accountInfo.WaitAmount = accountInfo.WaitAmount - orderProfit.UserInAmount
accountInfo.LoanAmount = accountInfo.LoanAmount + loadAmount
if _, err := txOrm.Update(accountInfo); err != nil {
logs.Error("结算update account 失败,错误信息:", err)
return err
}
return nil
}); err != nil {
return false
}
return true
}
/*
* 商户的押款释放处理,根据商户的押款时间进行处理
*/
func MerchantLoadSolve() {
hour := time.Now().Hour()
merchantDeployList := merchant.GetMerchantDeployByHour(hour)
for _, merchantDeploy := range merchantDeployList {
logs.Info(fmt.Sprintf("开始执行商户uid= #{merchantDeploy.MerchantUid},进行解款操作"))
loadDate := utils.GetDateBeforeDays(merchantDeploy.LoanDays)
params := make(map[string]string)
params["status"] = conf.NO
params["merchant_uid"] = merchantDeploy.MerchantUid
params["load_date"] = loadDate
merchantLoadList := merchant.GetMerchantLoadInfoByMap(params)
for _, merchantLoad := range merchantLoadList {
if MerchantAbleAmount(merchantLoad) {
logs.Info(fmt.Sprintf("商户uid= %s押款金额=%f押款通道= %s, 解款成功", merchantLoad.MerchantUid, merchantLoad.LoadAmount, merchantLoad.RoadUid))
} else {
logs.Error(fmt.Sprintf("商户uid=%s押款金额=%f押款通道=%s, 解款失败", merchantLoad.MerchantUid, merchantLoad.LoadAmount, merchantLoad.RoadUid))
}
}
}
}
/*
* 对应的商户的账户可用金额进行调整操作
*/
func MerchantAbleAmount(merchantLoad merchant.MerchantLoadInfo) bool {
o := orm.NewOrm()
if err := o.DoTx(func(ctx context.Context, txOrm orm.TxOrmer) error {
tmpLoad := new(merchant.MerchantLoadInfo)
if err := txOrm.Raw("select * from merchant_load_info where merchant_uid=? and road_uid=? and load_date=? for update",
merchantLoad.MerchantUid, merchantLoad.RoadUid, merchantLoad.LoadDate).QueryRow(tmpLoad); err != nil || tmpLoad.MerchantUid == "" {
logs.Error(fmt.Sprintf("解款操作获取商户押款信息失败fail %s", err))
return err
}
if tmpLoad.Status != conf.NO {
logs.Error(fmt.Sprintf("押款信息merchantuid=%s通道uid=%s 押款日期=%s,已经解款过,不需要再进行处理了", tmpLoad.MerchantUid, tmpLoad.RoadUid, tmpLoad.LoadDate))
return errors.New("已经解款过,不需要再进行处理了")
}
tmpLoad.UpdateTime = utils.GetBasicDateTime()
tmpLoad.Status = conf.YES
if _, err := txOrm.Update(tmpLoad); err != nil {
logs.Error(fmt.Sprintf("解款操作更新merchant load info 失败:%s", err))
return err
}
accountInfo := new(accounts.AccountInfo)
if err := txOrm.Raw("select * from account_info where account_uid = ? for update", merchantLoad.MerchantUid).QueryRow(accountInfo); err != nil || accountInfo.AccountUid == "" {
logs.Error("结款操作获取账户信息失败:", err)
return err
}
accountInfo.UpdateTime = utils.GetBasicDateTime()
if accountInfo.LoanAmount >= tmpLoad.LoadAmount {
accountInfo.LoanAmount = accountInfo.LoanAmount - tmpLoad.LoadAmount
accountInfo.SettleAmount = accountInfo.SettleAmount + tmpLoad.LoadAmount
} else {
accountInfo.LoanAmount = conf.ZERO
}
if _, err := txOrm.Update(accountInfo); err != nil {
logs.Error(fmt.Sprintf("解款操作更新account info 失败:%s账户uid=%s", err, accountInfo.AccountUid))
return err
}
return nil
}); err != nil {
return false
}
return true
}
func OrderSettleInit() {
//每隔5分钟巡查有没有可以进行结算的订单
go func() {
settleTimer := time.NewTimer(time.Duration(Interval) * time.Minute)
oneMinuteTimer := time.NewTimer(time.Duration(Minutes) * time.Minute)
for {
select {
case <-settleTimer.C:
settleTimer = time.NewTimer(time.Duration(Interval) * time.Minute)
logs.Info("开始对商户进行支付订单结算>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
OrderSettle()
case <-oneMinuteTimer.C:
oneMinuteTimer = time.NewTimer(time.Duration(Minutes) * time.Minute)
logs.Info("开始执行商户的解款操作>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
MerchantLoadSolve()
}
}
}()
}