300 lines
11 KiB
Go
300 lines
11 KiB
Go
package wechatrepoimpl
|
||
|
||
import (
|
||
"fmt"
|
||
"strings"
|
||
|
||
"github.com/go-kratos/kratos/v2/errors"
|
||
err2 "voucher/api/err"
|
||
)
|
||
|
||
// ErrCode 定义错误码类型
|
||
// https://pay.weixin.qq.com/doc/v3/merchant/4012463767
|
||
type ErrCode string
|
||
|
||
// 定义错误码常量
|
||
const (
|
||
APPID_MCHID_NOT_MATCH ErrCode = "APPID_MCHID_NOT_MATCH"
|
||
INVALID_REQUEST ErrCode = "INVALID_REQUEST"
|
||
PARAM_ERROR ErrCode = "PARAM_ERROR"
|
||
MCH_NOT_EXISTS ErrCode = "MCH_NOT_EXISTS"
|
||
NOT_ENOUGH ErrCode = "NOT_ENOUGH"
|
||
REQUEST_BLOCKED ErrCode = "REQUEST_BLOCKED"
|
||
RULE_LIMIT ErrCode = "RULE_LIMIT"
|
||
USER_ACCOUNT_ABNORMAL ErrCode = "USER_ACCOUNT_ABNORMAL"
|
||
RESOURCE_NOT_EXISTS ErrCode = "RESOURCE_NOT_EXISTS"
|
||
FREQUENCY_LIMITED ErrCode = "FREQUENCY_LIMITED"
|
||
)
|
||
|
||
// APIError 定义 API 错误结构体
|
||
type APIError struct {
|
||
StatusCode int `json:"status_code"`
|
||
ErrorCode ErrCode `json:"error_code"`
|
||
Description string `json:"description"`
|
||
Hint string `json:"hint"`
|
||
}
|
||
|
||
// 定义错误映射,方便根据错误码获取错误信息
|
||
var _ = map[ErrCode][]APIError{
|
||
APPID_MCHID_NOT_MATCH: {
|
||
{
|
||
StatusCode: 400,
|
||
ErrorCode: APPID_MCHID_NOT_MATCH,
|
||
Description: "商户号与AppID不匹配",
|
||
Hint: "调用接口的商户号需与接口传入的AppID有绑定关系,请参考常见问题Q4",
|
||
},
|
||
},
|
||
INVALID_REQUEST: {
|
||
{
|
||
StatusCode: 400,
|
||
ErrorCode: INVALID_REQUEST,
|
||
Description: "OpenID与AppID不匹配",
|
||
Hint: "OpenID与AppID需有对应关系",
|
||
},
|
||
{
|
||
StatusCode: 400,
|
||
ErrorCode: INVALID_REQUEST,
|
||
Description: "非法的商户号",
|
||
Hint: "请检查商户号准确性",
|
||
},
|
||
{
|
||
StatusCode: 400,
|
||
ErrorCode: INVALID_REQUEST,
|
||
Description: "调用频率过高",
|
||
Hint: "请降低API调用频率",
|
||
},
|
||
{
|
||
StatusCode: 400,
|
||
ErrorCode: INVALID_REQUEST,
|
||
Description: "活动已结束或未激活",
|
||
Hint: "请检查批次状态",
|
||
},
|
||
{
|
||
StatusCode: 400,
|
||
ErrorCode: INVALID_REQUEST,
|
||
Description: "批次信息获取失败,请确认参数是否有误",
|
||
Hint: "请检查创建商户号与批次号的对应关系",
|
||
},
|
||
},
|
||
PARAM_ERROR: {
|
||
{
|
||
StatusCode: 400,
|
||
ErrorCode: PARAM_ERROR,
|
||
Description: "AppID必填",
|
||
Hint: "请输入AppID",
|
||
},
|
||
{
|
||
StatusCode: 400,
|
||
ErrorCode: PARAM_ERROR,
|
||
Description: "OpenID必填",
|
||
Hint: "请输入OpenID",
|
||
},
|
||
{
|
||
StatusCode: 400,
|
||
ErrorCode: PARAM_ERROR,
|
||
Description: "批次号必填",
|
||
Hint: "请输入批次号",
|
||
},
|
||
{
|
||
StatusCode: 400,
|
||
ErrorCode: PARAM_ERROR,
|
||
Description: "商户号必填",
|
||
Hint: "请输入商户号",
|
||
},
|
||
{
|
||
StatusCode: 400,
|
||
ErrorCode: PARAM_ERROR,
|
||
Description: "非法的批次状态",
|
||
Hint: "请检查批次状态,仅支持发放状态为“运营中”的代金券批次",
|
||
},
|
||
},
|
||
MCH_NOT_EXISTS: {
|
||
{
|
||
StatusCode: 403,
|
||
ErrorCode: MCH_NOT_EXISTS,
|
||
Description: "商户号不合法",
|
||
Hint: "请检查商户号准确性",
|
||
},
|
||
},
|
||
NOT_ENOUGH: {
|
||
{
|
||
StatusCode: 403,
|
||
ErrorCode: NOT_ENOUGH,
|
||
Description: "批次预算不足",
|
||
Hint: "批次预算已发放完,请补充批次预算",
|
||
},
|
||
{
|
||
StatusCode: 403,
|
||
ErrorCode: NOT_ENOUGH,
|
||
Description: "发券超过单天限额",
|
||
Hint: "已超过该批次设置的单天发放限制额度,无法发放",
|
||
},
|
||
{
|
||
StatusCode: 403,
|
||
ErrorCode: NOT_ENOUGH,
|
||
Description: "账户余额不足,请充值",
|
||
Hint: "商户号余额不足,无法继续发券,请充值",
|
||
},
|
||
{
|
||
StatusCode: 403,
|
||
ErrorCode: NOT_ENOUGH,
|
||
Description: "批次预算耗尽",
|
||
Hint: "该批次的预算已经耗尽",
|
||
},
|
||
},
|
||
REQUEST_BLOCKED: {
|
||
{
|
||
StatusCode: 403,
|
||
ErrorCode: REQUEST_BLOCKED,
|
||
Description: "商户无权发券",
|
||
Hint: "该批次不支持其他商户发放,请参考常见问题Q1",
|
||
},
|
||
{
|
||
StatusCode: 403,
|
||
ErrorCode: REQUEST_BLOCKED,
|
||
Description: "批次不支持跨商户发券",
|
||
Hint: "该批次不支持其他商户发放,请参考常见问题Q1",
|
||
},
|
||
{
|
||
StatusCode: 403,
|
||
ErrorCode: REQUEST_BLOCKED,
|
||
Description: "用户被限领拦截",
|
||
Hint: "该用户已达到该批次的领取上限,请参考常见问题Q6",
|
||
},
|
||
{
|
||
StatusCode: 403,
|
||
ErrorCode: REQUEST_BLOCKED,
|
||
Description: "不能在API渠道发放",
|
||
Hint: "请检查批次信息,仅支持发放微信支付代金券,不支持发放立减与折扣",
|
||
},
|
||
{
|
||
StatusCode: 403,
|
||
ErrorCode: REQUEST_BLOCKED,
|
||
Description: "不支持指定面额发券",
|
||
Hint: "仅在发券时指定面额及门槛的场景才生效,常规发券场景请勿传入该信息",
|
||
},
|
||
{
|
||
StatusCode: 403,
|
||
ErrorCode: REQUEST_BLOCKED,
|
||
Description: "仅在广告场景下发放批次",
|
||
Hint: "该批次已在朋友圈广告发放,不支持在其他渠道发放",
|
||
},
|
||
},
|
||
RULE_LIMIT: {
|
||
{
|
||
StatusCode: 403,
|
||
ErrorCode: RULE_LIMIT,
|
||
Description: "用户已达最大领券次数",
|
||
Hint: "该用户已达到该批次的领取上限,请参考常见问题Q6",
|
||
},
|
||
{
|
||
StatusCode: 403,
|
||
ErrorCode: RULE_LIMIT,
|
||
Description: "被自然人规则拦截",
|
||
Hint: "该自然人已达到该批次的领取上限,请参考常见问题Q6",
|
||
},
|
||
},
|
||
USER_ACCOUNT_ABNORMAL: {
|
||
{
|
||
StatusCode: 403,
|
||
ErrorCode: USER_ACCOUNT_ABNORMAL,
|
||
Description: "用户非法",
|
||
Hint: "用户命中微信支付风控模型,请参考常见问题Q5",
|
||
},
|
||
},
|
||
RESOURCE_NOT_EXISTS: {
|
||
{
|
||
StatusCode: 404,
|
||
ErrorCode: RESOURCE_NOT_EXISTS,
|
||
Description: "批次不存在",
|
||
Hint: "请检查批次及制券商户号信息",
|
||
},
|
||
},
|
||
FREQUENCY_LIMITED: {
|
||
{
|
||
StatusCode: 429,
|
||
ErrorCode: FREQUENCY_LIMITED,
|
||
Description: "当前请求人数过多,请稍后重试",
|
||
Hint: "请降低API调用频率",
|
||
},
|
||
},
|
||
}
|
||
|
||
// 使用常量定义错误描述,减少硬编码
|
||
const (
|
||
ErrorUserIllegal = "用户非法"
|
||
ErrorAppIDMchIDMismatch = "商户号与AppID不匹配"
|
||
ErrorOpenIDAppIDMismatch = "OpenID与AppID不匹配"
|
||
ErrorInvalidMerchantID = "非法的商户号"
|
||
ErrorHighFrequency = "调用频率过高"
|
||
ErrorActivityInactive = "活动已结束或未激活"
|
||
ErrorBatchInfoError = "批次信息获取失败,请确认参数是否有误"
|
||
ErrorAppIDRequired = "AppID必填"
|
||
ErrorOpenIDRequired = "OpenID必填"
|
||
ErrorBatchIDRequired = "批次号必填"
|
||
ErrorMerchantIDRequired = "商户号必填"
|
||
ErrorInvalidBatchStatus = "非法的批次状态"
|
||
ErrorMchNotExists = "商户号不合法"
|
||
ErrorBatchBudgetInsufficient = "批次预算不足"
|
||
ErrorDailyLimitExceeded = "发券超过单天限额"
|
||
ErrorAccountBalanceInsufficient = "账户余额不足,请充值"
|
||
ErrorBatchBudgetDepleted = "批次预算耗尽"
|
||
ErrorMerchantNoPermission = "商户无权发券"
|
||
ErrorCrossMerchantNotSupported = "批次不支持跨商户发券"
|
||
ErrorUserReceiveLimit = "用户被限领拦截"
|
||
ErrorAPIChannelNotSupported = "不能在API渠道发放"
|
||
ErrorSpecifiedDenominationNotSupported = "不支持指定面额发券"
|
||
ErrorOnlyAdvertisingBatch = "仅在广告场景下发放批次"
|
||
ErrorUserMaxCoupons = "用户已达最大领券次数"
|
||
ErrorNaturalPersonRuleBlocked = "被自然人规则拦截"
|
||
ErrorResourceNotExists = "批次不存在"
|
||
ErrorFrequencyLimited = "当前请求人数过多,请稍后重试"
|
||
)
|
||
|
||
// WechatError 映射错误描述到具体的错误处理
|
||
var WechatError = map[string]*errors.Error{
|
||
ErrorUserIllegal: err2.ErrorWechatUserIllegal(ErrorUserIllegal),
|
||
ErrorAppIDMchIDMismatch: err2.ErrorWechatMismatch(ErrorAppIDMchIDMismatch),
|
||
ErrorOpenIDAppIDMismatch: err2.ErrorWechatMismatch(ErrorOpenIDAppIDMismatch),
|
||
ErrorInvalidMerchantID: err2.ErrorWechatInvalidMerchantID(ErrorInvalidMerchantID),
|
||
ErrorHighFrequency: err2.ErrorWechatHighFrequency(ErrorHighFrequency),
|
||
ErrorActivityInactive: err2.ErrorWechatActivityInactive(ErrorActivityInactive),
|
||
ErrorBatchInfoError: err2.ErrorWechatBatchInfoError(ErrorBatchInfoError),
|
||
ErrorAppIDRequired: err2.ErrorWechatParamRequired(ErrorAppIDRequired),
|
||
ErrorOpenIDRequired: err2.ErrorWechatParamRequired(ErrorOpenIDRequired),
|
||
ErrorBatchIDRequired: err2.ErrorWechatParamRequired(ErrorBatchIDRequired),
|
||
ErrorMerchantIDRequired: err2.ErrorWechatParamRequired(ErrorMerchantIDRequired),
|
||
ErrorInvalidBatchStatus: err2.ErrorWechatInvalidBatchStatus(ErrorInvalidBatchStatus),
|
||
ErrorMchNotExists: err2.ErrorWechatMchNotExists(ErrorMchNotExists),
|
||
ErrorBatchBudgetInsufficient: err2.ErrorWechatBatchBudgetInsufficient(ErrorBatchBudgetInsufficient),
|
||
ErrorDailyLimitExceeded: err2.ErrorWechatDailyLimitExceeded(ErrorDailyLimitExceeded),
|
||
ErrorAccountBalanceInsufficient: err2.ErrorWechatAccountBalanceInsufficient(ErrorAccountBalanceInsufficient),
|
||
ErrorBatchBudgetDepleted: err2.ErrorWechatBatchBudgetDepleted(ErrorBatchBudgetDepleted),
|
||
ErrorMerchantNoPermission: err2.ErrorWechatMerchantNoPermission(ErrorMerchantNoPermission),
|
||
ErrorCrossMerchantNotSupported: err2.ErrorWechatCrossMerchantNotSupported(ErrorCrossMerchantNotSupported),
|
||
ErrorUserReceiveLimit: err2.ErrorWechatUserReceiveLimit(ErrorUserReceiveLimit),
|
||
ErrorAPIChannelNotSupported: err2.ErrorWechatAPIChannelNotSupported(ErrorAPIChannelNotSupported),
|
||
ErrorSpecifiedDenominationNotSupported: err2.ErrorWechatSpecifiedDenominationNotSupported(ErrorSpecifiedDenominationNotSupported),
|
||
ErrorOnlyAdvertisingBatch: err2.ErrorWechatOnlyAdvertisingBatch(ErrorOnlyAdvertisingBatch),
|
||
ErrorUserMaxCoupons: err2.ErrorWechatUserMaxCoupons(ErrorUserMaxCoupons),
|
||
ErrorNaturalPersonRuleBlocked: err2.ErrorWechatNaturalPersonRuleBlocked(ErrorNaturalPersonRuleBlocked),
|
||
ErrorResourceNotExists: err2.ErrorWechatResourceNotExists(ErrorResourceNotExists),
|
||
ErrorFrequencyLimited: err2.ErrorWechatFrequencyLimited(ErrorFrequencyLimited),
|
||
}
|
||
|
||
type ErrBody struct {
|
||
Code ErrCode `json:"Code"`
|
||
Message string `json:"Message"`
|
||
}
|
||
|
||
// GetWechatError 根据错误描述获取具体的错误处理
|
||
func (s ErrBody) GetWechatError() *errors.Error {
|
||
lowerDesc := strings.ToLower(s.Message)
|
||
for desc, err := range WechatError {
|
||
if strings.ToLower(desc) == lowerDesc {
|
||
return err
|
||
}
|
||
}
|
||
return err2.ErrorWechatFAIL(fmt.Sprintf("微信返回错误:%s", s.Message))
|
||
}
|