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)) }