refactor(order): 优化订单金额校验与接口调用参数传递
- 调整SendCard方法参数,增加orderInfo传递订单金额信息 - 完善苹果卡、BatchSix供应商发送卡片时的金额使用,改用订单实际金额替换面额字段 - 增加CompleteRedeemExValue中订单金额一致性校验,防止面额数据不符错误 - 支付通知处理中校验实际支付金额与订单金额,金额不符时调用专用处理函数 - 修正扫描控制器调用CompleteRedeemExValue时传入的订单金额参数以确保准确校验
This commit is contained in:
@@ -179,9 +179,7 @@ func (c *ScanController) Scan() {
|
||||
return
|
||||
}
|
||||
|
||||
p.Params["exValue"], err = service.CompleteRedeemExValue(
|
||||
convertor.ToString(p.Params["exValue"]), strconv.FormatFloat(pm.ShowLabel, 'f', 0, 64),
|
||||
)
|
||||
p.Params["exValue"], err = service.CompleteRedeemExValue(ctx, orderPrice, convertor.ToString(p.Params["exValue"]), strconv.FormatFloat(pm.ShowLabel, 'f', 0, 64))
|
||||
if err != nil {
|
||||
p.Code = -1
|
||||
p.Msg = fmt.Sprintf("订单金额转换失败:%v", err.Error())
|
||||
|
||||
@@ -1,169 +1,172 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"gateway/internal/config"
|
||||
"gateway/internal/otelTrace"
|
||||
|
||||
"gateway/internal/service/supplier"
|
||||
|
||||
"gateway/internal/models/merchant"
|
||||
"gateway/internal/schema/response"
|
||||
"strconv"
|
||||
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// GetMerchantInfoByPayKey 通过payKey获取商户信息
|
||||
func GetMerchantInfoByPayKey(ctx context.Context, payKey string) (merchantInfo merchant.MerchantInfo, err error) {
|
||||
merchantInfo = merchant.GetMerchantByPasskey(ctx, payKey)
|
||||
if merchantInfo.MerchantUid == "" || len(merchantInfo.MerchantUid) == 0 {
|
||||
err = errors.New("商户不存在,请联系商户")
|
||||
return
|
||||
} else if merchantInfo.Status != config.ACTIVE {
|
||||
err = errors.New("商户状态已经被冻结或者被删除,请联系商户!")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetMerchantInfo 获取商户信息
|
||||
func GetMerchantInfo(ctx context.Context, params map[string]any) *response.PayBaseResp {
|
||||
c := new(response.PayBaseResp)
|
||||
c.Params = params
|
||||
merchantInfo := merchant.GetMerchantByPasskey(ctx, convertor.ToString(params["payKey"]))
|
||||
if merchantInfo.MerchantUid == "" || len(merchantInfo.MerchantUid) == 0 {
|
||||
c.Code = -1
|
||||
c.Msg = "商户不存在,或者paykey有误,请联系管理员"
|
||||
} else if merchantInfo.Status != config.ACTIVE {
|
||||
c.Code = -1
|
||||
c.Msg = "商户状态已经被冻结或者被删除,请联系管理员!"
|
||||
} else {
|
||||
c.MerchantInfo = merchantInfo
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func JudgeParams(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
|
||||
c = OrderIsValid(ctx, c)
|
||||
c = NotifyUrlIsValid(ctx, c)
|
||||
c = OrderPeriodIsValid(ctx, c)
|
||||
c = OrderPriceIsValid(ctx, c)
|
||||
c = ExValueIsValid(ctx, c)
|
||||
return c
|
||||
}
|
||||
|
||||
func ExValueIsValid(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
|
||||
if c.Params["exValue"] == "" || len(convertor.ToString(c.Params["exValue"])) == 0 {
|
||||
c.Code = -1
|
||||
c.Msg = "扩展参数不能为空"
|
||||
}
|
||||
isRedeemValid := true
|
||||
exRedeemValue := supplier.RedeemCardInfo{}
|
||||
if err := json.Unmarshal([]byte(convertor.ToString(c.Params["exValue"])), &exRedeemValue); err != nil {
|
||||
otelTrace.Logger.WithContext(ctx).Error("提交卡密格式错误,请检查", zap.Any("exValue", c.Params["exValue"]), zap.Error(err))
|
||||
isRedeemValid = false
|
||||
}
|
||||
if exRedeemValue.Data == "" || len(exRedeemValue.Data) == 0 {
|
||||
isRedeemValid = false
|
||||
}
|
||||
if !isRedeemValid {
|
||||
c.Code = -1
|
||||
c.Msg = "提交卡密格式错误,请检查"
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func CompleteRedeemExValue(exValueStr string, faceValue string) (string, error) {
|
||||
exValue := supplier.RedeemCardInfo{}
|
||||
if err := json.Unmarshal([]byte(exValueStr), &exValue); err != nil {
|
||||
return "", err
|
||||
}
|
||||
exValue.FaceType = faceValue
|
||||
res, err := json.Marshal(&exValue)
|
||||
return string(res), err
|
||||
}
|
||||
|
||||
func GetCompleteRedeemExValue(exValueStr string, faceValue string) (exValue supplier.RedeemCardInfo, err error) {
|
||||
exValue = supplier.RedeemCardInfo{}
|
||||
if err = json.Unmarshal([]byte(exValueStr), &exValue); err != nil {
|
||||
return exValue, err
|
||||
}
|
||||
exValue.FaceType = faceValue
|
||||
return
|
||||
}
|
||||
|
||||
func CompleteRechargeExValue(exValueStr string, faceValue string) (string, error) {
|
||||
exValue := supplier.RechargeCardInfo{}
|
||||
if err := json.Unmarshal([]byte(exValueStr), &exValue); err != nil {
|
||||
return "", err
|
||||
}
|
||||
exValue.FaceType = faceValue
|
||||
res, err := json.Marshal(&exValue)
|
||||
return string(res), err
|
||||
}
|
||||
|
||||
// NotifyUrlIsValid 判断回调地址是否符合规则
|
||||
func NotifyUrlIsValid(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
|
||||
if c.Params["notifyUrl"] == "" || len(convertor.ToString(c.Params["notifyUrl"])) == 0 {
|
||||
c.Code = -1
|
||||
c.Msg = "订单回调不能为空"
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// OsTypeIsValid 判断设备类型是否符合规则
|
||||
func OsTypeIsValid(c *response.PayBaseResp) *response.PayBaseResp {
|
||||
if c.Params["osType"] == "" || len(convertor.ToString(c.Params["osType"])) == 0 {
|
||||
c.Code = -1
|
||||
c.Msg = "支付设备系统类型不能为空,默认填写\"1\"即可"
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func OrderPeriodIsValid(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
|
||||
if c.Params["orderPeriod"] == "" || len(convertor.ToString(c.Params["orderPeriod"])) == 0 {
|
||||
c.Code = -1
|
||||
c.Msg = "订单过期时间不能为空,默认填写\"1\"即可"
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// OrderPriceIsValid 判断订单金额
|
||||
func OrderPriceIsValid(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
|
||||
if c.Params["orderPrice"] == "" || len(convertor.ToString(c.Params["orderPrice"])) == 0 {
|
||||
c.Code = -1
|
||||
c.Msg = "订单金额不能为空"
|
||||
return c
|
||||
}
|
||||
|
||||
a, err := strconv.ParseFloat(convertor.ToString(c.Params["orderPrice"]), 64)
|
||||
if err != nil {
|
||||
otelTrace.Logger.WithContext(ctx).Error("order price is invalid: ", zap.Any("orderPrice", c.Params["orderPrice"]), zap.Error(err))
|
||||
c.Code = -1
|
||||
c.Msg = "订单金额非法"
|
||||
}
|
||||
c.OrderAmount = a
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// OrderIsValid 判断金额订单号是否为空或者有重复
|
||||
func OrderIsValid(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
|
||||
if c.Params["orderNo"] == "" || len(convertor.ToString(c.Params["orderNo"])) == 0 {
|
||||
c.Code = -1
|
||||
c.Msg = "商户订单号不能为空"
|
||||
return c
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// IpIsWhite 判断ip是否在白名单中
|
||||
func IpIsWhite() bool {
|
||||
// TODO
|
||||
return true
|
||||
}
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"gateway/internal/config"
|
||||
"gateway/internal/otelTrace"
|
||||
|
||||
"gateway/internal/service/supplier"
|
||||
|
||||
"gateway/internal/models/merchant"
|
||||
"gateway/internal/schema/response"
|
||||
"strconv"
|
||||
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// GetMerchantInfoByPayKey 通过payKey获取商户信息
|
||||
func GetMerchantInfoByPayKey(ctx context.Context, payKey string) (merchantInfo merchant.MerchantInfo, err error) {
|
||||
merchantInfo = merchant.GetMerchantByPasskey(ctx, payKey)
|
||||
if merchantInfo.MerchantUid == "" || len(merchantInfo.MerchantUid) == 0 {
|
||||
err = errors.New("商户不存在,请联系商户")
|
||||
return
|
||||
} else if merchantInfo.Status != config.ACTIVE {
|
||||
err = errors.New("商户状态已经被冻结或者被删除,请联系商户!")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetMerchantInfo 获取商户信息
|
||||
func GetMerchantInfo(ctx context.Context, params map[string]any) *response.PayBaseResp {
|
||||
c := new(response.PayBaseResp)
|
||||
c.Params = params
|
||||
merchantInfo := merchant.GetMerchantByPasskey(ctx, convertor.ToString(params["payKey"]))
|
||||
if merchantInfo.MerchantUid == "" || len(merchantInfo.MerchantUid) == 0 {
|
||||
c.Code = -1
|
||||
c.Msg = "商户不存在,或者paykey有误,请联系管理员"
|
||||
} else if merchantInfo.Status != config.ACTIVE {
|
||||
c.Code = -1
|
||||
c.Msg = "商户状态已经被冻结或者被删除,请联系管理员!"
|
||||
} else {
|
||||
c.MerchantInfo = merchantInfo
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func JudgeParams(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
|
||||
c = OrderIsValid(ctx, c)
|
||||
c = NotifyUrlIsValid(ctx, c)
|
||||
c = OrderPeriodIsValid(ctx, c)
|
||||
c = OrderPriceIsValid(ctx, c)
|
||||
c = ExValueIsValid(ctx, c)
|
||||
return c
|
||||
}
|
||||
|
||||
func ExValueIsValid(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
|
||||
if c.Params["exValue"] == "" || len(convertor.ToString(c.Params["exValue"])) == 0 {
|
||||
c.Code = -1
|
||||
c.Msg = "扩展参数不能为空"
|
||||
}
|
||||
isRedeemValid := true
|
||||
exRedeemValue := supplier.RedeemCardInfo{}
|
||||
if err := json.Unmarshal([]byte(convertor.ToString(c.Params["exValue"])), &exRedeemValue); err != nil {
|
||||
otelTrace.Logger.WithContext(ctx).Error("提交卡密格式错误,请检查", zap.Any("exValue", c.Params["exValue"]), zap.Error(err))
|
||||
isRedeemValid = false
|
||||
}
|
||||
if exRedeemValue.Data == "" || len(exRedeemValue.Data) == 0 {
|
||||
isRedeemValid = false
|
||||
}
|
||||
if !isRedeemValid {
|
||||
c.Code = -1
|
||||
c.Msg = "提交卡密格式错误,请检查"
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func CompleteRedeemExValue(ctx context.Context, orderAmount float64, exValueStr string, faceValue string) (string, error) {
|
||||
exValue := supplier.RedeemCardInfo{}
|
||||
if err := json.Unmarshal([]byte(exValueStr), &exValue); err != nil {
|
||||
return "", err
|
||||
}
|
||||
exValue.FaceType = faceValue
|
||||
res, err := json.Marshal(&exValue)
|
||||
if orderAmount != exValue.GetFaceTypeFloat(ctx) {
|
||||
return "", errors.New("订单金额与提交的金额不一致")
|
||||
}
|
||||
return string(res), err
|
||||
}
|
||||
|
||||
func GetCompleteRedeemExValue(exValueStr string, faceValue string) (exValue supplier.RedeemCardInfo, err error) {
|
||||
exValue = supplier.RedeemCardInfo{}
|
||||
if err = json.Unmarshal([]byte(exValueStr), &exValue); err != nil {
|
||||
return exValue, err
|
||||
}
|
||||
exValue.FaceType = faceValue
|
||||
return
|
||||
}
|
||||
|
||||
func CompleteRechargeExValue(exValueStr string, faceValue string) (string, error) {
|
||||
exValue := supplier.RechargeCardInfo{}
|
||||
if err := json.Unmarshal([]byte(exValueStr), &exValue); err != nil {
|
||||
return "", err
|
||||
}
|
||||
exValue.FaceType = faceValue
|
||||
res, err := json.Marshal(&exValue)
|
||||
return string(res), err
|
||||
}
|
||||
|
||||
// NotifyUrlIsValid 判断回调地址是否符合规则
|
||||
func NotifyUrlIsValid(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
|
||||
if c.Params["notifyUrl"] == "" || len(convertor.ToString(c.Params["notifyUrl"])) == 0 {
|
||||
c.Code = -1
|
||||
c.Msg = "订单回调不能为空"
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// OsTypeIsValid 判断设备类型是否符合规则
|
||||
func OsTypeIsValid(c *response.PayBaseResp) *response.PayBaseResp {
|
||||
if c.Params["osType"] == "" || len(convertor.ToString(c.Params["osType"])) == 0 {
|
||||
c.Code = -1
|
||||
c.Msg = "支付设备系统类型不能为空,默认填写\"1\"即可"
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func OrderPeriodIsValid(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
|
||||
if c.Params["orderPeriod"] == "" || len(convertor.ToString(c.Params["orderPeriod"])) == 0 {
|
||||
c.Code = -1
|
||||
c.Msg = "订单过期时间不能为空,默认填写\"1\"即可"
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// OrderPriceIsValid 判断订单金额
|
||||
func OrderPriceIsValid(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
|
||||
if c.Params["orderPrice"] == "" || len(convertor.ToString(c.Params["orderPrice"])) == 0 {
|
||||
c.Code = -1
|
||||
c.Msg = "订单金额不能为空"
|
||||
return c
|
||||
}
|
||||
|
||||
a, err := strconv.ParseFloat(convertor.ToString(c.Params["orderPrice"]), 64)
|
||||
if err != nil {
|
||||
otelTrace.Logger.WithContext(ctx).Error("order price is invalid: ", zap.Any("orderPrice", c.Params["orderPrice"]), zap.Error(err))
|
||||
c.Code = -1
|
||||
c.Msg = "订单金额非法"
|
||||
}
|
||||
c.OrderAmount = a
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// OrderIsValid 判断金额订单号是否为空或者有重复
|
||||
func OrderIsValid(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
|
||||
if c.Params["orderNo"] == "" || len(convertor.ToString(c.Params["orderNo"])) == 0 {
|
||||
c.Code = -1
|
||||
c.Msg = "商户订单号不能为空"
|
||||
return c
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// IpIsWhite 判断ip是否在白名单中
|
||||
func IpIsWhite() bool {
|
||||
// TODO
|
||||
return true
|
||||
}
|
||||
|
||||
33
internal/service/supplier/third_party/apple.go
vendored
33
internal/service/supplier/third_party/apple.go
vendored
@@ -6,6 +6,7 @@ import (
|
||||
"crypto/cipher"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"gateway/internal/config"
|
||||
"gateway/internal/models/merchant"
|
||||
"gateway/internal/models/order"
|
||||
@@ -13,7 +14,6 @@ import (
|
||||
"gateway/internal/models/road"
|
||||
"gateway/internal/models/supply_model"
|
||||
"gateway/internal/otelTrace"
|
||||
|
||||
"gateway/internal/service"
|
||||
"gateway/internal/service/supplier"
|
||||
"gateway/internal/utils"
|
||||
@@ -77,14 +77,14 @@ func (c *AppleCardImpl) HasDependencyHTML() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *AppleCardImpl) SendCard(ctx context.Context, jsonStr string, cardInfo supplier.RedeemCardInfo, attach string, merchantId string) (bool, string) {
|
||||
func (c *AppleCardImpl) SendCard(ctx context.Context, jsonStr string, orderInfo order.OrderInfo, cardInfo supplier.RedeemCardInfo, attach string, merchantId string) (bool, string) {
|
||||
cfg := config.Config{}
|
||||
params := make(map[string]string)
|
||||
|
||||
params["callbackUrl"], _ = cfg.GetAppleNotifyUrl() // 回调地址
|
||||
params["attach"] = attach // 附带参数
|
||||
params["faceValue"] = cardInfo.FaceType // 面额
|
||||
params["cardNo"] = cardInfo.CardNo // 卡号
|
||||
params["callbackUrl"], _ = cfg.GetAppleNotifyUrl() // 回调地址
|
||||
params["attach"] = attach // 附带参数
|
||||
params["faceValue"] = fmt.Sprintf("%.2f", orderInfo.OrderAmount) // 面额
|
||||
params["cardNo"] = cardInfo.CardNo // 卡号
|
||||
params["cardPass"] = cardInfo.Data
|
||||
params["merchantId"] = merchantId
|
||||
|
||||
@@ -156,7 +156,7 @@ func (c *AppleCardImpl) Scan(ctx context.Context, orderInfo order.OrderInfo, roa
|
||||
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, orderInfo.MerchantOrderId)
|
||||
ok, str := c.SendCard(ctx, roadInfo.Params, orderInfo, cdata, orderInfo.BankOrderId, orderInfo.MerchantOrderId)
|
||||
var scanData supplier.ScanData
|
||||
if !ok {
|
||||
scanData = supplier.ScanData{
|
||||
@@ -215,13 +215,22 @@ func (c *AppleCardImpl) PayNotify() {
|
||||
}
|
||||
orderInfo.BankTransId = params["merchantId"]
|
||||
if params["status"] == "1" {
|
||||
// TODO 订单支付成功
|
||||
isOk := service.SolvePaySuccess(ctx, orderInfo.BankOrderId, orderInfo.FactAmount, params["merchantId"], "支付成功")
|
||||
if isOk {
|
||||
c.Ctx.WriteString("SUCCESS")
|
||||
} else {
|
||||
amount, err := strconv.ParseFloat(c.GetString("amount"), 64)
|
||||
if err != nil {
|
||||
c.Ctx.WriteString("FAIL")
|
||||
}
|
||||
if orderInfo.FactAmount != amount {
|
||||
SolvePaySuccessByAmountDifferent(ctx, orderInfo.BankOrderId, amount, orderInfo.BankOrderId, fmt.Sprintf("金额不一致,实际金额:%.2f,拉单金额:%.2f", amount, orderInfo.OrderAmount))
|
||||
|
||||
return
|
||||
} else {
|
||||
isOk := service.SolvePaySuccess(ctx, orderInfo.BankOrderId, orderInfo.FactAmount, params["merchantId"], "支付成功")
|
||||
if isOk {
|
||||
c.Ctx.WriteString("SUCCESS")
|
||||
} else {
|
||||
c.Ctx.WriteString("FAIL")
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
isOk := service.SolvePayFail(ctx, orderInfo.BankOrderId, "", params["remark"])
|
||||
|
||||
@@ -37,7 +37,7 @@ func (c *BatchSixImpl) HasDependencyHTML() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *BatchSixImpl) SendCard(ctx context.Context, jsonStr string, cardInfo supplier.RedeemCardInfo, attach string) (bool, string) {
|
||||
func (c *BatchSixImpl) SendCard(ctx context.Context, orderInfo order.OrderInfo, jsonStr string, cardInfo supplier.RedeemCardInfo, attach string) (bool, string) {
|
||||
ctx, span := otelTrace.Span(ctx, "BatchSixImpl", "sendCard", trace.WithAttributes(
|
||||
attribute.String("jsonStr", jsonStr),
|
||||
attribute.String("attach", attach),
|
||||
@@ -68,7 +68,7 @@ func (c *BatchSixImpl) SendCard(ctx context.Context, jsonStr string, cardInfo su
|
||||
Url: submitUrl,
|
||||
ChannelID: queue.ChannelBatchSix,
|
||||
ChannelCode: idInt,
|
||||
FaceValue: cardInfo.GetFaceTypeFloat(ctx),
|
||||
FaceValue: orderInfo.OrderAmount,
|
||||
CardNo: cardInfo.CardNo,
|
||||
CardPwd: cardInfo.Data,
|
||||
Mobile: gojson.Json(jsonStr).Get("username").Tostring(),
|
||||
@@ -105,7 +105,7 @@ func (c *BatchSixImpl) Scan(ctx context.Context, orderInfo order.OrderInfo, road
|
||||
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)
|
||||
ok, str := c.SendCard(ctx, orderInfo, roadInfo.Params, cdata, orderInfo.BankOrderId)
|
||||
var scanData supplier.ScanData
|
||||
if !ok {
|
||||
scanData = supplier.ScanData{
|
||||
|
||||
Reference in New Issue
Block a user