All checks were successful
continuous-integration/drone/push Build is passing
- 调整Camel相关函数的链路追踪span名称,保持一致性 - 请求失败时若包含“不匹配”,错误信息追加“请按照正确金额重新提交” - 修改Careless相关逻辑,更新URL匹配规则 - 修正测试用例中的IP固定值和请求地址 - 优化FavorableClouds提交订单HTTP请求,统一使用resty客户端并添加代理传递 - 修复Jinke支付通知链路追踪span名称及事件描述 - 调整ScanController中SubmitPool协程的context传递,避免丢失父context
284 lines
9.1 KiB
Go
284 lines
9.1 KiB
Go
package third_party
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"gateway/internal/config"
|
|
"gateway/internal/otelTrace"
|
|
"gateway/internal/service"
|
|
"gateway/internal/service/supplier"
|
|
"gateway/internal/service/supplier/third_party/pool/card_sender"
|
|
|
|
"gateway/internal/models/merchant"
|
|
"gateway/internal/models/merchant_deploy"
|
|
"gateway/internal/models/order"
|
|
"gateway/internal/models/payfor"
|
|
"gateway/internal/models/road"
|
|
"gateway/internal/models/supply_model"
|
|
"strconv"
|
|
|
|
"github.com/beego/beego/v2/client/httplib"
|
|
"github.com/duke-git/lancet/v2/convertor"
|
|
"go.opentelemetry.io/otel/attribute"
|
|
"go.opentelemetry.io/otel/trace"
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/beego/beego/v2/server/web"
|
|
"github.com/widuu/gojson"
|
|
)
|
|
|
|
type CamelImpl struct {
|
|
web.Controller
|
|
}
|
|
|
|
// HasDependencyHTML 是否有单独的支付页面
|
|
func (c *CamelImpl) HasDependencyHTML() bool {
|
|
return false
|
|
}
|
|
|
|
func (c *CamelImpl) SendCard(ctx context.Context, jsonStr string, cardInfo supplier.RedeemCardInfo, attach string, merchantInfo merchant.MerchantInfo, roadInfo road.RoadInfo) (bool, string) {
|
|
returnIfAmountErr := gojson.Json(roadInfo.Params).Get("returnIfAmountErr").Tostring()
|
|
orderAmount, err := (&cardTypeQuery{
|
|
OrderNo: attach,
|
|
QueryType: gojson.Json(roadInfo.Params).Get("queryType").Tostring(),
|
|
CardNo: cardInfo.CardNo,
|
|
CardPwd: cardInfo.Data,
|
|
Balance: cardInfo.GetFaceTypeFloat(ctx),
|
|
}).GetBalance(ctx)
|
|
if returnIfAmountErr == "1" && err != nil {
|
|
return false, err.Error()
|
|
}
|
|
cardInfo.FaceType = strconv.FormatFloat(orderAmount, 'f', 2, 64)
|
|
merchantDeploy := merchant_deploy.GetMerchantDeployByUidAndRoadUid(ctx, merchantInfo.MerchantUid, roadInfo.RoadUid)
|
|
if merchantDeploy.MerchantUid == "" {
|
|
return false, "商户不存在"
|
|
}
|
|
if merchantDeploy.SubmitStrategy == merchant_deploy.SUBMIT_STRATEGY_POOL {
|
|
if err := orderPoolService.PushOrder(ctx, card_sender.SendCardTask{
|
|
CardInfo: cardInfo,
|
|
RoadUid: roadInfo.RoadUid,
|
|
LocalOrderID: attach,
|
|
SendCardTaskType: card_sender.SendCardTaskTypeEnumCamel,
|
|
NeedQuery: gojson.Json(roadInfo.Params).Get("needQuery").Tostring() == "1",
|
|
}); err != nil {
|
|
otelTrace.Logger.WithContext(ctx).Error("推送订单失败", zap.Error(err))
|
|
return false, err.Error()
|
|
}
|
|
return true, "订单已提交"
|
|
}
|
|
if err := orderPoolService.SubmitOrder(ctx, card_sender.SendCardTask{
|
|
CardInfo: cardInfo,
|
|
RoadUid: roadInfo.RoadUid,
|
|
LocalOrderID: attach,
|
|
SendCardTaskType: card_sender.SendCardTaskTypeEnumCamel,
|
|
NeedQuery: gojson.Json(roadInfo.Params).Get("needQuery").Tostring() == "1",
|
|
}); err != nil {
|
|
return false, err.Error()
|
|
}
|
|
return true, "订单已提交"
|
|
}
|
|
|
|
func (c *CamelImpl) Scan(ctx context.Context, orderInfo order.OrderInfo, roadInfo road.RoadInfo, merchantInfo merchant.MerchantInfo) supplier.ScanData {
|
|
ctx, span := otelTrace.Span(ctx, "CamelImpl", "CamelImpl.Scan", trace.WithAttributes(
|
|
attribute.String("bankOrderId", orderInfo.BankOrderId),
|
|
attribute.String("merchantUid", orderInfo.MerchantUid),
|
|
attribute.String("exValue", orderInfo.ExValue),
|
|
))
|
|
defer span.End()
|
|
cdata := supplier.RedeemCardInfo{}
|
|
err := json.Unmarshal([]byte(orderInfo.ExValue), &cdata)
|
|
if err != nil {
|
|
otelTrace.Logger.WithContext(ctx).Error("格式化数据失败", zap.String("ExValue", orderInfo.ExValue))
|
|
return supplier.ScanData{Status: "-1", Msg: "订单有误,请稍后再试"}
|
|
}
|
|
ok, str := c.SendCard(ctx, roadInfo.Params, cdata, orderInfo.BankOrderId, merchantInfo, roadInfo)
|
|
var scanData supplier.ScanData
|
|
if !ok {
|
|
scanData = supplier.ScanData{
|
|
Status: "-1",
|
|
Msg: "失败:" + str,
|
|
BankNo: orderInfo.MerchantOrderId,
|
|
OrderNo: orderInfo.BankOrderId,
|
|
ReturnData: str,
|
|
}
|
|
return scanData
|
|
}
|
|
scanData.Status = "00"
|
|
scanData.OrderNo = orderInfo.BankOrderId
|
|
scanData.BankNo = orderInfo.MerchantOrderId
|
|
scanData.OrderPrice = strconv.FormatFloat(orderInfo.OrderAmount, 'f', 2, 64)
|
|
scanData.ReturnData = str
|
|
return scanData
|
|
}
|
|
|
|
func (c *CamelImpl) PayNotify() {
|
|
ctx := c.Ctx.Request.Context()
|
|
ctx, span := otelTrace.Span(ctx, "CamelImpl", "CamelImpl.PayNotify")
|
|
defer span.End()
|
|
respData := struct {
|
|
MchId string `json:"mchId" form:"mchId"`
|
|
MchOrderNo string `json:"mchOrderNo" form:"mchOrderNo"`
|
|
ProductId string `json:"productId" form:"productId"`
|
|
OrderAmount string `json:"orderAmount" form:"orderAmount"`
|
|
PayOrderId string `json:"payOrderId" form:"payOrderId"`
|
|
PaySuccessTime string `json:"paySuccessTime" form:"paySuccessTime"`
|
|
Sign string `json:"sign" form:"sign"`
|
|
Extra string `json:"extra" form:"extra"`
|
|
}{}
|
|
err := c.Bind(&respData)
|
|
if err != nil {
|
|
otelTrace.Logger.WithContext(ctx).Error("回调数据解析失败", zap.Error(err))
|
|
c.Ctx.WriteString("FAIL")
|
|
return
|
|
}
|
|
otelTrace.Logger.WithContext(ctx).Info("回调通知", zap.Any("req", respData))
|
|
|
|
localId, err := orderPoolService.GetLocalIdByOrderId(ctx, respData.MchOrderNo)
|
|
var orderInfo order.OrderInfo
|
|
if err != nil {
|
|
orderInfo = order.GetOrderByPoolOrderId(ctx, respData.MchOrderNo)
|
|
if orderInfo.Id == 0 {
|
|
otelTrace.Logger.WithContext(ctx).Error("获取本地订单ID失败", zap.Error(err))
|
|
c.Ctx.WriteString("FAIL")
|
|
return
|
|
}
|
|
} else {
|
|
orderInfo = order.GetOrderByBankOrderId(ctx, localId)
|
|
}
|
|
|
|
if orderInfo.BankOrderId == "" || len(orderInfo.BankOrderId) == 0 {
|
|
otelTrace.Logger.WithContext(ctx).Error("回调的订单号不存在")
|
|
c.Ctx.WriteString("FAIL")
|
|
return
|
|
}
|
|
|
|
if orderInfo.Status != "wait" {
|
|
otelTrace.Logger.WithContext(ctx).Error("订单状态不正确", zap.String("status", orderInfo.Status),
|
|
zap.String("bankOrderId", orderInfo.BankOrderId),
|
|
)
|
|
c.Ctx.WriteString("订单已经回调")
|
|
return
|
|
}
|
|
|
|
roadInfo := road.GetRoadInfoByRoadUid(ctx, orderInfo.RoadUid)
|
|
if roadInfo.RoadUid == "" || len(roadInfo.RoadUid) == 0 {
|
|
otelTrace.Logger.WithContext(ctx).Error("支付通道已经关系或者删除,不进行回调")
|
|
c.Ctx.WriteString("FAIL")
|
|
return
|
|
}
|
|
inPrice, err := convertor.ToFloat(respData.OrderAmount)
|
|
if err != nil {
|
|
otelTrace.Logger.WithContext(ctx).Error("回调的金额格式化失败", zap.Error(err))
|
|
c.Ctx.WriteString("FAIL")
|
|
return
|
|
}
|
|
|
|
isOk := false
|
|
if inPrice/100 == orderInfo.OrderAmount {
|
|
isOk = service.SolvePaySuccess(ctx, orderInfo.BankOrderId, orderInfo.OrderAmount, orderInfo.MerchantUid, "支付成功")
|
|
} else {
|
|
SolvePaySuccessByAmountDifferent(ctx, orderInfo.BankOrderId, inPrice, orderInfo.BankOrderId, convertor.ToString(respData))
|
|
}
|
|
// TODO 订单支付成功
|
|
if isOk {
|
|
c.Ctx.WriteString("SUCCESS")
|
|
} else {
|
|
c.Ctx.WriteString("FAIL")
|
|
}
|
|
return
|
|
|
|
}
|
|
|
|
func (c *CamelImpl) PayQuery(orderInfo order.OrderInfo, roadInfo road.RoadInfo) bool {
|
|
return false
|
|
}
|
|
|
|
func (c *CamelImpl) PayQueryV2(orderInfo order.OrderInfo, roadInfo road.RoadInfo) supply_model.MsgModel {
|
|
return supply_model.RemoteDataErr
|
|
}
|
|
|
|
func (c *CamelImpl) PayFor(info payfor.PayforInfo) string {
|
|
return ""
|
|
}
|
|
|
|
func (c *CamelImpl) PayForQuery(payFor payfor.PayforInfo) (string, string) {
|
|
cfg := config.Config{}
|
|
url1, err := cfg.GetMFCardQueryUrl()
|
|
if err != nil {
|
|
return config.PAYFOR_FAIL, ""
|
|
}
|
|
ctx := context.Background()
|
|
params := map[string]string{}
|
|
params["order_id"] = payFor.BankOrderId
|
|
params["app_key"] = gojson.Json("").Get("appKey").Tostring()
|
|
|
|
req := httplib.Post(url1)
|
|
marshal, err := json.Marshal(params)
|
|
if err != nil {
|
|
otelTrace.Logger.WithContext(ctx).Error("Map转化为byte数组失败,异常。", zap.Error(err))
|
|
// fmt.Printf("Map转化为byte数组失败,异常:%s\n",zap.Error(err))
|
|
return config.PAYFOR_FAIL, "内部错误请稍后再试试"
|
|
}
|
|
otelTrace.Logger.WithContext(ctx).Info("请求参数" + string(marshal))
|
|
req.Header("Content-Type", "application/json")
|
|
req.Body(marshal)
|
|
req.Header("Accept-Charset", "utf-8")
|
|
|
|
response, err := req.String()
|
|
if err != nil {
|
|
otelTrace.Logger.WithContext(ctx).Error("MF GetToken 请求失败:", zap.Error(err))
|
|
return config.PAYFOR_FAIL, ""
|
|
}
|
|
|
|
otelTrace.Logger.WithContext(ctx).Info("远端请求返回数据", zap.String("response", response))
|
|
|
|
if gojson.Json(response).Get("code").Tostring() == "" {
|
|
otelTrace.Logger.WithContext(ctx).Error("远程调用失败")
|
|
return config.PAYFOR_BANKING, ""
|
|
}
|
|
|
|
if gojson.Json(response).Get("code").Tostring() == "0" {
|
|
|
|
type data struct {
|
|
OrderID int64 `json:"order_id"`
|
|
CardNo string `json:"card_no"`
|
|
CardPwd string `json:"card_pwd"`
|
|
Status int `json:"status"`
|
|
RspInfo string `json:"rsp_info"`
|
|
FaceVal int `json:"face_val"`
|
|
Amount int `json:"amount"`
|
|
Discount string `json:"discount"`
|
|
}
|
|
|
|
var d data
|
|
|
|
err2 := json.Unmarshal([]byte(gojson.Json(response).Get("data").Tostring()), &d)
|
|
if err2 != nil {
|
|
return config.PAYFOR_FAIL, ""
|
|
}
|
|
|
|
if d.Status == 9 {
|
|
return config.PAYFOR_SUCCESS, ""
|
|
}
|
|
|
|
if d.Status == 4 {
|
|
return config.PAYFOR_BANKING, ""
|
|
}
|
|
|
|
if d.Status == 7 || d.Status == 8 {
|
|
return config.PAYFOR_FAIL, ""
|
|
}
|
|
}
|
|
|
|
otelTrace.Logger.WithContext(ctx).Error("远程调用失败")
|
|
return config.PAYFOR_BANKING, ""
|
|
}
|
|
|
|
func (c *CamelImpl) BalanceQuery(roadInfo road.RoadInfo) float64 {
|
|
return 0.00
|
|
}
|
|
|
|
func (c *CamelImpl) PayForNotify() string {
|
|
return ""
|
|
}
|