fix(withdrawal): preserve callback HTTP status

This commit is contained in:
hy001 2026-07-20 16:33:29 +08:00
parent 4ebfb3cc6b
commit c09787831c

View File

@ -1,6 +1,8 @@
package com.red.circle.console.adapter.integration;
import com.red.circle.console.app.service.app.user.UserBankBalanceBackService;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.ResponseErrorCode;
import com.red.circle.wallet.inner.model.cmd.ApprovalMoneyApplyCmd;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
@ -12,7 +14,6 @@ import java.util.List;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
@ -20,7 +21,6 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;
/**
* hyapp-server 统一提现双审对 ChatApp3/Yumi 钱包的终态回调入口.
@ -43,22 +43,24 @@ public class WithdrawalReviewIntegrationController {
@RequestHeader(value = "Authorization", required = false) String authorization,
@RequestBody @Valid DecisionRequest request) {
verifyToken(authorization);
if (!"PASS".equals(request.getDecision()) && !"NOT_PASS".equals(request.getDecision())) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "invalid withdrawal decision");
}
if ("PASS".equals(request.getDecision())
&& (request.getCredentialUrls() == null || request.getCredentialUrls().isEmpty())) {
// 财务通过必须带打款凭证来源钱包再次校验不能只依赖 Admin 前端门禁
throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
"withdrawal approval credential is required");
}
// Console 的全局异常处理器只识别框架 ResponseException使用统一断言才能保留
// 401/400 HTTP 语义避免 Admin 把确定性的鉴权或参数错误误当成 500 后持续重试
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
"invalid withdrawal decision",
"PASS".equals(request.getDecision()) || "NOT_PASS".equals(request.getDecision()));
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
"withdrawal approval credential is required",
!"PASS".equals(request.getDecision())
|| (request.getCredentialUrls() != null && !request.getCredentialUrls().isEmpty()));
long sourceApplicationId;
try {
sourceApplicationId = Long.parseLong(request.getSourceApplicationId());
} catch (NumberFormatException exception) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
"invalid source withdrawal application id", exception);
ResponseAssert.failure(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
"invalid source withdrawal application id");
// failure 必然抛出 ResponseException赋值只为满足 Java 的确定赋值检查
sourceApplicationId = 0L;
}
userBankBalanceBackService.approvalMoneyApply(new ApprovalMoneyApplyCmd()
.setId(sourceApplicationId)
@ -76,10 +78,8 @@ public class WithdrawalReviewIntegrationController {
boolean valid = !provided.isEmpty() && !expected.isEmpty()
&& MessageDigest.isEqual(provided.getBytes(StandardCharsets.UTF_8),
expected.getBytes(StandardCharsets.UTF_8));
if (!valid) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED,
"withdrawal callback authentication failed");
}
ResponseAssert.isTrue(ResponseErrorCode.UNAUTHORIZED,
"withdrawal callback authentication failed", valid);
}
@Data