From 22756c5e5bf11c31bdbec1e00f86d05d0f291ec5 Mon Sep 17 00:00:00 2001 From: zhx Date: Wed, 24 Jun 2026 11:56:58 +0800 Subject: [PATCH] feat: support h5 pay country configuration --- .../endpoint/api/PayCountryClientApi.java | 3 + .../cmd/SysPayApplicationCommodityCmd.java | 6 ++ .../dto/SysPayApplicationCommodityDTO.java | 15 ++++ .../sys/pay/SysPayOpenCountryController.java | 9 ++ .../app/sys/pay/SysPayCountryServiceImpl.java | 5 ++ .../app/sys/pay/SysPayCountryService.java | 5 ++ .../PayWebApplicationCommodityV2QueryExe.java | 60 +++++++++---- .../pay/web/PayWebH5OptionsQryExe.java | 35 +++++++- .../pay/web/PayWebPlaceAnOrderCmdExe.java | 3 + .../web/UserProfileAndCountryQueryExe.java | 26 ++++++ .../pay/ApplicationCommodityCardV2CO.java | 25 ++++++ .../clientobject/pay/PayWebH5AccountCO.java | 6 ++ .../clientobject/pay/PayWebH5ContextCO.java | 2 +- .../clientobject/pay/WebSiteUseProfileCO.java | 12 +++ .../cmd/PayWebApplicationCommodityCmd.java | 5 ++ .../order/app/dto/cmd/PayWebH5OptionsCmd.java | 4 +- .../endpoint/PayCountryClientEndpoint.java | 5 ++ .../service/PayCountryClientService.java | 2 + .../impl/PayApplicationClientServiceImpl.java | 87 ++++++++++++++++++- .../impl/PayCountryClientServiceImpl.java | 35 ++++++++ 20 files changed, 327 insertions(+), 23 deletions(-) diff --git a/rc-service/rc-inner-api/order-inner/order-inner-api/src/main/java/com/red/circle/order/inner/endpoint/api/PayCountryClientApi.java b/rc-service/rc-inner-api/order-inner/order-inner-api/src/main/java/com/red/circle/order/inner/endpoint/api/PayCountryClientApi.java index 2e04b6b9..8be65afc 100644 --- a/rc-service/rc-inner-api/order-inner/order-inner-api/src/main/java/com/red/circle/order/inner/endpoint/api/PayCountryClientApi.java +++ b/rc-service/rc-inner-api/order-inner/order-inner-api/src/main/java/com/red/circle/order/inner/endpoint/api/PayCountryClientApi.java @@ -78,6 +78,9 @@ public interface PayCountryClientApi { ResultResponse updateUsdExchangeRate(@RequestParam("id") Long id, @RequestParam("rate") BigDecimal rate); + @PostMapping("/syncAllUsdExchangeRate") + ResultResponse syncAllUsdExchangeRate(); + @GetMapping("/updateCountryCurrency") ResultResponse updateCountryCurrency(@RequestParam("id") Long id, @RequestParam("currency") String currency); diff --git a/rc-service/rc-inner-api/order-inner/order-inner-model/src/main/java/com/red/circle/order/inner/model/cmd/SysPayApplicationCommodityCmd.java b/rc-service/rc-inner-api/order-inner/order-inner-model/src/main/java/com/red/circle/order/inner/model/cmd/SysPayApplicationCommodityCmd.java index 615df323..594adc33 100644 --- a/rc-service/rc-inner-api/order-inner/order-inner-model/src/main/java/com/red/circle/order/inner/model/cmd/SysPayApplicationCommodityCmd.java +++ b/rc-service/rc-inner-api/order-inner/order-inner-model/src/main/java/com/red/circle/order/inner/model/cmd/SysPayApplicationCommodityCmd.java @@ -7,6 +7,7 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import java.io.Serial; import java.math.BigDecimal; +import java.util.List; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; @@ -46,6 +47,11 @@ public class SysPayApplicationCommodityCmd extends CommonCommand { @JsonSerialize(using = ToStringSerializer.class) private Long payCountryId; + /** + * 批量开通支付国家. + */ + private List payCountryIds; + /** * 区域ID. */ diff --git a/rc-service/rc-inner-api/order-inner/order-inner-model/src/main/java/com/red/circle/order/inner/model/dto/SysPayApplicationCommodityDTO.java b/rc-service/rc-inner-api/order-inner/order-inner-model/src/main/java/com/red/circle/order/inner/model/dto/SysPayApplicationCommodityDTO.java index 5ec31847..434a837d 100644 --- a/rc-service/rc-inner-api/order-inner/order-inner-model/src/main/java/com/red/circle/order/inner/model/dto/SysPayApplicationCommodityDTO.java +++ b/rc-service/rc-inner-api/order-inner/order-inner-model/src/main/java/com/red/circle/order/inner/model/dto/SysPayApplicationCommodityDTO.java @@ -52,6 +52,21 @@ public class SysPayApplicationCommodityDTO implements Serializable { @JsonSerialize(using = ToStringSerializer.class) private Long payCountryId; + /** + * 支付国家. + */ + private CountryCodeDTO country; + + /** + * 国家货币. + */ + private String currency; + + /** + * USD 汇率. + */ + private BigDecimal usdExchangeRate; + /** * 类型. */ diff --git a/rc-service/rc-service-console/console-adapter/src/main/java/com/red/circle/console/adapter/app/sys/pay/SysPayOpenCountryController.java b/rc-service/rc-service-console/console-adapter/src/main/java/com/red/circle/console/adapter/app/sys/pay/SysPayOpenCountryController.java index 6cfbca18..2651236f 100644 --- a/rc-service/rc-service-console/console-adapter/src/main/java/com/red/circle/console/adapter/app/sys/pay/SysPayOpenCountryController.java +++ b/rc-service/rc-service-console/console-adapter/src/main/java/com/red/circle/console/adapter/app/sys/pay/SysPayOpenCountryController.java @@ -86,6 +86,15 @@ public class SysPayOpenCountryController extends BaseController { sysPayCountryService.updateUsdExchangeRate(id, rate); } + /** + * 同步全部国家汇率. + */ + @OpsOperationReqLog("同步全部国家汇率") + @PostMapping("/sync-exchange-rate") + public Integer syncExchangeRate() { + return sysPayCountryService.syncAllUsdExchangeRate(); + } + /** * 修改国家货币code. */ diff --git a/rc-service/rc-service-console/console-application/src/main/java/com/red/circle/console/app/service/app/sys/pay/SysPayCountryServiceImpl.java b/rc-service/rc-service-console/console-application/src/main/java/com/red/circle/console/app/service/app/sys/pay/SysPayCountryServiceImpl.java index c8035779..c8601774 100644 --- a/rc-service/rc-service-console/console-application/src/main/java/com/red/circle/console/app/service/app/sys/pay/SysPayCountryServiceImpl.java +++ b/rc-service/rc-service-console/console-application/src/main/java/com/red/circle/console/app/service/app/sys/pay/SysPayCountryServiceImpl.java @@ -53,6 +53,11 @@ public class SysPayCountryServiceImpl implements SysPayCountryService { ResponseAssert.requiredSuccess(payCountryClient.updateUsdExchangeRate(id, rate)); } + @Override + public Integer syncAllUsdExchangeRate() { + return ResponseAssert.requiredSuccess(payCountryClient.syncAllUsdExchangeRate()); + } + @Override public void updateCountryCurrency(Long id, String currency) { ResponseAssert.requiredSuccess(payCountryClient.updateCountryCurrency(id, currency)); diff --git a/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/service/app/sys/pay/SysPayCountryService.java b/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/service/app/sys/pay/SysPayCountryService.java index 55fb285b..c024750a 100644 --- a/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/service/app/sys/pay/SysPayCountryService.java +++ b/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/service/app/sys/pay/SysPayCountryService.java @@ -44,6 +44,11 @@ public interface SysPayCountryService { */ void updateUsdExchangeRate(Long id, BigDecimal rate); + /** + * 同步全部开通支付国家美元汇率. + */ + Integer syncAllUsdExchangeRate(); + /** * 修改国家货币. */ diff --git a/rc-service/rc-service-order/order-application/src/main/java/com/red/circle/order/app/command/pay/web/PayWebApplicationCommodityV2QueryExe.java b/rc-service/rc-service-order/order-application/src/main/java/com/red/circle/order/app/command/pay/web/PayWebApplicationCommodityV2QueryExe.java index 80ff82c5..36a9735e 100644 --- a/rc-service/rc-service-order/order-application/src/main/java/com/red/circle/order/app/command/pay/web/PayWebApplicationCommodityV2QueryExe.java +++ b/rc-service/rc-service-order/order-application/src/main/java/com/red/circle/order/app/command/pay/web/PayWebApplicationCommodityV2QueryExe.java @@ -24,6 +24,8 @@ import com.red.circle.order.infra.database.rds.service.pay.PayApplicationService import com.red.circle.order.infra.database.rds.service.pay.PayChannelService; import com.red.circle.order.infra.database.rds.service.pay.PayCountryChannelDetailsService; import com.red.circle.order.infra.database.rds.service.pay.PayCountryService; +import com.red.circle.other.inner.endpoint.sys.SysCountryCodeClient; +import com.red.circle.other.inner.model.dto.sys.SysCountryCodeDTO; import com.red.circle.tool.core.collection.CollectionUtils; import com.red.circle.tool.core.num.ArithmeticUtils; import com.red.circle.tool.core.text.StringUtils; @@ -52,6 +54,7 @@ public class PayWebApplicationCommodityV2QueryExe { private final PayAppConvertor payAppConvertor; private final PayCountryService payCountryService; private final PayChannelService payChannelService; + private final SysCountryCodeClient sysCountryCodeClient; private final PayApplicationService payApplicationService; private final PayApplicationCommodityService payApplicationCommodityService; private final PayCountryChannelDetailsService payCountryChannelDetailsService; @@ -65,12 +68,12 @@ public class PayWebApplicationCommodityV2QueryExe { PayApplicationCO application = payAppConvertor .toPayApplicationCO(payApplicationService.getById(cmd.getApplicationId())); ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, application); + SysCountryCodeDTO country = getCountryCode(payCountry); List payApplicationCommodities = getPayApplicationCommodities(cmd); if (CollectionUtils.isEmpty(payApplicationCommodities)) { - return new ApplicationCommodityCardV2CO() - .setApplication(application); + return baseCard(application, payCountry, country); } // 所有支持的渠道 @@ -78,8 +81,7 @@ public class PayWebApplicationCommodityV2QueryExe { .listChannelCode(cmd.getPayCountryId()); if (CollectionUtils.isEmpty(countryChannelDetails)) { - return new ApplicationCommodityCardV2CO() - .setApplication(application); + return baseCard(application, payCountry, country); } // 商品 @@ -87,16 +89,14 @@ public class PayWebApplicationCommodityV2QueryExe { payApplicationCommodities); if (CollectionUtils.isEmpty(commodity)) { - return new ApplicationCommodityCardV2CO() - .setApplication(application); + return baseCard(application, payCountry, country); } // 过滤渠道限额范围 countryChannelDetails = filterCountryChannelLimit(countryChannelDetails, commodity); if (CollectionUtils.isEmpty(countryChannelDetails)) { - return new ApplicationCommodityCardV2CO() - .setApplication(application); + return baseCard(application, payCountry, country); } // 渠道资料信息 @@ -104,12 +104,10 @@ public class PayWebApplicationCommodityV2QueryExe { .listByChannelCodes(countryChannelDetails.stream() .map(PayCountryChannelDetails::getChannelCode).collect(Collectors.toSet())); if (CollectionUtils.isEmpty(payChannels)) { - return new ApplicationCommodityCardV2CO() - .setApplication(application); + return baseCard(application, payCountry, country); } - return new ApplicationCommodityCardV2CO() - .setApplication(application) + return baseCard(application, payCountry, country) .setCommodity(commodity) .setChannels(getPayChannels(payChannels, countryChannelDetails)); } @@ -165,9 +163,41 @@ public class PayWebApplicationCommodityV2QueryExe { } private PayCountry getPayCountry(PayWebApplicationCommodityCmd cmd) { - return Objects.isNull(cmd.getPayCountryId()) - ? payCountryService.getShelfSortMax() - : payCountryService.getById(cmd.getPayCountryId()); + if (Objects.nonNull(cmd.getPayCountryId())) { + return payCountryService.getById(cmd.getPayCountryId()); + } + + if (StringUtils.isNotBlank(cmd.getCountryCode())) { + SysCountryCodeDTO country = ResponseAssert.requiredSuccess( + sysCountryCodeClient.getByCode(cmd.getCountryCode().trim().toUpperCase()) + ); + ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, country); + return payCountryService.query() + .eq(PayCountry::getCountryId, country.getId()) + .eq(PayCountry::getShelf, Boolean.TRUE) + .orderByDesc(PayCountry::getSort) + .last(com.red.circle.framework.mybatis.constant.PageConstant.LIMIT_ONE) + .getOne(); + } + + return payCountryService.getShelfSortMax(); + } + + private SysCountryCodeDTO getCountryCode(PayCountry payCountry) { + SysCountryCodeDTO country = ResponseAssert.requiredSuccess( + sysCountryCodeClient.getById(payCountry.getCountryId())); + ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, country); + return country; + } + + private ApplicationCommodityCardV2CO baseCard(PayApplicationCO application, PayCountry payCountry, + SysCountryCodeDTO country) { + return new ApplicationCommodityCardV2CO() + .setApplication(application) + .setPayCountryId(Objects.toString(payCountry.getId())) + .setCountryCode(country.getAlphaTwo()) + .setCountryName(country.getCountryName()) + .setCurrencyCode(payCountry.getCurrency()); } private List getPayChannels(List payChannels, diff --git a/rc-service/rc-service-order/order-application/src/main/java/com/red/circle/order/app/command/pay/web/PayWebH5OptionsQryExe.java b/rc-service/rc-service-order/order-application/src/main/java/com/red/circle/order/app/command/pay/web/PayWebH5OptionsQryExe.java index 7f46eeba..f196489c 100644 --- a/rc-service/rc-service-order/order-application/src/main/java/com/red/circle/order/app/command/pay/web/PayWebH5OptionsQryExe.java +++ b/rc-service/rc-service-order/order-application/src/main/java/com/red/circle/order/app/command/pay/web/PayWebH5OptionsQryExe.java @@ -1,6 +1,7 @@ package com.red.circle.order.app.command.pay.web; import com.red.circle.common.business.core.amount.PayAmountArithmeticUtils; +import com.red.circle.framework.mybatis.constant.PageConstant; import com.red.circle.framework.core.asserts.ResponseAssert; import com.red.circle.framework.core.response.CommonErrorCode; import com.red.circle.order.app.dto.clientobject.pay.PayCountryCO; @@ -50,7 +51,7 @@ public class PayWebH5OptionsQryExe { public PayWebH5ContextCO context(PayWebUserCmd cmd) { defaultType(cmd); - UserProfileAndCountryCO source = userProfileAndCountryQueryExe.execute(cmd); + UserProfileAndCountryCO source = userProfileAndCountryQueryExe.h5Context(cmd); WebSiteUseProfileCO userProfile = source.getUserProfile(); ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, userProfile); @@ -63,6 +64,8 @@ public class PayWebH5OptionsQryExe { .setAvatar(userProfile.getUserAvatar()) .setAccount(userProfile.getAccount()) .setSysOrigin(userProfile.getSysOrigin()) + .setCountryName(userProfile.getCountryName()) + .setCountryCode(userProfile.getCountryCode()) .setFreightAgent(userProfile.getFreightAgent()) .setSuperFreightAgent(userProfile.getSuperFreightAgent()) .setAudienceType(resolveAudienceType(userProfile))) @@ -75,9 +78,7 @@ public class PayWebH5OptionsQryExe { PayApplication application = payApplicationService.getById(cmd.getApplicationId()); ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, application); - PayCountry payCountry = Objects.isNull(cmd.getPayCountryId()) - ? payCountryService.getShelfSortMax() - : payCountryService.getById(cmd.getPayCountryId()); + PayCountry payCountry = resolvePayCountry(cmd); ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, payCountry); SysCountryCodeDTO country = ResponseAssert.requiredSuccess( @@ -114,6 +115,32 @@ public class PayWebH5OptionsQryExe { .collect(Collectors.toList())); } + private PayCountry resolvePayCountry(PayWebH5OptionsCmd cmd) { + if (Objects.nonNull(cmd.getPayCountryId())) { + // H5 后续下单要使用同一个 payCountryId;显式传 id 时只校验后台是否仍存在且上架。 + PayCountry payCountry = payCountryService.getById(cmd.getPayCountryId()); + return Objects.nonNull(payCountry) && Boolean.TRUE.equals(payCountry.getShelf()) + ? payCountry + : null; + } + + if (StringUtils.isNotBlank(cmd.getCountryCode())) { + // 支付国家是否展示由本地 JSON 决定;服务端只把 JSON 国家码解析为后台支付国家,用于汇率和商品快照。 + SysCountryCodeDTO country = ResponseAssert.requiredSuccess( + sysCountryCodeClient.getByCode(cmd.getCountryCode().trim().toUpperCase()) + ); + ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, country); + return payCountryService.query() + .eq(PayCountry::getCountryId, country.getId()) + .eq(PayCountry::getShelf, Boolean.TRUE) + .orderByDesc(PayCountry::getSort) + .last(PageConstant.LIMIT_ONE) + .getOne(); + } + + return payCountryService.getShelfSortMax(); + } + private PayWebH5ProductCO toProduct(PayApplicationCommodity commodity, PayCountry payCountry) { BigDecimal amount = PayAmountArithmeticUtils.multiplyUpNotPoint( commodity.getAmountUsd(), diff --git a/rc-service/rc-service-order/order-application/src/main/java/com/red/circle/order/app/command/pay/web/PayWebPlaceAnOrderCmdExe.java b/rc-service/rc-service-order/order-application/src/main/java/com/red/circle/order/app/command/pay/web/PayWebPlaceAnOrderCmdExe.java index b77ba82e..b8a79840 100644 --- a/rc-service/rc-service-order/order-application/src/main/java/com/red/circle/order/app/command/pay/web/PayWebPlaceAnOrderCmdExe.java +++ b/rc-service/rc-service-order/order-application/src/main/java/com/red/circle/order/app/command/pay/web/PayWebPlaceAnOrderCmdExe.java @@ -69,6 +69,9 @@ public class PayWebPlaceAnOrderCmdExe { // 未知的应用 ResponseAssert.notNull(PayErrorCode.UNKNOWN_APPLICATION, application); PayApplicationCommodity commodity = getAppCommodity(cmd); + ResponseAssert.isTrue(CommonErrorCode.NOT_FOUND_MAPPING_INFO, + Objects.isNull(commodity.getPayCountryId()) + || Objects.equals(commodity.getPayCountryId(), cmd.getPayCountryId())); PayCountryChannelDetails channelDetails = payCountryChannelDetailsService .getSuggestScoreMax(cmd.getPayCountryId(), cmd.getChannelCode(), diff --git a/rc-service/rc-service-order/order-application/src/main/java/com/red/circle/order/app/command/pay/web/UserProfileAndCountryQueryExe.java b/rc-service/rc-service-order/order-application/src/main/java/com/red/circle/order/app/command/pay/web/UserProfileAndCountryQueryExe.java index a3a9d6fb..6f4b9de3 100644 --- a/rc-service/rc-service-order/order-application/src/main/java/com/red/circle/order/app/command/pay/web/UserProfileAndCountryQueryExe.java +++ b/rc-service/rc-service-order/order-application/src/main/java/com/red/circle/order/app/command/pay/web/UserProfileAndCountryQueryExe.java @@ -96,6 +96,32 @@ public class UserProfileAndCountryQueryExe { } + public UserProfileAndCountryCO h5Context(PayWebUserCmd cmd) { + + UserProfileDTO userProfile = getUserProfile(cmd); + ResponseAssert.notNull(UserErrorCode.USER_INFO_NOT_FOUND, userProfile); + + if (Objects.equals(cmd.getType(), PayApplicationCommodityType.FREIGHT_GOLD)) { + ResponseAssert.isTrue(UserErrorCode.USER_INFO_NOT_FOUND, + ResponseAssert.requiredSuccess(freightGoldClient.existsBalance(userProfile.getId()))); + } + + WebSiteUseProfileCO webSiteUseProfile = WebSiteUseProfileCO + .toWebSiteUseProfileCO(userProfile); + webSiteUseProfile.setAccount(userProfile.actualAccount()); + + // H5 的支付国家开关由 app JSON 控制,服务端 context 只确认账号和用户所在区域。 + // 这里不读取 OPEN_PAY_COUNTRY 关系,避免用户 region 未配置支付国家时阻断商品查询。 + String regionId = ResponseAssert.requiredSuccess( + userRegionClient.getRegionId(userProfile.getId()) + ); + + return new UserProfileAndCountryCO() + .setUserProfile(webSiteUseProfile) + .setRegionId(regionId); + + } + private UserProfileDTO getUserProfile(PayWebUserCmd cmd) { if (StringUtils.isNotBlank(cmd.getAccount()) && StringUtils.isNotBlank(cmd.getSysOrigin())) { return ResponseAssert.requiredSuccess( diff --git a/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/clientobject/pay/ApplicationCommodityCardV2CO.java b/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/clientobject/pay/ApplicationCommodityCardV2CO.java index e7a8ff48..562e9f51 100644 --- a/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/clientobject/pay/ApplicationCommodityCardV2CO.java +++ b/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/clientobject/pay/ApplicationCommodityCardV2CO.java @@ -1,5 +1,6 @@ package com.red.circle.order.app.dto.clientobject.pay; +import com.fasterxml.jackson.annotation.JsonProperty; import com.red.circle.framework.dto.ClientObject; import java.util.List; import lombok.Data; @@ -23,6 +24,30 @@ public class ApplicationCommodityCardV2CO extends ClientObject { */ private PayApplicationCO application; + /** + * 当前支付国家ID. + */ + @JsonProperty("pay_country_id") + private String payCountryId; + + /** + * 当前国家编码. + */ + @JsonProperty("country_code") + private String countryCode; + + /** + * 当前国家名称. + */ + @JsonProperty("country_name") + private String countryName; + + /** + * 当前国家货币. + */ + @JsonProperty("currency_code") + private String currencyCode; + /** * 渠道商品信息. */ diff --git a/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/clientobject/pay/PayWebH5AccountCO.java b/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/clientobject/pay/PayWebH5AccountCO.java index efea6fc1..4c804434 100644 --- a/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/clientobject/pay/PayWebH5AccountCO.java +++ b/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/clientobject/pay/PayWebH5AccountCO.java @@ -37,6 +37,12 @@ public class PayWebH5AccountCO extends ClientObject { @JsonProperty("sys_origin") private String sysOrigin; + @JsonProperty("country_name") + private String countryName; + + @JsonProperty("country_code") + private String countryCode; + @JsonProperty("audience_type") private String audienceType; diff --git a/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/clientobject/pay/PayWebH5ContextCO.java b/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/clientobject/pay/PayWebH5ContextCO.java index 63365ffe..d2f39577 100644 --- a/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/clientobject/pay/PayWebH5ContextCO.java +++ b/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/clientobject/pay/PayWebH5ContextCO.java @@ -8,7 +8,7 @@ import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; /** - * H5 充值页上下文,账号和国家都来自 Aslan 服务端,前端只拿它做展示和后续商品查询条件。 + * H5 充值页上下文,账号来自 Aslan 服务端;支付国家由 H5 app JSON 决定,服务端只返回兼容字段。 * * @author tf */ diff --git a/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/clientobject/pay/WebSiteUseProfileCO.java b/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/clientobject/pay/WebSiteUseProfileCO.java index 71a9e232..afdbfa41 100644 --- a/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/clientobject/pay/WebSiteUseProfileCO.java +++ b/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/clientobject/pay/WebSiteUseProfileCO.java @@ -49,6 +49,16 @@ public class WebSiteUseProfileCO extends ClientObject { */ private String sysOrigin; + /** + * 用户国家名称. + */ + private String countryName; + + /** + * 用户国家编码. + */ + private String countryCode; + /** * 是否金币代理. */ @@ -69,6 +79,8 @@ public class WebSiteUseProfileCO extends ClientObject { .setUserNickname(userProfile.getUserNickname()) .setAccount(userProfile.getAccount()) .setSysOrigin(userProfile.getOriginSys()) + .setCountryName(userProfile.getCountryName()) + .setCountryCode(userProfile.getCountryCode()) .setFreightAgent(userProfile.getIsFreightAgent()) .setSuperFreightAgent(userProfile.getIsSuperFreightAgent()); } diff --git a/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/cmd/PayWebApplicationCommodityCmd.java b/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/cmd/PayWebApplicationCommodityCmd.java index ef7d112b..d96c455b 100644 --- a/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/cmd/PayWebApplicationCommodityCmd.java +++ b/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/cmd/PayWebApplicationCommodityCmd.java @@ -32,6 +32,11 @@ public class PayWebApplicationCommodityCmd extends AppExtCommand { */ private Long payCountryId; + /** + * 国家码. + */ + private String countryCode; + /** * 金币类型. */ diff --git a/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/cmd/PayWebH5OptionsCmd.java b/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/cmd/PayWebH5OptionsCmd.java index e060778f..e43798a4 100644 --- a/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/cmd/PayWebH5OptionsCmd.java +++ b/rc-service/rc-service-order/order-client/src/main/java/com/red/circle/order/app/dto/cmd/PayWebH5OptionsCmd.java @@ -8,7 +8,7 @@ import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; /** - * H5 商品查询命令,商品类型和国家来自已确认账号上下文。 + * H5 商品查询命令,商品类型来自页面配置,支付国家来自 H5 app JSON 的国家码或已解析的 payCountryId。 * * @author tf */ @@ -24,6 +24,8 @@ public class PayWebH5OptionsCmd extends Command { private Long payCountryId; + private String countryCode; + private Long userId; private String regionId; diff --git a/rc-service/rc-service-order/order-inner-endpoint/src/main/java/com/red/circle/order/inner/endpoint/PayCountryClientEndpoint.java b/rc-service/rc-service-order/order-inner-endpoint/src/main/java/com/red/circle/order/inner/endpoint/PayCountryClientEndpoint.java index 732519d7..665b34e2 100644 --- a/rc-service/rc-service-order/order-inner-endpoint/src/main/java/com/red/circle/order/inner/endpoint/PayCountryClientEndpoint.java +++ b/rc-service/rc-service-order/order-inner-endpoint/src/main/java/com/red/circle/order/inner/endpoint/PayCountryClientEndpoint.java @@ -120,6 +120,11 @@ public class PayCountryClientEndpoint implements PayCountryClientApi { return ResultResponse.success(); } + @Override + public ResultResponse syncAllUsdExchangeRate() { + return ResultResponse.success(payCountryClientService.syncAllUsdExchangeRate()); + } + @Override public ResultResponse updateCountryCurrency(Long id, String currency) { payCountryClientService.updateCountryCurrency(id, currency); diff --git a/rc-service/rc-service-order/order-inner-endpoint/src/main/java/com/red/circle/order/inner/service/PayCountryClientService.java b/rc-service/rc-service-order/order-inner-endpoint/src/main/java/com/red/circle/order/inner/service/PayCountryClientService.java index 98ee79e6..eb94001c 100644 --- a/rc-service/rc-service-order/order-inner-endpoint/src/main/java/com/red/circle/order/inner/service/PayCountryClientService.java +++ b/rc-service/rc-service-order/order-inner-endpoint/src/main/java/com/red/circle/order/inner/service/PayCountryClientService.java @@ -51,6 +51,8 @@ public interface PayCountryClientService { void updateUsdExchangeRate(Long id, BigDecimal rate); + Integer syncAllUsdExchangeRate(); + void updateCountryCurrency(Long id, String currency); void updateSort(Long id, Integer sort); diff --git a/rc-service/rc-service-order/order-inner-endpoint/src/main/java/com/red/circle/order/inner/service/impl/PayApplicationClientServiceImpl.java b/rc-service/rc-service-order/order-inner-endpoint/src/main/java/com/red/circle/order/inner/service/impl/PayApplicationClientServiceImpl.java index 0d4f8751..ec66e787 100644 --- a/rc-service/rc-service-order/order-inner-endpoint/src/main/java/com/red/circle/order/inner/service/impl/PayApplicationClientServiceImpl.java +++ b/rc-service/rc-service-order/order-inner-endpoint/src/main/java/com/red/circle/order/inner/service/impl/PayApplicationClientServiceImpl.java @@ -3,23 +3,30 @@ package com.red.circle.order.inner.service.impl; import com.alibaba.nacos.shaded.com.google.common.collect.Lists; import com.red.circle.framework.core.asserts.ResponseAssert; import com.red.circle.framework.dto.PageResult; +import com.red.circle.framework.mybatis.constant.PageConstant; import com.red.circle.order.infra.database.rds.entity.pay.PayApplication; import com.red.circle.order.infra.database.rds.entity.pay.PayApplicationCommodity; +import com.red.circle.order.infra.database.rds.entity.pay.PayCountry; import com.red.circle.order.infra.database.rds.service.pay.PayApplicationCommodityService; import com.red.circle.order.infra.database.rds.service.pay.PayApplicationService; +import com.red.circle.order.infra.database.rds.service.pay.PayCountryService; import com.red.circle.order.inner.convertor.WebPayInnerConvertor; import com.red.circle.order.inner.model.cmd.SysPayApplicationCommodityCmd; import com.red.circle.order.inner.model.cmd.SysPayApplicationCommodityQryCmd; import com.red.circle.order.inner.model.dto.SysPayApplicationCommodityDTO; import com.red.circle.order.inner.model.dto.SysPayApplicationDTO; import com.red.circle.order.inner.service.PayApplicationClientService; +import com.red.circle.other.inner.endpoint.sys.SysCountryCodeClient; +import com.red.circle.other.inner.model.dto.sys.SysCountryCodeDTO; import com.red.circle.tool.core.collection.CollectionUtils; +import com.red.circle.tool.core.date.TimestampUtils; import com.red.circle.tool.core.text.StringUtils; import com.red.circle.other.inner.endpoint.user.region.RegionConfigClient; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -34,6 +41,8 @@ import org.springframework.stereotype.Service; public class PayApplicationClientServiceImpl implements PayApplicationClientService { private final RegionConfigClient regionConfigClient; + private final PayCountryService payCountryService; + private final SysCountryCodeClient sysCountryCodeClient; private final WebPayInnerConvertor webPayInnerConvertor; private final PayApplicationService payApplicationService; private final PayApplicationCommodityService payApplicationCommodityService; @@ -88,12 +97,21 @@ public class PayApplicationClientServiceImpl implements PayApplicationClientServ } Map mapRegionName = getMapRegionName(commodityPage); + Map mapPayCountry = getMapPayCountry(commodityPage); + Map mapCountryCode = getMapCountryCode(mapPayCountry); return commodityPage.convert(commodity -> { if (StringUtils.isNotBlank(commodity.getRegionId())) { commodity.setRegionName(mapRegionName.get(commodity.getRegionId())); } + PayCountry payCountry = mapPayCountry.get(commodity.getPayCountryId()); + if (Objects.nonNull(payCountry)) { + commodity.setCurrency(payCountry.getCurrency()); + commodity.setUsdExchangeRate(payCountry.getUsdExchangeRate()); + commodity.setCountry(webPayInnerConvertor.toCountryCodeDTO( + mapCountryCode.get(payCountry.getCountryId()))); + } return commodity; }); } @@ -106,10 +124,75 @@ public class PayApplicationClientServiceImpl implements PayApplicationClientServ Collectors.toSet()))); } + private Map getMapPayCountry( + PageResult commodityPage) { + + Set payCountryIds = commodityPage.getRecords().stream() + .map(SysPayApplicationCommodityDTO::getPayCountryId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + if (CollectionUtils.isEmpty(payCountryIds)) { + return CollectionUtils.newHashMap(); + } + return payCountryService.mapByIds(payCountryIds); + } + + private Map getMapCountryCode(Map mapPayCountry) { + if (CollectionUtils.isEmpty(mapPayCountry)) { + return CollectionUtils.newHashMap(); + } + return ResponseAssert.requiredSuccess( + sysCountryCodeClient.mapByIdes(mapPayCountry.values().stream() + .map(PayCountry::getCountryId) + .filter(Objects::nonNull) + .collect(Collectors.toSet())) + ); + } + @Override public void addOrUpdateCommodity(SysPayApplicationCommodityCmd param) { - payApplicationCommodityService.saveOrUpdate( - webPayInnerConvertor.toPayApplicationCommodity(param)); + if (Objects.nonNull(param.getId()) || CollectionUtils.isEmpty(param.getPayCountryIds())) { + payApplicationCommodityService.saveOrUpdate( + webPayInnerConvertor.toPayApplicationCommodity(param)); + return; + } + + List commodities = param.getPayCountryIds().stream() + .filter(Objects::nonNull) + .distinct() + .map(payCountryId -> { + PayApplicationCommodity commodity = getOrCreateCommodity(param, payCountryId); + commodity.setApplicationId(param.getApplicationId()); + commodity.setPayCountryId(payCountryId); + commodity.setRegionId(StringUtils.isBlankOrElse(param.getRegionId(), "")); + commodity.setType(param.getType()); + commodity.setContent(param.getContent()); + commodity.setAwardContent(StringUtils.isBlankOrElse(param.getAwardContent(), "0")); + commodity.setAmountUsd(param.getAmountUsd()); + commodity.setShelf(Boolean.TRUE.equals(param.getShelf())); + commodity.setUpdateTime(TimestampUtils.now()); + if (Objects.isNull(commodity.getId())) { + commodity.setCreateTime(TimestampUtils.now()); + } + return commodity; + }) + .collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(commodities)) { + payApplicationCommodityService.saveOrUpdateBatch(commodities); + } + } + + private PayApplicationCommodity getOrCreateCommodity(SysPayApplicationCommodityCmd param, + Long payCountryId) { + PayApplicationCommodity commodity = payApplicationCommodityService.query() + .eq(PayApplicationCommodity::getApplicationId, param.getApplicationId()) + .eq(PayApplicationCommodity::getPayCountryId, payCountryId) + .eq(PayApplicationCommodity::getRegionId, StringUtils.isBlankOrElse(param.getRegionId(), "")) + .eq(PayApplicationCommodity::getType, param.getType()) + .eq(PayApplicationCommodity::getAmountUsd, param.getAmountUsd()) + .last(PageConstant.LIMIT_ONE) + .getOne(); + return Objects.nonNull(commodity) ? commodity : new PayApplicationCommodity(); } @Override diff --git a/rc-service/rc-service-order/order-inner-endpoint/src/main/java/com/red/circle/order/inner/service/impl/PayCountryClientServiceImpl.java b/rc-service/rc-service-order/order-inner-endpoint/src/main/java/com/red/circle/order/inner/service/impl/PayCountryClientServiceImpl.java index 3692dcba..c05bbe56 100644 --- a/rc-service/rc-service-order/order-inner-endpoint/src/main/java/com/red/circle/order/inner/service/impl/PayCountryClientServiceImpl.java +++ b/rc-service/rc-service-order/order-inner-endpoint/src/main/java/com/red/circle/order/inner/service/impl/PayCountryClientServiceImpl.java @@ -5,6 +5,7 @@ import com.google.api.client.util.Maps; import com.red.circle.framework.core.asserts.ResponseAssert; import com.red.circle.framework.dto.PageResult; import com.red.circle.framework.mybatis.constant.PageConstant; +import com.red.circle.order.app.command.pay.web.strategy.PayPlaceAnOrderService; import com.red.circle.order.infra.database.rds.entity.pay.PayCountry; import com.red.circle.order.infra.database.rds.entity.pay.PayCountryChannel; import com.red.circle.order.infra.database.rds.entity.pay.PayCountryChannelDetails; @@ -31,9 +32,11 @@ import java.math.BigDecimal; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; /** @@ -43,9 +46,11 @@ import org.springframework.stereotype.Service; */ @Service @RequiredArgsConstructor +@Slf4j public class PayCountryClientServiceImpl implements PayCountryClientService { private final PayCountryService payCountryService; + private final PayPlaceAnOrderService payPlaceAnOrderService; private final SysCountryCodeClient countryCodeClient; private final WebPayInnerConvertor webPayInnerConvertor; private final RegionRelationClient regionRelationClient; @@ -246,6 +251,36 @@ public class PayCountryClientServiceImpl implements PayCountryClientService { payCountryService.updateUsdExchangeRate(id, rate); } + @Override + public Integer syncAllUsdExchangeRate() { + List payCountries = payCountryService.listOpenPayCountry(null); + if (CollectionUtils.isEmpty(payCountries)) { + return 0; + } + + int successCount = 0; + for (PayCountry payCountry : payCountries) { + if (StringUtils.isBlank(payCountry.getCurrency())) { + log.warn("Skip exchange rate sync because currency is blank, payCountryId={}", + payCountry.getId()); + continue; + } + + BigDecimal rate = "USD".equalsIgnoreCase(payCountry.getCurrency()) + ? BigDecimal.ONE + : payPlaceAnOrderService.getRealTimeExchangeRate("USD", payCountry.getCurrency()); + if (Objects.isNull(rate)) { + log.warn("Skip exchange rate sync because realtime rate is empty, payCountryId={}, currency={}", + payCountry.getId(), payCountry.getCurrency()); + continue; + } + + payCountryService.updateUsdExchangeRate(payCountry.getId(), rate); + successCount++; + } + return successCount; + } + @Override public void updateCountryCurrency(Long id, String currency) { payCountryService.updateCountryCurrency(id, currency);