refactor: 清理 YAML 支付配置遗留代码,重命名 Card* 常量为 Asset*,新增支付配置相关错误码

- 删除 PaymentConfig 结构体和 WechatConfig.Payment 字段(YAML 方案已废弃)
- 删除 wechat.payment 配置节和 NewPaymentApp() 函数
- 删除 validateWechatConfig 中所有 wechatCfg.Payment.* 校验代码
- pkg/constants/wallet.go: Card* 前缀统一重命名为 Asset*,旧名保留废弃别名
- pkg/constants/redis.go: 新增 RedisWechatConfigActiveKey()
- pkg/errors/codes.go: 新增错误码 1170-1175
- go.mod: 新增 golang.org/x/text 依赖(富友支付 GBK 编解码)

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-03-16 23:28:29 +08:00
parent 7f18765911
commit b0da71bd25
9 changed files with 115 additions and 152 deletions

View File

@@ -359,12 +359,11 @@ func initGateway(cfg *config.Config, appLogger *zap.Logger) *gateway.Client {
func validateWechatConfig(cfg *config.Config, appLogger *zap.Logger) { func validateWechatConfig(cfg *config.Config, appLogger *zap.Logger) {
wechatCfg := cfg.Wechat wechatCfg := cfg.Wechat
if wechatCfg.OfficialAccount.AppID == "" && wechatCfg.Payment.AppID == "" { if wechatCfg.OfficialAccount.AppID == "" {
appLogger.Warn("微信配置未设置,微信相关功能将不可用") appLogger.Warn("微信公众号配置未设置,OAuth 相关功能将不可用")
return return
} }
if wechatCfg.OfficialAccount.AppID != "" {
if wechatCfg.OfficialAccount.AppSecret == "" { if wechatCfg.OfficialAccount.AppSecret == "" {
appLogger.Fatal("微信公众号配置不完整", appLogger.Fatal("微信公众号配置不完整",
zap.String("missing", "app_secret"), zap.String("missing", "app_secret"),
@@ -372,47 +371,4 @@ func validateWechatConfig(cfg *config.Config, appLogger *zap.Logger) {
} }
appLogger.Info("微信公众号配置已验证", appLogger.Info("微信公众号配置已验证",
zap.String("app_id", wechatCfg.OfficialAccount.AppID)) zap.String("app_id", wechatCfg.OfficialAccount.AppID))
}
if wechatCfg.Payment.AppID != "" {
missingFields := []string{}
if wechatCfg.Payment.MchID == "" {
missingFields = append(missingFields, "mch_id (JUNHONG_WECHAT_PAYMENT_MCH_ID)")
}
if wechatCfg.Payment.APIV3Key == "" {
missingFields = append(missingFields, "api_v3_key (JUNHONG_WECHAT_PAYMENT_API_V3_KEY)")
}
if wechatCfg.Payment.CertPath == "" {
missingFields = append(missingFields, "cert_path (JUNHONG_WECHAT_PAYMENT_CERT_PATH)")
}
if wechatCfg.Payment.KeyPath == "" {
missingFields = append(missingFields, "key_path (JUNHONG_WECHAT_PAYMENT_KEY_PATH)")
}
if wechatCfg.Payment.SerialNo == "" {
missingFields = append(missingFields, "serial_no (JUNHONG_WECHAT_PAYMENT_SERIAL_NO)")
}
if wechatCfg.Payment.NotifyURL == "" {
missingFields = append(missingFields, "notify_url (JUNHONG_WECHAT_PAYMENT_NOTIFY_URL)")
}
if len(missingFields) > 0 {
appLogger.Fatal("微信支付配置不完整",
zap.Strings("missing_fields", missingFields))
}
if _, err := os.Stat(wechatCfg.Payment.CertPath); os.IsNotExist(err) {
appLogger.Fatal("微信支付证书文件不存在",
zap.String("cert_path", wechatCfg.Payment.CertPath))
}
if _, err := os.Stat(wechatCfg.Payment.KeyPath); os.IsNotExist(err) {
appLogger.Fatal("微信支付私钥文件不存在",
zap.String("key_path", wechatCfg.Payment.KeyPath))
}
appLogger.Info("微信支付配置已验证",
zap.String("app_id", wechatCfg.Payment.AppID),
zap.String("mch_id", wechatCfg.Payment.MchID))
}
} }

6
go.mod
View File

@@ -1,6 +1,6 @@
module github.com/break/junhong_cmp_fiber module github.com/break/junhong_cmp_fiber
go 1.25 go 1.25.0
require ( require (
github.com/ArtisanCloud/PowerWeChat/v3 v3.4.38 github.com/ArtisanCloud/PowerWeChat/v3 v3.4.38
@@ -20,6 +20,7 @@ require (
github.com/xuri/excelize/v2 v2.8.1 github.com/xuri/excelize/v2 v2.8.1
go.uber.org/zap v1.27.1 go.uber.org/zap v1.27.1
golang.org/x/crypto v0.47.0 golang.org/x/crypto v0.47.0
golang.org/x/text v0.35.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
gorm.io/datatypes v1.2.7 gorm.io/datatypes v1.2.7
@@ -88,9 +89,8 @@ require (
go.yaml.in/yaml/v3 v3.0.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
golang.org/x/net v0.48.0 // indirect golang.org/x/net v0.48.0 // indirect
golang.org/x/sync v0.19.0 // indirect golang.org/x/sync v0.20.0 // indirect
golang.org/x/sys v0.40.0 // indirect golang.org/x/sys v0.40.0 // indirect
golang.org/x/text v0.33.0 // indirect
golang.org/x/time v0.14.0 // indirect golang.org/x/time v0.14.0 // indirect
google.golang.org/protobuf v1.36.10 // indirect google.golang.org/protobuf v1.36.10 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect

8
go.sum
View File

@@ -298,15 +298,15 @@ golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=

View File

@@ -160,7 +160,6 @@ type PresignConfig struct {
// WechatConfig 微信配置 // WechatConfig 微信配置
type WechatConfig struct { type WechatConfig struct {
OfficialAccount OfficialAccountConfig `mapstructure:"official_account"` OfficialAccount OfficialAccountConfig `mapstructure:"official_account"`
Payment PaymentConfig `mapstructure:"payment"`
} }
// OfficialAccountConfig 微信公众号配置 // OfficialAccountConfig 微信公众号配置
@@ -172,20 +171,6 @@ type OfficialAccountConfig struct {
OAuthRedirectURL string `mapstructure:"oauth_redirect_url"` OAuthRedirectURL string `mapstructure:"oauth_redirect_url"`
} }
// PaymentConfig 微信支付配置
type PaymentConfig struct {
AppID string `mapstructure:"app_id"`
MchID string `mapstructure:"mch_id"`
APIV3Key string `mapstructure:"api_v3_key"`
APIV2Key string `mapstructure:"api_v2_key"`
CertPath string `mapstructure:"cert_path"`
KeyPath string `mapstructure:"key_path"`
SerialNo string `mapstructure:"serial_no"`
NotifyURL string `mapstructure:"notify_url"`
HttpDebug bool `mapstructure:"http_debug"`
Timeout time.Duration `mapstructure:"timeout"`
}
type requiredField struct { type requiredField struct {
value string value string
name string name string

View File

@@ -120,14 +120,4 @@ wechat:
token: "" # 可选JUNHONG_WECHAT_OFFICIAL_ACCOUNT_TOKEN token: "" # 可选JUNHONG_WECHAT_OFFICIAL_ACCOUNT_TOKEN
aes_key: "" # 可选JUNHONG_WECHAT_OFFICIAL_ACCOUNT_AES_KEY敏感 aes_key: "" # 可选JUNHONG_WECHAT_OFFICIAL_ACCOUNT_AES_KEY敏感
oauth_redirect_url: "" # 可选JUNHONG_WECHAT_OFFICIAL_ACCOUNT_OAUTH_REDIRECT_URL oauth_redirect_url: "" # 可选JUNHONG_WECHAT_OFFICIAL_ACCOUNT_OAUTH_REDIRECT_URL
payment:
app_id: "" # 必填JUNHONG_WECHAT_PAYMENT_APP_ID
mch_id: "" # 必填JUNHONG_WECHAT_PAYMENT_MCH_ID
api_v3_key: "" # 必填JUNHONG_WECHAT_PAYMENT_API_V3_KEY敏感
api_v2_key: "" # 可选JUNHONG_WECHAT_PAYMENT_API_V2_KEY敏感
cert_path: "" # 必填JUNHONG_WECHAT_PAYMENT_CERT_PATH证书文件路径
key_path: "" # 必填JUNHONG_WECHAT_PAYMENT_KEY_PATH私钥文件路径
serial_no: "" # 必填JUNHONG_WECHAT_PAYMENT_SERIAL_NO
notify_url: "" # 必填JUNHONG_WECHAT_PAYMENT_NOTIFY_URL
http_debug: false
timeout: "30s"

View File

@@ -313,3 +313,14 @@ func RedisDeviceRefreshCooldownKey(deviceID uint) string {
func RedisPollingQueueProtectKey() string { func RedisPollingQueueProtectKey() string {
return "polling:queue:protect" return "polling:queue:protect"
} }
// ========================================
// 微信配置相关 Redis Key
// ========================================
// RedisWechatConfigActiveKey 生效支付配置缓存键
// 用途缓存当前激活的微信参数配置JSON 或 "none" 空标记)
// 过期时间5 分钟(有配置)/ 1 分钟(空标记)
func RedisWechatConfigActiveKey() string {
return "wechat:config:active"
}

View File

@@ -47,37 +47,37 @@ const (
AgentRechargeMaxAmount = 100000000 // 最大充值金额1000000元 AgentRechargeMaxAmount = 100000000 // 最大充值金额1000000元
) )
// ========== 钱包常量 ========== // ========== 资产钱包常量 ==========
// 钱包资源类型 // 资产钱包资源类型
const ( const (
CardWalletResourceTypeIotCard = "iot_card" // 物联网卡钱包 AssetWalletResourceTypeIotCard = "iot_card" // 物联网卡钱包
CardWalletResourceTypeDevice = "device" // 设备钱包(多卡共享) AssetWalletResourceTypeDevice = "device" // 设备钱包(多卡共享)
) )
// 钱包状态 // 资产钱包状态
const ( const (
CardWalletStatusNormal = 1 // 正常 AssetWalletStatusNormal = 1 // 正常
CardWalletStatusFrozen = 2 // 冻结 AssetWalletStatusFrozen = 2 // 冻结
CardWalletStatusClosed = 3 // 关闭 AssetWalletStatusClosed = 3 // 关闭
) )
// 钱包交易类型 // 资产钱包交易类型
const ( const (
CardTransactionTypeRecharge = "recharge" // 充值 AssetTransactionTypeRecharge = "recharge" // 充值
CardTransactionTypeDeduct = "deduct" // 扣款 AssetTransactionTypeDeduct = "deduct" // 扣款
CardTransactionTypeRefund = "refund" // 退款 AssetTransactionTypeRefund = "refund" // 退款
) )
// 充值订单号前缀 // 资产充值订单号前缀
const ( const (
CardRechargeOrderPrefix = "CRCH" // 充值订单号前缀 AssetRechargeOrderPrefix = "CRCH" // 资产充值订单号前缀
) )
// 充值金额限制(单位:分) // 资产充值金额限制(单位:分)
const ( const (
CardRechargeMinAmount = 100 // 最小充值金额1元 AssetRechargeMinAmount = 100 // 最小充值金额1元
CardRechargeMaxAmount = 10000000 // 最大充值金额100000元 AssetRechargeMaxAmount = 10000000 // 最大充值金额100000元
) )
// ========== 通用常量 ========== // ========== 通用常量 ==========
@@ -154,31 +154,31 @@ const WalletTypeMain = AgentWalletTypeMain
// WalletTypeCommission 分佣钱包(已废弃,使用 AgentWalletTypeCommission // WalletTypeCommission 分佣钱包(已废弃,使用 AgentWalletTypeCommission
const WalletTypeCommission = AgentWalletTypeCommission const WalletTypeCommission = AgentWalletTypeCommission
// WalletResourceTypeIotCard 物联网卡钱包(已废弃,使用 CardWalletResourceTypeIotCard // WalletResourceTypeIotCard 物联网卡钱包(已废弃,使用 AssetWalletResourceTypeIotCard
const WalletResourceTypeIotCard = CardWalletResourceTypeIotCard const WalletResourceTypeIotCard = AssetWalletResourceTypeIotCard
// WalletResourceTypeDevice 设备钱包(已废弃,使用 CardWalletResourceTypeDevice // WalletResourceTypeDevice 设备钱包(已废弃,使用 AssetWalletResourceTypeDevice
const WalletResourceTypeDevice = CardWalletResourceTypeDevice const WalletResourceTypeDevice = AssetWalletResourceTypeDevice
// WalletResourceTypeShop 店铺钱包(已废弃,代理钱包不再使用 resource_type // WalletResourceTypeShop 店铺钱包(已废弃,代理钱包不再使用 resource_type
const WalletResourceTypeShop = "shop" const WalletResourceTypeShop = "shop"
// WalletStatusNormal 钱包状态-正常(已废弃,使用 AgentWalletStatusNormal 或 CardWalletStatusNormal // WalletStatusNormal 钱包状态-正常(已废弃,使用 AgentWalletStatusNormal 或 AssetWalletStatusNormal
const WalletStatusNormal = AgentWalletStatusNormal const WalletStatusNormal = AgentWalletStatusNormal
// WalletStatusFrozen 钱包状态-冻结(已废弃,使用 AgentWalletStatusFrozen 或 CardWalletStatusFrozen // WalletStatusFrozen 钱包状态-冻结(已废弃,使用 AgentWalletStatusFrozen 或 AssetWalletStatusFrozen
const WalletStatusFrozen = AgentWalletStatusFrozen const WalletStatusFrozen = AgentWalletStatusFrozen
// WalletStatusClosed 钱包状态-关闭(已废弃,使用 AgentWalletStatusClosed 或 CardWalletStatusClosed // WalletStatusClosed 钱包状态-关闭(已废弃,使用 AgentWalletStatusClosed 或 AssetWalletStatusClosed
const WalletStatusClosed = AgentWalletStatusClosed const WalletStatusClosed = AgentWalletStatusClosed
// TransactionTypeRecharge 交易类型-充值(已废弃,使用 AgentTransactionTypeRecharge 或 CardTransactionTypeRecharge // TransactionTypeRecharge 交易类型-充值(已废弃,使用 AgentTransactionTypeRecharge 或 AssetTransactionTypeRecharge
const TransactionTypeRecharge = AgentTransactionTypeRecharge const TransactionTypeRecharge = AgentTransactionTypeRecharge
// TransactionTypeDeduct 交易类型-扣款(已废弃,使用 AgentTransactionTypeDeduct 或 CardTransactionTypeDeduct // TransactionTypeDeduct 交易类型-扣款(已废弃,使用 AgentTransactionTypeDeduct 或 AssetTransactionTypeDeduct
const TransactionTypeDeduct = AgentTransactionTypeDeduct const TransactionTypeDeduct = AgentTransactionTypeDeduct
// TransactionTypeRefund 交易类型-退款(已废弃,使用 AgentTransactionTypeRefund 或 CardTransactionTypeRefund // TransactionTypeRefund 交易类型-退款(已废弃,使用 AgentTransactionTypeRefund 或 AssetTransactionTypeRefund
const TransactionTypeRefund = AgentTransactionTypeRefund const TransactionTypeRefund = AgentTransactionTypeRefund
// TransactionTypeCommission 交易类型-分佣(已废弃,使用 AgentTransactionTypeCommission // TransactionTypeCommission 交易类型-分佣(已废弃,使用 AgentTransactionTypeCommission
@@ -187,11 +187,46 @@ const TransactionTypeCommission = AgentTransactionTypeCommission
// TransactionTypeWithdrawal 交易类型-提现(已废弃,使用 AgentTransactionTypeWithdrawal // TransactionTypeWithdrawal 交易类型-提现(已废弃,使用 AgentTransactionTypeWithdrawal
const TransactionTypeWithdrawal = AgentTransactionTypeWithdrawal const TransactionTypeWithdrawal = AgentTransactionTypeWithdrawal
// RechargeOrderPrefix 充值订单号前缀(已废弃,使用 AgentRechargeOrderPrefix 或 CardRechargeOrderPrefix // RechargeOrderPrefix 充值订单号前缀(已废弃,使用 AgentRechargeOrderPrefix 或 AssetRechargeOrderPrefix
const RechargeOrderPrefix = "RCH" const RechargeOrderPrefix = "RCH"
// RechargeMinAmount 最小充值金额(已废弃,使用 AgentRechargeMinAmount 或 CardRechargeMinAmount // RechargeMinAmount 最小充值金额(已废弃,使用 AgentRechargeMinAmount 或 AssetRechargeMinAmount
const RechargeMinAmount = CardRechargeMinAmount const RechargeMinAmount = AssetRechargeMinAmount
// RechargeMaxAmount 最大充值金额(已废弃,使用 AgentRechargeMaxAmount 或 CardRechargeMaxAmount // RechargeMaxAmount 最大充值金额(已废弃,使用 AgentRechargeMaxAmount 或 AssetRechargeMaxAmount
const RechargeMaxAmount = CardRechargeMaxAmount const RechargeMaxAmount = AssetRechargeMaxAmount
// ========== Card* 废弃别名(向后兼容)==========
// Deprecated: 使用 AssetWalletResourceTypeIotCard
const CardWalletResourceTypeIotCard = AssetWalletResourceTypeIotCard
// Deprecated: 使用 AssetWalletResourceTypeDevice
const CardWalletResourceTypeDevice = AssetWalletResourceTypeDevice
// Deprecated: 使用 AssetWalletStatusNormal
const CardWalletStatusNormal = AssetWalletStatusNormal
// Deprecated: 使用 AssetWalletStatusFrozen
const CardWalletStatusFrozen = AssetWalletStatusFrozen
// Deprecated: 使用 AssetWalletStatusClosed
const CardWalletStatusClosed = AssetWalletStatusClosed
// Deprecated: 使用 AssetTransactionTypeRecharge
const CardTransactionTypeRecharge = AssetTransactionTypeRecharge
// Deprecated: 使用 AssetTransactionTypeDeduct
const CardTransactionTypeDeduct = AssetTransactionTypeDeduct
// Deprecated: 使用 AssetTransactionTypeRefund
const CardTransactionTypeRefund = AssetTransactionTypeRefund
// Deprecated: 使用 AssetRechargeOrderPrefix
const CardRechargeOrderPrefix = AssetRechargeOrderPrefix
// Deprecated: 使用 AssetRechargeMinAmount
const CardRechargeMinAmount = AssetRechargeMinAmount
// Deprecated: 使用 AssetRechargeMaxAmount
const CardRechargeMaxAmount = AssetRechargeMaxAmount

View File

@@ -126,13 +126,21 @@ const (
CodePollingCleanupConfigNotFound = 1155 // 数据清理配置不存在 CodePollingCleanupConfigNotFound = 1155 // 数据清理配置不存在
CodePollingManualTriggerLimit = 1156 // 手动触发次数已达上限 CodePollingManualTriggerLimit = 1156 // 手动触发次数已达上限
// 套餐相关错误 (1160-1179) // 套餐相关错误 (1160-1169)
CodeNoAvailablePackage = 1160 // 没有可用套餐 CodeNoAvailablePackage = 1160 // 没有可用套餐
CodePackageActivationConflict = 1161 // 套餐正在激活中 CodePackageActivationConflict = 1161 // 套餐正在激活中
CodeNoMainPackage = 1162 // 必须有主套餐才能购买加油包 CodeNoMainPackage = 1162 // 必须有主套餐才能购买加油包
CodeRealnameRequired = 1163 // 设备/卡必须先完成实名认证才能购买套餐 CodeRealnameRequired = 1163 // 设备/卡必须先完成实名认证才能购买套餐
CodeMixedOrderForbidden = 1164 // 同订单不能同时购买正式套餐和加油包 CodeMixedOrderForbidden = 1164 // 同订单不能同时购买正式套餐和加油包
// 微信配置相关错误 (1170-1179)
CodeWechatConfigNotFound = 1170 // 微信支付配置不存在
CodeWechatConfigActive = 1171 // 不能删除/操作当前生效的支付配置
CodeWechatConfigHasPendingOrders = 1172 // 该配置存在未完成的支付订单
CodeFuiouPayFailed = 1173 // 富友支付发起失败
CodeFuiouCallbackInvalid = 1174 // 富友回调签名验证失败
CodeNoPaymentConfig = 1175 // 当前无可用的支付配置
// 服务端错误 (2000-2999) -> 5xx HTTP 状态码 // 服务端错误 (2000-2999) -> 5xx HTTP 状态码
CodeInternalError = 2001 // 内部服务器错误 CodeInternalError = 2001 // 内部服务器错误
CodeDatabaseError = 2002 // 数据库错误 CodeDatabaseError = 2002 // 数据库错误
@@ -244,6 +252,12 @@ var allErrorCodes = []int{
CodeNoMainPackage, CodeNoMainPackage,
CodeRealnameRequired, CodeRealnameRequired,
CodeMixedOrderForbidden, CodeMixedOrderForbidden,
CodeWechatConfigNotFound,
CodeWechatConfigActive,
CodeWechatConfigHasPendingOrders,
CodeFuiouPayFailed,
CodeFuiouCallbackInvalid,
CodeNoPaymentConfig,
CodeInternalError, CodeInternalError,
CodeDatabaseError, CodeDatabaseError,
CodeRedisError, CodeRedisError,
@@ -353,6 +367,12 @@ var errorMessages = map[int]string{
CodeNoMainPackage: "必须有主套餐才能购买加油包", CodeNoMainPackage: "必须有主套餐才能购买加油包",
CodeRealnameRequired: "设备/卡必须先完成实名认证才能购买套餐", CodeRealnameRequired: "设备/卡必须先完成实名认证才能购买套餐",
CodeMixedOrderForbidden: "同订单不能同时购买正式套餐和加油包", CodeMixedOrderForbidden: "同订单不能同时购买正式套餐和加油包",
CodeWechatConfigNotFound: "微信支付配置不存在",
CodeWechatConfigActive: "不能删除当前生效的支付配置,请先停用",
CodeWechatConfigHasPendingOrders: "该配置存在未完成的支付订单,暂时无法删除",
CodeFuiouPayFailed: "支付发起失败,请重试",
CodeFuiouCallbackInvalid: "支付回调签名验证失败",
CodeNoPaymentConfig: "当前无可用的支付配置,请联系管理员",
CodeInvalidCredentials: "用户名或密码错误", CodeInvalidCredentials: "用户名或密码错误",
CodeAccountLocked: "账号已锁定", CodeAccountLocked: "账号已锁定",
CodePasswordExpired: "密码已过期", CodePasswordExpired: "密码已过期",

View File

@@ -5,7 +5,6 @@ import (
"github.com/ArtisanCloud/PowerWeChat/v3/src/kernel" "github.com/ArtisanCloud/PowerWeChat/v3/src/kernel"
"github.com/ArtisanCloud/PowerWeChat/v3/src/officialAccount" "github.com/ArtisanCloud/PowerWeChat/v3/src/officialAccount"
"github.com/ArtisanCloud/PowerWeChat/v3/src/payment"
"github.com/break/junhong_cmp_fiber/pkg/config" "github.com/break/junhong_cmp_fiber/pkg/config"
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
"go.uber.org/zap" "go.uber.org/zap"
@@ -50,36 +49,3 @@ func NewOfficialAccountApp(cfg *config.Config, cache kernel.CacheInterface, logg
logger.Info("微信公众号应用初始化成功", zap.String("app_id", oaCfg.AppID)) logger.Info("微信公众号应用初始化成功", zap.String("app_id", oaCfg.AppID))
return app, nil return app, nil
} }
// NewPaymentApp 创建微信支付应用实例
func NewPaymentApp(cfg *config.Config, cache kernel.CacheInterface, logger *zap.Logger) (*payment.Payment, error) {
payCfg := cfg.Wechat.Payment
if payCfg.AppID == "" || payCfg.MchID == "" {
return nil, fmt.Errorf("微信支付配置不完整:缺少 AppID 或 MchID")
}
userConfig := &payment.UserConfig{
AppID: payCfg.AppID,
MchID: payCfg.MchID,
MchApiV3Key: payCfg.APIV3Key,
Key: payCfg.APIV2Key,
CertPath: payCfg.CertPath,
KeyPath: payCfg.KeyPath,
SerialNo: payCfg.SerialNo,
NotifyURL: payCfg.NotifyURL,
HttpDebug: payCfg.HttpDebug,
Cache: cache,
}
app, err := payment.NewPayment(userConfig)
if err != nil {
logger.Error("创建微信支付应用失败", zap.Error(err))
return nil, fmt.Errorf("创建微信支付应用失败: %w", err)
}
logger.Info("微信支付应用初始化成功",
zap.String("app_id", payCfg.AppID),
zap.String("mch_id", payCfg.MchID),
)
return app, nil
}