feat: add h5 mifapay recharge endpoints
This commit is contained in:
parent
73adb48c1c
commit
a92739a2bc
2
.gitignore
vendored
2
.gitignore
vendored
@ -94,3 +94,5 @@ target/
|
||||
|
||||
devops-monitor-id_rsa.key
|
||||
/.claude/
|
||||
|
||||
build.md
|
||||
|
||||
@ -5,8 +5,13 @@ import com.red.circle.common.business.dto.cmd.IdStringCmd;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.ApplicationCommodityCardV2CO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PayApplicationCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PayCountryCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PayWebH5ContextCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PayWebH5OptionsCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PayWebH5OrderCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PlaceAnOrderResponseCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.UserProfileAndCountryCO;
|
||||
import com.red.circle.order.app.dto.cmd.PayWebH5OptionsCmd;
|
||||
import com.red.circle.order.app.dto.cmd.PayWebH5PlaceOrderCmd;
|
||||
import com.red.circle.order.app.dto.cmd.PayPlaceAnOrderCmd;
|
||||
import com.red.circle.order.app.dto.cmd.PayPlaceAnOrderReceiptCmd;
|
||||
import com.red.circle.order.app.dto.cmd.PayWebApplicationCommodityCmd;
|
||||
@ -91,6 +96,58 @@ public class WebPayRestController {
|
||||
return webPayService.getChannelCommodityV2(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* H5 充值账号上下文.
|
||||
*
|
||||
* @eo.name H5 充值账号上下文.
|
||||
* @eo.url /h5/context
|
||||
* @eo.method get
|
||||
* @eo.request-type formdata
|
||||
*/
|
||||
@GetMapping("/h5/context")
|
||||
public PayWebH5ContextCO h5Context(@Validated PayWebUserCmd cmd) {
|
||||
return webPayService.getH5Context(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* H5 充值商品列表.
|
||||
*
|
||||
* @eo.name H5 充值商品列表.
|
||||
* @eo.url /h5/options
|
||||
* @eo.method get
|
||||
* @eo.request-type formdata
|
||||
*/
|
||||
@GetMapping("/h5/options")
|
||||
public PayWebH5OptionsCO h5Options(@Validated PayWebH5OptionsCmd cmd) {
|
||||
return webPayService.getH5Options(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* H5 MiFaPay 下单.
|
||||
*
|
||||
* @eo.name H5 MiFaPay 下单.
|
||||
* @eo.url /h5/orders
|
||||
* @eo.method post
|
||||
* @eo.request-type json
|
||||
*/
|
||||
@PostMapping("/h5/orders")
|
||||
public PayWebH5OrderCO h5Order(@RequestBody @Validated PayWebH5PlaceOrderCmd cmd) {
|
||||
return webPayService.createH5Order(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* H5 订单状态.
|
||||
*
|
||||
* @eo.name H5 订单状态.
|
||||
* @eo.url /h5/orders/{orderId}
|
||||
* @eo.method get
|
||||
* @eo.request-type formdata
|
||||
*/
|
||||
@GetMapping("/h5/orders/{orderId}")
|
||||
public PayWebH5OrderCO h5OrderStatus(@PathVariable("orderId") String orderId) {
|
||||
return webPayService.getH5Order(orderId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下单.
|
||||
*
|
||||
|
||||
@ -0,0 +1,158 @@
|
||||
package com.red.circle.order.app.command.pay.web;
|
||||
|
||||
import com.red.circle.common.business.core.amount.PayAmountArithmeticUtils;
|
||||
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;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PayWebH5AccountCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PayWebH5ContextCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PayWebH5OptionsCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PayWebH5ProductCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.UserProfileAndCountryCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.WebSiteUseProfileCO;
|
||||
import com.red.circle.order.app.dto.cmd.PayWebH5OptionsCmd;
|
||||
import com.red.circle.order.app.dto.cmd.PayWebUserCmd;
|
||||
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.model.enums.PayApplicationCommodityType;
|
||||
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.text.StringUtils;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Aslan H5 充值上下文和商品查询。
|
||||
*
|
||||
* <p>商品价格必须从后台商品表实时读取,H5 本地 JSON 只决定 MiFaPay 国家和方式,不能参与金额计算。</p>
|
||||
*
|
||||
* @author tf
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class PayWebH5OptionsQryExe {
|
||||
|
||||
private final PayCountryService payCountryService;
|
||||
private final PayApplicationService payApplicationService;
|
||||
private final SysCountryCodeClient sysCountryCodeClient;
|
||||
private final UserProfileAndCountryQueryExe userProfileAndCountryQueryExe;
|
||||
private final PayApplicationCommodityService payApplicationCommodityService;
|
||||
|
||||
public PayWebH5ContextCO context(PayWebUserCmd cmd) {
|
||||
defaultType(cmd);
|
||||
UserProfileAndCountryCO source = userProfileAndCountryQueryExe.execute(cmd);
|
||||
WebSiteUseProfileCO userProfile = source.getUserProfile();
|
||||
ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, userProfile);
|
||||
|
||||
return new PayWebH5ContextCO()
|
||||
.setAuthMode("display_user_id")
|
||||
.setAccount(new PayWebH5AccountCO()
|
||||
.setUserId(userProfile.getId())
|
||||
.setDisplayUserId(userProfile.getId())
|
||||
.setUsername(userProfile.getUserNickname())
|
||||
.setAvatar(userProfile.getUserAvatar())
|
||||
.setAccount(userProfile.getAccount())
|
||||
.setSysOrigin(userProfile.getSysOrigin())
|
||||
.setFreightAgent(userProfile.getFreightAgent())
|
||||
.setSuperFreightAgent(userProfile.getSuperFreightAgent())
|
||||
.setAudienceType(resolveAudienceType(userProfile)))
|
||||
.setCountryList(source.getCountryList())
|
||||
.setRegionId(source.getRegionId());
|
||||
}
|
||||
|
||||
public PayWebH5OptionsCO options(PayWebH5OptionsCmd cmd) {
|
||||
defaultType(cmd);
|
||||
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());
|
||||
ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, payCountry);
|
||||
|
||||
SysCountryCodeDTO country = ResponseAssert.requiredSuccess(
|
||||
sysCountryCodeClient.getById(payCountry.getCountryId())
|
||||
);
|
||||
ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, country);
|
||||
|
||||
List<PayApplicationCommodity> commodities = payApplicationCommodityService
|
||||
.listCommodityByApplicationCountry(
|
||||
cmd.getApplicationId(),
|
||||
payCountry.getId(),
|
||||
cmd.getType(),
|
||||
null
|
||||
);
|
||||
if (CollectionUtils.isEmpty(commodities) && StringUtils.isNotBlank(cmd.getRegionId())) {
|
||||
// Aslan 后台有按区域维护商品的历史配置;国家商品为空时只降级到同区域商品,不放宽应用或类型条件。
|
||||
commodities = payApplicationCommodityService.listCommodityByApplicationCountry(
|
||||
cmd.getApplicationId(),
|
||||
null,
|
||||
cmd.getType(),
|
||||
cmd.getRegionId()
|
||||
);
|
||||
}
|
||||
|
||||
BigDecimal exchangeRate = payCountry.getUsdExchangeRate();
|
||||
return new PayWebH5OptionsCO()
|
||||
.setPayCountryId(Objects.toString(payCountry.getId()))
|
||||
.setCountryCode(country.getAlphaTwo())
|
||||
.setCountryName(country.getCountryName())
|
||||
.setCurrencyCode(payCountry.getCurrency())
|
||||
.setUsdToCurrencyRate(exchangeRate)
|
||||
.setProducts(commodities.stream()
|
||||
.map(commodity -> toProduct(commodity, payCountry))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private PayWebH5ProductCO toProduct(PayApplicationCommodity commodity, PayCountry payCountry) {
|
||||
BigDecimal amount = PayAmountArithmeticUtils.multiplyUpNotPoint(
|
||||
commodity.getAmountUsd(),
|
||||
payCountry.getUsdExchangeRate()
|
||||
);
|
||||
return new PayWebH5ProductCO()
|
||||
.setProductId(Objects.toString(commodity.getId()))
|
||||
.setCoinAmount(commodity.getObtainGoldsQuantity().stripTrailingZeros().toPlainString())
|
||||
.setAmountUsd(commodity.getAmountUsd())
|
||||
.setAmountUsdtMicro(minor(commodity.getAmountUsd(), 1_000_000L))
|
||||
.setAmountMinor(minor(commodity.getAmountUsd(), 100L))
|
||||
.setProviderAmountMinor(minor(amount, 100L))
|
||||
.setCurrencyCode(payCountry.getCurrency())
|
||||
.setType(commodity.getType());
|
||||
}
|
||||
|
||||
private Long minor(BigDecimal amount, Long scale) {
|
||||
return amount.multiply(BigDecimal.valueOf(scale)).setScale(0, RoundingMode.DOWN).longValue();
|
||||
}
|
||||
|
||||
private String resolveAudienceType(WebSiteUseProfileCO userProfile) {
|
||||
if (Boolean.TRUE.equals(userProfile.getSuperFreightAgent())) {
|
||||
return "super_freight_agent";
|
||||
}
|
||||
if (Boolean.TRUE.equals(userProfile.getFreightAgent())) {
|
||||
return "coin_seller";
|
||||
}
|
||||
return "normal";
|
||||
}
|
||||
|
||||
private void defaultType(PayWebUserCmd cmd) {
|
||||
if (Objects.isNull(cmd.getType())) {
|
||||
cmd.setType(PayApplicationCommodityType.GOLD);
|
||||
}
|
||||
}
|
||||
|
||||
private void defaultType(PayWebH5OptionsCmd cmd) {
|
||||
if (Objects.isNull(cmd.getType())) {
|
||||
cmd.setType(PayApplicationCommodityType.GOLD);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,199 @@
|
||||
package com.red.circle.order.app.command.pay.web;
|
||||
|
||||
import com.red.circle.common.business.core.amount.PayAmountArithmeticUtils;
|
||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||
import com.red.circle.framework.core.response.CommonErrorCode;
|
||||
import com.red.circle.framework.core.response.ResponseErrorCode;
|
||||
import com.red.circle.order.app.command.pay.web.strategy.PayPlaceAnOrderDetailsV2;
|
||||
import com.red.circle.order.app.command.pay.web.strategy.PayPlaceAnOrderService;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PayWebH5OrderCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PlaceAnOrderResponseCO;
|
||||
import com.red.circle.order.app.dto.cmd.PayWebH5PlaceOrderCmd;
|
||||
import com.red.circle.order.infra.database.mongo.order.InAppPurchaseDetailsService;
|
||||
import com.red.circle.order.infra.database.mongo.order.entity.InAppPurchaseDetails;
|
||||
import com.red.circle.order.infra.database.mongo.order.entity.assist.InAppPurchaseProduct;
|
||||
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.entity.pay.PayCountryChannelDetails;
|
||||
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.infra.util.IpUtils;
|
||||
import com.red.circle.order.inner.model.enums.PayApplicationCommodityType;
|
||||
import com.red.circle.order.inner.model.enums.inapp.InAppPurchaseReceiptType;
|
||||
import com.red.circle.order.inner.model.enums.inapp.InAppPurchaseStatus;
|
||||
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.num.ArithmeticUtils;
|
||||
import com.red.circle.tool.core.sequence.IdWorkerUtils;
|
||||
import com.red.circle.tool.core.text.StringUtils;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Aslan H5 MiFaPay 下单和查单。
|
||||
*
|
||||
* <p>前端只提交商品 id 和支付方式标识;金额、金币数、商品类型、币种和汇率全部从后台表重新生成。</p>
|
||||
*
|
||||
* @author tf
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class PayWebH5PlaceOrderCmdExe {
|
||||
|
||||
private static final String PROVIDER_MIFAPAY = "mifapay";
|
||||
private static final String FACTORY_MIFAPAY = "MIFA_PAY";
|
||||
|
||||
private final PayCountryService payCountryService;
|
||||
private final PayApplicationService payApplicationService;
|
||||
private final SysCountryCodeClient sysCountryCodeClient;
|
||||
private final PayPlaceAnOrderService payPlaceAnOrderService;
|
||||
private final InAppPurchaseDetailsService inAppPurchaseDetailsService;
|
||||
private final PayApplicationCommodityService payApplicationCommodityService;
|
||||
|
||||
public PayWebH5OrderCO execute(PayWebH5PlaceOrderCmd cmd) {
|
||||
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
||||
PROVIDER_MIFAPAY.equalsIgnoreCase(Objects.toString(cmd.getProviderCode(), "")));
|
||||
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
||||
Objects.nonNull(cmd.getApplicationId())
|
||||
&& Objects.nonNull(cmd.getGoodsId())
|
||||
&& Objects.nonNull(cmd.getPayCountryId())
|
||||
&& Objects.nonNull(cmd.getUserId())
|
||||
&& StringUtils.isNotBlank(cmd.getPayWay())
|
||||
&& StringUtils.isNotBlank(cmd.getPayType()));
|
||||
|
||||
PayPlaceAnOrderDetailsV2 details = buildDetails(cmd);
|
||||
PlaceAnOrderResponseCO response = payPlaceAnOrderService.doRequest(details);
|
||||
return new PayWebH5OrderCO()
|
||||
.setOrderId(details.getOrderId())
|
||||
.setProviderCode(PROVIDER_MIFAPAY)
|
||||
.setPayUrl(response.getRequestUrl())
|
||||
.setStatus("redirected")
|
||||
.setProviderAmountMinor(minor(details.getAmount(), 100L))
|
||||
.setUsdMinorAmount(minor(details.getAmountUsd(), 100L))
|
||||
.setCurrencyCode(details.getCurrency())
|
||||
.setFailureReason("");
|
||||
}
|
||||
|
||||
public PayWebH5OrderCO getOrder(String orderId) {
|
||||
InAppPurchaseDetails order = inAppPurchaseDetailsService.getById(orderId);
|
||||
ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, order);
|
||||
return new PayWebH5OrderCO()
|
||||
.setOrderId(order.getId())
|
||||
.setProviderCode(PROVIDER_MIFAPAY)
|
||||
.setStatus(toH5Status(order.getStatus()))
|
||||
.setProviderAmountMinor(minor(order.getAmount(), 100L))
|
||||
.setUsdMinorAmount(minor(order.getAmountUsd(), 100L))
|
||||
.setCurrencyCode(order.getCurrency())
|
||||
.setFailureReason(order.getReason());
|
||||
}
|
||||
|
||||
private PayPlaceAnOrderDetailsV2 buildDetails(PayWebH5PlaceOrderCmd cmd) {
|
||||
PayApplication application = payApplicationService.getById(cmd.getApplicationId());
|
||||
ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, application);
|
||||
|
||||
PayApplicationCommodity commodity = payApplicationCommodityService
|
||||
.getAppCommodity(cmd.getGoodsId(), cmd.getApplicationId());
|
||||
ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_MAPPING_INFO, commodity);
|
||||
ResponseAssert.isTrue(CommonErrorCode.QUANTITY_MUST_GT_ZERO,
|
||||
ArithmeticUtils.gtZero(commodity.getObtainGoldsQuantity()));
|
||||
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
||||
Boolean.TRUE.equals(commodity.getShelf()));
|
||||
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
||||
Objects.isNull(cmd.getType()) || Objects.equals(cmd.getType().name(), commodity.getType()));
|
||||
|
||||
PayCountry payCountry = payCountryService.getById(cmd.getPayCountryId());
|
||||
ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, payCountry);
|
||||
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
||||
Boolean.TRUE.equals(payCountry.getShelf()));
|
||||
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
||||
Objects.isNull(commodity.getPayCountryId())
|
||||
|| Objects.equals(commodity.getPayCountryId(), payCountry.getId()));
|
||||
|
||||
SysCountryCodeDTO sysCountryCode = ResponseAssert.requiredSuccess(
|
||||
sysCountryCodeClient.getById(payCountry.getCountryId())
|
||||
);
|
||||
ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, sysCountryCode);
|
||||
|
||||
BigDecimal amount = PayAmountArithmeticUtils.multiplyUpNotPoint(
|
||||
commodity.getAmountUsd(),
|
||||
payCountry.getUsdExchangeRate()
|
||||
);
|
||||
PayPlaceAnOrderDetailsV2 details = new PayPlaceAnOrderDetailsV2();
|
||||
details.setOrderId(IdWorkerUtils.getIdStr());
|
||||
details.setReceiptType(InAppPurchaseReceiptType.PAYMENT);
|
||||
details.setApplicationId(Objects.toString(application.getId()));
|
||||
details.setAppCommodityType(commodity.getType());
|
||||
details.setSysOrigin(application.getAppCode());
|
||||
details.setAcceptUserId(cmd.getUserId());
|
||||
details.setCreateUserId(cmd.getUserId());
|
||||
details.setAmount(amount);
|
||||
details.setAmountUsd(commodity.getAmountUsd());
|
||||
details.setProducts(List.of(new InAppPurchaseProduct()
|
||||
.setId(commodity.getId())
|
||||
.setName(commodity.getType())
|
||||
.setCode(commodity.getType())
|
||||
.setDescribe(productDescriptor(commodity))
|
||||
.setContent(commodity.getObtainGoldsQuantity().stripTrailingZeros().toPlainString())
|
||||
.setAmountUsd(commodity.getAmountUsd())
|
||||
.setQuantity(1)));
|
||||
details.setProductDescriptor(productDescriptor(commodity));
|
||||
details.setChannelDetails(mifaPayChannel(cmd, payCountry));
|
||||
details.setCountry(sysCountryCode);
|
||||
details.setPayCountry(payCountry);
|
||||
details.setRechargeUrl(StringUtils.isBlankOrElse(cmd.getReturnUrl(), ""));
|
||||
details.setSuccessRedirectUrl(StringUtils.isBlankOrElse(cmd.getReturnUrl(), ""));
|
||||
details.setCancelRedirectUrl(StringUtils.isBlankOrElse(cmd.getReturnUrl(), ""));
|
||||
details.setNewVersion(Boolean.TRUE);
|
||||
details.setRequestIp(IpUtils.getIpAddr());
|
||||
return details;
|
||||
}
|
||||
|
||||
private PayCountryChannelDetails mifaPayChannel(PayWebH5PlaceOrderCmd cmd, PayCountry payCountry) {
|
||||
String channelCode = StringUtils.isNotBlank(cmd.getChannelCode())
|
||||
? cmd.getChannelCode()
|
||||
: cmd.getPayWay() + "_" + cmd.getPayType();
|
||||
// 这里刻意不查后台渠道明细表:H5 支付国家和方式来自 app JSON,本对象只为复用现有 MiFaPay 策略和订单快照。
|
||||
return new PayCountryChannelDetails()
|
||||
.setId(0L)
|
||||
.setPayCountryId(payCountry.getId())
|
||||
.setChannelCode(channelCode)
|
||||
.setFactoryCode(FACTORY_MIFAPAY)
|
||||
.setFactoryChannel(cmd.getPayType())
|
||||
.setFactoryCurrencyPoint(2)
|
||||
.setShelf(Boolean.TRUE);
|
||||
}
|
||||
|
||||
private String productDescriptor(PayApplicationCommodity commodity) {
|
||||
return PayApplicationCommodityType.GOLD.eq(commodity.getType())
|
||||
? commodity.getType()
|
||||
: commodity.getAmountUsd().stripTrailingZeros().toPlainString()
|
||||
+ "USD = "
|
||||
+ StringUtils.isBlankOrElse(commodity.getContent(), "0")
|
||||
+ commodity.getType();
|
||||
}
|
||||
|
||||
private String toH5Status(InAppPurchaseStatus status) {
|
||||
if (Objects.equals(status, InAppPurchaseStatus.SUCCESS)) {
|
||||
return "credited";
|
||||
}
|
||||
if (Objects.equals(status, InAppPurchaseStatus.FAIL)
|
||||
|| Objects.equals(status, InAppPurchaseStatus.CANCEL)
|
||||
|| Objects.equals(status, InAppPurchaseStatus.REFUND)) {
|
||||
return "failed";
|
||||
}
|
||||
return "pending";
|
||||
}
|
||||
|
||||
private Long minor(BigDecimal amount, Long scale) {
|
||||
if (Objects.isNull(amount)) {
|
||||
return 0L;
|
||||
}
|
||||
return amount.multiply(BigDecimal.valueOf(scale)).setScale(0, RoundingMode.DOWN).longValue();
|
||||
}
|
||||
}
|
||||
@ -31,7 +31,7 @@ public class MiFaPayService {
|
||||
private final MiFaPayProperties miFaPayProperties;
|
||||
private final RcHttpClient rcHttpClient = RcHttpClient.builder().build();
|
||||
|
||||
public MiFaPayService(@Value("${spring.profiles.active:dev}") String active,
|
||||
public MiFaPayService(@Value("${spring.profiles.active:prod}") String active,
|
||||
MiFaPayProperties miFaPayProperties) {
|
||||
this.active = active;
|
||||
this.miFaPayProperties = miFaPayProperties;
|
||||
|
||||
@ -3,12 +3,19 @@ package com.red.circle.order.app.service;
|
||||
import com.red.circle.common.business.dto.cmd.IdLongCmd;
|
||||
import com.red.circle.order.app.command.pay.PayApplicationQryExe;
|
||||
import com.red.circle.order.app.command.pay.web.PayWebApplicationCommodityV2QueryExe;
|
||||
import com.red.circle.order.app.command.pay.web.PayWebH5OptionsQryExe;
|
||||
import com.red.circle.order.app.command.pay.web.PayWebH5PlaceOrderCmdExe;
|
||||
import com.red.circle.order.app.command.pay.web.PayWebOpenPayCountryQueryExe;
|
||||
import com.red.circle.order.app.command.pay.web.UserProfileAndCountryQueryExe;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.ApplicationCommodityCardV2CO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PayApplicationCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PayCountryCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PayWebH5ContextCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PayWebH5OptionsCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PayWebH5OrderCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.UserProfileAndCountryCO;
|
||||
import com.red.circle.order.app.dto.cmd.PayWebH5OptionsCmd;
|
||||
import com.red.circle.order.app.dto.cmd.PayWebH5PlaceOrderCmd;
|
||||
import com.red.circle.order.app.dto.cmd.PayWebApplicationCommodityCmd;
|
||||
import com.red.circle.order.app.dto.cmd.PayWebUserCmd;
|
||||
import java.util.List;
|
||||
@ -28,6 +35,8 @@ public class WebPayServiceImpl implements WebPayService {
|
||||
private final PayWebOpenPayCountryQueryExe payWebOpenPayCountryQueryExe;
|
||||
private final UserProfileAndCountryQueryExe userProfileAndCountryQueryExe;
|
||||
private final PayWebApplicationCommodityV2QueryExe payWebApplicationCommodityV2QueryExe;
|
||||
private final PayWebH5OptionsQryExe payWebH5OptionsQryExe;
|
||||
private final PayWebH5PlaceOrderCmdExe payWebH5PlaceOrderCmdExe;
|
||||
|
||||
@Override
|
||||
public PayApplicationCO getApplication(IdLongCmd cmd) {
|
||||
@ -50,4 +59,24 @@ public class WebPayServiceImpl implements WebPayService {
|
||||
return userProfileAndCountryQueryExe.execute(cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayWebH5ContextCO getH5Context(PayWebUserCmd cmd) {
|
||||
return payWebH5OptionsQryExe.context(cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayWebH5OptionsCO getH5Options(PayWebH5OptionsCmd cmd) {
|
||||
return payWebH5OptionsQryExe.options(cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayWebH5OrderCO createH5Order(PayWebH5PlaceOrderCmd cmd) {
|
||||
return payWebH5PlaceOrderCmdExe.execute(cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayWebH5OrderCO getH5Order(String orderId) {
|
||||
return payWebH5PlaceOrderCmdExe.getOrder(orderId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,48 @@
|
||||
package com.red.circle.order.app.dto.clientobject.pay;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.red.circle.framework.dto.ClientObject;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* H5 充值页账号快照,只暴露确认充值对象需要的公开字段。
|
||||
*
|
||||
* @author tf
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class PayWebH5AccountCO extends ClientObject {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
@JsonProperty("user_id")
|
||||
private Long userId;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
@JsonProperty("display_user_id")
|
||||
private Long displayUserId;
|
||||
|
||||
private String username;
|
||||
|
||||
private String avatar;
|
||||
|
||||
private String account;
|
||||
|
||||
@JsonProperty("sys_origin")
|
||||
private String sysOrigin;
|
||||
|
||||
@JsonProperty("audience_type")
|
||||
private String audienceType;
|
||||
|
||||
@JsonProperty("freight_agent")
|
||||
private Boolean freightAgent;
|
||||
|
||||
@JsonProperty("super_freight_agent")
|
||||
private Boolean superFreightAgent;
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
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;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* H5 充值页上下文,账号和国家都来自 Aslan 服务端,前端只拿它做展示和后续商品查询条件。
|
||||
*
|
||||
* @author tf
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class PayWebH5ContextCO extends ClientObject {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@JsonProperty("auth_mode")
|
||||
private String authMode;
|
||||
|
||||
private PayWebH5AccountCO account;
|
||||
|
||||
@JsonProperty("country_list")
|
||||
private List<PayCountryCO> countryList;
|
||||
|
||||
@JsonProperty("region_id")
|
||||
private String regionId;
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package com.red.circle.order.app.dto.clientobject.pay;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.red.circle.framework.dto.ClientObject;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* H5 商品列表和当前支付国家汇率快照,支付方式由本地 JSON 合并。
|
||||
*
|
||||
* @author tf
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class PayWebH5OptionsCO extends ClientObject {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private List<PayWebH5ProductCO> products;
|
||||
|
||||
@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;
|
||||
|
||||
@JsonProperty("usd_to_currency_rate")
|
||||
private BigDecimal usdToCurrencyRate;
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package com.red.circle.order.app.dto.clientobject.pay;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.red.circle.framework.dto.ClientObject;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* H5 订单状态快照,终态由服务端订单状态决定,前端只负责跳转和轮询展示。
|
||||
*
|
||||
* @author tf
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class PayWebH5OrderCO extends ClientObject {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@JsonProperty("order_id")
|
||||
private String orderId;
|
||||
|
||||
@JsonProperty("provider_code")
|
||||
private String providerCode;
|
||||
|
||||
@JsonProperty("pay_url")
|
||||
private String payUrl;
|
||||
|
||||
private String status;
|
||||
|
||||
@JsonProperty("provider_amount_minor")
|
||||
private Long providerAmountMinor;
|
||||
|
||||
@JsonProperty("usd_minor_amount")
|
||||
private Long usdMinorAmount;
|
||||
|
||||
@JsonProperty("currency_code")
|
||||
private String currencyCode;
|
||||
|
||||
@JsonProperty("failure_reason")
|
||||
private String failureReason;
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package com.red.circle.order.app.dto.clientobject.pay;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.red.circle.framework.dto.ClientObject;
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* H5 商品卡片快照,金额由后端按后台商品表和支付国家汇率计算,前端不参与定价。
|
||||
*
|
||||
* @author tf
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class PayWebH5ProductCO extends ClientObject {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@JsonProperty("product_id")
|
||||
private String productId;
|
||||
|
||||
@JsonProperty("coin_amount")
|
||||
private String coinAmount;
|
||||
|
||||
@JsonProperty("amount_usdt_micro")
|
||||
private Long amountUsdtMicro;
|
||||
|
||||
@JsonProperty("amount_minor")
|
||||
private Long amountMinor;
|
||||
|
||||
@JsonProperty("provider_amount_minor")
|
||||
private Long providerAmountMinor;
|
||||
|
||||
@JsonProperty("currency_code")
|
||||
private String currencyCode;
|
||||
|
||||
@JsonProperty("amount_usd")
|
||||
private BigDecimal amountUsd;
|
||||
|
||||
private String type;
|
||||
}
|
||||
@ -49,6 +49,16 @@ public class WebSiteUseProfileCO extends ClientObject {
|
||||
*/
|
||||
private String sysOrigin;
|
||||
|
||||
/**
|
||||
* 是否金币代理.
|
||||
*/
|
||||
private Boolean freightAgent;
|
||||
|
||||
/**
|
||||
* 是否超级金币代理.
|
||||
*/
|
||||
private Boolean superFreightAgent;
|
||||
|
||||
public static WebSiteUseProfileCO toWebSiteUseProfileCO(UserProfileDTO userProfile) {
|
||||
if (userProfile == null) {
|
||||
return null;
|
||||
@ -58,6 +68,8 @@ public class WebSiteUseProfileCO extends ClientObject {
|
||||
.setUserAvatar(userProfile.getUserAvatar())
|
||||
.setUserNickname(userProfile.getUserNickname())
|
||||
.setAccount(userProfile.getAccount())
|
||||
.setSysOrigin(userProfile.getOriginSys());
|
||||
.setSysOrigin(userProfile.getOriginSys())
|
||||
.setFreightAgent(userProfile.getIsFreightAgent())
|
||||
.setSuperFreightAgent(userProfile.getIsSuperFreightAgent());
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
package com.red.circle.order.app.dto.cmd;
|
||||
|
||||
import com.red.circle.framework.dto.Command;
|
||||
import com.red.circle.order.inner.model.enums.PayApplicationCommodityType;
|
||||
import java.io.Serial;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* H5 商品查询命令,商品类型和国家来自已确认账号上下文。
|
||||
*
|
||||
* @author tf
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class PayWebH5OptionsCmd extends Command {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long applicationId;
|
||||
|
||||
private Long payCountryId;
|
||||
|
||||
private Long userId;
|
||||
|
||||
private String regionId;
|
||||
|
||||
private PayApplicationCommodityType type;
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
package com.red.circle.order.app.dto.cmd;
|
||||
|
||||
import com.red.circle.framework.dto.Command;
|
||||
import com.red.circle.order.inner.model.enums.PayApplicationCommodityType;
|
||||
import java.io.Serial;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* H5 下单命令只接收商品和支付方式标识;金额、金币数、币种由服务端重新查表计算。
|
||||
*
|
||||
* @author tf
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class PayWebH5PlaceOrderCmd extends Command {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long applicationId;
|
||||
|
||||
private Long goodsId;
|
||||
|
||||
private Long payCountryId;
|
||||
|
||||
private Long userId;
|
||||
|
||||
private String providerCode;
|
||||
|
||||
private String payWay;
|
||||
|
||||
private String payType;
|
||||
|
||||
private String channelCode;
|
||||
|
||||
private String returnUrl;
|
||||
|
||||
private String commandId;
|
||||
|
||||
private String language;
|
||||
|
||||
private PayApplicationCommodityType type;
|
||||
}
|
||||
@ -4,7 +4,12 @@ import com.red.circle.common.business.dto.cmd.IdLongCmd;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.ApplicationCommodityCardV2CO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PayApplicationCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PayCountryCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PayWebH5ContextCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PayWebH5OptionsCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.PayWebH5OrderCO;
|
||||
import com.red.circle.order.app.dto.clientobject.pay.UserProfileAndCountryCO;
|
||||
import com.red.circle.order.app.dto.cmd.PayWebH5OptionsCmd;
|
||||
import com.red.circle.order.app.dto.cmd.PayWebH5PlaceOrderCmd;
|
||||
import com.red.circle.order.app.dto.cmd.PayWebApplicationCommodityCmd;
|
||||
import com.red.circle.order.app.dto.cmd.PayWebUserCmd;
|
||||
import java.util.List;
|
||||
@ -39,4 +44,24 @@ public interface WebPayService {
|
||||
*/
|
||||
UserProfileAndCountryCO getUserProfileAndCountry(PayWebUserCmd cmd);
|
||||
|
||||
/**
|
||||
* H5 充值账号上下文.
|
||||
*/
|
||||
PayWebH5ContextCO getH5Context(PayWebUserCmd cmd);
|
||||
|
||||
/**
|
||||
* H5 商品列表.
|
||||
*/
|
||||
PayWebH5OptionsCO getH5Options(PayWebH5OptionsCmd cmd);
|
||||
|
||||
/**
|
||||
* H5 下单.
|
||||
*/
|
||||
PayWebH5OrderCO createH5Order(PayWebH5PlaceOrderCmd cmd);
|
||||
|
||||
/**
|
||||
* H5 订单状态.
|
||||
*/
|
||||
PayWebH5OrderCO getH5Order(String orderId);
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user