代理在线充值
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m6s

This commit is contained in:
2026-07-27 16:02:55 +08:00
parent a2166c8011
commit cbf909b878
42 changed files with 3121 additions and 195 deletions

View File

@@ -0,0 +1,30 @@
// Package agentrecharge 定义代理在线充值的纯业务规则。
package agentrecharge
import (
"strings"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/break/junhong_cmp_fiber/pkg/errors"
)
// ValidateOnlineCreation 校验代理在线充值的角色、金额和支付方式不变量。
func ValidateOnlineCreation(userType int, amount int64, paymentMethod string) error {
if userType != constants.UserTypeAgent {
return errors.New(errors.CodeForbidden, "仅代理账号可以创建在线扫码充值")
}
if amount < constants.AgentOnlineRechargeMinAmount || amount > constants.AgentRechargeMaxAmount {
return errors.New(errors.CodeInvalidParam, "在线充值金额必须在100元至100万元之间")
}
switch strings.TrimSpace(paymentMethod) {
case constants.RechargeMethodWechat, constants.RechargeMethodAlipay:
return nil
default:
return errors.New(errors.CodeInvalidParam, "在线充值支付方式无效")
}
}
// CanCloseAfterPreCreateFailure 判断预下单明确失败后能否关闭充值单。
func CanCloseAfterPreCreateFailure(status int) bool {
return status == constants.RechargeStatusPending
}

View File

@@ -0,0 +1,82 @@
package agentrecharge
import (
"strings"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/break/junhong_cmp_fiber/pkg/errors"
)
// PaymentState 是支付单在确认用例中的领域状态。
type PaymentState int
const (
// PaymentStatePending 表示支付单仍待确认。
PaymentStatePending PaymentState = iota
// PaymentStatePaid 表示支付单已确认收款。
PaymentStatePaid
// PaymentStateFailed 表示支付单曾被明确关闭。
PaymentStateFailed
// PaymentStateRefunded 表示支付单已经退款。
PaymentStateRefunded
)
// PaymentConfirmationFacts 是支付确认所需的渠道与本地权威事实。
type PaymentConfirmationFacts struct {
OrderType string
ExpectedOrderType string
PaymentMethod string
RechargePaymentMethod string
RechargePaymentChannel string
PaymentConfigID uint
RechargePaymentConfigID uint
ConfirmedConfigID uint
MerchantIdentity string
ConfirmedMerchantIdentity string
PaymentAmount int64
RechargeAmount int64
ConfirmedAmount int64
PaymentOrderID uint
RechargeID uint
PaymentState PaymentState
RechargeStatus int
StoredTradeNo string
ConfirmedTradeNo string
}
// ValidatePaymentConfirmation 校验支付确认不变量,并返回是否属于完全一致的重复确认。
func ValidatePaymentConfirmation(facts PaymentConfirmationFacts) (bool, error) {
if facts.ExpectedOrderType == "" || facts.OrderType != facts.ExpectedOrderType ||
facts.RechargeID == 0 || facts.PaymentOrderID != facts.RechargeID {
return false, errors.New(errors.CodeConflict, "支付单与代理充值单关联不一致")
}
method := strings.TrimSpace(facts.PaymentMethod)
if method == "" || method != strings.TrimSpace(facts.RechargePaymentMethod) ||
method != strings.TrimSpace(facts.RechargePaymentChannel) {
return false, errors.New(errors.CodeConflict, "支付渠道与代理充值单不一致")
}
identity := strings.TrimSpace(facts.MerchantIdentity)
if facts.PaymentConfigID == 0 || facts.PaymentConfigID != facts.RechargePaymentConfigID ||
facts.PaymentConfigID != facts.ConfirmedConfigID || identity == "" ||
identity != strings.TrimSpace(facts.ConfirmedMerchantIdentity) {
return false, errors.New(errors.CodeConflict, "支付配置身份与创建记录不一致")
}
tradeNo := strings.TrimSpace(facts.ConfirmedTradeNo)
if tradeNo == "" || facts.ConfirmedAmount <= 0 || facts.PaymentAmount != facts.RechargeAmount ||
facts.PaymentAmount != facts.ConfirmedAmount {
return false, errors.New(errors.CodeConflict, "支付金额或第三方交易号无效")
}
if facts.PaymentState == PaymentStatePaid {
if strings.TrimSpace(facts.StoredTradeNo) == tradeNo &&
(facts.RechargeStatus == constants.RechargeStatusPaid || facts.RechargeStatus == constants.RechargeStatusCompleted) {
return true, nil
}
return false, errors.New(errors.CodeConflict, "支付单已存在不一致的确认事实")
}
validPending := facts.PaymentState == PaymentStatePending && facts.RechargeStatus == constants.RechargeStatusPending
validLateSuccess := facts.PaymentState == PaymentStateFailed && facts.RechargeStatus == constants.RechargeStatusClosed
if !validPending && !validLateSuccess {
return false, errors.New(errors.CodeInvalidStatus, "代理充值单当前状态不可确认支付")
}
return false, nil
}