Files
kami_gateway/internal/service/supplier/third_party/fat_six.go
2025-02-24 21:45:06 +08:00

292 lines
9.0 KiB
Go

package third_party
import (
"context"
"encoding/json"
"gateway/internal/config"
"gateway/internal/otelTrace"
"gateway/internal/service/supplier"
"time"
"gateway/internal/models/merchant"
"gateway/internal/models/order"
"gateway/internal/models/payfor"
"gateway/internal/models/road"
"gateway/internal/models/supply_model"
"gateway/internal/service"
"net/http"
"net/url"
"sort"
"strconv"
"strings"
"github.com/beego/beego/v2/server/web"
"github.com/duke-git/lancet/v2/convertor"
"github.com/duke-git/lancet/v2/cryptor"
"github.com/duke-git/lancet/v2/formatter"
"github.com/duke-git/lancet/v2/maputil"
"github.com/duke-git/lancet/v2/netutil"
"github.com/duke-git/lancet/v2/pointer"
"github.com/duke-git/lancet/v2/structs"
"github.com/widuu/gojson"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
)
type FatSixImpl struct {
*web.Controller
}
type sendCardReq struct {
Mid string `json:"mid"` // 商户号
MerOrderTid string `json:"merOrderTid"` // 商户单号
Money string `json:"money"` // 金额
ChannelCode string `json:"channelCode"` // 通道编码
//ClientUserPayRemark string `json:"clientUserPayRemark"` // 付款人备注
//ClientUserId string `json:"clientUserId"` // 商户端用户Id
NotifyUrl string `json:"notifyUrl"`
}
func sign(params map[string]any, keys []string, paySecret string) string {
sort.Strings(keys)
str := ""
for i := 0; i < len(keys); i++ {
k := keys[i]
if len(convertor.ToString(params[k])) == 0 || k == "sign" {
continue
}
str += k + "=" + convertor.ToString(params[k]) + "&"
}
str += paySecret
return strings.ToUpper(cryptor.Md5String(str))
}
type sendCardResp struct {
Status int `json:"status"`
ErrMsg string `json:"errMsg"`
Result struct {
Tid string `json:"tid"`
MerOrderTid string `json:"merOrderTid"`
PayUrl string `json:"payUrl"`
PayOrderStatus int `json:"payOrderStatus"`
} `json:"result"`
}
func (f *FatSixImpl) sendCard(ctx context.Context, jsonStr string, cardInfo supplier.RedeemCardInfo, attach string) (bool, *sendCardResp) {
response := &sendCardResp{}
req := sendCardReq{
Mid: gojson.Json(jsonStr).Get("mid").Tostring(),
MerOrderTid: attach,
Money: cardInfo.FaceType,
ChannelCode: gojson.Json(jsonStr).Get("channelCode").Tostring(),
NotifyUrl: config.GetConfig().GetSixFatNotifyUrl(),
}
params, _ := structs.ToMap(req)
params["sign"] = sign(params, maputil.Keys(params), gojson.Json(jsonStr).Get("paySecret").Tostring())
pretty, _ := formatter.Pretty(params)
otelTrace.Logger.WithContext(ctx).Info("请求参数:" + pretty)
//urlParams := url.Values{}
//for k, v := range params {
// urlParams.Add(k, v.(string))
//}
body, err := json.Marshal(params)
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("解析参数失败", zap.Error(err))
return false, response
}
header := http.Header{}
header.Add("Content-Type", "application/x-www-form-urlencoded")
request := &netutil.HttpRequest{
Headers: header,
RawURL: "http://ti8lj4yj3am3mr4id0tl.itxitongsf.xyz/api/services/app/Api_PayOrder/CreateOrderPay",
Method: "POST",
//FormData: urlParams,
Body: body,
}
httpClient := netutil.NewHttpClient()
httpClient.Timeout = 30 * time.Second
httpClient.Transport = otelhttp.NewTransport(http.DefaultTransport)
resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 {
otelTrace.Logger.WithContext(ctx).Error("发送数据失败", zap.Error(err))
return false, response
}
err = httpClient.DecodeResponse(resp, &response)
if err != nil || pointer.IsNil(response) {
otelTrace.Logger.WithContext(ctx).Error("解析分解会结构失败", zap.Error(err), zap.Any("response", response))
return false, response
}
pretty, _ = formatter.Pretty(response)
otelTrace.Logger.WithContext(ctx).Info("返回参数:" + pretty)
if response.Status == 0 {
return true, response
}
return false, response
}
func (f *FatSixImpl) Scan(ctx context.Context, orderInfo order.OrderInfo, roadInfo road.RoadInfo, info3 merchant.MerchantInfo) supplier.ScanData {
ctx, cancel := otelTrace.Span(ctx, "胖小六", "Scan", trace.WithAttributes(
attribute.String("BankOrderId", orderInfo.BankOrderId),
attribute.String("MerchantUid", orderInfo.MerchantUid),
attribute.String("ExValue", orderInfo.ExValue),
))
defer cancel()
cdata := supplier.RedeemCardInfo{
FaceType: convertor.ToString(orderInfo.OrderAmount),
}
//err := json.Unmarshal([]byte(orderInfo.ExValue), &cdata)
//if err != nil {
// otel.Logger.WithContext(ctx).Error("格式化数据失败", orderInfo.ExValue)
// return supplier.ScanData{Status: "-1", Msg: "订单有有误,请稍后再试"}
//}
ok, response := f.sendCard(ctx, roadInfo.Params, cdata, orderInfo.BankOrderId)
if !ok {
return supplier.ScanData{
Status: "-1",
Msg: "订单有有误,请稍后再试:" + convertor.ToString(response.ErrMsg),
BankNo: orderInfo.MerchantOrderId,
OrderNo: orderInfo.BankOrderId,
ReturnData: convertor.ToString(response.ErrMsg),
}
}
scanData := supplier.ScanData{
OrderNo: orderInfo.BankOrderId,
BankNo: orderInfo.MerchantOrderId,
OrderPrice: strconv.FormatFloat(orderInfo.OrderAmount, 'f', 2, 64),
Status: "00",
PayUrl: response.Result.PayUrl,
Msg: "",
ReturnData: convertor.ToString(response.ErrMsg),
UpStreamOrderNo: response.Result.Tid,
}
return scanData
}
func (f *FatSixImpl) PayNotify() {
ctx := f.Ctx.Request.Context()
resp := struct {
MerOrderTid string `json:"merOrderTid"`
Tid string `json:"tid"`
Money string `json:"money"`
Sign string `json:"sign"`
Status int `json:"status"` // 状态 0=待处理 1=成功 2=失败 3=异常 4=超时关闭
}{}
err := f.Bind(&resp)
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("解析参数失败", zap.Error(err))
f.Ctx.WriteString("fail")
return
}
orderInfo := order.GetOrderByBankOrderId(ctx, resp.MerOrderTid)
roadInfo := road.GetRoadInfoByRoadUid(ctx, orderInfo.RoadUid)
//解析token
params, _ := structs.ToMap(resp)
respSign := resp.Sign
tmpSign := sign(params, maputil.Keys(params), gojson.Json(roadInfo.Params).Get("paySecret").Tostring())
if tmpSign != respSign {
otelTrace.Logger.WithContext(ctx).Error("签名错误", zap.Error(err))
f.Ctx.WriteString("fail")
return
}
if resp.Status == 1 {
// TODO 订单支付成功
money, err := convertor.ToFloat(resp.Money)
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("金额转换失败", zap.Error(err))
f.Ctx.WriteString("fail")
}
isOk := service.SolvePaySuccess(ctx, orderInfo.BankOrderId, money, resp.Tid, "支付成功")
if isOk {
f.Ctx.WriteString("SUCCESS")
} else {
f.Ctx.WriteString("FAIL")
}
} else {
isOk := service.SolvePayFail(f.Ctx.Request.Context(), orderInfo.BankOrderId, resp.Tid, "")
if isOk {
f.Ctx.WriteString("SUCCESS")
} else {
f.Ctx.WriteString("FAIL")
}
}
f.Ctx.WriteString("success")
}
func (f *FatSixImpl) PayQuery(info order.OrderInfo, info2 road.RoadInfo) bool {
//TODO implement me
panic("implement me")
}
func (f *FatSixImpl) PayQueryV2(info order.OrderInfo, roadInfo road.RoadInfo) supply_model.MsgModel {
ctx := f.Ctx.Request.Context()
params := map[string]any{
"mid": "",
}
params["sign"] = sign(params, maputil.Keys(params), gojson.Json(roadInfo.Params).Get("paySecret").Tostring())
urlParams := url.Values{}
for k, v := range params {
urlParams.Add(k, v.(string))
}
request := &netutil.HttpRequest{
RawURL: "http://ti8lj4yj3am3mr4id0tl.itxitongsf.xyz/api/services/app/Api_PayOrder/QueryBalance",
Method: "POST",
FormData: urlParams,
}
httpClient := netutil.NewHttpClient()
resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 {
otelTrace.Logger.WithContext(ctx).Error("发送数据失败", zap.Error(err))
return "发送数据失败"
}
response := struct {
Status int `json:"status"`
ErrMsg interface{} `json:"errMsg"`
Result struct {
MerName string `json:"merName"`
Mid string `json:"mid"`
Balance string `json:"balance"`
} `json:"result"`
}{}
err = httpClient.DecodeResponse(resp, &response)
if err != nil || pointer.IsNil(response) {
otelTrace.Logger.WithContext(ctx).Error("解析分解会结构失败", zap.Error(err), zap.Any("response", response))
return "解析分解会结构失败"
}
return convertor.ToString(response.Result.Balance)
}
func (f *FatSixImpl) PayFor(info payfor.PayforInfo) string {
//TODO implement me
panic("implement me")
}
func (f *FatSixImpl) PayForNotify() string {
//TODO implement me
panic("implement me")
}
func (f *FatSixImpl) PayForQuery(info payfor.PayforInfo) (string, string) {
//TODO implement me
panic("implement me")
}
func (f *FatSixImpl) BalanceQuery(info road.RoadInfo) float64 {
//TODO implement me
panic("implement me")
}
func (f *FatSixImpl) HasDependencyHTML() bool {
return true
}