docs(exception): 给 OperationFailException 抛出点补充中文注释

This commit is contained in:
DaxPay Dev
2026-07-28 09:23:29 +08:00
parent a6d3363583
commit fb205727e2
9 changed files with 43 additions and 8 deletions

View File

@@ -128,6 +128,7 @@ public class PayCloseService {
throw re;
}
}
// 支付: 关闭订单失败
throw new OperationFailException(CommonCode.FAIL_CODE, "pay.error.pay.closeFailed");
}
},

View File

@@ -177,6 +177,7 @@ public class GatewayPayAssistService {
PlatformUrlConfig urlConfig = platformUrlConfigService.getUrlConfig();
String gatewayBase = urlConfig.getPaymentGatewayBaseUrl();
if (StrUtil.isBlank(gatewayBase)) {
// 网关: 支付网关前端地址未配置
throw new OperationFailException(CommonCode.FAIL_CODE, "error.common.gatewayUrlNotConfigured");
}
gatewayBase = StrUtil.removeSuffix(gatewayBase, "/");

View File

@@ -142,9 +142,11 @@ public class MchTerminalDeviceService {
.orElseThrow(() -> new DataNotExistException("error.device.terminal.channelNotFound"));
if (!Objects.equals(system.getMchNo(), channel.getMchNo())
|| !Objects.equals(channel.getMchNo(), requireMchNo())) {
// 终端: 系统终端与通道终端须属于同一商户
throw new OperationFailException(CommonCode.FAIL_CODE, "error.device.terminal.mchMismatch");
}
if (terminalChannelBindManager.existsBind(param.getSystemTerminalNo(), param.getChannelTerminalId())) {
// 终端: 绑定关系已存在
throw new OperationFailException(CommonCode.FAIL_CODE, "error.device.terminal.bindExists");
}
TerminalChannelBind bind = new TerminalChannelBind();
@@ -161,6 +163,7 @@ public class MchTerminalDeviceService {
.orElseThrow(() -> new DataNotExistException("error.device.terminal.systemNotFound"));
this.checkTerminal(system);
if (!terminalChannelBindManager.existsBind(param.getSystemTerminalNo(), param.getChannelTerminalId())) {
// 终端: 绑定关系不存在
throw new OperationFailException(CommonCode.FAIL_CODE, "error.device.terminal.bindNotFound");
}
terminalChannelBindManager.deleteBind(param.getSystemTerminalNo(), param.getChannelTerminalId());
@@ -212,6 +215,7 @@ public class MchTerminalDeviceService {
MchStoreInfo store = mchStoreInfoManager.findByStoreNo(storeNo)
.orElseThrow(() -> new DataNotExistException("error.payment.merchant.storeNotFound"));
if (!Objects.equals(store.getMchNo(), mchNo)) {
// 商户: 门店不属于当前商户
throw new OperationFailException(CommonCode.FAIL_CODE, "error.payment.merchant.storeNoMatch");
}
return storeNo;

View File

@@ -102,13 +102,14 @@ public class CodePayAssistService {
/// 码牌发起支付: 普通订单 + source=cashier_code; 策略仅读码牌配置
public NormalPayResult pay(CodePayParam param) {
DeviceQrCode entity = this.loadEnabledAssigned(param.getCode());
var entity = this.loadEnabledAssigned(param.getCode());
merchantContextLoader.initMch(entity.getMchNo());
var mchApp = merchantContextLoader.resolveApp(entity.getMchNo(), entity.getAppId());
// 获取金额
long amount = this.resolveAmount(entity, param.getAmount());
ClientEnvEnum clientEnv = ClientEnvEnum.findByCode(param.getClientEnv());
if (clientEnv == ClientEnvEnum.BROWSER) {
// 码牌: 当前打开环境不支持码牌支付, 请使用微信/支付宝等扫码
throw new OperationFailException(CommonCode.FAIL_CODE, "error.device.qrcode.clientEnvNotSupport");
}
@@ -119,6 +120,7 @@ public class CodePayAssistService {
var resolved = codePayResolveService.resolveRequired(mchApp.getAppId(), clientEnv, payForm);
// JSAPI/MINI 必须已在授权回跳页换好 openId支付只带 openId、禁止支付时再换 code
if (PayMethodOpenIdSupport.needsOpenId(resolved.method()) && StrUtil.isBlank(param.getOpenId())) {
// 码牌: 当前支付方式需要 openId, 请先完成授权
throw new OperationFailException(CommonCode.FAIL_CODE, "error.device.qrcode.openIdRequired");
}
@@ -158,12 +160,14 @@ public class CodePayAssistService {
ClientEnvEnum clientEnv = ClientEnvEnum.findByCode(param.getClientEnv());
if (clientEnv == ClientEnvEnum.BROWSER) {
// 码牌: 当前打开环境不支持码牌支付, 请使用微信/支付宝等扫码
throw new OperationFailException(CommonCode.FAIL_CODE, "error.device.qrcode.clientEnvNotSupport");
}
CodePayFormEnum payForm = CodePayFormEnum.fromProgramType(entity.getProgramType());
var resolved = codePayResolveService.resolveRequired(mchApp.getAppId(), clientEnv, payForm);
if (!PayMethodOpenIdSupport.canAcquireOpenId(resolved.method(), clientEnv)) {
// 当前支付方式/环境无法走 OAuth付款码/APP/PC/外部浏览器/union_pay 一期)
// 码牌: 当前支付方式/环境不需要授权
throw new OperationFailException(CommonCode.FAIL_CODE, "error.device.qrcode.authNotRequired");
}
@@ -230,9 +234,11 @@ public class CodePayAssistService {
DeviceQrCode entity = deviceQrCodeManager.findByCode(code)
.orElseThrow(() -> new DataNotExistException("error.device.qrcode.notFound"));
if (!QrCodeStatusEnum.ENABLED.getCode().equals(entity.getStatus())) {
// 码牌: 码牌未启用
throw new OperationFailException(CommonCode.FAIL_CODE, "error.device.qrcode.disabled");
}
if (StrUtil.isBlank(entity.getMchNo())) {
// 码牌: 码牌未分配商户
throw new OperationFailException(CommonCode.FAIL_CODE, "error.device.qrcode.notAssigned");
}
return entity;
@@ -242,11 +248,13 @@ public class CodePayAssistService {
QrCodeAmountTypeEnum amountType = QrCodeAmountTypeEnum.findByCode(entity.getAmountType());
if (amountType == QrCodeAmountTypeEnum.FIXED) {
if (entity.getFixedAmount() == null || entity.getFixedAmount() <= 0) {
// 码牌: 固定金额必须大于0
throw new OperationFailException(CommonCode.FAIL_CODE, "error.device.qrcode.fixedAmountInvalid");
}
return entity.getFixedAmount();
}
if (requestAmount == null || requestAmount <= 0) {
// 码牌: 金额必须大于0
throw new OperationFailException(CommonCode.FAIL_CODE, "error.device.qrcode.amountRequired");
}
return requestAmount;
@@ -256,6 +264,7 @@ public class CodePayAssistService {
private String resolveMethod(DeviceQrCode entity, String clientEnvCode) {
ClientEnvEnum clientEnv = ClientEnvEnum.findByCode(clientEnvCode);
if (clientEnv == ClientEnvEnum.BROWSER) {
// 码牌: 当前打开环境不支持码牌支付, 请使用微信/支付宝等扫码
throw new OperationFailException(CommonCode.FAIL_CODE, "error.device.qrcode.clientEnvNotSupport");
}
merchantContextLoader.initMch(entity.getMchNo());
@@ -294,7 +303,10 @@ public class CodePayAssistService {
case ALIPAY -> "alipay";
case UNION_PAY -> "union-pay";
case DOUYIN -> "douyin";
default -> throw new OperationFailException(CommonCode.FAIL_CODE, "error.device.qrcode.clientEnvNotSupport");
default -> {
// 码牌: 不支持的客户端环境, 无法确定分端页
throw new OperationFailException(CommonCode.FAIL_CODE, "error.device.qrcode.clientEnvNotSupport");
}
};
return "/h/" + segment + "/" + code + "?authed=1";
}

View File

@@ -85,21 +85,22 @@ public class SocialAutoLoginConfigService {
}
List<String> sources = this.resolveParamSources(item);
if (CollUtil.isEmpty(sources)) {
// 开启自动登录时必须至少选择一个平台
// 社交登录: 开启自动登录时必须至少选择一个平台
throw new OperationFailException("error.social.autoLogin.sourceRequired", clientCode);
}
for (String code : sources) {
if (!AUTO_LOGIN_ALLOWED_SOURCES.contains(code)) {
// 所选平台不支持应用内自动登录(如微信开放平台扫码)
// 社交登录: 所选平台不支持应用内自动登录(如微信开放平台扫码)
throw new OperationFailException("error.social.autoLogin.sourceNotAllowed", code);
}
SocialSourceEnum source = SocialSourceEnum.of(code);
if (source == null) {
// 社交登录: 不支持的平台
throw new OperationFailException("error.social.unsupportedSource");
}
SocialLoginConfig enabled = socialLoginConfigService.findEnabledBySource(code);
if (enabled == null) {
// 所选平台未配置或未启用
// 社交登录: 所选平台未配置或未启用
throw new OperationFailException("error.social.autoLogin.sourceNotEnabled", code);
}
}

View File

@@ -91,6 +91,7 @@ public class SocialLoginConfigService {
public void update(SocialLoginConfigParam param) {
SocialSourceEnum socialSource = SocialSourceEnum.of(param.getSource());
if (socialSource == null) {
// 社交登录: 不支持的平台
throw new OperationFailException("error.social.unsupportedSource");
}
// 跳转型(SocialSourceEnum.isPlatformRedirect, 如 ALIPAY): 不校验/不写入 clientId, 只启停
@@ -100,6 +101,7 @@ public class SocialLoginConfigService {
}
// 标准 OAuth 平台: clientId 必填
if (StrUtil.isBlank(param.getClientId())) {
// 社交登录: 平台未配置, 请先填写 clientId
throw new OperationFailException("error.social.notConfigured");
}
SocialLoginConfig entity = socialLoginConfigManager.findBySource(param.getSource())
@@ -116,6 +118,7 @@ public class SocialLoginConfigService {
public void updateEnabled(String source, Boolean enabled) {
SocialSourceEnum socialSource = SocialSourceEnum.of(source);
if (socialSource == null) {
// 社交登录: 不支持的平台
throw new OperationFailException("error.social.unsupportedSource");
}
if (this.isPlatformRedirectSource(socialSource)) {
@@ -130,6 +133,7 @@ public class SocialLoginConfigService {
.orElseThrow(() -> new OperationFailException("error.social.configNotExist"));
// 社交登录: 未配置平台不允许启停
if (!entity.isConfigured()) {
// 社交登录: 平台未配置, 请先填写 clientId
throw new OperationFailException("error.social.notConfigured");
}
entity.setEnabled(enabled);

View File

@@ -141,6 +141,7 @@ public class SocialLoginService {
// 按 client 解析前端 baseUrl
String baseUrl = this.resolveBaseUrl(socialClient);
if (StrUtil.isBlank(baseUrl)) {
// 社交登录: 运营/商户端前端地址未配置
throw new OperationFailException(this.endpointMissingKey(socialClient));
}
SocialAuthMode authMode = this.resolveMode(mode);
@@ -231,6 +232,7 @@ public class SocialLoginService {
// 当前用户必须属于该身份域, 防止跨端绑定
UserInfoResult userInfo = userQueryService.findById(userId);
if (!Objects.equals(clientCode, userInfo.getClientCode())) {
// 社交登录: 绑定用户不属于当前终端
throw new OperationFailException("error.social.bind.clientMismatch");
}
String baseUrl = this.requireBaseUrl(socialClient);
@@ -270,6 +272,7 @@ public class SocialLoginService {
SocialAuthConfig authConfig = socialLoginConfigService.buildAuthConfig(config, redirectUri);
SocialSourceEnum socialSource = SocialSourceEnum.of(source);
if (socialSource == null) {
// 社交登录: 不支持的平台
throw new OperationFailException("error.social.unsupportedSource");
}
// 公众号: 凭据来自平台级配置
@@ -285,6 +288,7 @@ public class SocialLoginService {
}
PlatformWechatMpAuthConfig mp = platformWechatMpAuthConfigService.getWechatMpAuthConfig();
if (mp == null || StrUtil.isBlank(mp.getAppId()) || StrUtil.isBlank(mp.getAppSecret())) {
// 社交登录: 微信公众号配置不完整
throw new OperationFailException("error.social.wechatMpNotConfigured");
}
authConfig.setClientId(mp.getAppId());
@@ -315,7 +319,10 @@ public class SocialLoginService {
/// 校验并解析社交登录终端(仅 admin/merchant)
private SocialClientEnum requireSocialClient(String clientCode) {
return SocialClientEnum.findByCode(clientCode)
.orElseThrow(() -> new OperationFailException("error.social.unsupportedClient"));
.orElseThrow(() -> {
// 社交登录: 不支持的终端编码(仅 admin/merchant)
throw new OperationFailException("error.social.unsupportedClient");
});
}
/// 解析并校验 baseUrl 非空

View File

@@ -81,13 +81,18 @@ public class WechatMessageRecordService {
/// 重发(仅公众号模板消息, 只允许重发失败的记录)
public void resend(Long recordId) {
WechatMessageRecord record = recordManager.findById(recordId)
.orElseThrow(() -> new OperationFailException("error.channel.wechat.messageRecordNotExist"));
.orElseThrow(() -> {
// 微信: 消息记录不存在
throw new OperationFailException("error.channel.wechat.messageRecordNotExist");
});
if (!STATUS_FAILED.equals(record.getStatus())) {
// 微信: 只允许重发失败的记录
throw new OperationFailException("error.channel.wechat.onlyFailedCanResend");
}
// 从三方平台取 AppId/AppSecret
PlatformWechatMpAuthConfig auth = mpAuthConfigService.getWechatMpAuthConfig();
if (StrUtil.isBlank(auth.getAppId()) || StrUtil.isBlank(auth.getAppSecret())) {
// 微信: 公众号授权配置不完整
throw new OperationFailException("error.channel.wechat.mpAuthConfigIncomplete");
}
// 构造发送参数