feat(order): 添加订单货币转换功能
- 在CustomerOrder实体中添加原始货币、支付货币、汇率等相关字段 - 实现货币转换计算接口,支持自动转换不支持的货币到USD - 添加货币转换信息更新服务方法 - 在订单创建时初始化货币转换相关字段 - 扩展订单响应DTO包含完整的货币转换信息 - 实现汇率锁定和转换记录功能
This commit is contained in:
@@ -1331,3 +1331,179 @@ org.springframework.web.client.HttpClientErrorException$UnprocessableEntity: 422
|
|||||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
|
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
|
||||||
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
|
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
|
||||||
at java.base/java.lang.Thread.run(Thread.java:842)
|
at java.base/java.lang.Thread.run(Thread.java:842)
|
||||||
|
2025-12-23 16:27:00.878 [main] ERROR com.mtkj.mtkjpay.MtkjpayApplication -
|
||||||
|
╔══════════════════════════════════════════════════════════╗
|
||||||
|
║ ║
|
||||||
|
║ ❌ MTKJ PAY 支付系统启动失败! ❌ ║
|
||||||
|
║ ║
|
||||||
|
╚══════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
org.springframework.boot.devtools.restart.SilentExitExceptionHandler$SilentExitException: null
|
||||||
|
at org.springframework.boot.devtools.restart.SilentExitExceptionHandler.exitCurrentThread(SilentExitExceptionHandler.java:92)
|
||||||
|
at org.springframework.boot.devtools.restart.Restarter.immediateRestart(Restarter.java:179)
|
||||||
|
at org.springframework.boot.devtools.restart.Restarter.initialize(Restarter.java:163)
|
||||||
|
at org.springframework.boot.devtools.restart.Restarter.initialize(Restarter.java:532)
|
||||||
|
at org.springframework.boot.devtools.restart.RestartApplicationListener.onApplicationStartingEvent(RestartApplicationListener.java:98)
|
||||||
|
at org.springframework.boot.devtools.restart.RestartApplicationListener.onApplicationEvent(RestartApplicationListener.java:51)
|
||||||
|
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:178)
|
||||||
|
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:171)
|
||||||
|
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:149)
|
||||||
|
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:137)
|
||||||
|
at org.springframework.boot.context.event.EventPublishingRunListener.multicastInitialEvent(EventPublishingRunListener.java:136)
|
||||||
|
at org.springframework.boot.context.event.EventPublishingRunListener.starting(EventPublishingRunListener.java:75)
|
||||||
|
at org.springframework.boot.SpringApplicationRunListeners.lambda$starting$0(SpringApplicationRunListeners.java:54)
|
||||||
|
at java.base/java.lang.Iterable.forEach(Iterable.java:75)
|
||||||
|
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:118)
|
||||||
|
at org.springframework.boot.SpringApplicationRunListeners.starting(SpringApplicationRunListeners.java:54)
|
||||||
|
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
|
||||||
|
at com.mtkj.mtkjpay.MtkjpayApplication.main(MtkjpayApplication.java:33)
|
||||||
|
2025-12-23 16:57:03.165 [main] ERROR com.mtkj.mtkjpay.MtkjpayApplication -
|
||||||
|
╔══════════════════════════════════════════════════════════╗
|
||||||
|
║ ║
|
||||||
|
║ ❌ MTKJ PAY 支付系统启动失败! ❌ ║
|
||||||
|
║ ║
|
||||||
|
╚══════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
org.springframework.boot.devtools.restart.SilentExitExceptionHandler$SilentExitException: null
|
||||||
|
at org.springframework.boot.devtools.restart.SilentExitExceptionHandler.exitCurrentThread(SilentExitExceptionHandler.java:92)
|
||||||
|
at org.springframework.boot.devtools.restart.Restarter.immediateRestart(Restarter.java:179)
|
||||||
|
at org.springframework.boot.devtools.restart.Restarter.initialize(Restarter.java:163)
|
||||||
|
at org.springframework.boot.devtools.restart.Restarter.initialize(Restarter.java:532)
|
||||||
|
at org.springframework.boot.devtools.restart.RestartApplicationListener.onApplicationStartingEvent(RestartApplicationListener.java:98)
|
||||||
|
at org.springframework.boot.devtools.restart.RestartApplicationListener.onApplicationEvent(RestartApplicationListener.java:51)
|
||||||
|
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:178)
|
||||||
|
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:171)
|
||||||
|
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:149)
|
||||||
|
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:137)
|
||||||
|
at org.springframework.boot.context.event.EventPublishingRunListener.multicastInitialEvent(EventPublishingRunListener.java:136)
|
||||||
|
at org.springframework.boot.context.event.EventPublishingRunListener.starting(EventPublishingRunListener.java:75)
|
||||||
|
at org.springframework.boot.SpringApplicationRunListeners.lambda$starting$0(SpringApplicationRunListeners.java:54)
|
||||||
|
at java.base/java.lang.Iterable.forEach(Iterable.java:75)
|
||||||
|
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:118)
|
||||||
|
at org.springframework.boot.SpringApplicationRunListeners.starting(SpringApplicationRunListeners.java:54)
|
||||||
|
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
|
||||||
|
at com.mtkj.mtkjpay.MtkjpayApplication.main(MtkjpayApplication.java:33)
|
||||||
|
2025-12-23 17:06:54.545 [http-nio-8082-exec-4] ERROR com.mtkj.mtpay.exception.GlobalExceptionHandler - 系统异常
|
||||||
|
org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' is not supported
|
||||||
|
at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.handleNoMatch(RequestMappingInfoHandlerMapping.java:265)
|
||||||
|
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:441)
|
||||||
|
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:382)
|
||||||
|
at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.getHandlerInternal(RequestMappingInfoHandlerMapping.java:126)
|
||||||
|
at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.getHandlerInternal(RequestMappingInfoHandlerMapping.java:68)
|
||||||
|
at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:507)
|
||||||
|
at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1283)
|
||||||
|
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1065)
|
||||||
|
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)
|
||||||
|
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
|
||||||
|
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)
|
||||||
|
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590)
|
||||||
|
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
|
||||||
|
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
|
||||||
|
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205)
|
||||||
|
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
|
||||||
|
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
|
||||||
|
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
|
||||||
|
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
|
||||||
|
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
|
||||||
|
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
|
||||||
|
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
|
||||||
|
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
|
||||||
|
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
|
||||||
|
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
|
||||||
|
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
|
||||||
|
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
|
||||||
|
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
|
||||||
|
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
|
||||||
|
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
|
||||||
|
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
|
||||||
|
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
|
||||||
|
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
|
||||||
|
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
|
||||||
|
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
|
||||||
|
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
|
||||||
|
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
|
||||||
|
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:340)
|
||||||
|
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391)
|
||||||
|
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
|
||||||
|
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896)
|
||||||
|
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1744)
|
||||||
|
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
|
||||||
|
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
|
||||||
|
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
|
||||||
|
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
|
||||||
|
at java.base/java.lang.Thread.run(Thread.java:842)
|
||||||
|
2025-12-23 17:07:40.917 [http-nio-8082-exec-7] ERROR com.mtkj.mtpay.exception.GlobalExceptionHandler - 系统异常
|
||||||
|
org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' is not supported
|
||||||
|
at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.handleNoMatch(RequestMappingInfoHandlerMapping.java:265)
|
||||||
|
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:441)
|
||||||
|
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:382)
|
||||||
|
at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.getHandlerInternal(RequestMappingInfoHandlerMapping.java:126)
|
||||||
|
at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.getHandlerInternal(RequestMappingInfoHandlerMapping.java:68)
|
||||||
|
at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:507)
|
||||||
|
at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1283)
|
||||||
|
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1065)
|
||||||
|
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)
|
||||||
|
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
|
||||||
|
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)
|
||||||
|
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590)
|
||||||
|
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
|
||||||
|
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
|
||||||
|
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205)
|
||||||
|
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
|
||||||
|
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
|
||||||
|
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
|
||||||
|
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
|
||||||
|
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
|
||||||
|
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
|
||||||
|
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
|
||||||
|
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
|
||||||
|
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
|
||||||
|
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
|
||||||
|
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
|
||||||
|
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
|
||||||
|
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
|
||||||
|
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
|
||||||
|
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
|
||||||
|
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
|
||||||
|
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
|
||||||
|
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
|
||||||
|
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
|
||||||
|
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
|
||||||
|
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
|
||||||
|
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
|
||||||
|
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:340)
|
||||||
|
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391)
|
||||||
|
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
|
||||||
|
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896)
|
||||||
|
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1744)
|
||||||
|
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
|
||||||
|
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
|
||||||
|
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
|
||||||
|
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
|
||||||
|
at java.base/java.lang.Thread.run(Thread.java:842)
|
||||||
|
2025-12-23 17:10:22.913 [main] ERROR com.mtkj.mtkjpay.MtkjpayApplication -
|
||||||
|
╔══════════════════════════════════════════════════════════╗
|
||||||
|
║ ║
|
||||||
|
║ ❌ MTKJ PAY 支付系统启动失败! ❌ ║
|
||||||
|
║ ║
|
||||||
|
╚══════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
org.springframework.boot.devtools.restart.SilentExitExceptionHandler$SilentExitException: null
|
||||||
|
at org.springframework.boot.devtools.restart.SilentExitExceptionHandler.exitCurrentThread(SilentExitExceptionHandler.java:92)
|
||||||
|
at org.springframework.boot.devtools.restart.Restarter.immediateRestart(Restarter.java:179)
|
||||||
|
at org.springframework.boot.devtools.restart.Restarter.initialize(Restarter.java:163)
|
||||||
|
at org.springframework.boot.devtools.restart.Restarter.initialize(Restarter.java:532)
|
||||||
|
at org.springframework.boot.devtools.restart.RestartApplicationListener.onApplicationStartingEvent(RestartApplicationListener.java:98)
|
||||||
|
at org.springframework.boot.devtools.restart.RestartApplicationListener.onApplicationEvent(RestartApplicationListener.java:51)
|
||||||
|
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:178)
|
||||||
|
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:171)
|
||||||
|
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:149)
|
||||||
|
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:137)
|
||||||
|
at org.springframework.boot.context.event.EventPublishingRunListener.multicastInitialEvent(EventPublishingRunListener.java:136)
|
||||||
|
at org.springframework.boot.context.event.EventPublishingRunListener.starting(EventPublishingRunListener.java:75)
|
||||||
|
at org.springframework.boot.SpringApplicationRunListeners.lambda$starting$0(SpringApplicationRunListeners.java:54)
|
||||||
|
at java.base/java.lang.Iterable.forEach(Iterable.java:75)
|
||||||
|
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:118)
|
||||||
|
at org.springframework.boot.SpringApplicationRunListeners.starting(SpringApplicationRunListeners.java:54)
|
||||||
|
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
|
||||||
|
at com.mtkj.mtkjpay.MtkjpayApplication.main(MtkjpayApplication.java:33)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,12 @@
|
|||||||
package com.mtkj.mtpay.controller;
|
package com.mtkj.mtpay.controller;
|
||||||
|
|
||||||
import com.mtkj.mtpay.common.Result;
|
import com.mtkj.mtpay.common.Result;
|
||||||
|
import com.mtkj.mtpay.dto.request.CalculateCurrencyConversionRequestDTO;
|
||||||
import com.mtkj.mtpay.dto.request.CreateCustomerOrderRequestDTO;
|
import com.mtkj.mtpay.dto.request.CreateCustomerOrderRequestDTO;
|
||||||
|
import com.mtkj.mtpay.dto.response.CurrencyConversionDTO;
|
||||||
import com.mtkj.mtpay.dto.response.CustomerOrderResponseDTO;
|
import com.mtkj.mtpay.dto.response.CustomerOrderResponseDTO;
|
||||||
import com.mtkj.mtpay.service.CustomerOrderService;
|
import com.mtkj.mtpay.service.CustomerOrderService;
|
||||||
|
import com.mtkj.mtpay.service.ExchangeRateService;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -19,6 +22,7 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
public class CustomerOrderController {
|
public class CustomerOrderController {
|
||||||
|
|
||||||
private final CustomerOrderService customerOrderService;
|
private final CustomerOrderService customerOrderService;
|
||||||
|
private final ExchangeRateService exchangeRateService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建客户订单
|
* 创建客户订单
|
||||||
@@ -30,8 +34,84 @@ public class CustomerOrderController {
|
|||||||
return Result.success("订单创建成功", order);
|
return Result.success("订单创建成功", order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算并更新订单的货币转换信息
|
||||||
|
* 在订单确认页面加载时调用,提前计算货币转换信息
|
||||||
|
* 注意:这个路由必须放在 /{orderNo} 之前,避免路由冲突
|
||||||
|
*/
|
||||||
|
@PostMapping("/calculate-currency-conversion")
|
||||||
|
public Result<CurrencyConversionDTO> calculateCurrencyConversion(
|
||||||
|
@Valid @RequestBody CalculateCurrencyConversionRequestDTO request) {
|
||||||
|
log.info("计算订单货币转换信息,订单号:{},原始货币:{},原始金额:{}",
|
||||||
|
request.getOrderNo(), request.getOriginalCurrency(), request.getOriginalAmount());
|
||||||
|
|
||||||
|
// 检查货币是否需要转换
|
||||||
|
java.util.Set<String> supportedCurrencies = java.util.Set.of(
|
||||||
|
"USD", "EUR", "GBP", "AUD", "CAD", "JPY", "CNY", "HKD", "SGD", "NZD",
|
||||||
|
"CHF", "SEK", "NOK", "DKK", "PLN", "MXN", "BRL", "INR", "KRW", "THB"
|
||||||
|
);
|
||||||
|
|
||||||
|
String originalCurrency = request.getOriginalCurrency();
|
||||||
|
String paymentCurrency = originalCurrency;
|
||||||
|
java.math.BigDecimal paymentAmount = request.getOriginalAmount();
|
||||||
|
java.math.BigDecimal exchangeRate = java.math.BigDecimal.ONE;
|
||||||
|
boolean conversionRequired = false;
|
||||||
|
|
||||||
|
// 如果货币不支持,转换为USD
|
||||||
|
if (!supportedCurrencies.contains(originalCurrency)) {
|
||||||
|
conversionRequired = true;
|
||||||
|
paymentCurrency = "USD";
|
||||||
|
|
||||||
|
// 计算汇率和转换后的金额
|
||||||
|
Double rate = exchangeRateService.getExchangeRate(originalCurrency, paymentCurrency);
|
||||||
|
Double convertedAmount = exchangeRateService.convertAmount(
|
||||||
|
request.getOriginalAmount().doubleValue(),
|
||||||
|
originalCurrency,
|
||||||
|
paymentCurrency
|
||||||
|
);
|
||||||
|
|
||||||
|
exchangeRate = java.math.BigDecimal.valueOf(rate);
|
||||||
|
paymentAmount = java.math.BigDecimal.valueOf(convertedAmount);
|
||||||
|
|
||||||
|
log.info("货币转换:{} {} -> {} {} (汇率: {})",
|
||||||
|
request.getOriginalAmount(), originalCurrency,
|
||||||
|
paymentAmount, paymentCurrency, exchangeRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建货币转换DTO
|
||||||
|
CurrencyConversionDTO conversionDTO = CurrencyConversionDTO.builder()
|
||||||
|
.originalCurrency(originalCurrency)
|
||||||
|
.originalAmount(request.getOriginalAmount())
|
||||||
|
.paymentCurrency(paymentCurrency)
|
||||||
|
.paymentAmount(paymentAmount)
|
||||||
|
.exchangeRate(exchangeRate)
|
||||||
|
.rateLockedAt(java.time.LocalDateTime.now())
|
||||||
|
.conversionRequired(conversionRequired)
|
||||||
|
.rateDescription(buildRateDescription(originalCurrency, paymentCurrency, exchangeRate.doubleValue()))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 更新订单的货币转换信息
|
||||||
|
try {
|
||||||
|
customerOrderService.updateCurrencyConversion(
|
||||||
|
request.getOrderNo(),
|
||||||
|
originalCurrency,
|
||||||
|
request.getOriginalAmount(),
|
||||||
|
paymentCurrency,
|
||||||
|
paymentAmount,
|
||||||
|
exchangeRate
|
||||||
|
);
|
||||||
|
log.info("订单货币转换信息已更新,订单号:{}", request.getOrderNo());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("更新订单货币转换信息失败,订单号:{}", request.getOrderNo(), e);
|
||||||
|
// 不抛出异常,仍然返回计算结果
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.success("货币转换信息计算成功", conversionDTO);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据订单号获取订单详情
|
* 根据订单号获取订单详情
|
||||||
|
* 注意:这个路由必须放在 /calculate-currency-conversion 之后,避免路由冲突
|
||||||
*/
|
*/
|
||||||
@GetMapping("/{orderNo}")
|
@GetMapping("/{orderNo}")
|
||||||
public Result<CustomerOrderResponseDTO> getOrderByOrderNo(@PathVariable String orderNo) {
|
public Result<CustomerOrderResponseDTO> getOrderByOrderNo(@PathVariable String orderNo) {
|
||||||
@@ -49,5 +129,15 @@ public class CustomerOrderController {
|
|||||||
CustomerOrderResponseDTO order = customerOrderService.getOrderById(id);
|
CustomerOrderResponseDTO order = customerOrderService.getOrderById(id);
|
||||||
return Result.success(order);
|
return Result.success(order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建汇率说明文本
|
||||||
|
*/
|
||||||
|
private String buildRateDescription(String fromCurrency, String toCurrency, Double rate) {
|
||||||
|
if (fromCurrency.equals(toCurrency)) {
|
||||||
|
return "无需货币转换";
|
||||||
|
}
|
||||||
|
return String.format("1 %s = %.6f %s", fromCurrency, rate, toCurrency);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,15 @@ public class CustomerOrderResponseDTO implements Serializable {
|
|||||||
private BigDecimal unitPrice;
|
private BigDecimal unitPrice;
|
||||||
private BigDecimal totalAmount;
|
private BigDecimal totalAmount;
|
||||||
private String currency;
|
private String currency;
|
||||||
|
|
||||||
|
// 货币转换信息
|
||||||
|
private String originalCurrency; // 原始货币代码
|
||||||
|
private BigDecimal originalAmount; // 原始订单金额
|
||||||
|
private String paymentCurrency; // 实际支付货币代码
|
||||||
|
private BigDecimal paymentAmount; // 实际支付金额
|
||||||
|
private BigDecimal exchangeRate; // 使用的汇率
|
||||||
|
private LocalDateTime rateLockedAt; // 汇率锁定时间
|
||||||
|
|
||||||
private String status;
|
private String status;
|
||||||
private String customerName;
|
private String customerName;
|
||||||
private String customerPhone;
|
private String customerPhone;
|
||||||
|
|||||||
@@ -68,11 +68,47 @@ public class CustomerOrder {
|
|||||||
private BigDecimal totalAmount;
|
private BigDecimal totalAmount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 货币代码
|
* 货币代码(保留字段,兼容旧数据)
|
||||||
*/
|
*/
|
||||||
@TableField(value = "currency", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
|
@TableField(value = "currency", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
|
||||||
private String currency;
|
private String currency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原始货币代码(客户选择的货币)
|
||||||
|
*/
|
||||||
|
@TableField(value = "original_currency", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
|
||||||
|
private String originalCurrency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原始订单金额(原始货币)
|
||||||
|
*/
|
||||||
|
@TableField(value = "original_amount", jdbcType = org.apache.ibatis.type.JdbcType.DECIMAL)
|
||||||
|
private BigDecimal originalAmount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实际支付货币代码(PayPal支持的货币,如USD)
|
||||||
|
*/
|
||||||
|
@TableField(value = "payment_currency", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
|
||||||
|
private String paymentCurrency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实际支付金额(支付货币)
|
||||||
|
*/
|
||||||
|
@TableField(value = "payment_amount", jdbcType = org.apache.ibatis.type.JdbcType.DECIMAL)
|
||||||
|
private BigDecimal paymentAmount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用的汇率(原始货币 -> 支付货币)
|
||||||
|
*/
|
||||||
|
@TableField(value = "exchange_rate", jdbcType = org.apache.ibatis.type.JdbcType.DECIMAL)
|
||||||
|
private BigDecimal exchangeRate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 汇率锁定时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "rate_locked_at", jdbcType = org.apache.ibatis.type.JdbcType.TIMESTAMP)
|
||||||
|
private LocalDateTime rateLockedAt;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 订单状态:PENDING-待支付,PAID-已支付,SHIPPED-已发货,COMPLETED-已完成,CANCELLED-已取消
|
* 订单状态:PENDING-待支付,PAID-已支付,SHIPPED-已发货,COMPLETED-已完成,CANCELLED-已取消
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -43,5 +43,20 @@ public interface CustomerOrderService {
|
|||||||
* @param status 订单状态
|
* @param status 订单状态
|
||||||
*/
|
*/
|
||||||
void updateOrderStatus(String orderNo, String status);
|
void updateOrderStatus(String orderNo, String status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新订单货币转换信息
|
||||||
|
* @param orderNo 订单号
|
||||||
|
* @param originalCurrency 原始货币代码
|
||||||
|
* @param originalAmount 原始金额
|
||||||
|
* @param paymentCurrency 支付货币代码
|
||||||
|
* @param paymentAmount 支付金额
|
||||||
|
* @param exchangeRate 汇率
|
||||||
|
*/
|
||||||
|
void updateCurrencyConversion(String orderNo, String originalCurrency,
|
||||||
|
java.math.BigDecimal originalAmount,
|
||||||
|
String paymentCurrency,
|
||||||
|
java.math.BigDecimal paymentAmount,
|
||||||
|
java.math.BigDecimal exchangeRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,8 +70,18 @@ public class CustomerOrderServiceImpl implements CustomerOrderService {
|
|||||||
order.setSkuName(sku.getSku());
|
order.setSkuName(sku.getSku());
|
||||||
order.setQuantity(request.getQuantity());
|
order.setQuantity(request.getQuantity());
|
||||||
order.setUnitPrice(sku.getPrice());
|
order.setUnitPrice(sku.getPrice());
|
||||||
order.setTotalAmount(sku.getPrice().multiply(new BigDecimal(request.getQuantity())));
|
BigDecimal totalAmount = sku.getPrice().multiply(new BigDecimal(request.getQuantity()));
|
||||||
|
order.setTotalAmount(totalAmount);
|
||||||
order.setCurrency(sku.getCurrency());
|
order.setCurrency(sku.getCurrency());
|
||||||
|
|
||||||
|
// 设置原始货币信息(创建订单时的货币)
|
||||||
|
order.setOriginalCurrency(sku.getCurrency());
|
||||||
|
order.setOriginalAmount(totalAmount);
|
||||||
|
// 支付货币和金额将在创建PayPal订单时设置
|
||||||
|
order.setPaymentCurrency(sku.getCurrency()); // 默认与原始货币相同
|
||||||
|
order.setPaymentAmount(totalAmount); // 默认与原始金额相同
|
||||||
|
order.setExchangeRate(BigDecimal.ONE); // 默认汇率为1
|
||||||
|
|
||||||
order.setStatus("PENDING");
|
order.setStatus("PENDING");
|
||||||
order.setPaymentStatus("UNPAID");
|
order.setPaymentStatus("UNPAID");
|
||||||
|
|
||||||
@@ -165,6 +175,37 @@ public class CustomerOrderServiceImpl implements CustomerOrderService {
|
|||||||
log.info("订单支付状态更新成功,订单号: {}", orderNo);
|
log.info("订单支付状态更新成功,订单号: {}", orderNo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateCurrencyConversion(String orderNo, String originalCurrency,
|
||||||
|
BigDecimal originalAmount,
|
||||||
|
String paymentCurrency,
|
||||||
|
BigDecimal paymentAmount,
|
||||||
|
BigDecimal exchangeRate) {
|
||||||
|
log.info("更新订单货币转换信息,订单号: {}, 原始: {} {}, 支付: {} {} (汇率: {})",
|
||||||
|
orderNo, originalAmount, originalCurrency, paymentAmount, paymentCurrency, exchangeRate);
|
||||||
|
|
||||||
|
CustomerOrder order = customerOrderMapper.selectOne(
|
||||||
|
new LambdaQueryWrapper<CustomerOrder>()
|
||||||
|
.eq(CustomerOrder::getOrderNo, orderNo)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (order == null) {
|
||||||
|
log.warn("订单不存在,订单号: {}", orderNo);
|
||||||
|
throw new BusinessException(ResultCode.DATA_NOT_FOUND, "订单不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新货币转换信息
|
||||||
|
order.setOriginalCurrency(originalCurrency);
|
||||||
|
order.setOriginalAmount(originalAmount);
|
||||||
|
order.setPaymentCurrency(paymentCurrency);
|
||||||
|
order.setPaymentAmount(paymentAmount);
|
||||||
|
order.setExchangeRate(exchangeRate);
|
||||||
|
order.setRateLockedAt(java.time.LocalDateTime.now());
|
||||||
|
|
||||||
|
customerOrderMapper.updateById(order);
|
||||||
|
log.info("订单货币转换信息更新成功,订单号: {}", orderNo);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateOrderStatus(String orderNo, String status) {
|
public void updateOrderStatus(String orderNo, String status) {
|
||||||
log.info("更新订单状态,订单号: {}, 状态: {}", orderNo, status);
|
log.info("更新订单状态,订单号: {}, 状态: {}", orderNo, status);
|
||||||
|
|||||||
Reference in New Issue
Block a user