feat: complete finance and overseas receiving workflow

This commit is contained in:
2026-09-10 22:43:11 +08:00
parent e531ae9407
commit 56635ad4e4
66 changed files with 1601 additions and 417 deletions
@@ -0,0 +1,23 @@
package com.baiyue.order.client;
import com.baiyue.common.core.api.ApiResponse;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import java.math.BigDecimal;
import java.time.LocalDate;
@FeignClient(name = "finance-service", contextId = "orderFinanceWalletClient",
url = "${baiyue.clients.finance.url:}", path = "/internal/finance/v1/wallet")
public interface FinanceWalletClient {
@GetMapping("/accounts/{customerId}")
ApiResponse<WalletAccount> account(
@RequestHeader("X-Internal-Service-Token") String internalToken,
@PathVariable("customerId") long customerId);
record WalletAccount(BigDecimal actualBalance, BigDecimal availableBalance,
BigDecimal creditLimit, BigDecimal availableCredit,
LocalDate creditExpiresOn, boolean creditActive) { }
}
@@ -3,14 +3,18 @@ package com.baiyue.order.service;
import com.baiyue.common.core.api.ResultCode;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.order.client.TenantEligibilityClient;
import com.baiyue.order.client.FinanceWalletClient;
import feign.FeignException;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
@Service
public class OrderEligibilityGuard {
@Resource private TenantEligibilityClient client;
@Resource private FinanceWalletClient financeWalletClient;
@Value("${baiyue.security.internal-service-token}") private String internalToken;
public void requireApproved(long tenantId) {
@@ -32,6 +36,7 @@ public class OrderEligibilityGuard {
throw new BizException(ResultCode.FORBIDDEN,
response.data().reason() == null ? "Enterprise review approval is required" : response.data().reason());
}
requireNonNegativeActualBalance(tenantId);
} catch (FeignException exception) {
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "IAM eligibility service is unavailable");
} catch (BizException exception) {
@@ -41,4 +46,23 @@ public class OrderEligibilityGuard {
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "IAM 下单资格响应无效");
}
}
private void requireNonNegativeActualBalance(long tenantId) {
try {
var response = financeWalletClient.account(internalToken, tenantId);
if (response == null || !response.successful() || response.data() == null
|| response.data().actualBalance() == null) {
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "Unable to verify customer account balance");
}
if (response.data().actualBalance().compareTo(BigDecimal.ZERO) < 0) {
throw new BizException(ResultCode.FORBIDDEN, "账户实际余额为负,请充值后再下单");
}
} catch (FeignException exception) {
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "Finance account service is unavailable");
} catch (BizException exception) {
throw exception;
} catch (RuntimeException exception) {
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "Finance account response is invalid");
}
}
}