feat: update mifapay and region config flows
This commit is contained in:
parent
f7d821ae37
commit
2fd0976d0d
@ -34,8 +34,8 @@ red-circle:
|
|||||||
access-url: ${LIKEI_TENCENT_COS_ACCESS_URL}
|
access-url: ${LIKEI_TENCENT_COS_ACCESS_URL}
|
||||||
instant-message:
|
instant-message:
|
||||||
broadcast-group:
|
broadcast-group:
|
||||||
LOTFUN: ${LIKEI_IM_BROADCAST_GROUP_LOTFUN}
|
LOTFUN: "${LIKEI_IM_BROADCAST_GROUP_LOTFUN}"
|
||||||
LIKEI: ${LIKEI_IM_BROADCAST_GROUP_LIKEI}
|
LIKEI: "${LIKEI_IM_BROADCAST_GROUP_LIKEI}"
|
||||||
tencet-trtc:
|
tencet-trtc:
|
||||||
secretId: ${LIKEI_TRTC_SECRET_ID}
|
secretId: ${LIKEI_TRTC_SECRET_ID}
|
||||||
secretKey: ${LIKEI_TRTC_SECRET_KEY}
|
secretKey: ${LIKEI_TRTC_SECRET_KEY}
|
||||||
|
|||||||
@ -52,6 +52,7 @@ red-circle:
|
|||||||
gateway-base-url: ${LIKEI_MIFA_PAY_GATEWAY_BASE_URL}
|
gateway-base-url: ${LIKEI_MIFA_PAY_GATEWAY_BASE_URL}
|
||||||
rsa-private-key: ${LIKEI_MIFA_PAY_RSA_PRIVATE_KEY}
|
rsa-private-key: ${LIKEI_MIFA_PAY_RSA_PRIVATE_KEY}
|
||||||
platform-rsa-public-key: ${LIKEI_MIFA_PAY_PLATFORM_RSA_PUBLIC_KEY}
|
platform-rsa-public-key: ${LIKEI_MIFA_PAY_PLATFORM_RSA_PUBLIC_KEY}
|
||||||
|
notify-url: ${LIKEI_MIFA_PAY_NOTIFY_URL:https://jvapi.haiyihy.com/play-server-notice/mifa_pay/receive_payment}
|
||||||
|
|
||||||
airwallex:
|
airwallex:
|
||||||
client-id: ${LIKEI_AIRWALLEX_CLIENT_ID}
|
client-id: ${LIKEI_AIRWALLEX_CLIENT_ID}
|
||||||
|
|||||||
@ -114,7 +114,7 @@ activity:
|
|||||||
|
|
||||||
|
|
||||||
scheduler:
|
scheduler:
|
||||||
room-empty-clean: false
|
room-online-quantity-reconcile: true
|
||||||
room-red-packet-expire: false
|
room-red-packet-expire: false
|
||||||
game-king-reward: false
|
game-king-reward: false
|
||||||
noble-daily-reward: false
|
noble-daily-reward: false
|
||||||
|
|||||||
@ -0,0 +1,119 @@
|
|||||||
|
package com.red.circle.common.business.core.util;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.red.circle.tool.core.json.JacksonUtils;
|
||||||
|
import com.red.circle.tool.core.text.StringUtils;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国家码别名工具.
|
||||||
|
*/
|
||||||
|
public final class CountryCodeAliasUtils {
|
||||||
|
|
||||||
|
private static final String SA = "SA";
|
||||||
|
private static final String KSA = "KSA";
|
||||||
|
|
||||||
|
private CountryCodeAliasUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 归一化国家码.
|
||||||
|
*/
|
||||||
|
public static String normalize(String code) {
|
||||||
|
return StringUtils.isBlank(code) ? null : code.trim().toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 沙特兼容归一化,保留非沙特国家原有写法.
|
||||||
|
*/
|
||||||
|
public static String normalizeSaudiCode(String code) {
|
||||||
|
String normalized = normalize(code);
|
||||||
|
return isSaudiCode(normalized) ? SA : normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否是沙特国家码.
|
||||||
|
*/
|
||||||
|
public static boolean isSaudiCode(String code) {
|
||||||
|
String normalized = normalize(code);
|
||||||
|
return SA.equals(normalized) || KSA.equals(normalized);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取国家码别名集合.
|
||||||
|
*/
|
||||||
|
public static Set<String> legacyAliases(String code) {
|
||||||
|
return buildMatchCodes(code, null, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析存储中的别名数组.
|
||||||
|
*/
|
||||||
|
public static List<String> parseAliasCodes(String aliasCodes) {
|
||||||
|
if (StringUtils.isBlank(aliasCodes)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<String> values = JacksonUtils.readValue(aliasCodes, new TypeReference<List<String>>() {});
|
||||||
|
return normalizeCodes(values);
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
return normalizeCodes(List.of(aliasCodes.split(",")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 序列化别名数组到存储值.
|
||||||
|
*/
|
||||||
|
public static String toAliasCodesJson(Collection<String> aliasCodes) {
|
||||||
|
List<String> values = normalizeCodes(aliasCodes);
|
||||||
|
if (values.isEmpty()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return JacksonUtils.toJson(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造完整匹配国家码集合.
|
||||||
|
*/
|
||||||
|
public static Set<String> buildMatchCodes(String alphaTwo, String alphaThree,
|
||||||
|
Collection<String> aliasCodes) {
|
||||||
|
LinkedHashSet<String> result = new LinkedHashSet<>();
|
||||||
|
appendCode(result, alphaTwo);
|
||||||
|
appendCode(result, alphaThree);
|
||||||
|
if (aliasCodes != null) {
|
||||||
|
aliasCodes.forEach(code -> appendCode(result, code));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.stream().anyMatch(CountryCodeAliasUtils::isSaudiCode)) {
|
||||||
|
result.add(SA);
|
||||||
|
result.add(KSA);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 规范化国家码列表.
|
||||||
|
*/
|
||||||
|
public static List<String> normalizeCodes(Collection<String> codes) {
|
||||||
|
if (codes == null || codes.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
LinkedHashSet<String> result = new LinkedHashSet<>();
|
||||||
|
codes.stream().map(CountryCodeAliasUtils::normalize).filter(StringUtils::isNotBlank)
|
||||||
|
.forEach(result::add);
|
||||||
|
return new ArrayList<>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void appendCode(Set<String> result, String code) {
|
||||||
|
String normalized = normalize(code);
|
||||||
|
if (StringUtils.isNotBlank(normalized)) {
|
||||||
|
result.add(normalized);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
|||||||
import com.red.circle.framework.core.dto.CommonCommand;
|
import com.red.circle.framework.core.dto.CommonCommand;
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
import java.util.List;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
@ -56,6 +57,11 @@ public class SysCountryCodeCmd extends CommonCommand {
|
|||||||
*/
|
*/
|
||||||
private String aliasName;
|
private String aliasName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国家码别名集合.
|
||||||
|
*/
|
||||||
|
private List<String> countryCodeAliases;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 代码分配情况.
|
* 代码分配情况.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
|||||||
import com.red.circle.framework.dto.DTO;
|
import com.red.circle.framework.dto.DTO;
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
import java.util.List;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
@ -56,6 +57,11 @@ public class SysCountryCodeDTO extends DTO {
|
|||||||
*/
|
*/
|
||||||
private String aliasName;
|
private String aliasName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国家码别名集合.
|
||||||
|
*/
|
||||||
|
private List<String> countryCodeAliases;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 代码分配情况.
|
* 代码分配情况.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -67,6 +67,8 @@ red-circle:
|
|||||||
ignore-urls:
|
ignore-urls:
|
||||||
- /console/account/login
|
- /console/account/login
|
||||||
- /console/actuator/**
|
- /console/actuator/**
|
||||||
|
- /console/internal/resident-activity/invite/grant-gold
|
||||||
|
- /console/internal/resident-activity/invite/grant-props
|
||||||
- /console/datav/active/user-country-code
|
- /console/datav/active/user-country-code
|
||||||
- /console/datav/online/user/count
|
- /console/datav/online/user/count
|
||||||
- /console/datav/online/room/count
|
- /console/datav/online/room/count
|
||||||
|
|||||||
@ -5,8 +5,10 @@ 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.ApplicationCommodityCardV2CO;
|
||||||
import com.red.circle.order.app.dto.clientobject.pay.PayApplicationCO;
|
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.PayCountryCO;
|
||||||
|
import com.red.circle.order.app.dto.clientobject.pay.PayOrderStatusCO;
|
||||||
import com.red.circle.order.app.dto.clientobject.pay.PlaceAnOrderResponseCO;
|
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.clientobject.pay.UserProfileAndCountryCO;
|
||||||
|
import com.red.circle.order.app.dto.cmd.PayOrderStatusCmd;
|
||||||
import com.red.circle.order.app.dto.cmd.PayPlaceAnOrderCmd;
|
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.PayPlaceAnOrderReceiptCmd;
|
||||||
import com.red.circle.order.app.dto.cmd.PayWebApplicationCommodityCmd;
|
import com.red.circle.order.app.dto.cmd.PayWebApplicationCommodityCmd;
|
||||||
@ -104,6 +106,19 @@ public class WebPayRestController {
|
|||||||
return inAppPurchaseProductService.placeAnOrder(cmd);
|
return inAppPurchaseProductService.placeAnOrder(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询支付单状态.
|
||||||
|
*
|
||||||
|
* @eo.name 查询支付单状态.
|
||||||
|
* @eo.url /order-status
|
||||||
|
* @eo.method get
|
||||||
|
* @eo.request-type formdata
|
||||||
|
*/
|
||||||
|
@GetMapping("/order-status")
|
||||||
|
public PayOrderStatusCO orderStatus(@Validated PayOrderStatusCmd cmd) {
|
||||||
|
return inAppPurchaseProductService.orderStatus(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付收据 (后续版本计划移除).
|
* 支付收据 (后续版本计划移除).
|
||||||
*
|
*
|
||||||
|
|||||||
@ -2,14 +2,14 @@ package com.red.circle.order.app.command.pay.web;
|
|||||||
|
|
||||||
import com.red.circle.component.pay.paymax.PayMaxUtils;
|
import com.red.circle.component.pay.paymax.PayMaxUtils;
|
||||||
import com.red.circle.order.app.common.InAppPurchaseCommon;
|
import com.red.circle.order.app.common.InAppPurchaseCommon;
|
||||||
|
import com.red.circle.order.app.common.MiFaPayMysqlOrderSupport;
|
||||||
import com.red.circle.order.domain.order.MiFaPayReceivePaymentNotice;
|
import com.red.circle.order.domain.order.MiFaPayReceivePaymentNotice;
|
||||||
import com.red.circle.order.infra.config.MiFaPayProperties;
|
import com.red.circle.order.infra.config.MiFaPayProperties;
|
||||||
import com.red.circle.order.infra.database.mongo.order.InAppPurchaseCollectionReceiptService;
|
import com.red.circle.order.infra.database.mongo.order.InAppPurchaseCollectionReceiptService;
|
||||||
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.InAppPurchaseDetails;
|
||||||
import com.red.circle.order.infra.database.mongo.order.entity.assist.InAppPurchaseEventNotice;
|
import com.red.circle.order.infra.database.rds.service.order.OrderUserPurchasePayNoticeService;
|
||||||
import com.red.circle.order.inner.model.enums.inapp.InAppPurchaseStatus;
|
import com.red.circle.order.infra.database.rds.entity.order.OrderUserPurchasePay;
|
||||||
import com.red.circle.tool.core.date.TimestampUtils;
|
import com.red.circle.order.infra.database.rds.service.order.OrderUserPurchasePayService;
|
||||||
import com.red.circle.tool.core.text.StringUtils;
|
import com.red.circle.tool.core.text.StringUtils;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -33,8 +33,9 @@ public class MiFaPayServerNoticeReceivePaymentCmdExe {
|
|||||||
|
|
||||||
private final MiFaPayProperties miFaPayProperties;
|
private final MiFaPayProperties miFaPayProperties;
|
||||||
private final InAppPurchaseCommon inAppPurchaseCommon;
|
private final InAppPurchaseCommon inAppPurchaseCommon;
|
||||||
private final InAppPurchaseDetailsService inAppPurchaseDetailsService;
|
|
||||||
private final InAppPurchaseCollectionReceiptService inAppPurchaseCollectionReceiptService;
|
private final InAppPurchaseCollectionReceiptService inAppPurchaseCollectionReceiptService;
|
||||||
|
private final OrderUserPurchasePayNoticeService orderUserPurchasePayNoticeService;
|
||||||
|
private final OrderUserPurchasePayService orderUserPurchasePayService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理MiFaPay支付回调
|
* 处理MiFaPay支付回调
|
||||||
@ -78,68 +79,72 @@ public class MiFaPayServerNoticeReceivePaymentCmdExe {
|
|||||||
|
|
||||||
MiFaPayReceivePaymentNotice.MiFaPayNoticeData noticeData = notice.getNoticeData();
|
MiFaPayReceivePaymentNotice.MiFaPayNoticeData noticeData = notice.getNoticeData();
|
||||||
|
|
||||||
// 查询订单
|
OrderUserPurchasePay mysqlOrder = getMysqlOrder(noticeData.getOrderId());
|
||||||
InAppPurchaseDetails order = inAppPurchaseDetailsService.getById(noticeData.getOrderId());
|
if (Objects.isNull(mysqlOrder)) {
|
||||||
if (Objects.isNull(order)) {
|
log.error("MiFaPay回调未找到MySQL订单: orderId={}", noticeData.getOrderId());
|
||||||
log.error("MiFaPay回调未找到订单: orderId={}", noticeData.getOrderId());
|
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
return handleMysqlOrder(notice, noticeData, mysqlOrder);
|
||||||
// 检查订单状态,避免重复处理
|
|
||||||
if (!Objects.equals(order.getStatus(), InAppPurchaseStatus.CREATE)) {
|
|
||||||
log.warn("MiFaPay订单已处理: orderId={}, status={}", order.getId(), order.getStatus());
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 记录回调通知
|
private String handleMysqlOrder(MiFaPayReceivePaymentNotice notice,
|
||||||
inAppPurchaseDetailsService.addPayNotices(order.getId(),
|
MiFaPayReceivePaymentNotice.MiFaPayNoticeData noticeData,
|
||||||
new InAppPurchaseEventNotice()
|
OrderUserPurchasePay mysqlOrder) {
|
||||||
.setEventId(notice.getSign())
|
orderUserPurchasePayNoticeService.addNotice(
|
||||||
.setNoticeType("mifapay-" + noticeData.getOrderStatus())
|
mysqlOrder.getId(),
|
||||||
.setNoticeData(notice)
|
notice.getSign(),
|
||||||
.setCreateTime(TimestampUtils.now())
|
"mifapay-" + noticeData.getOrderStatus(),
|
||||||
|
notice,
|
||||||
|
mysqlOrder.getUpdateUser()
|
||||||
);
|
);
|
||||||
|
|
||||||
// 处理支付成功
|
if (!Objects.equals(mysqlOrder.getPayStatus(), MiFaPayMysqlOrderSupport.PAY_STATUS_PREPAYMENT)) {
|
||||||
|
log.warn("MiFaPay订单已处理(MySQL): orderId={}, status={}",
|
||||||
|
mysqlOrder.getId(), mysqlOrder.getPayStatus());
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
InAppPurchaseDetails order = MiFaPayMysqlOrderSupport.toInAppPurchaseDetails(mysqlOrder);
|
||||||
|
|
||||||
if (noticeData.isSuccess()) {
|
if (noticeData.isSuccess()) {
|
||||||
if (!Objects.equals(order.statusEqCreate(), Boolean.TRUE)) {
|
|
||||||
log.warn("MiFaPay订单状态不是CREATE: orderId={}", order.getId());
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 收款单
|
|
||||||
if (order.receiptTypeEqReceipt()) {
|
if (order.receiptTypeEqReceipt()) {
|
||||||
inAppPurchaseCommon.inAppPurchaseReceipt(order);
|
inAppPurchaseCommon.inAppPurchaseReceipt(order,
|
||||||
log.info("MiFaPay收款单处理成功: orderId={}", order.getId());
|
() -> orderUserPurchasePayService.updateSuccess(mysqlOrder.getId()));
|
||||||
|
log.info("MiFaPay收款单处理成功(MySQL): orderId={}", mysqlOrder.getId());
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 付款单
|
|
||||||
if (order.receiptTypeEqPayment()) {
|
if (order.receiptTypeEqPayment()) {
|
||||||
inAppPurchaseCommon.inAppPurchasePayment(order);
|
inAppPurchaseCommon.inAppPurchasePayment(order,
|
||||||
log.info("MiFaPay付款单处理成功: orderId={}", order.getId());
|
() -> orderUserPurchasePayService.updateSuccess(mysqlOrder.getId()));
|
||||||
|
log.info("MiFaPay付款单处理成功(MySQL): orderId={}", mysqlOrder.getId());
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.error("MiFaPay订单类型错误: orderId={}", order.getId());
|
log.error("MiFaPay订单类型错误(MySQL): orderId={}", mysqlOrder.getId());
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理支付失败
|
|
||||||
if (noticeData.isFailed()) {
|
if (noticeData.isFailed()) {
|
||||||
if (order.receiptTypeEqReceipt()) {
|
if (order.receiptTypeEqReceipt() && StringUtils.isNotBlank(mysqlOrder.getReferenceId())) {
|
||||||
inAppPurchaseCollectionReceiptService.updateStatusSuccessFail(order.getId());
|
inAppPurchaseCollectionReceiptService.updateStatusSuccessFail(
|
||||||
|
mysqlOrder.getReferenceId());
|
||||||
}
|
}
|
||||||
inAppPurchaseDetailsService.updateStatusReason(
|
orderUserPurchasePayService.updateFail(
|
||||||
order.getId(),
|
mysqlOrder.getId(),
|
||||||
InAppPurchaseStatus.FAIL,
|
|
||||||
String.format("MiFaPay支付失败: %s", noticeData.getOrderStatus())
|
String.format("MiFaPay支付失败: %s", noticeData.getOrderStatus())
|
||||||
);
|
);
|
||||||
log.info("MiFaPay支付失败处理完成: orderId={}", order.getId());
|
log.info("MiFaPay支付失败处理完成(MySQL): orderId={}", mysqlOrder.getId());
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.error("MiFaPay未知订单状态: orderId={}, status={}", order.getId(), noticeData.getOrderStatus());
|
log.error("MiFaPay未知订单状态(MySQL): orderId={}, status={}",
|
||||||
|
mysqlOrder.getId(), noticeData.getOrderStatus());
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private OrderUserPurchasePay getMysqlOrder(String orderId) {
|
||||||
|
Long mysqlOrderId = MiFaPayMysqlOrderSupport.parseOrderId(orderId);
|
||||||
|
return mysqlOrderId == null ? null : orderUserPurchasePayService.getById(mysqlOrderId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,51 @@
|
|||||||
|
package com.red.circle.order.app.command.pay.web;
|
||||||
|
|
||||||
|
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||||
|
import com.red.circle.order.app.common.MiFaPayMysqlOrderSupport;
|
||||||
|
import com.red.circle.order.app.dto.clientobject.pay.PayOrderStatusCO;
|
||||||
|
import com.red.circle.order.app.dto.cmd.PayOrderStatusCmd;
|
||||||
|
import com.red.circle.order.infra.database.rds.entity.order.OrderUserPurchasePay;
|
||||||
|
import com.red.circle.order.infra.database.rds.service.order.OrderUserPurchasePayService;
|
||||||
|
import com.red.circle.order.inner.asserts.OrderErrorCode;
|
||||||
|
import com.red.circle.order.inner.model.enums.inapp.InAppPurchaseStatus;
|
||||||
|
import java.util.Objects;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付单状态查询.
|
||||||
|
*
|
||||||
|
* @author system
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class PayWebOrderStatusQueryExe {
|
||||||
|
|
||||||
|
private final OrderUserPurchasePayService orderUserPurchasePayService;
|
||||||
|
|
||||||
|
public PayOrderStatusCO execute(PayOrderStatusCmd cmd) {
|
||||||
|
OrderUserPurchasePay mysqlOrder = getMysqlOrder(cmd.getOrderId());
|
||||||
|
ResponseAssert.notNull(OrderErrorCode.NO_PURCHASE_RECORD_FOUND, mysqlOrder);
|
||||||
|
ResponseAssert.isTrue(OrderErrorCode.NO_PURCHASE_RECORD_FOUND,
|
||||||
|
Objects.equals(mysqlOrder.getUserId(), cmd.getReqUserId()));
|
||||||
|
InAppPurchaseStatus status = MiFaPayMysqlOrderSupport
|
||||||
|
.toInAppPurchaseStatus(mysqlOrder.getPayStatus());
|
||||||
|
return new PayOrderStatusCO()
|
||||||
|
.setOrderId(Objects.toString(mysqlOrder.getId(), null))
|
||||||
|
.setTradeNo(mysqlOrder.getFactoryOrderId())
|
||||||
|
.setStatus(Objects.toString(status, null))
|
||||||
|
.setSuccess(MiFaPayMysqlOrderSupport.isSuccess(mysqlOrder.getPayStatus()))
|
||||||
|
.setFinished(MiFaPayMysqlOrderSupport.isFinished(mysqlOrder.getPayStatus()))
|
||||||
|
.setReason(mysqlOrder.getReason())
|
||||||
|
.setFactoryCode(mysqlOrder.getFactoryCode())
|
||||||
|
.setFactoryChannelCode(mysqlOrder.getPaymentChannel())
|
||||||
|
.setCurrency(mysqlOrder.getPaymentUnit())
|
||||||
|
.setAmount(mysqlOrder.getPaymentAmount())
|
||||||
|
.setUpdateTime(mysqlOrder.getUpdateTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
private OrderUserPurchasePay getMysqlOrder(String orderId) {
|
||||||
|
Long mysqlOrderId = MiFaPayMysqlOrderSupport.parseOrderId(orderId);
|
||||||
|
return mysqlOrderId == null ? null : orderUserPurchasePayService.getById(mysqlOrderId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package com.red.circle.order.app.command.pay.web.strategy;
|
package com.red.circle.order.app.command.pay.web.strategy;
|
||||||
|
|
||||||
import com.red.circle.component.pay.paymax.service.PlaceAnOrderParam;
|
import com.red.circle.component.pay.paymax.service.PlaceAnOrderParam;
|
||||||
|
import com.red.circle.common.business.core.util.CountryCodeAliasUtils;
|
||||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||||
import com.red.circle.framework.core.response.ResponseErrorCode;
|
import com.red.circle.framework.core.response.ResponseErrorCode;
|
||||||
import com.red.circle.order.app.common.MiFaPayPlaceAnOrderParam;
|
import com.red.circle.order.app.common.MiFaPayPlaceAnOrderParam;
|
||||||
@ -104,7 +105,7 @@ public class MiFaPayWebPayPlaceAnOrderStrategy implements PayWebPlaceAnOrderStra
|
|||||||
.payType(details.getFactoryChannel())
|
.payType(details.getFactoryChannel())
|
||||||
.userIp(details.getRequestIp())
|
.userIp(details.getRequestIp())
|
||||||
.returnUrl(details.getSuccessRedirectUrl())
|
.returnUrl(details.getSuccessRedirectUrl())
|
||||||
.notifyUrl(MiFaPayService.NOTIFY_URL)
|
.notifyUrl(miFaPayService.getNotifyUrl())
|
||||||
.language("en")
|
.language("en")
|
||||||
.email(memberInfo.getEmail())
|
.email(memberInfo.getEmail())
|
||||||
.countryCode(replaceCountryCode(details.getCountryCode()))
|
.countryCode(replaceCountryCode(details.getCountryCode()))
|
||||||
@ -126,11 +127,7 @@ public class MiFaPayWebPayPlaceAnOrderStrategy implements PayWebPlaceAnOrderStra
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static String replaceCountryCode(String countryCode) {
|
private static String replaceCountryCode(String countryCode) {
|
||||||
if ("KSA".equalsIgnoreCase(countryCode)) {
|
return CountryCodeAliasUtils.normalizeSaudiCode(countryCode);
|
||||||
return countryCode.replaceAll("K", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
return countryCode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import com.google.api.client.util.Maps;
|
|||||||
import com.red.circle.component.pay.paymax.PayMaxUtils;
|
import com.red.circle.component.pay.paymax.PayMaxUtils;
|
||||||
import com.red.circle.framework.core.request.RequestClientEnum;
|
import com.red.circle.framework.core.request.RequestClientEnum;
|
||||||
import com.red.circle.framework.web.props.EnvProperties;
|
import com.red.circle.framework.web.props.EnvProperties;
|
||||||
|
import com.red.circle.order.app.common.MiFaPayMysqlOrderSupport;
|
||||||
import com.red.circle.order.app.common.PayerMaxProperties;
|
import com.red.circle.order.app.common.PayerMaxProperties;
|
||||||
import com.red.circle.order.app.common.QuoteQueryParam;
|
import com.red.circle.order.app.common.QuoteQueryParam;
|
||||||
import com.red.circle.order.app.common.QuoteQueryResponse;
|
import com.red.circle.order.app.common.QuoteQueryResponse;
|
||||||
@ -13,6 +14,8 @@ import com.red.circle.order.infra.database.mongo.order.entity.InAppPurchaseDetai
|
|||||||
import com.red.circle.order.infra.database.mongo.order.entity.assist.InAppPurchaseEventNotice;
|
import com.red.circle.order.infra.database.mongo.order.entity.assist.InAppPurchaseEventNotice;
|
||||||
import com.red.circle.order.infra.database.mongo.order.entity.assist.InAppPurchaseFactory;
|
import com.red.circle.order.infra.database.mongo.order.entity.assist.InAppPurchaseFactory;
|
||||||
import com.red.circle.order.infra.database.mongo.order.entity.assist.InAppPurchaseStatusStep;
|
import com.red.circle.order.infra.database.mongo.order.entity.assist.InAppPurchaseStatusStep;
|
||||||
|
import com.red.circle.order.infra.database.rds.service.order.OrderUserPurchasePayNoticeService;
|
||||||
|
import com.red.circle.order.infra.database.rds.service.order.OrderUserPurchasePayService;
|
||||||
import com.red.circle.order.inner.model.enums.inapp.InAppPurchaseStatus;
|
import com.red.circle.order.inner.model.enums.inapp.InAppPurchaseStatus;
|
||||||
import com.red.circle.tool.core.date.TimestampUtils;
|
import com.red.circle.tool.core.date.TimestampUtils;
|
||||||
import com.red.circle.tool.core.http.RcHttpClient;
|
import com.red.circle.tool.core.http.RcHttpClient;
|
||||||
@ -34,6 +37,8 @@ public class PayPlaceAnOrderService {
|
|||||||
|
|
||||||
private final EnvProperties envProperties;
|
private final EnvProperties envProperties;
|
||||||
private final InAppPurchaseDetailsService inAppPurchaseDetailsService;
|
private final InAppPurchaseDetailsService inAppPurchaseDetailsService;
|
||||||
|
private final OrderUserPurchasePayNoticeService orderUserPurchasePayNoticeService;
|
||||||
|
private final OrderUserPurchasePayService orderUserPurchasePayService;
|
||||||
private final FactoryPlaceAnOrderStrategyV2 factoryPlaceAnOrderStrategyV2;
|
private final FactoryPlaceAnOrderStrategyV2 factoryPlaceAnOrderStrategyV2;
|
||||||
private final PayerMaxProperties payerMaxProperties;
|
private final PayerMaxProperties payerMaxProperties;
|
||||||
private final RcHttpClient rcHttpClient = RcHttpClient.builder().build();
|
private final RcHttpClient rcHttpClient = RcHttpClient.builder().build();
|
||||||
@ -44,6 +49,19 @@ public class PayPlaceAnOrderService {
|
|||||||
param.getStrategyCode())
|
param.getStrategyCode())
|
||||||
.doOperation(param);
|
.doOperation(param);
|
||||||
|
|
||||||
|
if (MiFaPayMysqlOrderSupport.isMiFaPay(param.getFactoryCode())) {
|
||||||
|
Long purchasePayId = MiFaPayMysqlOrderSupport.parseOrderId(param.getOrderId());
|
||||||
|
orderUserPurchasePayService.save(
|
||||||
|
MiFaPayMysqlOrderSupport.buildPrepaymentOrder(param, response, env()));
|
||||||
|
orderUserPurchasePayNoticeService.addNotice(
|
||||||
|
purchasePayId,
|
||||||
|
"custom-request-response-param",
|
||||||
|
"API-INTERNAL-PARAMETERS",
|
||||||
|
response.extra(),
|
||||||
|
param.getCreateUserId());
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
// 创建站内:预支付订单.
|
// 创建站内:预支付订单.
|
||||||
inAppPurchaseDetailsService.create(
|
inAppPurchaseDetailsService.create(
|
||||||
new InAppPurchaseDetails()
|
new InAppPurchaseDetails()
|
||||||
|
|||||||
@ -81,6 +81,13 @@ public class InAppPurchaseCommon {
|
|||||||
private final UserProfileClient userProfileClient;
|
private final UserProfileClient userProfileClient;
|
||||||
|
|
||||||
public void inAppPurchaseReceipt(InAppPurchaseDetails order) {
|
public void inAppPurchaseReceipt(InAppPurchaseDetails order) {
|
||||||
|
inAppPurchaseReceipt(order,
|
||||||
|
() -> inAppPurchaseDetailsService.updateStatus(order.getId(), InAppPurchaseStatus.SUCCESS));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inAppPurchaseReceipt(InAppPurchaseDetails order, Runnable successHandler) {
|
||||||
|
Runnable finalSuccessHandler = successHandler != null ? successHandler : () -> {
|
||||||
|
};
|
||||||
|
|
||||||
if (!order.receiptTypeEqReceipt()) {
|
if (!order.receiptTypeEqReceipt()) {
|
||||||
return;
|
return;
|
||||||
@ -92,7 +99,7 @@ public class InAppPurchaseCommon {
|
|||||||
|
|
||||||
if (CollectionUtils.isEmpty(order.getProducts())) {
|
if (CollectionUtils.isEmpty(order.getProducts())) {
|
||||||
inAppPurchaseCollectionReceiptService.updateStatusSuccess(order.getTrackId());
|
inAppPurchaseCollectionReceiptService.updateStatusSuccess(order.getTrackId());
|
||||||
inAppPurchaseDetailsService.updateStatus(order.getId(), InAppPurchaseStatus.SUCCESS);
|
finalSuccessHandler.run();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,10 +130,17 @@ public class InAppPurchaseCommon {
|
|||||||
);
|
);
|
||||||
|
|
||||||
inAppPurchaseCollectionReceiptService.updateStatusSuccess(order.getTrackId());
|
inAppPurchaseCollectionReceiptService.updateStatusSuccess(order.getTrackId());
|
||||||
inAppPurchaseDetailsService.updateStatus(order.getId(), InAppPurchaseStatus.SUCCESS);
|
finalSuccessHandler.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void inAppPurchasePayment(InAppPurchaseDetails order) {
|
public void inAppPurchasePayment(InAppPurchaseDetails order) {
|
||||||
|
inAppPurchasePayment(order,
|
||||||
|
() -> inAppPurchaseDetailsService.updateStatus(order.getId(), InAppPurchaseStatus.SUCCESS));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inAppPurchasePayment(InAppPurchaseDetails order, Runnable successHandler) {
|
||||||
|
Runnable finalSuccessHandler = successHandler != null ? successHandler : () -> {
|
||||||
|
};
|
||||||
InAppPurchaseProduct product = order.firstProduct();
|
InAppPurchaseProduct product = order.firstProduct();
|
||||||
ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_MAPPING_INFO, product);
|
ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_MAPPING_INFO, product);
|
||||||
|
|
||||||
@ -141,7 +155,7 @@ public class InAppPurchaseCommon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 修改订单状态
|
// 修改订单状态
|
||||||
inAppPurchaseDetailsService.updateStatus(order.getId(), InAppPurchaseStatus.SUCCESS);
|
finalSuccessHandler.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,168 @@
|
|||||||
|
package com.red.circle.order.app.common;
|
||||||
|
|
||||||
|
import com.red.circle.framework.core.request.RequestClientEnum;
|
||||||
|
import com.red.circle.order.app.command.pay.web.strategy.PayPlaceAnOrderDetailsV2;
|
||||||
|
import com.red.circle.order.app.dto.clientobject.pay.PlaceAnOrderResponseCO;
|
||||||
|
import com.red.circle.order.infra.database.mongo.order.entity.InAppPurchaseDetails;
|
||||||
|
import com.red.circle.order.infra.database.mongo.order.entity.assist.InAppPurchaseFactory;
|
||||||
|
import com.red.circle.order.infra.database.mongo.order.entity.assist.InAppPurchaseProduct;
|
||||||
|
import com.red.circle.order.infra.database.rds.entity.order.OrderUserPurchasePay;
|
||||||
|
import com.red.circle.order.inner.model.enums.inapp.InAppPurchaseReceiptType;
|
||||||
|
import com.red.circle.order.inner.model.enums.inapp.InAppPurchaseStatus;
|
||||||
|
import com.red.circle.tool.core.date.TimestampUtils;
|
||||||
|
import com.red.circle.tool.core.text.StringUtils;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MiFaPay MySQL订单映射工具.
|
||||||
|
*/
|
||||||
|
public final class MiFaPayMysqlOrderSupport {
|
||||||
|
|
||||||
|
public static final String FACTORY_CODE = "MIFA_PAY";
|
||||||
|
public static final String PAY_STATUS_PREPAYMENT = "PREPAYMENT";
|
||||||
|
public static final String PAY_STATUS_SUCCESSFUL = "SUCCESSFUL";
|
||||||
|
public static final String PAY_STATUS_FAIL = "FAIL";
|
||||||
|
public static final String REFUND_STATUS_NONE = "NONE";
|
||||||
|
|
||||||
|
private MiFaPayMysqlOrderSupport() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isMiFaPay(String factoryCode) {
|
||||||
|
return Objects.equals(FACTORY_CODE, factoryCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Long parseOrderId(String orderId) {
|
||||||
|
if (StringUtils.isBlank(orderId)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Long.valueOf(orderId.trim());
|
||||||
|
} catch (NumberFormatException ignore) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OrderUserPurchasePay buildPrepaymentOrder(PayPlaceAnOrderDetailsV2 param,
|
||||||
|
PlaceAnOrderResponseCO response, String env) {
|
||||||
|
Timestamp now = TimestampUtils.now();
|
||||||
|
InAppPurchaseProduct product = firstProduct(param.getProducts());
|
||||||
|
Long referenceId = parseOrderId(param.getApplicationId());
|
||||||
|
|
||||||
|
return new OrderUserPurchasePay()
|
||||||
|
.setId(parseOrderId(param.getOrderId()))
|
||||||
|
.setEvn(env)
|
||||||
|
.setSysOrigin(param.getSysOrigin())
|
||||||
|
.setUserId(param.getAcceptUserId())
|
||||||
|
.setFactoryCode(param.getFactoryCode())
|
||||||
|
.setFactoryOrderId(Objects.toString(response.getTradeNo(), ""))
|
||||||
|
.setReferenceId(Objects.toString(param.getApplicationId(), ""))
|
||||||
|
.setReceiptType(Objects.toString(param.getReceiptType(),
|
||||||
|
InAppPurchaseReceiptType.PAYMENT.name()))
|
||||||
|
.setPaymentChannel(Objects.toString(param.getChannelCode(), ""))
|
||||||
|
.setFactoryChannel(Objects.toString(param.getFactoryChannel(), ""))
|
||||||
|
.setProductCode(product != null ? Objects.toString(product.getCode(), "") : "")
|
||||||
|
.setProductContent(product != null ? Objects.toString(product.getContent(), "") : "")
|
||||||
|
.setProductDescriptor(Objects.toString(param.getProductDescriptor(), ""))
|
||||||
|
.setPaymentUnit(Objects.toString(param.getCurrency(), ""))
|
||||||
|
.setPaymentAmount(defaultDecimal(param.getAmount()))
|
||||||
|
.setComputeUsdAmount(defaultDecimal(param.getAmountUsd()))
|
||||||
|
.setComputeUsdRate(computeUsdRate(param.getAmount(), param.getAmountUsd()))
|
||||||
|
.setGiveAwayContent("")
|
||||||
|
.setCountryId(param.getCountry() != null ? param.getCountry().getId() : 0L)
|
||||||
|
.setCountryCode(Objects.toString(response.getCountryCode(), param.getCountryCode()))
|
||||||
|
.setPayCountryId(param.getPayCountry() != null ? param.getPayCountry().getId() : 0L)
|
||||||
|
.setPayStatus(PAY_STATUS_PREPAYMENT)
|
||||||
|
.setReason("")
|
||||||
|
.setRefundStatus(REFUND_STATUS_NONE)
|
||||||
|
.setReceiptDetailsId(referenceId != null ? referenceId : 0L)
|
||||||
|
.setCreateTime(now)
|
||||||
|
.setUpdateTime(now)
|
||||||
|
.setCreateUser(param.getCreateUserId())
|
||||||
|
.setUpdateUser(param.getCreateUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InAppPurchaseDetails toInAppPurchaseDetails(OrderUserPurchasePay order) {
|
||||||
|
List<InAppPurchaseProduct> products = StringUtils.isBlank(order.getProductCode())
|
||||||
|
? Collections.emptyList()
|
||||||
|
: List.of(new InAppPurchaseProduct()
|
||||||
|
.setId(order.getReceiptDetailsId())
|
||||||
|
.setName(order.getProductCode())
|
||||||
|
.setCode(order.getProductCode())
|
||||||
|
.setDescribe(order.getProductDescriptor())
|
||||||
|
.setContent(order.getProductContent())
|
||||||
|
.setAmountUsd(defaultDecimal(order.getComputeUsdAmount()))
|
||||||
|
.setQuantity(1));
|
||||||
|
|
||||||
|
return new InAppPurchaseDetails()
|
||||||
|
.setId(Objects.toString(order.getId(), null))
|
||||||
|
.setReceiptType(parseReceiptType(order.getReceiptType()))
|
||||||
|
.setTrackId(order.getReferenceId())
|
||||||
|
.setSysOrigin(order.getSysOrigin())
|
||||||
|
.setAcceptUserId(order.getUserId())
|
||||||
|
.setOrderId(order.getFactoryOrderId())
|
||||||
|
.setEnv(order.getEvn())
|
||||||
|
.setFactory(new InAppPurchaseFactory()
|
||||||
|
.setPlatform(RequestClientEnum.H5.getClientName())
|
||||||
|
.setFactoryCode(order.getFactoryCode())
|
||||||
|
.setFactoryChannelCode(order.getPaymentChannel()))
|
||||||
|
.setProducts(products)
|
||||||
|
.setProductDescriptor(order.getProductDescriptor())
|
||||||
|
.setCountryCode(order.getCountryCode())
|
||||||
|
.setCurrency(order.getPaymentUnit())
|
||||||
|
.setAmount(defaultDecimal(order.getPaymentAmount()))
|
||||||
|
.setAmountUsd(defaultDecimal(order.getComputeUsdAmount()))
|
||||||
|
.setTrialPeriod(Boolean.FALSE)
|
||||||
|
.setStatus(toInAppPurchaseStatus(order.getPayStatus()))
|
||||||
|
.setReason(order.getReason())
|
||||||
|
.setCreateTime(order.getCreateTime())
|
||||||
|
.setUpdateTime(order.getUpdateTime())
|
||||||
|
.setCreateUser(order.getCreateUser());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InAppPurchaseStatus toInAppPurchaseStatus(String payStatus) {
|
||||||
|
if (Objects.equals(PAY_STATUS_SUCCESSFUL, payStatus)) {
|
||||||
|
return InAppPurchaseStatus.SUCCESS;
|
||||||
|
}
|
||||||
|
if (Objects.equals(PAY_STATUS_FAIL, payStatus)) {
|
||||||
|
return InAppPurchaseStatus.FAIL;
|
||||||
|
}
|
||||||
|
return InAppPurchaseStatus.CREATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isSuccess(String payStatus) {
|
||||||
|
return Objects.equals(PAY_STATUS_SUCCESSFUL, payStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isFinished(String payStatus) {
|
||||||
|
return isSuccess(payStatus) || Objects.equals(PAY_STATUS_FAIL, payStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String computeUsdRate(BigDecimal paymentAmount, BigDecimal usdAmount) {
|
||||||
|
if (paymentAmount == null || usdAmount == null || BigDecimal.ZERO.compareTo(usdAmount) == 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return paymentAmount.divide(usdAmount, 8, RoundingMode.HALF_UP)
|
||||||
|
.stripTrailingZeros()
|
||||||
|
.toPlainString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InAppPurchaseProduct firstProduct(List<InAppPurchaseProduct> products) {
|
||||||
|
return products == null || products.isEmpty() ? null : products.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InAppPurchaseReceiptType parseReceiptType(String receiptType) {
|
||||||
|
if (Objects.equals(InAppPurchaseReceiptType.RECEIPT.name(), receiptType)) {
|
||||||
|
return InAppPurchaseReceiptType.RECEIPT;
|
||||||
|
}
|
||||||
|
return InAppPurchaseReceiptType.PAYMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BigDecimal defaultDecimal(BigDecimal value) {
|
||||||
|
return value != null ? value : BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -24,6 +24,7 @@ import com.red.circle.order.app.command.pay.web.AirwallexServerNoticeCmdExe;
|
|||||||
import com.red.circle.order.app.command.pay.web.ClipspayServerNoticeCmdExe;
|
import com.red.circle.order.app.command.pay.web.ClipspayServerNoticeCmdExe;
|
||||||
import com.red.circle.order.app.command.pay.web.CollectionReceiptQueryExe;
|
import com.red.circle.order.app.command.pay.web.CollectionReceiptQueryExe;
|
||||||
import com.red.circle.order.app.command.pay.web.PayPalServerNoticeCmdExe;
|
import com.red.circle.order.app.command.pay.web.PayPalServerNoticeCmdExe;
|
||||||
|
import com.red.circle.order.app.command.pay.web.PayWebOrderStatusQueryExe;
|
||||||
import com.red.circle.order.app.command.pay.web.PayWebPlaceAnOrderCmdExe;
|
import com.red.circle.order.app.command.pay.web.PayWebPlaceAnOrderCmdExe;
|
||||||
import com.red.circle.order.app.command.pay.web.PayerMaxServerNoticeReceivePaymentCmdExe;
|
import com.red.circle.order.app.command.pay.web.PayerMaxServerNoticeReceivePaymentCmdExe;
|
||||||
import com.red.circle.order.app.command.pay.web.PayerMaxServerNoticeRefundNoticeCmdExe;
|
import com.red.circle.order.app.command.pay.web.PayerMaxServerNoticeRefundNoticeCmdExe;
|
||||||
@ -33,8 +34,10 @@ import com.red.circle.order.app.command.pay.web.ReceiptPayWebPlaceAnOrderReceipt
|
|||||||
import com.red.circle.order.app.dto.clientobject.PayMaxResponseCO;
|
import com.red.circle.order.app.dto.clientobject.PayMaxResponseCO;
|
||||||
import com.red.circle.order.app.dto.clientobject.PayerMaxResponseV2CO;
|
import com.red.circle.order.app.dto.clientobject.PayerMaxResponseV2CO;
|
||||||
import com.red.circle.order.app.dto.clientobject.PurchaseReceiptCO;
|
import com.red.circle.order.app.dto.clientobject.PurchaseReceiptCO;
|
||||||
|
import com.red.circle.order.app.dto.clientobject.pay.PayOrderStatusCO;
|
||||||
import com.red.circle.order.app.dto.clientobject.pay.PlaceAnOrderResponseCO;
|
import com.red.circle.order.app.dto.clientobject.pay.PlaceAnOrderResponseCO;
|
||||||
import com.red.circle.order.app.dto.cmd.AbstractPurchaseCmd;
|
import com.red.circle.order.app.dto.cmd.AbstractPurchaseCmd;
|
||||||
|
import com.red.circle.order.app.dto.cmd.PayOrderStatusCmd;
|
||||||
import com.red.circle.order.app.dto.cmd.PayPlaceAnOrderCmd;
|
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.PayPlaceAnOrderReceiptCmd;
|
||||||
import com.red.circle.tool.core.date.LocalDateTimeUtils;
|
import com.red.circle.tool.core.date.LocalDateTimeUtils;
|
||||||
@ -60,6 +63,7 @@ public class InAppPurchaseProductServiceImpl implements InAppPurchaseProductServ
|
|||||||
|
|
||||||
private final AppInAppPurchaseCmdExe appInAppPurchaseCmdExe;
|
private final AppInAppPurchaseCmdExe appInAppPurchaseCmdExe;
|
||||||
private final PayWebPlaceAnOrderCmdExe payWebPlaceAnOrderCmdExe;
|
private final PayWebPlaceAnOrderCmdExe payWebPlaceAnOrderCmdExe;
|
||||||
|
private final PayWebOrderStatusQueryExe payWebOrderStatusQueryExe;
|
||||||
private final PayPalServerNoticeCmdExe payPalServerNoticeCmdExe;
|
private final PayPalServerNoticeCmdExe payPalServerNoticeCmdExe;
|
||||||
private final CollectionReceiptQueryExe collectionReceiptQueryExe;
|
private final CollectionReceiptQueryExe collectionReceiptQueryExe;
|
||||||
private final ClipspayServerNoticeCmdExe clipspayServerNoticeCmdExe;
|
private final ClipspayServerNoticeCmdExe clipspayServerNoticeCmdExe;
|
||||||
@ -149,6 +153,11 @@ public class InAppPurchaseProductServiceImpl implements InAppPurchaseProductServ
|
|||||||
return payWebPlaceAnOrderCmdExe.execute(cmd);
|
return payWebPlaceAnOrderCmdExe.execute(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PayOrderStatusCO orderStatus(PayOrderStatusCmd cmd) {
|
||||||
|
return payWebOrderStatusQueryExe.execute(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PlaceAnOrderResponseCO payReceipt(PayPlaceAnOrderReceiptCmd cmd) {
|
public PlaceAnOrderResponseCO payReceipt(PayPlaceAnOrderReceiptCmd cmd) {
|
||||||
return receiptPayWebPlaceAnOrderReceiptCmdExe.execute(cmd);
|
return receiptPayWebPlaceAnOrderReceiptCmdExe.execute(cmd);
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import com.red.circle.order.app.dto.clientobject.MiFaPayResponseCO;
|
|||||||
import com.red.circle.order.infra.config.MiFaPayProperties;
|
import com.red.circle.order.infra.config.MiFaPayProperties;
|
||||||
import com.red.circle.tool.core.http.RcHttpClient;
|
import com.red.circle.tool.core.http.RcHttpClient;
|
||||||
import com.red.circle.tool.core.json.JacksonUtils;
|
import com.red.circle.tool.core.json.JacksonUtils;
|
||||||
|
import com.red.circle.tool.core.text.StringUtils;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
@ -25,7 +26,6 @@ public class MiFaPayService {
|
|||||||
/**
|
/**
|
||||||
* 下单接口路径
|
* 下单接口路径
|
||||||
*/
|
*/
|
||||||
public static final String NOTIFY_URL = "";
|
|
||||||
private static final String PLACE_ORDER_PATH = "/paygateway/mbpay/order/en_v2";
|
private static final String PLACE_ORDER_PATH = "/paygateway/mbpay/order/en_v2";
|
||||||
|
|
||||||
private final String active;
|
private final String active;
|
||||||
@ -45,6 +45,8 @@ public class MiFaPayService {
|
|||||||
* @return 支付响应
|
* @return 支付响应
|
||||||
*/
|
*/
|
||||||
public MiFaPayResponseCO placeAnOrder(MiFaPayPlaceAnOrderParam param) {
|
public MiFaPayResponseCO placeAnOrder(MiFaPayPlaceAnOrderParam param) {
|
||||||
|
validateRequiredConfig();
|
||||||
|
|
||||||
// 设置商户编号
|
// 设置商户编号
|
||||||
param.setMerNo(miFaPayProperties.getMerNo());
|
param.setMerNo(miFaPayProperties.getMerNo());
|
||||||
|
|
||||||
@ -82,21 +84,54 @@ public class MiFaPayService {
|
|||||||
log.warn("MiFaPay Response: {}", JacksonUtils.toJson(response));
|
log.warn("MiFaPay Response: {}", JacksonUtils.toJson(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证响应签名
|
verifySuccessfulResponse(response);
|
||||||
if (response != null && response.isSuccess() && response.getData() != null) {
|
|
||||||
// boolean validSign = PayMaxUtils.validSignRsa(
|
|
||||||
// response.getData(),
|
|
||||||
// response.getSign(),
|
|
||||||
// miFaPayProperties.getPlatformRsaPublicKey()
|
|
||||||
// );
|
|
||||||
// if (!validSign) {
|
|
||||||
// log.error("MiFaPay response sign verification failed!");
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getNotifyUrl() {
|
||||||
|
validateRequiredValue("notifyUrl", miFaPayProperties.getNotifyUrl());
|
||||||
|
return miFaPayProperties.getNotifyUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifySuccessfulResponse(MiFaPayResponseCO response) {
|
||||||
|
if (response == null || !response.isSuccess()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
validateRequiredValue("response.data", response.getData());
|
||||||
|
validateRequiredValue("response.sign", response.getSign());
|
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(response.getMerAccount())
|
||||||
|
&& !Objects.equals(response.getMerAccount(), miFaPayProperties.getMerAccount())) {
|
||||||
|
throw new IllegalStateException("MiFaPay response merAccount mismatch");
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean validSign = PayMaxUtils.validSignRsa(
|
||||||
|
response.getData(),
|
||||||
|
response.getSign(),
|
||||||
|
miFaPayProperties.getPlatformRsaPublicKey()
|
||||||
|
);
|
||||||
|
if (!validSign) {
|
||||||
|
throw new IllegalStateException("MiFaPay response signature verification failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateRequiredConfig() {
|
||||||
|
validateRequiredValue("merAccount", miFaPayProperties.getMerAccount());
|
||||||
|
validateRequiredValue("merNo", miFaPayProperties.getMerNo());
|
||||||
|
validateRequiredValue("gatewayBaseUrl", miFaPayProperties.getGatewayBaseUrl());
|
||||||
|
validateRequiredValue("rsaPrivateKey", miFaPayProperties.getRsaPrivateKey());
|
||||||
|
validateRequiredValue("platformRsaPublicKey", miFaPayProperties.getPlatformRsaPublicKey());
|
||||||
|
validateRequiredValue("notifyUrl", miFaPayProperties.getNotifyUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateRequiredValue(String fieldName, String value) {
|
||||||
|
if (StringUtils.isBlank(value)) {
|
||||||
|
throw new IllegalStateException("MiFaPay config missing: " + fieldName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MiFaPay请求体结构
|
* MiFaPay请求体结构
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -0,0 +1,76 @@
|
|||||||
|
package com.red.circle.order.app.dto.clientobject.pay;
|
||||||
|
|
||||||
|
import com.red.circle.framework.dto.DTO;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付单状态.
|
||||||
|
*
|
||||||
|
* @author system
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class PayOrderStatusCO extends DTO {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 站内支付单号.
|
||||||
|
*/
|
||||||
|
private String orderId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 第三方平台订单号.
|
||||||
|
*/
|
||||||
|
private String tradeNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前支付状态.
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否支付成功.
|
||||||
|
*/
|
||||||
|
private Boolean success;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否已进入终态.
|
||||||
|
*/
|
||||||
|
private Boolean finished;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 失败或挂起原因.
|
||||||
|
*/
|
||||||
|
private String reason;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 厂商编码.
|
||||||
|
*/
|
||||||
|
private String factoryCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 厂商渠道编码.
|
||||||
|
*/
|
||||||
|
private String factoryChannelCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 币种.
|
||||||
|
*/
|
||||||
|
private String currency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 金额.
|
||||||
|
*/
|
||||||
|
private BigDecimal amount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最后更新时间.
|
||||||
|
*/
|
||||||
|
private Timestamp updateTime;
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
package com.red.circle.order.app.dto.cmd;
|
||||||
|
|
||||||
|
import com.red.circle.common.business.dto.cmd.AppExtCommand;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import java.io.Serial;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付单状态查询.
|
||||||
|
*
|
||||||
|
* @author system
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class PayOrderStatusCmd extends AppExtCommand {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 站内支付单号.
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "orderId required.")
|
||||||
|
private String orderId;
|
||||||
|
}
|
||||||
@ -5,8 +5,10 @@ import com.red.circle.common.business.dto.cmd.IdStringCmd;
|
|||||||
import com.red.circle.order.app.dto.clientobject.PayMaxResponseCO;
|
import com.red.circle.order.app.dto.clientobject.PayMaxResponseCO;
|
||||||
import com.red.circle.order.app.dto.clientobject.PayerMaxResponseV2CO;
|
import com.red.circle.order.app.dto.clientobject.PayerMaxResponseV2CO;
|
||||||
import com.red.circle.order.app.dto.clientobject.PurchaseReceiptCO;
|
import com.red.circle.order.app.dto.clientobject.PurchaseReceiptCO;
|
||||||
|
import com.red.circle.order.app.dto.clientobject.pay.PayOrderStatusCO;
|
||||||
import com.red.circle.order.app.dto.clientobject.pay.PlaceAnOrderResponseCO;
|
import com.red.circle.order.app.dto.clientobject.pay.PlaceAnOrderResponseCO;
|
||||||
import com.red.circle.order.app.dto.cmd.AbstractPurchaseCmd;
|
import com.red.circle.order.app.dto.cmd.AbstractPurchaseCmd;
|
||||||
|
import com.red.circle.order.app.dto.cmd.PayOrderStatusCmd;
|
||||||
import com.red.circle.order.app.dto.cmd.PayPlaceAnOrderCmd;
|
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.PayPlaceAnOrderReceiptCmd;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -32,6 +34,11 @@ public interface InAppPurchaseProductService {
|
|||||||
|
|
||||||
PlaceAnOrderResponseCO placeAnOrder(PayPlaceAnOrderCmd cmd);
|
PlaceAnOrderResponseCO placeAnOrder(PayPlaceAnOrderCmd cmd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询支付单状态.
|
||||||
|
*/
|
||||||
|
PayOrderStatusCO orderStatus(PayOrderStatusCmd cmd);
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
PlaceAnOrderResponseCO payReceipt(PayPlaceAnOrderReceiptCmd cmd);
|
PlaceAnOrderResponseCO payReceipt(PayPlaceAnOrderReceiptCmd cmd);
|
||||||
|
|
||||||
|
|||||||
@ -40,4 +40,9 @@ public class MiFaPayProperties {
|
|||||||
* 平台公钥(用于验签)
|
* 平台公钥(用于验签)
|
||||||
*/
|
*/
|
||||||
private String platformRsaPublicKey;
|
private String platformRsaPublicKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付结果异步通知地址
|
||||||
|
*/
|
||||||
|
private String notifyUrl;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,8 @@ import org.springframework.stereotype.Service;
|
|||||||
public class InAppPurchaseCollectionReceiptServiceImpl implements
|
public class InAppPurchaseCollectionReceiptServiceImpl implements
|
||||||
InAppPurchaseCollectionReceiptService {
|
InAppPurchaseCollectionReceiptService {
|
||||||
|
|
||||||
|
private static final String ID_FIELD = "_id";
|
||||||
|
|
||||||
private final MongoTemplate mongoTemplate;
|
private final MongoTemplate mongoTemplate;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -34,7 +36,7 @@ public class InAppPurchaseCollectionReceiptServiceImpl implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(InAppPurchaseCollectionReceipt receipt) {
|
public void update(InAppPurchaseCollectionReceipt receipt) {
|
||||||
mongoTemplate.updateFirst(Query.query(Criteria.where("id").is(receipt.getId())),
|
mongoTemplate.updateFirst(Query.query(Criteria.where(ID_FIELD).is(receipt.getId())),
|
||||||
new Update()
|
new Update()
|
||||||
.set("acceptUserId", receipt.getAcceptUserId())
|
.set("acceptUserId", receipt.getAcceptUserId())
|
||||||
.set("amount", receipt.getAmount())
|
.set("amount", receipt.getAmount())
|
||||||
@ -52,7 +54,7 @@ public class InAppPurchaseCollectionReceiptServiceImpl implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close(String id, Long operationUserId) {
|
public void close(String id, Long operationUserId) {
|
||||||
mongoTemplate.updateFirst(Query.query(Criteria.where("id").is(id)),
|
mongoTemplate.updateFirst(Query.query(Criteria.where(ID_FIELD).is(id)),
|
||||||
new Update()
|
new Update()
|
||||||
.set("updateTime", TimestampUtils.now())
|
.set("updateTime", TimestampUtils.now())
|
||||||
.set("status", InAppPurchaseCollectionReceiptStatus.CLOSE)
|
.set("status", InAppPurchaseCollectionReceiptStatus.CLOSE)
|
||||||
@ -62,7 +64,7 @@ public class InAppPurchaseCollectionReceiptServiceImpl implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateStatusSuccess(String id) {
|
public void updateStatusSuccess(String id) {
|
||||||
mongoTemplate.updateFirst(Query.query(Criteria.where("id").is(id)),
|
mongoTemplate.updateFirst(Query.query(Criteria.where(ID_FIELD).is(id)),
|
||||||
new Update()
|
new Update()
|
||||||
.set("updateTime", TimestampUtils.now())
|
.set("updateTime", TimestampUtils.now())
|
||||||
.set("status", InAppPurchaseCollectionReceiptStatus.SUCCESS)
|
.set("status", InAppPurchaseCollectionReceiptStatus.SUCCESS)
|
||||||
@ -72,7 +74,7 @@ public class InAppPurchaseCollectionReceiptServiceImpl implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateStatusSuccessFail(String id) {
|
public void updateStatusSuccessFail(String id) {
|
||||||
mongoTemplate.updateFirst(Query.query(Criteria.where("id").is(id)),
|
mongoTemplate.updateFirst(Query.query(Criteria.where(ID_FIELD).is(id)),
|
||||||
new Update()
|
new Update()
|
||||||
.set("updateTime", TimestampUtils.now())
|
.set("updateTime", TimestampUtils.now())
|
||||||
.set("status", InAppPurchaseCollectionReceiptStatus.FAIL)
|
.set("status", InAppPurchaseCollectionReceiptStatus.FAIL)
|
||||||
@ -90,7 +92,7 @@ public class InAppPurchaseCollectionReceiptServiceImpl implements
|
|||||||
|
|
||||||
if (StringUtils.isNotBlank(query.getId())) {
|
if (StringUtils.isNotBlank(query.getId())) {
|
||||||
query.setLastId(null);
|
query.setLastId(null);
|
||||||
criteria.and("id").is(query.getId());
|
criteria.and(ID_FIELD).is(query.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(query.getStatus())) {
|
if (StringUtils.isNotBlank(query.getStatus())) {
|
||||||
@ -113,7 +115,7 @@ public class InAppPurchaseCollectionReceiptServiceImpl implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Objects.nonNull(query.getLastId())) {
|
if (Objects.nonNull(query.getLastId())) {
|
||||||
criteria.and("id").lt(query.getLastId());
|
criteria.and(ID_FIELD).lt(query.getLastId());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Objects.isNull(query.getLimit())) {
|
if (Objects.isNull(query.getLimit())) {
|
||||||
@ -121,20 +123,20 @@ public class InAppPurchaseCollectionReceiptServiceImpl implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
return mongoTemplate.find(Query.query(criteria)
|
return mongoTemplate.find(Query.query(criteria)
|
||||||
.with(Sort.by(Sort.Order.desc("id")))
|
.with(Sort.by(Sort.Order.desc(ID_FIELD)))
|
||||||
.limit(query.getLimit()),
|
.limit(query.getLimit()),
|
||||||
InAppPurchaseCollectionReceipt.class);
|
InAppPurchaseCollectionReceipt.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InAppPurchaseCollectionReceipt getById(String id) {
|
public InAppPurchaseCollectionReceipt getById(String id) {
|
||||||
return mongoTemplate.findOne(Query.query(Criteria.where("id").is(id)),
|
return mongoTemplate.findOne(Query.query(Criteria.where(ID_FIELD).is(id)),
|
||||||
InAppPurchaseCollectionReceipt.class);
|
InAppPurchaseCollectionReceipt.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void lockTime(String id, long minute) {
|
public void lockTime(String id, long minute) {
|
||||||
mongoTemplate.updateFirst(Query.query(Criteria.where("id").is(id)),
|
mongoTemplate.updateFirst(Query.query(Criteria.where(ID_FIELD).is(id)),
|
||||||
new Update()
|
new Update()
|
||||||
.set("updateTime", TimestampUtils.now())
|
.set("updateTime", TimestampUtils.now())
|
||||||
.set("lockTime", TimestampUtils.nowPlusMinutes(minute)),
|
.set("lockTime", TimestampUtils.nowPlusMinutes(minute)),
|
||||||
|
|||||||
@ -35,6 +35,8 @@ import org.springframework.stereotype.Service;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class InAppPurchaseDetailsServiceImpl implements InAppPurchaseDetailsService {
|
public class InAppPurchaseDetailsServiceImpl implements InAppPurchaseDetailsService {
|
||||||
|
|
||||||
|
private static final String ID_FIELD = "_id";
|
||||||
|
|
||||||
private final MongoTemplate mongoTemplate;
|
private final MongoTemplate mongoTemplate;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -44,7 +46,7 @@ public class InAppPurchaseDetailsServiceImpl implements InAppPurchaseDetailsServ
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InAppPurchaseDetails getById(String id) {
|
public InAppPurchaseDetails getById(String id) {
|
||||||
return mongoTemplate.findOne(Query.query(Criteria.where("id").is(id)),
|
return mongoTemplate.findOne(Query.query(Criteria.where(ID_FIELD).is(id)),
|
||||||
InAppPurchaseDetails.class);
|
InAppPurchaseDetails.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +60,7 @@ public class InAppPurchaseDetailsServiceImpl implements InAppPurchaseDetailsServ
|
|||||||
@Override
|
@Override
|
||||||
public boolean existsPayNotice(String id, String eventId, String noticeType) {
|
public boolean existsPayNotice(String id, String eventId, String noticeType) {
|
||||||
return mongoTemplate.exists(Query.query(
|
return mongoTemplate.exists(Query.query(
|
||||||
Criteria.where("id").is(id)
|
Criteria.where(ID_FIELD).is(id)
|
||||||
.elemMatch(Criteria.where("eventId").is(eventId).is("noticeType").is(noticeType))
|
.elemMatch(Criteria.where("eventId").is(eventId).is("noticeType").is(noticeType))
|
||||||
), InAppPurchaseDetails.class);
|
), InAppPurchaseDetails.class);
|
||||||
}
|
}
|
||||||
@ -66,21 +68,21 @@ public class InAppPurchaseDetailsServiceImpl implements InAppPurchaseDetailsServ
|
|||||||
@Override
|
@Override
|
||||||
public boolean existsPayNoticeByEventId(String id, String eventId) {
|
public boolean existsPayNoticeByEventId(String id, String eventId) {
|
||||||
return mongoTemplate.exists(Query.query(
|
return mongoTemplate.exists(Query.query(
|
||||||
Criteria.where("id").is(id).elemMatch(Criteria.where("eventId").is(eventId))
|
Criteria.where(ID_FIELD).is(id).elemMatch(Criteria.where("eventId").is(eventId))
|
||||||
), InAppPurchaseDetails.class);
|
), InAppPurchaseDetails.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean existsPayNoticeByNoticeType(String id, String noticeType) {
|
public boolean existsPayNoticeByNoticeType(String id, String noticeType) {
|
||||||
return mongoTemplate.exists(Query.query(
|
return mongoTemplate.exists(Query.query(
|
||||||
Criteria.where("id").is(id).elemMatch(Criteria.where("noticeType").is(noticeType))
|
Criteria.where(ID_FIELD).is(id).elemMatch(Criteria.where("noticeType").is(noticeType))
|
||||||
), InAppPurchaseDetails.class);
|
), InAppPurchaseDetails.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addPayNotices(String id, InAppPurchaseEventNotice payNotice) {
|
public void addPayNotices(String id, InAppPurchaseEventNotice payNotice) {
|
||||||
mongoTemplate.updateFirst(
|
mongoTemplate.updateFirst(
|
||||||
Query.query(Criteria.where("id").is(id)),
|
Query.query(Criteria.where(ID_FIELD).is(id)),
|
||||||
new Update()
|
new Update()
|
||||||
.push("payNotices", payNotice)
|
.push("payNotices", payNotice)
|
||||||
.set("updateTime", TimestampUtils.now()),
|
.set("updateTime", TimestampUtils.now()),
|
||||||
@ -102,7 +104,7 @@ public class InAppPurchaseDetailsServiceImpl implements InAppPurchaseDetailsServ
|
|||||||
@Override
|
@Override
|
||||||
public void updateStatus(String id, InAppPurchaseStatus status) {
|
public void updateStatus(String id, InAppPurchaseStatus status) {
|
||||||
mongoTemplate.updateFirst(
|
mongoTemplate.updateFirst(
|
||||||
Query.query(Criteria.where("id").is(id)),
|
Query.query(Criteria.where(ID_FIELD).is(id)),
|
||||||
new Update()
|
new Update()
|
||||||
.set("status", status)
|
.set("status", status)
|
||||||
.push("statusSteps", new InAppPurchaseStatusStep()
|
.push("statusSteps", new InAppPurchaseStatusStep()
|
||||||
@ -117,7 +119,7 @@ public class InAppPurchaseDetailsServiceImpl implements InAppPurchaseDetailsServ
|
|||||||
@Override
|
@Override
|
||||||
public void updateStatusReason(String id, InAppPurchaseStatus status, String reason) {
|
public void updateStatusReason(String id, InAppPurchaseStatus status, String reason) {
|
||||||
mongoTemplate.updateFirst(
|
mongoTemplate.updateFirst(
|
||||||
Query.query(Criteria.where("id").is(id)),
|
Query.query(Criteria.where(ID_FIELD).is(id)),
|
||||||
new Update()
|
new Update()
|
||||||
.set("status", status)
|
.set("status", status)
|
||||||
.set("reason", reason)
|
.set("reason", reason)
|
||||||
@ -141,7 +143,7 @@ public class InAppPurchaseDetailsServiceImpl implements InAppPurchaseDetailsServ
|
|||||||
String newKey = key.replaceAll("\\.", "_").replaceAll("\\$", "_");
|
String newKey = key.replaceAll("\\.", "_").replaceAll("\\$", "_");
|
||||||
details.getMetadata().put(newKey, val);
|
details.getMetadata().put(newKey, val);
|
||||||
return mongoTemplate.updateFirst(
|
return mongoTemplate.updateFirst(
|
||||||
Query.query(Criteria.where("id").is(details.getId())
|
Query.query(Criteria.where(ID_FIELD).is(details.getId())
|
||||||
.and("version").is(details.getVersion())),
|
.and("version").is(details.getVersion())),
|
||||||
new Update()
|
new Update()
|
||||||
.set("metadata", details.getMetadata())
|
.set("metadata", details.getMetadata())
|
||||||
@ -158,7 +160,7 @@ public class InAppPurchaseDetailsServiceImpl implements InAppPurchaseDetailsServ
|
|||||||
|
|
||||||
if (StringUtils.isNotBlank(query.getId())) {
|
if (StringUtils.isNotBlank(query.getId())) {
|
||||||
query.setLastId(null);
|
query.setLastId(null);
|
||||||
criteria.and("id").is(query.getId());
|
criteria.and(ID_FIELD).is(query.getId());
|
||||||
}
|
}
|
||||||
if (Objects.nonNull(query.getReceiptType())) {
|
if (Objects.nonNull(query.getReceiptType())) {
|
||||||
criteria.and("receiptType").is(query.getReceiptType());
|
criteria.and("receiptType").is(query.getReceiptType());
|
||||||
@ -204,7 +206,7 @@ public class InAppPurchaseDetailsServiceImpl implements InAppPurchaseDetailsServ
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(query.getLastId())) {
|
if (StringUtils.isNotBlank(query.getLastId())) {
|
||||||
criteria.and("id").lt(query.getLastId());
|
criteria.and(ID_FIELD).lt(query.getLastId());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Objects.isNull(query.getLimit()) || query.getLimit() <= 0) {
|
if (Objects.isNull(query.getLimit()) || query.getLimit() <= 0) {
|
||||||
@ -213,7 +215,7 @@ public class InAppPurchaseDetailsServiceImpl implements InAppPurchaseDetailsServ
|
|||||||
|
|
||||||
return mongoTemplate
|
return mongoTemplate
|
||||||
.find(Query.query(criteria)
|
.find(Query.query(criteria)
|
||||||
.with(Sort.by(Sort.Order.desc("id")))
|
.with(Sort.by(Sort.Order.desc(ID_FIELD)))
|
||||||
.limit(query.getLimit()), InAppPurchaseDetails.class);
|
.limit(query.getLimit()), InAppPurchaseDetails.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,7 +224,7 @@ public class InAppPurchaseDetailsServiceImpl implements InAppPurchaseDetailsServ
|
|||||||
Criteria criteria = new Criteria();
|
Criteria criteria = new Criteria();
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(query.getId())) {
|
if (StringUtils.isNotBlank(query.getId())) {
|
||||||
criteria.and("id").is(query.getId());
|
criteria.and(ID_FIELD).is(query.getId());
|
||||||
}
|
}
|
||||||
if (Objects.nonNull(query.getReceiptType())) {
|
if (Objects.nonNull(query.getReceiptType())) {
|
||||||
criteria.and("receiptType").is(query.getReceiptType());
|
criteria.and("receiptType").is(query.getReceiptType());
|
||||||
@ -338,7 +340,7 @@ public class InAppPurchaseDetailsServiceImpl implements InAppPurchaseDetailsServ
|
|||||||
@Override
|
@Override
|
||||||
public void updateMetadata(String id, Map<String, String> metadata) {
|
public void updateMetadata(String id, Map<String, String> metadata) {
|
||||||
mongoTemplate.updateFirst(
|
mongoTemplate.updateFirst(
|
||||||
Query.query(Criteria.where("id").is(id)),
|
Query.query(Criteria.where(ID_FIELD).is(id)),
|
||||||
new Update()
|
new Update()
|
||||||
.set("metadata", metadata),
|
.set("metadata", metadata),
|
||||||
InAppPurchaseDetails.class
|
InAppPurchaseDetails.class
|
||||||
|
|||||||
@ -0,0 +1,10 @@
|
|||||||
|
package com.red.circle.order.infra.database.rds.dao.order;
|
||||||
|
|
||||||
|
import com.red.circle.framework.mybatis.dao.BaseDAO;
|
||||||
|
import com.red.circle.order.infra.database.rds.entity.order.OrderUserPurchasePay;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Web支付预下单 Mapper.
|
||||||
|
*/
|
||||||
|
public interface OrderUserPurchasePayDAO extends BaseDAO<OrderUserPurchasePay> {
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package com.red.circle.order.infra.database.rds.dao.order;
|
||||||
|
|
||||||
|
import com.red.circle.framework.mybatis.dao.BaseDAO;
|
||||||
|
import com.red.circle.order.infra.database.rds.entity.order.OrderUserPurchasePayNotice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Web支付通知明细 Mapper.
|
||||||
|
*/
|
||||||
|
public interface OrderUserPurchasePayNoticeDAO extends BaseDAO<OrderUserPurchasePayNotice> {
|
||||||
|
}
|
||||||
@ -0,0 +1,113 @@
|
|||||||
|
package com.red.circle.order.infra.database.rds.entity.order;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Web支付预下单记录.
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@TableName("order_user_purchase_pay")
|
||||||
|
public class OrderUserPurchasePay implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(value = "id", type = IdType.INPUT)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@TableField("evn")
|
||||||
|
private String evn;
|
||||||
|
|
||||||
|
@TableField("sys_origin")
|
||||||
|
private String sysOrigin;
|
||||||
|
|
||||||
|
@TableField("user_id")
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
@TableField("factory_code")
|
||||||
|
private String factoryCode;
|
||||||
|
|
||||||
|
@TableField("factory_order_id")
|
||||||
|
private String factoryOrderId;
|
||||||
|
|
||||||
|
@TableField("reference_id")
|
||||||
|
private String referenceId;
|
||||||
|
|
||||||
|
@TableField("receipt_type")
|
||||||
|
private String receiptType;
|
||||||
|
|
||||||
|
@TableField("payment_channel")
|
||||||
|
private String paymentChannel;
|
||||||
|
|
||||||
|
@TableField("factory_channel")
|
||||||
|
private String factoryChannel;
|
||||||
|
|
||||||
|
@TableField("product_code")
|
||||||
|
private String productCode;
|
||||||
|
|
||||||
|
@TableField("product_content")
|
||||||
|
private String productContent;
|
||||||
|
|
||||||
|
@TableField("product_descriptor")
|
||||||
|
private String productDescriptor;
|
||||||
|
|
||||||
|
@TableField("payment_unit")
|
||||||
|
private String paymentUnit;
|
||||||
|
|
||||||
|
@TableField("payment_amount")
|
||||||
|
private BigDecimal paymentAmount;
|
||||||
|
|
||||||
|
@TableField("compute_usd_amount")
|
||||||
|
private BigDecimal computeUsdAmount;
|
||||||
|
|
||||||
|
@TableField("compute_usd_rate")
|
||||||
|
private String computeUsdRate;
|
||||||
|
|
||||||
|
@TableField("give_away_content")
|
||||||
|
private String giveAwayContent;
|
||||||
|
|
||||||
|
@TableField("country_id")
|
||||||
|
private Long countryId;
|
||||||
|
|
||||||
|
@TableField("country_code")
|
||||||
|
private String countryCode;
|
||||||
|
|
||||||
|
@TableField("pay_country_id")
|
||||||
|
private Long payCountryId;
|
||||||
|
|
||||||
|
@TableField("pay_status")
|
||||||
|
private String payStatus;
|
||||||
|
|
||||||
|
@TableField("reason")
|
||||||
|
private String reason;
|
||||||
|
|
||||||
|
@TableField("refund_status")
|
||||||
|
private String refundStatus;
|
||||||
|
|
||||||
|
@TableField("receipt_details_id")
|
||||||
|
private Long receiptDetailsId;
|
||||||
|
|
||||||
|
@TableField("create_time")
|
||||||
|
private Timestamp createTime;
|
||||||
|
|
||||||
|
@TableField("update_time")
|
||||||
|
private Timestamp updateTime;
|
||||||
|
|
||||||
|
@TableField("create_user")
|
||||||
|
private Long createUser;
|
||||||
|
|
||||||
|
@TableField("update_user")
|
||||||
|
private Long updateUser;
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
package com.red.circle.order.infra.database.rds.entity.order;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.red.circle.framework.mybatis.entity.TimestampBaseEntity;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Web支付通知明细.
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@TableName("order_user_purchase_pay_notice")
|
||||||
|
public class OrderUserPurchasePayNotice extends TimestampBaseEntity {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@TableField("purchase_pay_id")
|
||||||
|
private Long purchasePayId;
|
||||||
|
|
||||||
|
@TableField("event_id")
|
||||||
|
private String eventId;
|
||||||
|
|
||||||
|
@TableField("notice_type")
|
||||||
|
private String noticeType;
|
||||||
|
|
||||||
|
@TableField("notice_data")
|
||||||
|
private String noticeData;
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
package com.red.circle.order.infra.database.rds.service.order;
|
||||||
|
|
||||||
|
import com.red.circle.framework.mybatis.service.BaseService;
|
||||||
|
import com.red.circle.order.infra.database.rds.entity.order.OrderUserPurchasePayNotice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Web支付通知明细服务.
|
||||||
|
*/
|
||||||
|
public interface OrderUserPurchasePayNoticeService extends BaseService<OrderUserPurchasePayNotice> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存通知.
|
||||||
|
*/
|
||||||
|
void addNotice(Long purchasePayId, String eventId, String noticeType, Object noticeData,
|
||||||
|
Long operationUserId);
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package com.red.circle.order.infra.database.rds.service.order;
|
||||||
|
|
||||||
|
import com.red.circle.framework.mybatis.service.BaseService;
|
||||||
|
import com.red.circle.order.infra.database.rds.entity.order.OrderUserPurchasePay;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Web支付预下单服务.
|
||||||
|
*/
|
||||||
|
public interface OrderUserPurchasePayService extends BaseService<OrderUserPurchasePay> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标记支付成功.
|
||||||
|
*/
|
||||||
|
void updateSuccess(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标记支付失败.
|
||||||
|
*/
|
||||||
|
void updateFail(Long id, String reason);
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package com.red.circle.order.infra.database.rds.service.order.impl;
|
||||||
|
|
||||||
|
import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl;
|
||||||
|
import com.red.circle.order.infra.database.rds.dao.order.OrderUserPurchasePayNoticeDAO;
|
||||||
|
import com.red.circle.order.infra.database.rds.entity.order.OrderUserPurchasePayNotice;
|
||||||
|
import com.red.circle.order.infra.database.rds.service.order.OrderUserPurchasePayNoticeService;
|
||||||
|
import com.red.circle.tool.core.json.JacksonUtils;
|
||||||
|
import java.util.Objects;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Web支付通知明细服务实现.
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class OrderUserPurchasePayNoticeServiceImpl
|
||||||
|
extends BaseServiceImpl<OrderUserPurchasePayNoticeDAO, OrderUserPurchasePayNotice>
|
||||||
|
implements OrderUserPurchasePayNoticeService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addNotice(Long purchasePayId, String eventId, String noticeType, Object noticeData,
|
||||||
|
Long operationUserId) {
|
||||||
|
OrderUserPurchasePayNotice notice = new OrderUserPurchasePayNotice()
|
||||||
|
.setPurchasePayId(purchasePayId)
|
||||||
|
.setEventId(Objects.toString(eventId, ""))
|
||||||
|
.setNoticeType(Objects.toString(noticeType, ""))
|
||||||
|
.setNoticeData(JacksonUtils.toJson(noticeData));
|
||||||
|
notice.setCreateUser(operationUserId);
|
||||||
|
notice.setUpdateUser(operationUserId);
|
||||||
|
save(notice);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
package com.red.circle.order.infra.database.rds.service.order.impl;
|
||||||
|
|
||||||
|
import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl;
|
||||||
|
import com.red.circle.order.infra.database.rds.dao.order.OrderUserPurchasePayDAO;
|
||||||
|
import com.red.circle.order.infra.database.rds.entity.order.OrderUserPurchasePay;
|
||||||
|
import com.red.circle.order.infra.database.rds.service.order.OrderUserPurchasePayService;
|
||||||
|
import com.red.circle.tool.core.date.TimestampUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Web支付预下单服务实现.
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class OrderUserPurchasePayServiceImpl
|
||||||
|
extends BaseServiceImpl<OrderUserPurchasePayDAO, OrderUserPurchasePay>
|
||||||
|
implements OrderUserPurchasePayService {
|
||||||
|
|
||||||
|
private static final String PAY_STATUS_SUCCESSFUL = "SUCCESSFUL";
|
||||||
|
private static final String PAY_STATUS_FAIL = "FAIL";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateSuccess(Long id) {
|
||||||
|
update()
|
||||||
|
.set(OrderUserPurchasePay::getPayStatus, PAY_STATUS_SUCCESSFUL)
|
||||||
|
.set(OrderUserPurchasePay::getReason, "")
|
||||||
|
.set(OrderUserPurchasePay::getUpdateTime, TimestampUtils.now())
|
||||||
|
.eq(OrderUserPurchasePay::getId, id)
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateFail(Long id, String reason) {
|
||||||
|
update()
|
||||||
|
.set(OrderUserPurchasePay::getPayStatus, PAY_STATUS_FAIL)
|
||||||
|
.set(OrderUserPurchasePay::getReason, reason)
|
||||||
|
.set(OrderUserPurchasePay::getUpdateTime, TimestampUtils.now())
|
||||||
|
.eq(OrderUserPurchasePay::getId, id)
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,6 +7,7 @@ import com.red.circle.other.app.dto.clientobject.gift.ActivityGiftCO;
|
|||||||
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
|
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
|
||||||
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
|
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
|
||||||
import com.red.circle.other.domain.model.user.UserProfile;
|
import com.red.circle.other.domain.model.user.UserProfile;
|
||||||
|
import com.red.circle.other.infra.common.sys.CountryCodeAliasSupport;
|
||||||
import com.red.circle.other.infra.database.cache.service.other.BannerCacheService;
|
import com.red.circle.other.infra.database.cache.service.other.BannerCacheService;
|
||||||
import com.red.circle.other.infra.database.mongo.entity.sys.ActivityConfig;
|
import com.red.circle.other.infra.database.mongo.entity.sys.ActivityConfig;
|
||||||
import com.red.circle.other.infra.database.mongo.service.sys.ActivityConfigService;
|
import com.red.circle.other.infra.database.mongo.service.sys.ActivityConfigService;
|
||||||
@ -39,6 +40,7 @@ public class ActivityGiftListQryExe {
|
|||||||
private final BannerConfigService bannerConfigService;
|
private final BannerConfigService bannerConfigService;
|
||||||
private final UserProfileGateway userProfileGateway;
|
private final UserProfileGateway userProfileGateway;
|
||||||
private final UserRegionGateway userRegionGateway;
|
private final UserRegionGateway userRegionGateway;
|
||||||
|
private final CountryCodeAliasSupport countryCodeAliasSupport;
|
||||||
|
|
||||||
public List<ActivityGiftCO> execute(AppExtCommand cmd) {
|
public List<ActivityGiftCO> execute(AppExtCommand cmd) {
|
||||||
// 获取进行中的活动
|
// 获取进行中的活动
|
||||||
@ -82,7 +84,8 @@ public class ActivityGiftListQryExe {
|
|||||||
.in(BannerConfig::getId, bannerIds);
|
.in(BannerConfig::getId, bannerIds);
|
||||||
bannerUrlMap = bannerConfigService.list(query).stream()
|
bannerUrlMap = bannerConfigService.list(query).stream()
|
||||||
.filter(bannerCache -> StringUtils.isBlank(bannerCache.getRegions()) || bannerCache.getRegions().contains(regionId))
|
.filter(bannerCache -> StringUtils.isBlank(bannerCache.getRegions()) || bannerCache.getRegions().contains(regionId))
|
||||||
.filter(bannerCache -> StringUtils.isBlank(bannerCache.getCountryCode()) || bannerCache.getCountryCode().contains(countryCode))
|
.filter(bannerCache -> StringUtils.isBlank(bannerCache.getCountryCode())
|
||||||
|
|| countryCodeAliasSupport.containsCode(bannerCache.getCountryCode(), countryCode))
|
||||||
.collect(Collectors.toMap(BannerConfig::getId, e -> e, (u1, u2) -> u1));
|
.collect(Collectors.toMap(BannerConfig::getId, e -> e, (u1, u2) -> u1));
|
||||||
} else {
|
} else {
|
||||||
bannerUrlMap = new HashMap<>();
|
bannerUrlMap = new HashMap<>();
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import com.red.circle.other.app.dto.clientobject.room.RoomBrowseRecordsV2CO;
|
|||||||
import com.red.circle.other.app.dto.clientobject.room.RoomVoiceProfileCO;
|
import com.red.circle.other.app.dto.clientobject.room.RoomVoiceProfileCO;
|
||||||
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
|
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
|
||||||
import com.red.circle.other.domain.gateway.user.ability.UserSVipGateway;
|
import com.red.circle.other.domain.gateway.user.ability.UserSVipGateway;
|
||||||
|
import com.red.circle.other.infra.common.sys.CountryCodeAliasSupport;
|
||||||
import com.red.circle.other.infra.database.mongo.entity.activity.RankQueenCount;
|
import com.red.circle.other.infra.database.mongo.entity.activity.RankQueenCount;
|
||||||
import com.red.circle.other.infra.database.mongo.entity.activity.RankQueenType;
|
import com.red.circle.other.infra.database.mongo.entity.activity.RankQueenType;
|
||||||
import com.red.circle.other.infra.database.mongo.entity.live.ActiveVoiceRoom;
|
import com.red.circle.other.infra.database.mongo.entity.live.ActiveVoiceRoom;
|
||||||
@ -40,6 +41,7 @@ public class RoomGiftListQueryExe {
|
|||||||
private final UserSVipGateway userSVipGateway;
|
private final UserSVipGateway userSVipGateway;
|
||||||
private final RankCountService rankCountService;
|
private final RankCountService rankCountService;
|
||||||
private final UserRegionGateway userRegionGateway;
|
private final UserRegionGateway userRegionGateway;
|
||||||
|
private final CountryCodeAliasSupport countryCodeAliasSupport;
|
||||||
private final RoomProfileAppConvertor roomProfileAppConvertor;
|
private final RoomProfileAppConvertor roomProfileAppConvertor;
|
||||||
private final ActiveVoiceRoomService activeVoiceRoomService;
|
private final ActiveVoiceRoomService activeVoiceRoomService;
|
||||||
private final RoomVoiceProfileCommon roomVoiceProfileCommon;
|
private final RoomVoiceProfileCommon roomVoiceProfileCommon;
|
||||||
@ -183,7 +185,8 @@ public class RoomGiftListQueryExe {
|
|||||||
return assemblyRoomVoiceProfile(activeVoiceRooms, cmd);
|
return assemblyRoomVoiceProfile(activeVoiceRooms, cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> excludeCountryCodes = List.of("SA", "AE", "EG", "MA", "US");
|
List<String> excludeCountryCodes = new ArrayList<>(
|
||||||
|
countryCodeAliasSupport.expandCodes(List.of("SA", "AE", "EG", "MA", "US")));
|
||||||
List<RoomBrowseRecordsV2CO> roomVoiceProfiles = Lists.newArrayList();
|
List<RoomBrowseRecordsV2CO> roomVoiceProfiles = Lists.newArrayList();
|
||||||
if (CollectionUtils.isEmpty(activeVoiceRooms)) {
|
if (CollectionUtils.isEmpty(activeVoiceRooms)) {
|
||||||
List<RoomVoiceProfileCO> roomVoiceProfileCos = roomVoiceProfileCommon.listRoomVoiceProfilesV2(
|
List<RoomVoiceProfileCO> roomVoiceProfileCos = roomVoiceProfileCommon.listRoomVoiceProfilesV2(
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
|
|||||||
import com.red.circle.other.domain.gateway.user.ability.UserSVipGateway;
|
import com.red.circle.other.domain.gateway.user.ability.UserSVipGateway;
|
||||||
import com.red.circle.other.domain.model.user.UserProfile;
|
import com.red.circle.other.domain.model.user.UserProfile;
|
||||||
import com.red.circle.other.domain.rocket.RocketStatus;
|
import com.red.circle.other.domain.rocket.RocketStatus;
|
||||||
|
import com.red.circle.other.infra.common.sys.CountryCodeAliasSupport;
|
||||||
import com.red.circle.other.infra.database.cache.service.user.RegionRoomCacheService;
|
import com.red.circle.other.infra.database.cache.service.user.RegionRoomCacheService;
|
||||||
import com.red.circle.other.infra.database.mongo.entity.live.ActiveVoiceRoom;
|
import com.red.circle.other.infra.database.mongo.entity.live.ActiveVoiceRoom;
|
||||||
import com.red.circle.other.infra.database.mongo.entity.live.RoomProfileManager;
|
import com.red.circle.other.infra.database.mongo.entity.live.RoomProfileManager;
|
||||||
@ -63,6 +64,7 @@ public class RoomVoiceDiscoverQryExe {
|
|||||||
private final RocketStatusCacheService rocketStatusCacheService;
|
private final RocketStatusCacheService rocketStatusCacheService;
|
||||||
private final GameLudoService gameLudoService;
|
private final GameLudoService gameLudoService;
|
||||||
private final UserProfileGateway userProfileGateway;
|
private final UserProfileGateway userProfileGateway;
|
||||||
|
private final CountryCodeAliasSupport countryCodeAliasSupport;
|
||||||
|
|
||||||
private static final String EMPTY_ROOM_CACHE_KEY = "empty_room_cache:*";
|
private static final String EMPTY_ROOM_CACHE_KEY = "empty_room_cache:*";
|
||||||
|
|
||||||
@ -261,7 +263,8 @@ public class RoomVoiceDiscoverQryExe {
|
|||||||
return emptyRooms.stream()
|
return emptyRooms.stream()
|
||||||
.filter(room -> Objects.equals(sysOrigin, room.getSysOrigin()) &&
|
.filter(room -> Objects.equals(sysOrigin, room.getSysOrigin()) &&
|
||||||
(isAllRegion || shouldShowRoom(region, room.getRegion())) &&
|
(isAllRegion || shouldShowRoom(region, room.getRegion())) &&
|
||||||
(!SA_REGIONS.contains(region) || userCountryCode == null || userCountryCode.equals(room.getCountryCode())))
|
(!SA_REGIONS.contains(region) || userCountryCode == null
|
||||||
|
|| countryCodeAliasSupport.matches(userCountryCode, room.getCountryCode())))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import com.red.circle.other.app.dto.clientobject.sys.BannerCO;
|
|||||||
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
|
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
|
||||||
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
|
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
|
||||||
import com.red.circle.other.domain.model.user.UserProfile;
|
import com.red.circle.other.domain.model.user.UserProfile;
|
||||||
|
import com.red.circle.other.infra.common.sys.CountryCodeAliasSupport;
|
||||||
import com.red.circle.other.infra.database.cache.entity.sys.BannerCache;
|
import com.red.circle.other.infra.database.cache.entity.sys.BannerCache;
|
||||||
import com.red.circle.other.infra.database.cache.service.other.BannerCacheService;
|
import com.red.circle.other.infra.database.cache.service.other.BannerCacheService;
|
||||||
import com.red.circle.other.infra.database.rds.entity.sys.BannerConfig;
|
import com.red.circle.other.infra.database.rds.entity.sys.BannerConfig;
|
||||||
@ -39,6 +40,7 @@ public class BannerQryExe {
|
|||||||
private final SysConfigAppConvertor sysConfigAppConvertor;
|
private final SysConfigAppConvertor sysConfigAppConvertor;
|
||||||
private final OrderPurchaseHistoryClient orderPurchaseHistoryClient;
|
private final OrderPurchaseHistoryClient orderPurchaseHistoryClient;
|
||||||
private final UserProfileGateway userProfileGateway;
|
private final UserProfileGateway userProfileGateway;
|
||||||
|
private final CountryCodeAliasSupport countryCodeAliasSupport;
|
||||||
|
|
||||||
public List<BannerCO> execute(AppExtCommand cmd, List<String> typeList) {
|
public List<BannerCO> execute(AppExtCommand cmd, List<String> typeList) {
|
||||||
UserProfile userProfile = userProfileGateway.getByUserId(cmd.requiredReqUserId());
|
UserProfile userProfile = userProfileGateway.getByUserId(cmd.requiredReqUserId());
|
||||||
@ -57,7 +59,8 @@ public class BannerQryExe {
|
|||||||
return sysConfigAppConvertor.toListBannerCache(configs);
|
return sysConfigAppConvertor.toListBannerCache(configs);
|
||||||
}).stream()
|
}).stream()
|
||||||
.filter(bannerCache -> StringUtils.isBlank(bannerCache.getRegions()) || bannerCache.getRegions().contains(regionId))
|
.filter(bannerCache -> StringUtils.isBlank(bannerCache.getRegions()) || bannerCache.getRegions().contains(regionId))
|
||||||
.filter(bannerCache -> StringUtils.isBlank(bannerCache.getCountryCode()) || bannerCache.getCountryCode().contains(countryCode))
|
.filter(bannerCache -> StringUtils.isBlank(bannerCache.getCountryCode())
|
||||||
|
|| countryCodeAliasSupport.containsCode(bannerCache.getCountryCode(), countryCode))
|
||||||
.toList();
|
.toList();
|
||||||
return sysConfigAppConvertor.toListBannerCO(list);
|
return sysConfigAppConvertor.toListBannerCO(list);
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package com.red.circle.other.app.command.sys.query;
|
|||||||
|
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import com.red.circle.common.business.core.util.CountryCodeAliasUtils;
|
||||||
import com.red.circle.other.app.dto.clientobject.sys.CountryCodeCO;
|
import com.red.circle.other.app.dto.clientobject.sys.CountryCodeCO;
|
||||||
import com.red.circle.other.infra.database.rds.entity.sys.SysCountryCode;
|
import com.red.circle.other.infra.database.rds.entity.sys.SysCountryCode;
|
||||||
import com.red.circle.other.infra.database.rds.service.sys.SysCountryCodeService;
|
import com.red.circle.other.infra.database.rds.service.sys.SysCountryCodeService;
|
||||||
@ -43,6 +44,10 @@ public class SysCountryOpenTopQryExe {
|
|||||||
.setAlphaThree(sysCountryCode.getAlphaThree())
|
.setAlphaThree(sysCountryCode.getAlphaThree())
|
||||||
.setCountryName(sysCountryCode.getCountryName())
|
.setCountryName(sysCountryCode.getCountryName())
|
||||||
.setAliasName(sysCountryCode.getAliasName())
|
.setAliasName(sysCountryCode.getAliasName())
|
||||||
|
.setCountryCodeAliases(CountryCodeAliasUtils.normalizeCodes(
|
||||||
|
CountryCodeAliasUtils.buildMatchCodes(sysCountryCode.getAlphaTwo(),
|
||||||
|
sysCountryCode.getAlphaThree(),
|
||||||
|
CountryCodeAliasUtils.parseAliasCodes(sysCountryCode.getAliasCodes()))))
|
||||||
.setNationalFlag(sysCountryCode.getNationalFlag())
|
.setNationalFlag(sysCountryCode.getNationalFlag())
|
||||||
.setPhonePrefix(sysCountryCode.getPhonePrefix())
|
.setPhonePrefix(sysCountryCode.getPhonePrefix())
|
||||||
.setOpen(sysCountryCode.getOpen())
|
.setOpen(sysCountryCode.getOpen())
|
||||||
|
|||||||
@ -372,8 +372,7 @@ public class GameLuckyGiftCommon {
|
|||||||
|
|
||||||
|
|
||||||
private static int getRewardMultiple(GameLuckyGiftParam param, Long rewardAmount) {
|
private static int getRewardMultiple(GameLuckyGiftParam param, Long rewardAmount) {
|
||||||
long payAmount = param.getQuantity() * param.getGift().getGiftCandy().longValue();
|
return LuckyGiftMultipleCalculator.calculate(rewardAmount, param.getGift().getGiftCandy());
|
||||||
return (int) (rewardAmount / payAmount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -461,7 +460,7 @@ public class GameLuckyGiftCommon {
|
|||||||
private void saveLuckGiftCount(GameLuckyGiftParam param, Long awardAmount) {
|
private void saveLuckGiftCount(GameLuckyGiftParam param, Long awardAmount) {
|
||||||
|
|
||||||
long payAmount = param.getQuantity() * param.getGift().getGiftCandy().longValue();
|
long payAmount = param.getQuantity() * param.getGift().getGiftCandy().longValue();
|
||||||
int multiple = (int) (awardAmount / payAmount);
|
int multiple = LuckyGiftMultipleCalculator.calculate(awardAmount, param.getGift().getGiftCandy());
|
||||||
|
|
||||||
gameLuckyGiftCountService.save(new GameLuckyGiftCount()
|
gameLuckyGiftCountService.save(new GameLuckyGiftCount()
|
||||||
.setId(param.getId())
|
.setId(param.getId())
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
package com.red.circle.other.app.common.gift;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
final class LuckyGiftMultipleCalculator {
|
||||||
|
|
||||||
|
private LuckyGiftMultipleCalculator() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static int calculate(Long rewardAmount, BigDecimal giftUnitPrice) {
|
||||||
|
if (rewardAmount == null || rewardAmount <= 0 || giftUnitPrice == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
long unitPrice = giftUnitPrice.longValue();
|
||||||
|
if (unitPrice <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) (rewardAmount / unitPrice);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -81,7 +81,8 @@ public class LuckyGiftResultProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
UserPropsResourcesDTO avatarFrame = getUserAvatarFrameProps(sendUserProfile);
|
UserPropsResourcesDTO avatarFrame = getUserAvatarFrameProps(sendUserProfile);
|
||||||
long payAmount = resolvePayAmount(event, giftConfig);
|
BigDecimal giftUnitPrice = resolveGiftUnitPrice(event, giftConfig);
|
||||||
|
long payAmount = resolvePayAmount(event, giftUnitPrice);
|
||||||
BigDecimal balanceAfter = BigDecimal.valueOf(Objects.requireNonNullElse(response.getBalanceAfter(), 0L));
|
BigDecimal balanceAfter = BigDecimal.valueOf(Objects.requireNonNullElse(response.getBalanceAfter(), 0L));
|
||||||
|
|
||||||
for (LuckyGiftGoClient.LuckyGiftGoDrawResult result : response.getResults()) {
|
for (LuckyGiftGoClient.LuckyGiftGoDrawResult result : response.getResults()) {
|
||||||
@ -91,7 +92,7 @@ public class LuckyGiftResultProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
long rewardNum = Objects.requireNonNullElse(result.getRewardNum(), 0L);
|
long rewardNum = Objects.requireNonNullElse(result.getRewardNum(), 0L);
|
||||||
int multiple = payAmount > 0 && rewardNum > 0 ? (int) (rewardNum / payAmount) : 0;
|
int multiple = LuckyGiftMultipleCalculator.calculate(rewardNum, giftUnitPrice);
|
||||||
|
|
||||||
gameLuckyGiftCountService.saveOrUpdate(new GameLuckyGiftCount()
|
gameLuckyGiftCountService.saveOrUpdate(new GameLuckyGiftCount()
|
||||||
.setId(Long.valueOf(result.getId()))
|
.setId(Long.valueOf(result.getId()))
|
||||||
@ -121,9 +122,15 @@ public class LuckyGiftResultProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private long resolvePayAmount(GameLuckyGiftBusinessEvent event, GiftConfigDTO giftConfig) {
|
private BigDecimal resolveGiftUnitPrice(GameLuckyGiftBusinessEvent event, GiftConfigDTO giftConfig) {
|
||||||
BigDecimal giftPrice = Objects.nonNull(event.getGiftPrice()) ? event.getGiftPrice() : giftConfig.getGiftCandy();
|
return Objects.nonNull(event.getGiftPrice()) ? event.getGiftPrice() : giftConfig.getGiftCandy();
|
||||||
return giftPrice.multiply(BigDecimal.valueOf(Objects.requireNonNullElse(event.getQuantity(), 0))).longValue();
|
}
|
||||||
|
|
||||||
|
private long resolvePayAmount(GameLuckyGiftBusinessEvent event, BigDecimal giftUnitPrice) {
|
||||||
|
if (giftUnitPrice == null) {
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
return giftUnitPrice.multiply(BigDecimal.valueOf(Objects.requireNonNullElse(event.getQuantity(), 0))).longValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendLuckyGiftMessage(
|
private void sendLuckyGiftMessage(
|
||||||
|
|||||||
@ -151,6 +151,7 @@ public class RoomVoiceProfileCommon {
|
|||||||
if (Objects.isNull(roomVoiceProfile)) {
|
if (Objects.isNull(roomVoiceProfile)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
roomVoiceProfile.putRoomMemberQuantity(toRoomMemberQuantity(activeVoiceRoom.getOnlineQuantity()));
|
||||||
roomVoiceProfile.setHotRoom(activeVoiceRoom.getHot());
|
roomVoiceProfile.setHotRoom(activeVoiceRoom.getHot());
|
||||||
roomVoiceProfile.setRoomGameIcon("");
|
roomVoiceProfile.setRoomGameIcon("");
|
||||||
roomVoiceProfile.setUserSVipLevel(SVIPLevelEnum.valueOf(activeVoiceRoom.getSuperVipLevel()));
|
roomVoiceProfile.setUserSVipLevel(SVIPLevelEnum.valueOf(activeVoiceRoom.getSuperVipLevel()));
|
||||||
@ -185,5 +186,12 @@ public class RoomVoiceProfileCommon {
|
|||||||
&& !Objects.equals(manager.getEvent(), RoomEventEnum.CLOSE.name());
|
&& !Objects.equals(manager.getEvent(), RoomEventEnum.CLOSE.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Integer toRoomMemberQuantity(Long onlineQuantity) {
|
||||||
|
if (Objects.isNull(onlineQuantity) || onlineQuantity < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return onlineQuantity > Integer.MAX_VALUE ? Integer.MAX_VALUE : onlineQuantity.intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
package com.red.circle.other.app.convertor.sys;
|
package com.red.circle.other.app.convertor.sys;
|
||||||
|
|
||||||
|
import com.red.circle.common.business.core.util.CountryCodeAliasUtils;
|
||||||
import com.red.circle.framework.core.convertor.ConvertorModel;
|
import com.red.circle.framework.core.convertor.ConvertorModel;
|
||||||
import com.red.circle.other.app.dto.clientobject.sys.CountryCodeCO;
|
import com.red.circle.other.app.dto.clientobject.sys.CountryCodeCO;
|
||||||
import com.red.circle.other.infra.database.rds.entity.sys.SysCountryCode;
|
import com.red.circle.other.infra.database.rds.entity.sys.SysCountryCode;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author pengliang on 2021/3/10
|
* @author pengliang on 2021/3/10
|
||||||
@ -14,5 +16,15 @@ public interface SysCountryAppConvertor {
|
|||||||
|
|
||||||
List<CountryCodeCO> toListCountryCodeCO(List<SysCountryCode> countryCodes);
|
List<CountryCodeCO> toListCountryCodeCO(List<SysCountryCode> countryCodes);
|
||||||
|
|
||||||
|
@Mapping(target = "countryCodeAliases", source = ".")
|
||||||
CountryCodeCO toCountryCodeCO(SysCountryCode countryCode);
|
CountryCodeCO toCountryCodeCO(SysCountryCode countryCode);
|
||||||
|
|
||||||
|
default List<String> mapCountryCodeAliases(SysCountryCode countryCode) {
|
||||||
|
if (countryCode == null) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
return CountryCodeAliasUtils.normalizeCodes(
|
||||||
|
CountryCodeAliasUtils.buildMatchCodes(countryCode.getAlphaTwo(), countryCode.getAlphaThree(),
|
||||||
|
CountryCodeAliasUtils.parseAliasCodes(countryCode.getAliasCodes())));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,75 +0,0 @@
|
|||||||
// 路径: rc-service-other/other-application/src/main/java/com/red/circle/other/app/scheduler/EmptyRoomCleanTask.java
|
|
||||||
package com.red.circle.other.app.scheduler;
|
|
||||||
|
|
||||||
import com.alibaba.nacos.client.naming.utils.CollectionUtils;
|
|
||||||
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
|
||||||
import com.red.circle.component.redis.annotation.TaskCacheLock;
|
|
||||||
import com.red.circle.live.inner.endpoint.LiveMicClient;
|
|
||||||
import com.red.circle.other.infra.database.mongo.entity.live.ActiveVoiceRoom;
|
|
||||||
import com.red.circle.other.infra.database.mongo.service.live.ActiveVoiceRoomService;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清理空房间定时任务
|
|
||||||
* 每2分钟清理一次DB中没人的房间
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@ConditionalOnProperty(name = "scheduler.room-empty-clean", havingValue = "true", matchIfMissing = true)
|
|
||||||
public class EmptyRoomCleanTask {
|
|
||||||
|
|
||||||
private final ActiveVoiceRoomService activeVoiceRoomService;
|
|
||||||
private final LiveMicClient liveMicClient;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 每2分钟清理一次空房间
|
|
||||||
*/
|
|
||||||
@Scheduled(cron = "0 */2 * * * ?")
|
|
||||||
@TaskCacheLock(key = "EMPTY_ROOM_CLEAN_TASK", expireSecond = 59 * 2)
|
|
||||||
public void cleanEmptyRooms() {
|
|
||||||
try {
|
|
||||||
// 获取所有活跃房间
|
|
||||||
List<ActiveVoiceRoom> allRooms = activeVoiceRoomService.listDiscover(SysOriginPlatformEnum.LIKEI.name(),true,"",null,200);
|
|
||||||
if (CollectionUtils.isEmpty(allRooms)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Long> emptyRoomIds = new ArrayList<>();
|
|
||||||
|
|
||||||
// 检查每个房间的在线人数
|
|
||||||
for (ActiveVoiceRoom room : allRooms) {
|
|
||||||
// 跳过固定权重的房间(这些是固定展示的房间)
|
|
||||||
if (room.getFixedWeights() != 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Long roomUserCount = liveMicClient.getLiveRoomUserSize(room.getId()).getBody();
|
|
||||||
if (roomUserCount != null && roomUserCount == 0) {
|
|
||||||
emptyRoomIds.add(room.getId());
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 批量删除空房间
|
|
||||||
if (!CollectionUtils.isEmpty(emptyRoomIds)) {
|
|
||||||
activeVoiceRoomService.removeByIds(emptyRoomIds);
|
|
||||||
log.info("清理空房间完成,删除房间数量: {}, 房间ID: {}", emptyRoomIds.size(), emptyRoomIds);
|
|
||||||
} else {
|
|
||||||
log.warn("清理空房间失败, 无法获取房间在线人数");
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("清理空房间任务执行失败", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,92 @@
|
|||||||
|
package com.red.circle.other.app.scheduler;
|
||||||
|
|
||||||
|
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
||||||
|
import com.red.circle.component.redis.annotation.TaskCacheLock;
|
||||||
|
import com.red.circle.live.inner.endpoint.LiveMicClient;
|
||||||
|
import com.red.circle.other.infra.database.mongo.entity.live.ActiveVoiceRoom;
|
||||||
|
import com.red.circle.other.infra.database.mongo.service.live.ActiveVoiceRoomService;
|
||||||
|
import com.red.circle.tool.core.collection.CollectionUtils;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定时对账在线房间人数,修正 ActiveVoiceRoom.onlineQuantity 漂移。
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@ConditionalOnProperty(name = "scheduler.room-online-quantity-reconcile", havingValue = "true", matchIfMissing = true)
|
||||||
|
public class RoomOnlineQuantityReconcileTask {
|
||||||
|
|
||||||
|
private static final int PER_SYS_ORIGIN_LIMIT = 200;
|
||||||
|
|
||||||
|
private final ActiveVoiceRoomService activeVoiceRoomService;
|
||||||
|
private final LiveMicClient liveMicClient;
|
||||||
|
|
||||||
|
@Scheduled(cron = "0 */2 * * * ?")
|
||||||
|
@TaskCacheLock(key = "ROOM_ONLINE_QUANTITY_RECONCILE_TASK", expireSecond = 59 * 2)
|
||||||
|
public void reconcileOnlineQuantity() {
|
||||||
|
try {
|
||||||
|
List<ActiveVoiceRoom> activeRooms = listActiveRooms();
|
||||||
|
if (CollectionUtils.isEmpty(activeRooms)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int correctedCount = 0;
|
||||||
|
int failedCount = 0;
|
||||||
|
for (ActiveVoiceRoom room : activeRooms) {
|
||||||
|
if (Objects.isNull(room.getId()) || Objects.isNull(room.getRoomAccount())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Long actualQuantity = liveMicClient.getLiveRoomUserSize(room.getId()).getBody();
|
||||||
|
actualQuantity = Objects.nonNull(actualQuantity) ? actualQuantity : 0L;
|
||||||
|
Long currentQuantity = Objects.nonNull(room.getOnlineQuantity()) ? room.getOnlineQuantity() : 0L;
|
||||||
|
if (Objects.equals(currentQuantity, actualQuantity)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
activeVoiceRoomService.updateQuantityByRoomAccount(room.getRoomAccount(), actualQuantity);
|
||||||
|
correctedCount++;
|
||||||
|
log.info("reconcile room online quantity, roomId={}, roomAccount={}, currentQuantity={}, actualQuantity={}",
|
||||||
|
room.getId(), room.getRoomAccount(), currentQuantity, actualQuantity);
|
||||||
|
} catch (Exception e) {
|
||||||
|
failedCount++;
|
||||||
|
log.warn("reconcile room online quantity failed, roomId={}, roomAccount={}",
|
||||||
|
room.getId(), room.getRoomAccount(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("room online quantity reconcile finished, scanCount={}, correctedCount={}, failedCount={}",
|
||||||
|
activeRooms.size(), correctedCount, failedCount);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("room online quantity reconcile task failed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ActiveVoiceRoom> listActiveRooms() {
|
||||||
|
Map<Long, ActiveVoiceRoom> rooms = new LinkedHashMap<>();
|
||||||
|
for (SysOriginPlatformEnum sysOrigin : SysOriginPlatformEnum.getVoiceSystems()) {
|
||||||
|
List<ActiveVoiceRoom> currentRooms = activeVoiceRoomService.listDiscover(
|
||||||
|
sysOrigin.name(),
|
||||||
|
true,
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
PER_SYS_ORIGIN_LIMIT
|
||||||
|
);
|
||||||
|
if (CollectionUtils.isEmpty(currentRooms)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
currentRooms.forEach(room -> rooms.putIfAbsent(room.getId(), room));
|
||||||
|
}
|
||||||
|
return List.copyOf(rooms.values());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package com.red.circle.other.app.command.party3rd.callback.trtc;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import com.red.circle.external.inner.model.callback.trtc.EventInfo;
|
||||||
|
import com.red.circle.external.inner.model.callback.trtc.TrtcCallbackEvent;
|
||||||
|
import com.red.circle.other.app.common.live.OnlineRoomCommon;
|
||||||
|
import com.red.circle.other.infra.database.cache.service.other.RoomManagerCacheService;
|
||||||
|
import com.red.circle.other.infra.database.mongo.service.live.ActiveVoiceRoomService;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
class EnterRoomCallbackStrategyTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void doOperation_shouldUpdateOnlineQuantityWithIncrementedRoomUserSize() {
|
||||||
|
OnlineRoomCommon onlineRoomCommon = mock(OnlineRoomCommon.class);
|
||||||
|
ActiveVoiceRoomService activeVoiceRoomService = mock(ActiveVoiceRoomService.class);
|
||||||
|
RoomManagerCacheService roomManagerCacheService = mock(RoomManagerCacheService.class);
|
||||||
|
EnterRoomCallbackStrategy strategy = new EnterRoomCallbackStrategy(
|
||||||
|
onlineRoomCommon,
|
||||||
|
activeVoiceRoomService,
|
||||||
|
roomManagerCacheService
|
||||||
|
);
|
||||||
|
|
||||||
|
TrtcCallbackEvent event = new TrtcCallbackEvent();
|
||||||
|
EventInfo eventInfo = new EventInfo();
|
||||||
|
eventInfo.setRoomId("123456");
|
||||||
|
eventInfo.setUserId("9527");
|
||||||
|
eventInfo.setEventTs("1710000000");
|
||||||
|
event.setEventInfo(eventInfo);
|
||||||
|
|
||||||
|
when(activeVoiceRoomService.existsByRoomAccount("123456")).thenReturn(true);
|
||||||
|
when(roomManagerCacheService.incrementNumberPeople("123456")).thenReturn(6L);
|
||||||
|
|
||||||
|
strategy.doOperation(event);
|
||||||
|
|
||||||
|
verify(activeVoiceRoomService).updateQuantityByRoomAccount("123456", 6L);
|
||||||
|
verify(onlineRoomCommon, never()).addOnlineRoomByAccount("123456");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,126 @@
|
|||||||
|
package com.red.circle.other.app.common.gift;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import com.red.circle.component.redis.service.RedisService;
|
||||||
|
import com.red.circle.external.inner.endpoint.message.ImGroupClient;
|
||||||
|
import com.red.circle.external.inner.model.cmd.message.BroadcastGroupMsgBodyCmd;
|
||||||
|
import com.red.circle.mq.business.model.event.gift.GameLuckyGiftBusinessEvent;
|
||||||
|
import com.red.circle.mq.business.model.event.gift.GameLuckyGiftUser;
|
||||||
|
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
|
||||||
|
import com.red.circle.other.app.dto.clientobject.game.GameLuckyGiftMsgCO;
|
||||||
|
import com.red.circle.other.app.service.task.RoomDailyTaskProgressService;
|
||||||
|
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
|
||||||
|
import com.red.circle.other.domain.model.user.UserProfile;
|
||||||
|
import com.red.circle.other.infra.database.cache.service.other.GiftCacheService;
|
||||||
|
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
|
||||||
|
import com.red.circle.other.infra.database.rds.entity.game.GameLuckyGiftCount;
|
||||||
|
import com.red.circle.other.infra.database.rds.service.game.GameLuckyGiftCountService;
|
||||||
|
import com.red.circle.other.infra.database.rds.service.live.RoomMemberService;
|
||||||
|
import com.red.circle.other.inner.model.dto.material.GiftConfigDTO;
|
||||||
|
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
|
||||||
|
class LuckyGiftResultProcessorTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void process_shouldUseGiftUnitPriceToCalculateMultiple() {
|
||||||
|
GameLuckyGiftCountService gameLuckyGiftCountService = mock(GameLuckyGiftCountService.class);
|
||||||
|
GiftCacheService giftCacheService = mock(GiftCacheService.class);
|
||||||
|
UserProfileGateway userProfileGateway = mock(UserProfileGateway.class);
|
||||||
|
UserProfileAppConvertor userProfileAppConvertor = mock(UserProfileAppConvertor.class);
|
||||||
|
ImGroupClient imGroupClient = mock(ImGroupClient.class);
|
||||||
|
RoomDailyTaskProgressService roomDailyTaskProgressService = mock(RoomDailyTaskProgressService.class);
|
||||||
|
RoomMemberService roomMemberService = mock(RoomMemberService.class);
|
||||||
|
RedisService redisService = mock(RedisService.class);
|
||||||
|
RoomProfileManagerService roomProfileManagerService = mock(RoomProfileManagerService.class);
|
||||||
|
GameLuckyGiftCommon gameLuckyGiftCommon = mock(GameLuckyGiftCommon.class);
|
||||||
|
LuckyGiftResultProcessor processor = new LuckyGiftResultProcessor(
|
||||||
|
gameLuckyGiftCountService,
|
||||||
|
giftCacheService,
|
||||||
|
userProfileGateway,
|
||||||
|
userProfileAppConvertor,
|
||||||
|
imGroupClient,
|
||||||
|
roomDailyTaskProgressService,
|
||||||
|
roomMemberService,
|
||||||
|
redisService,
|
||||||
|
roomProfileManagerService,
|
||||||
|
gameLuckyGiftCommon
|
||||||
|
);
|
||||||
|
|
||||||
|
GiftConfigDTO giftConfig = new GiftConfigDTO()
|
||||||
|
.setId(11L)
|
||||||
|
.setGiftCandy(BigDecimal.valueOf(173))
|
||||||
|
.setGiftPhoto("gift.png");
|
||||||
|
UserProfile senderProfile = new UserProfile();
|
||||||
|
senderProfile.setId(1001L);
|
||||||
|
senderProfile.setAccount("sender001");
|
||||||
|
senderProfile.setUserNickname("sender");
|
||||||
|
|
||||||
|
UserProfile acceptProfile = new UserProfile();
|
||||||
|
acceptProfile.setId(2002L);
|
||||||
|
acceptProfile.setUserNickname("receiver");
|
||||||
|
|
||||||
|
UserProfileDTO senderProfileDTO = new UserProfileDTO();
|
||||||
|
senderProfileDTO.setId(1001L);
|
||||||
|
senderProfileDTO.setAccount("sender001");
|
||||||
|
senderProfileDTO.setUserNickname("sender");
|
||||||
|
senderProfileDTO.setUserAvatar("sender.png");
|
||||||
|
|
||||||
|
when(giftCacheService.getById(11L)).thenReturn(giftConfig);
|
||||||
|
when(userProfileGateway.getByUserId(1001L)).thenReturn(senderProfile);
|
||||||
|
when(userProfileGateway.getByUserId(2002L)).thenReturn(acceptProfile);
|
||||||
|
when(userProfileAppConvertor.toUserProfileDTO(senderProfile)).thenReturn(senderProfileDTO);
|
||||||
|
when(gameLuckyGiftCommon.getRewardMultipleType(20)).thenReturn("SUPER");
|
||||||
|
when(roomMemberService.getRoomMember(3003L, 1001L)).thenReturn(null);
|
||||||
|
|
||||||
|
GameLuckyGiftBusinessEvent event = new GameLuckyGiftBusinessEvent()
|
||||||
|
.setBusinessId("biz-001")
|
||||||
|
.setUserId(1001L)
|
||||||
|
.setRoomId(3003L)
|
||||||
|
.setRoomAccount("room-account")
|
||||||
|
.setSysOrigin("LIKEI")
|
||||||
|
.setGiftId(11L)
|
||||||
|
.setGiftPrice(BigDecimal.valueOf(173))
|
||||||
|
.setQuantity(4)
|
||||||
|
.setGiftCombos(0)
|
||||||
|
.setRegionCode("SA")
|
||||||
|
.setUsers(List.of(
|
||||||
|
new GameLuckyGiftUser()
|
||||||
|
.setId(90001L)
|
||||||
|
.setAcceptUserId(2002L)
|
||||||
|
));
|
||||||
|
|
||||||
|
LuckyGiftGoClient.LuckyGiftGoDrawResponse response = new LuckyGiftGoClient.LuckyGiftGoDrawResponse()
|
||||||
|
.setBusinessId("biz-001")
|
||||||
|
.setBalanceAfter(999999L)
|
||||||
|
.setResults(List.of(
|
||||||
|
new LuckyGiftGoClient.LuckyGiftGoDrawResult()
|
||||||
|
.setId("90001")
|
||||||
|
.setAcceptUserId(2002L)
|
||||||
|
.setIsWin(true)
|
||||||
|
.setRewardNum(3460L)
|
||||||
|
));
|
||||||
|
|
||||||
|
processor.process(event, response);
|
||||||
|
|
||||||
|
ArgumentCaptor<GameLuckyGiftCount> countCaptor = ArgumentCaptor.forClass(GameLuckyGiftCount.class);
|
||||||
|
verify(gameLuckyGiftCountService).saveOrUpdate(countCaptor.capture());
|
||||||
|
GameLuckyGiftCount saved = countCaptor.getValue();
|
||||||
|
assertEquals(Long.valueOf(692L), saved.getPayAmount());
|
||||||
|
assertEquals(Integer.valueOf(20), saved.getMultiple());
|
||||||
|
assertEquals(Long.valueOf(3460L), saved.getAwardAmount());
|
||||||
|
|
||||||
|
ArgumentCaptor<BroadcastGroupMsgBodyCmd> messageCaptor = ArgumentCaptor.forClass(BroadcastGroupMsgBodyCmd.class);
|
||||||
|
verify(imGroupClient).sendMessageBroadcast(messageCaptor.capture());
|
||||||
|
GameLuckyGiftMsgCO message = (GameLuckyGiftMsgCO) messageCaptor.getValue().getData();
|
||||||
|
assertEquals(Integer.valueOf(20), message.getMultiple());
|
||||||
|
assertEquals(Long.valueOf(3460L), message.getAwardAmount());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,105 @@
|
|||||||
|
package com.red.circle.other.app.common.room;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyMap;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import com.red.circle.other.app.convertor.live.RoomProfileAppConvertor;
|
||||||
|
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
|
||||||
|
import com.red.circle.other.app.dto.clientobject.family.RoomSettingCO;
|
||||||
|
import com.red.circle.other.app.dto.clientobject.room.RoomVoiceProfileCO;
|
||||||
|
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
|
||||||
|
import com.red.circle.other.infra.database.mongo.entity.live.ActiveVoiceRoom;
|
||||||
|
import com.red.circle.other.infra.database.mongo.entity.live.RoomCounter;
|
||||||
|
import com.red.circle.other.infra.database.mongo.entity.live.RoomProfileManager;
|
||||||
|
import com.red.circle.other.infra.database.mongo.entity.live.RoomSetting;
|
||||||
|
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
|
||||||
|
import com.red.circle.other.inner.enums.room.RoomEventEnum;
|
||||||
|
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
class RoomVoiceProfileCommonTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void toListRoomVoiceProfileCO_shouldUseActiveVoiceRoomOnlineQuantityAsMemberQuantity() {
|
||||||
|
UserProfileGateway userProfileGateway = mock(UserProfileGateway.class);
|
||||||
|
UserProfileAppConvertor userProfileAppConvertor = mock(UserProfileAppConvertor.class);
|
||||||
|
RoomProfileAppConvertor roomProfileAppConvertor = mock(RoomProfileAppConvertor.class);
|
||||||
|
RoomProfileManagerService roomProfileManagerService = mock(RoomProfileManagerService.class);
|
||||||
|
RoomVoiceProfileCommon roomVoiceProfileCommon = new RoomVoiceProfileCommon(
|
||||||
|
userProfileGateway,
|
||||||
|
userProfileAppConvertor,
|
||||||
|
roomProfileAppConvertor,
|
||||||
|
roomProfileManagerService
|
||||||
|
);
|
||||||
|
|
||||||
|
ActiveVoiceRoom activeVoiceRoom = new ActiveVoiceRoom()
|
||||||
|
.setId(10001L)
|
||||||
|
.setUserId(20001L)
|
||||||
|
.setOnlineQuantity(6L)
|
||||||
|
.setSuperVipLevel("NONE");
|
||||||
|
|
||||||
|
RoomProfileManager roomProfileManager = new RoomProfileManager();
|
||||||
|
roomProfileManager.setId(10001L);
|
||||||
|
roomProfileManager.setUserId(20001L);
|
||||||
|
roomProfileManager.setDel(Boolean.FALSE);
|
||||||
|
roomProfileManager.setEvent(RoomEventEnum.AVAILABLE.name());
|
||||||
|
roomProfileManager.setSetting(RoomSetting.createDefaultRoomSetting());
|
||||||
|
roomProfileManager.setCounter(new RoomCounter().setMemberCount(1).setAdminCount(0));
|
||||||
|
|
||||||
|
UserProfileDTO userProfileDTO = new UserProfileDTO();
|
||||||
|
userProfileDTO.setId(20001L);
|
||||||
|
|
||||||
|
RoomVoiceProfileCO convertedProfile = new RoomVoiceProfileCO()
|
||||||
|
.setId(10001L)
|
||||||
|
.setUserId(20001L);
|
||||||
|
|
||||||
|
when(roomProfileManagerService.mapByRoomIds(java.util.Set.of(10001L)))
|
||||||
|
.thenReturn(Map.of(10001L, roomProfileManager));
|
||||||
|
when(userProfileGateway.mapByUserIds(java.util.Set.of(20001L)))
|
||||||
|
.thenReturn(Map.of());
|
||||||
|
when(userProfileAppConvertor.toMapUserProfileDTO(anyMap()))
|
||||||
|
.thenReturn(Map.of(20001L, userProfileDTO));
|
||||||
|
when(roomProfileAppConvertor.toRoomVoiceProfileCO(roomProfileManager))
|
||||||
|
.thenReturn(convertedProfile);
|
||||||
|
when(roomProfileAppConvertor.toRoomSettingCO(roomProfileManager.getSetting()))
|
||||||
|
.thenReturn(new RoomSettingCO());
|
||||||
|
|
||||||
|
List<RoomVoiceProfileCO> roomProfiles = roomVoiceProfileCommon.toListRoomVoiceProfileCO(
|
||||||
|
List.of(activeVoiceRoom));
|
||||||
|
|
||||||
|
assertEquals(1, roomProfiles.size());
|
||||||
|
assertEquals("6", getExtValue(roomProfiles.get(0), "memberQuantity"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object getExtValue(RoomVoiceProfileCO roomVoiceProfileCO, String key) {
|
||||||
|
Map<?, ?> extValues = findExtValues(roomVoiceProfileCO);
|
||||||
|
assertNotNull(extValues, "extValues should exist on RoomVoiceProfileCO");
|
||||||
|
return extValues.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<?, ?> findExtValues(Object target) {
|
||||||
|
Class<?> current = target.getClass();
|
||||||
|
while (current != null) {
|
||||||
|
try {
|
||||||
|
Field field = current.getDeclaredField("extValues");
|
||||||
|
field.setAccessible(true);
|
||||||
|
Object value = field.get(target);
|
||||||
|
if (value instanceof Map<?, ?> extValues) {
|
||||||
|
return extValues;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} catch (NoSuchFieldException ignored) {
|
||||||
|
current = current.getSuperclass();
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new IllegalStateException("read extValues failed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
|||||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||||
import com.red.circle.framework.dto.ClientObject;
|
import com.red.circle.framework.dto.ClientObject;
|
||||||
|
import java.util.List;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
@ -45,6 +46,11 @@ public class CountryCodeCO extends ClientObject {
|
|||||||
*/
|
*/
|
||||||
private String aliasName;
|
private String aliasName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国家码别名集合.
|
||||||
|
*/
|
||||||
|
private List<String> countryCodeAliases;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 国旗.
|
* 国旗.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -0,0 +1,82 @@
|
|||||||
|
package com.red.circle.other.infra.common.sys;
|
||||||
|
|
||||||
|
import com.red.circle.common.business.core.util.CountryCodeAliasUtils;
|
||||||
|
import com.red.circle.other.infra.database.rds.entity.sys.SysCountryCode;
|
||||||
|
import com.red.circle.other.infra.database.rds.service.sys.SysCountryCodeService;
|
||||||
|
import com.red.circle.tool.core.text.StringUtils;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国家码别名支持.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CountryCodeAliasSupport {
|
||||||
|
|
||||||
|
private final SysCountryCodeService sysCountryCodeService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取某个国家码的全部可匹配代码.
|
||||||
|
*/
|
||||||
|
public Set<String> getMatchCodes(String code) {
|
||||||
|
String normalized = CountryCodeAliasUtils.normalize(code);
|
||||||
|
if (StringUtils.isBlank(normalized)) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
SysCountryCode sysCountryCode = sysCountryCodeService.getByCode(normalized);
|
||||||
|
if (sysCountryCode == null) {
|
||||||
|
return CountryCodeAliasUtils.legacyAliases(normalized);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CountryCodeAliasUtils.buildMatchCodes(sysCountryCode.getAlphaTwo(),
|
||||||
|
sysCountryCode.getAlphaThree(),
|
||||||
|
CountryCodeAliasUtils.parseAliasCodes(sysCountryCode.getAliasCodes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扩展多组国家码.
|
||||||
|
*/
|
||||||
|
public Set<String> expandCodes(Collection<String> codes) {
|
||||||
|
if (codes == null || codes.isEmpty()) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkedHashSet<String> result = new LinkedHashSet<>();
|
||||||
|
for (String code : codes) {
|
||||||
|
result.addAll(getMatchCodes(code));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 两个国家码是否匹配.
|
||||||
|
*/
|
||||||
|
public boolean matches(String leftCode, String rightCode) {
|
||||||
|
Set<String> leftCodes = getMatchCodes(leftCode);
|
||||||
|
Set<String> rightCodes = getMatchCodes(rightCode);
|
||||||
|
if (leftCodes.isEmpty() || rightCodes.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return leftCodes.stream().anyMatch(rightCodes::contains);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 逗号分隔国家列表是否包含指定国家码.
|
||||||
|
*/
|
||||||
|
public boolean containsCode(String csvCodes, String countryCode) {
|
||||||
|
if (StringUtils.isBlank(csvCodes) || StringUtils.isBlank(countryCode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Arrays.stream(csvCodes.split(","))
|
||||||
|
.map(CountryCodeAliasUtils::normalize)
|
||||||
|
.filter(StringUtils::isNotBlank)
|
||||||
|
.anyMatch(code -> matches(code, countryCode));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
package com.red.circle.other.infra.convertor.sys;
|
package com.red.circle.other.infra.convertor.sys;
|
||||||
|
|
||||||
|
import com.red.circle.common.business.core.util.CountryCodeAliasUtils;
|
||||||
import com.red.circle.framework.core.convertor.ConvertorModel;
|
import com.red.circle.framework.core.convertor.ConvertorModel;
|
||||||
import com.red.circle.other.infra.database.rds.entity.sys.SysCountryCode;
|
import com.red.circle.other.infra.database.rds.entity.sys.SysCountryCode;
|
||||||
import com.red.circle.other.inner.model.cmd.sys.SysCountryCodeCmd;
|
import com.red.circle.other.inner.model.cmd.sys.SysCountryCodeCmd;
|
||||||
@ -7,6 +8,7 @@ import com.red.circle.other.inner.model.dto.sys.SysCountryCodeDTO;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author pengliang on 2023/5/24
|
* @author pengliang on 2023/5/24
|
||||||
@ -14,6 +16,7 @@ import org.mapstruct.Mapper;
|
|||||||
@Mapper(componentModel = ConvertorModel.SPRING)
|
@Mapper(componentModel = ConvertorModel.SPRING)
|
||||||
public interface CountryCodeInnerConvertor {
|
public interface CountryCodeInnerConvertor {
|
||||||
|
|
||||||
|
@Mapping(target = "countryCodeAliases", source = ".")
|
||||||
SysCountryCodeDTO toSysCountryCodeDTO(SysCountryCode sysCountryCode);
|
SysCountryCodeDTO toSysCountryCodeDTO(SysCountryCode sysCountryCode);
|
||||||
|
|
||||||
List<SysCountryCodeDTO> toListSysCountryCodeDTO(List<SysCountryCode> sysCountryCodes);
|
List<SysCountryCodeDTO> toListSysCountryCodeDTO(List<SysCountryCode> sysCountryCodes);
|
||||||
@ -21,6 +24,20 @@ public interface CountryCodeInnerConvertor {
|
|||||||
Map<Long, SysCountryCodeDTO> toMapLongSysCountryCodeDTO(
|
Map<Long, SysCountryCodeDTO> toMapLongSysCountryCodeDTO(
|
||||||
Map<Long, SysCountryCode> sysCountryCodeMap);
|
Map<Long, SysCountryCode> sysCountryCodeMap);
|
||||||
|
|
||||||
|
@Mapping(target = "aliasCodes", source = "countryCodeAliases")
|
||||||
SysCountryCode toSysCountryCode(SysCountryCodeCmd cmd);
|
SysCountryCode toSysCountryCode(SysCountryCodeCmd cmd);
|
||||||
|
|
||||||
|
default List<String> mapCountryCodeAliases(SysCountryCode sysCountryCode) {
|
||||||
|
if (sysCountryCode == null) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
return CountryCodeAliasUtils.normalizeCodes(
|
||||||
|
CountryCodeAliasUtils.buildMatchCodes(sysCountryCode.getAlphaTwo(), sysCountryCode.getAlphaThree(),
|
||||||
|
CountryCodeAliasUtils.parseAliasCodes(sysCountryCode.getAliasCodes())));
|
||||||
|
}
|
||||||
|
|
||||||
|
default String mapCountryCodeAliases(List<String> countryCodeAliases) {
|
||||||
|
return CountryCodeAliasUtils.toAliasCodesJson(countryCodeAliases);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package com.red.circle.other.infra.database.mongo.service.live.impl;
|
|||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
||||||
import com.red.circle.framework.mybatis.constant.PageConstant;
|
import com.red.circle.framework.mybatis.constant.PageConstant;
|
||||||
|
import com.red.circle.other.infra.common.sys.CountryCodeAliasSupport;
|
||||||
import com.red.circle.other.infra.database.mongo.dto.query.live.ActiveVoiceRoomQuery;
|
import com.red.circle.other.infra.database.mongo.dto.query.live.ActiveVoiceRoomQuery;
|
||||||
import com.red.circle.other.infra.database.mongo.dto.query.live.FamilyOnlineRoomQuery;
|
import com.red.circle.other.infra.database.mongo.dto.query.live.FamilyOnlineRoomQuery;
|
||||||
import com.red.circle.other.infra.database.mongo.entity.live.ActiveVoiceRoom;
|
import com.red.circle.other.infra.database.mongo.entity.live.ActiveVoiceRoom;
|
||||||
@ -35,6 +36,7 @@ import org.springframework.stereotype.Service;
|
|||||||
public class ActiveVoiceRoomServiceImpl implements ActiveVoiceRoomService {
|
public class ActiveVoiceRoomServiceImpl implements ActiveVoiceRoomService {
|
||||||
|
|
||||||
private final MongoTemplate mongoTemplate;
|
private final MongoTemplate mongoTemplate;
|
||||||
|
private final CountryCodeAliasSupport countryCodeAliasSupport;
|
||||||
|
|
||||||
private static final Set<String> TR_REGIONS = Set.of("TR");
|
private static final Set<String> TR_REGIONS = Set.of("TR");
|
||||||
private static final Set<String> SA_REGIONS = Set.of("BD","SA", "IN", "PK");
|
private static final Set<String> SA_REGIONS = Set.of("BD","SA", "IN", "PK");
|
||||||
@ -117,7 +119,7 @@ public class ActiveVoiceRoomServiceImpl implements ActiveVoiceRoomService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(qryCmd.getCountryCode())) {
|
if (StringUtils.isNotBlank(qryCmd.getCountryCode())) {
|
||||||
criteria.and("countryCode").is(qryCmd.getCountryCode());
|
criteria.and("countryCode").in(countryCodeAliasSupport.getMatchCodes(qryCmd.getCountryCode()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Query query = Query.query(criteria);
|
Query query = Query.query(criteria);
|
||||||
@ -150,7 +152,7 @@ public class ActiveVoiceRoomServiceImpl implements ActiveVoiceRoomService {
|
|||||||
}
|
}
|
||||||
// SA_REGIONS 用户只能看到相同国家的房间
|
// SA_REGIONS 用户只能看到相同国家的房间
|
||||||
if (SA_REGIONS.contains(region) && !isAllRegion && StringUtils.isNotBlank(countryCode)) {
|
if (SA_REGIONS.contains(region) && !isAllRegion && StringUtils.isNotBlank(countryCode)) {
|
||||||
criteria.and("countryCode").is(countryCode);
|
criteria.and("countryCode").in(countryCodeAliasSupport.getMatchCodes(countryCode));
|
||||||
}
|
}
|
||||||
Aggregation aggregation = Aggregation.newAggregation(
|
Aggregation aggregation = Aggregation.newAggregation(
|
||||||
// 1. 匹配国家(可选条件)
|
// 1. 匹配国家(可选条件)
|
||||||
@ -238,7 +240,8 @@ public class ActiveVoiceRoomServiceImpl implements ActiveVoiceRoomService {
|
|||||||
Integer limit) {
|
Integer limit) {
|
||||||
|
|
||||||
Query query = Query.query(
|
Query query = Query.query(
|
||||||
Criteria.where("sysOrigin").is(sysOrigin).and("countryCode").is(countryCode)
|
Criteria.where("sysOrigin").is(sysOrigin)
|
||||||
|
.and("countryCode").in(countryCodeAliasSupport.getMatchCodes(countryCode))
|
||||||
);
|
);
|
||||||
|
|
||||||
return mongoTemplate.find(query.limit(limit), ActiveVoiceRoom.class);
|
return mongoTemplate.find(query.limit(limit), ActiveVoiceRoom.class);
|
||||||
@ -261,7 +264,7 @@ public class ActiveVoiceRoomServiceImpl implements ActiveVoiceRoomService {
|
|||||||
public List<ActiveVoiceRoom> listExcludeCountry(AppActiveVoiceRoomQryCmd query) {
|
public List<ActiveVoiceRoom> listExcludeCountry(AppActiveVoiceRoomQryCmd query) {
|
||||||
Criteria criteria = Criteria.where("sysOrigin").is(query.getSysOrigin());
|
Criteria criteria = Criteria.where("sysOrigin").is(query.getSysOrigin());
|
||||||
if (StringUtils.isNotBlank(query.getCountryCode())) {
|
if (StringUtils.isNotBlank(query.getCountryCode())) {
|
||||||
criteria.and("countryCode").nin(query.getCountryCode());
|
criteria.and("countryCode").nin(countryCodeAliasSupport.getMatchCodes(query.getCountryCode()));
|
||||||
criteria.and("region").nin("AR", "TR");
|
criteria.and("region").nin("AR", "TR");
|
||||||
}
|
}
|
||||||
Query mQuery = Query.query(criteria);
|
Query mQuery = Query.query(criteria);
|
||||||
@ -279,7 +282,7 @@ public class ActiveVoiceRoomServiceImpl implements ActiveVoiceRoomService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(query.getCountryCode())) {
|
if (StringUtils.isNotBlank(query.getCountryCode())) {
|
||||||
criteria.and("countryCode").is(query.getCountryCode());
|
criteria.and("countryCode").in(countryCodeAliasSupport.getMatchCodes(query.getCountryCode()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(query.getRoomTag())) {
|
if (StringUtils.isNotBlank(query.getRoomTag())) {
|
||||||
@ -318,7 +321,8 @@ public class ActiveVoiceRoomServiceImpl implements ActiveVoiceRoomService {
|
|||||||
if (Objects.nonNull(query.getRoomId())) {
|
if (Objects.nonNull(query.getRoomId())) {
|
||||||
criteria.and("roomId").is(query.getRoomId());
|
criteria.and("roomId").is(query.getRoomId());
|
||||||
}
|
}
|
||||||
criteria.and("countryCode").nin("SA", "AE", "EG", "MA", "US");
|
criteria.and("countryCode").nin(
|
||||||
|
countryCodeAliasSupport.expandCodes(List.of("SA", "AE", "EG", "MA", "US")));
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(query.getRoomTag())) {
|
if (StringUtils.isNotBlank(query.getRoomTag())) {
|
||||||
criteria.and("roomTag").is(query.getRoomTag());
|
criteria.and("roomTag").is(query.getRoomTag());
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import com.mongodb.BasicDBObject;
|
|||||||
import com.red.circle.common.business.core.ReplaceString;
|
import com.red.circle.common.business.core.ReplaceString;
|
||||||
import com.red.circle.common.business.core.SensitiveWordFilter;
|
import com.red.circle.common.business.core.SensitiveWordFilter;
|
||||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||||
|
import com.red.circle.other.infra.common.sys.CountryCodeAliasSupport;
|
||||||
import com.red.circle.other.infra.database.cache.service.other.RoomManagerCacheService;
|
import com.red.circle.other.infra.database.cache.service.other.RoomManagerCacheService;
|
||||||
import com.red.circle.other.infra.database.mongo.entity.live.RoomCounter;
|
import com.red.circle.other.infra.database.mongo.entity.live.RoomCounter;
|
||||||
import com.red.circle.other.infra.database.mongo.entity.live.RoomProfile;
|
import com.red.circle.other.infra.database.mongo.entity.live.RoomProfile;
|
||||||
@ -57,6 +58,7 @@ public class RoomProfileManagerServiceImpl implements RoomProfileManagerService
|
|||||||
private final RedisTemplate<String, String> redisTemplate;
|
private final RedisTemplate<String, String> redisTemplate;
|
||||||
private final ActiveVoiceRoomService activeVoiceRoomService;
|
private final ActiveVoiceRoomService activeVoiceRoomService;
|
||||||
private final RoomManagerCacheService roomManagerCacheService;
|
private final RoomManagerCacheService roomManagerCacheService;
|
||||||
|
private final CountryCodeAliasSupport countryCodeAliasSupport;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redis缓存Key前缀
|
* Redis缓存Key前缀
|
||||||
@ -265,7 +267,7 @@ public class RoomProfileManagerServiceImpl implements RoomProfileManagerService
|
|||||||
Criteria criteria = Criteria.where("sysOrigin").in(sysOrigin)
|
Criteria criteria = Criteria.where("sysOrigin").in(sysOrigin)
|
||||||
.and("del").is(Boolean.FALSE);
|
.and("del").is(Boolean.FALSE);
|
||||||
if (StringUtils.isNotBlank(countryCode)) {
|
if (StringUtils.isNotBlank(countryCode)) {
|
||||||
criteria.and("countryCode").is(countryCode);
|
criteria.and("countryCode").in(countryCodeAliasSupport.getMatchCodes(countryCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CollectionUtils.isNotEmpty(excludeIds)) {
|
if (CollectionUtils.isNotEmpty(excludeIds)) {
|
||||||
@ -284,7 +286,7 @@ public class RoomProfileManagerServiceImpl implements RoomProfileManagerService
|
|||||||
|
|
||||||
Criteria criteria = Criteria.where("sysOrigin").in(sysOrigin);
|
Criteria criteria = Criteria.where("sysOrigin").in(sysOrigin);
|
||||||
if (CollectionUtils.isNotEmpty(countryCodes)) {
|
if (CollectionUtils.isNotEmpty(countryCodes)) {
|
||||||
criteria.and("countryCode").nin(countryCodes);
|
criteria.and("countryCode").nin(countryCodeAliasSupport.expandCodes(countryCodes));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CollectionUtils.isNotEmpty(excludeIds)) {
|
if (CollectionUtils.isNotEmpty(excludeIds)) {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package com.red.circle.other.infra.database.mongo.service.team.team.impl;
|
package com.red.circle.other.infra.database.mongo.service.team.team.impl;
|
||||||
|
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
import com.red.circle.other.infra.common.sys.CountryCodeAliasSupport;
|
||||||
import com.red.circle.other.infra.database.mongo.dto.team.TeamPolicy;
|
import com.red.circle.other.infra.database.mongo.dto.team.TeamPolicy;
|
||||||
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamPolicyManager;
|
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamPolicyManager;
|
||||||
import com.red.circle.other.infra.database.mongo.service.team.team.TeamPolicyManagerService;
|
import com.red.circle.other.infra.database.mongo.service.team.team.TeamPolicyManagerService;
|
||||||
@ -28,6 +29,7 @@ import java.util.stream.Collectors;
|
|||||||
public class TeamPolicyManagerServiceImpl implements TeamPolicyManagerService {
|
public class TeamPolicyManagerServiceImpl implements TeamPolicyManagerService {
|
||||||
|
|
||||||
private final MongoTemplate mongoTemplate;
|
private final MongoTemplate mongoTemplate;
|
||||||
|
private final CountryCodeAliasSupport countryCodeAliasSupport;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TeamPolicyManager> listSysOriginRegion(String sysOrigin, String region) {
|
public List<TeamPolicyManager> listSysOriginRegion(String sysOrigin, String region) {
|
||||||
@ -58,7 +60,7 @@ public class TeamPolicyManagerServiceImpl implements TeamPolicyManagerService {
|
|||||||
criteria.and("policyType").ne(TeamPolicyTypeEnum.SALARY_DIAMOND.name());
|
criteria.and("policyType").ne(TeamPolicyTypeEnum.SALARY_DIAMOND.name());
|
||||||
}
|
}
|
||||||
if (StringUtils.isNotBlank(countryCode)) {
|
if (StringUtils.isNotBlank(countryCode)) {
|
||||||
criteria.and("countryCode").is(countryCode);
|
criteria.and("countryCode").in(countryCodeAliasSupport.getMatchCodes(countryCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
return mongoTemplate.find( Query.query(criteria).with(Sort.by(Sort.Order.desc("createTime"))), TeamPolicyManager.class);
|
return mongoTemplate.find( Query.query(criteria).with(Sort.by(Sort.Order.desc("createTime"))), TeamPolicyManager.class);
|
||||||
@ -97,7 +99,7 @@ public class TeamPolicyManagerServiceImpl implements TeamPolicyManagerService {
|
|||||||
criteria.and("policyType").ne(TeamPolicyTypeEnum.SALARY_DIAMOND.name());
|
criteria.and("policyType").ne(TeamPolicyTypeEnum.SALARY_DIAMOND.name());
|
||||||
}
|
}
|
||||||
if (StringUtils.isNotBlank(countryCode)) {
|
if (StringUtils.isNotBlank(countryCode)) {
|
||||||
criteria.and("countryCode").is(countryCode);
|
criteria.and("countryCode").in(countryCodeAliasSupport.getMatchCodes(countryCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
return mongoTemplate.findOne(Query.query(criteria), TeamPolicyManager.class);
|
return mongoTemplate.findOne(Query.query(criteria), TeamPolicyManager.class);
|
||||||
|
|||||||
@ -64,6 +64,12 @@ public class SysCountryCode extends TimestampBaseEntity {
|
|||||||
@TableField("alias_name")
|
@TableField("alias_name")
|
||||||
private String aliasName;
|
private String aliasName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国家码别名集合(JSON数组).
|
||||||
|
*/
|
||||||
|
@TableField("alias_codes")
|
||||||
|
private String aliasCodes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 代码分配情况.
|
* 代码分配情况.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
package com.red.circle.other.infra.database.rds.service.sys.impl;
|
package com.red.circle.other.infra.database.rds.service.sys.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.red.circle.framework.dto.PageResult;
|
import com.red.circle.framework.dto.PageResult;
|
||||||
import com.red.circle.framework.mybatis.constant.PageConstant;
|
import com.red.circle.framework.mybatis.constant.PageConstant;
|
||||||
import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl;
|
import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl;
|
||||||
|
import com.red.circle.other.infra.common.sys.CountryCodeAliasSupport;
|
||||||
import com.red.circle.other.infra.database.rds.dao.sys.BannerConfigDAO;
|
import com.red.circle.other.infra.database.rds.dao.sys.BannerConfigDAO;
|
||||||
import com.red.circle.other.infra.database.rds.entity.sys.BannerConfig;
|
import com.red.circle.other.infra.database.rds.entity.sys.BannerConfig;
|
||||||
import com.red.circle.other.infra.database.rds.service.sys.BannerConfigService;
|
import com.red.circle.other.infra.database.rds.service.sys.BannerConfigService;
|
||||||
@ -11,9 +13,11 @@ import com.red.circle.tool.core.collection.CollectionUtils;
|
|||||||
import com.red.circle.tool.core.date.TimestampUtils;
|
import com.red.circle.tool.core.date.TimestampUtils;
|
||||||
import com.red.circle.tool.core.text.StringUtils;
|
import com.red.circle.tool.core.text.StringUtils;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Arrays;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,9 +29,12 @@ import org.springframework.stereotype.Service;
|
|||||||
* @since 2021-01-26
|
* @since 2021-01-26
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class BannerConfigServiceImpl extends
|
public class BannerConfigServiceImpl extends
|
||||||
BaseServiceImpl<BannerConfigDAO, BannerConfig> implements BannerConfigService {
|
BaseServiceImpl<BannerConfigDAO, BannerConfig> implements BannerConfigService {
|
||||||
|
|
||||||
|
private final CountryCodeAliasSupport countryCodeAliasSupport;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<BannerConfig> listEffective(String sysOrigin, String platform, String countryCode, List<String> types) {
|
public List<BannerConfig> listEffective(String sysOrigin, String platform, String countryCode, List<String> types) {
|
||||||
return query()
|
return query()
|
||||||
@ -37,7 +44,7 @@ public class BannerConfigServiceImpl extends
|
|||||||
wrapper.in(BannerConfig::getPlatform, "", platform)
|
wrapper.in(BannerConfig::getPlatform, "", platform)
|
||||||
)
|
)
|
||||||
.and(StringUtils.isNotBlank(countryCode), wrapper ->
|
.and(StringUtils.isNotBlank(countryCode), wrapper ->
|
||||||
wrapper.apply("(country_code = '' OR FIND_IN_SET({0}, country_code))", countryCode)
|
applyCountryCodeFilter(wrapper, countryCode)
|
||||||
)
|
)
|
||||||
.gt(BannerConfig::getExpiredTime, LocalDateTime.now())
|
.gt(BannerConfig::getExpiredTime, LocalDateTime.now())
|
||||||
.eq(BannerConfig::getShowcase, Boolean.TRUE)
|
.eq(BannerConfig::getShowcase, Boolean.TRUE)
|
||||||
@ -53,7 +60,7 @@ public class BannerConfigServiceImpl extends
|
|||||||
wrapper.in(BannerConfig::getPlatform, "", query.getPlatform())
|
wrapper.in(BannerConfig::getPlatform, "", query.getPlatform())
|
||||||
)
|
)
|
||||||
.and(StringUtils.isNotBlank(query.getCountryCode()), wrapper ->
|
.and(StringUtils.isNotBlank(query.getCountryCode()), wrapper ->
|
||||||
wrapper.apply("(country_code = '' OR FIND_IN_SET({0}, country_code))", query.getCountryCode())
|
applyCountryCodeFilter(wrapper, query.getCountryCode())
|
||||||
)
|
)
|
||||||
.eq(Objects.equals(query.getShowcase(), 1), BannerConfig::getShowcase, Boolean.TRUE)
|
.eq(Objects.equals(query.getShowcase(), 1), BannerConfig::getShowcase, Boolean.TRUE)
|
||||||
.gt(Objects.equals(query.getShowcase(), 1), BannerConfig::getExpiredTime, TimestampUtils.now())
|
.gt(Objects.equals(query.getShowcase(), 1), BannerConfig::getExpiredTime, TimestampUtils.now())
|
||||||
@ -87,4 +94,17 @@ public class BannerConfigServiceImpl extends
|
|||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void applyCountryCodeFilter(LambdaQueryWrapper<BannerConfig> wrapper, String countryCode) {
|
||||||
|
Set<String> countryCodes = countryCodeAliasSupport.getMatchCodes(countryCode);
|
||||||
|
List<String> aliasList = new ArrayList<>(countryCodes);
|
||||||
|
StringBuilder sql = new StringBuilder("(country_code = ''");
|
||||||
|
Object[] params = new Object[aliasList.size()];
|
||||||
|
for (int i = 0; i < aliasList.size(); i++) {
|
||||||
|
sql.append(" OR FIND_IN_SET({").append(i).append("}, country_code)");
|
||||||
|
params[i] = aliasList.get(i);
|
||||||
|
}
|
||||||
|
sql.append(")");
|
||||||
|
wrapper.apply(sql.toString(), params);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package com.red.circle.other.infra.database.rds.service.sys.impl;
|
package com.red.circle.other.infra.database.rds.service.sys.impl;
|
||||||
|
|
||||||
|
import com.red.circle.common.business.core.util.CountryCodeAliasUtils;
|
||||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||||
import com.red.circle.framework.core.response.CommonErrorCode;
|
import com.red.circle.framework.core.response.CommonErrorCode;
|
||||||
import com.red.circle.framework.dto.PageResult;
|
import com.red.circle.framework.dto.PageResult;
|
||||||
@ -40,12 +41,31 @@ public class SysCountryCodeServiceImpl extends
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String normalizedCode = CountryCodeAliasUtils.normalize(code);
|
||||||
|
SysCountryCode countryCode = getByExactCode(normalizedCode);
|
||||||
|
if (Objects.nonNull(countryCode)) {
|
||||||
|
return countryCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return query().list().stream()
|
||||||
|
.filter(item -> CountryCodeAliasUtils
|
||||||
|
.buildMatchCodes(item.getAlphaTwo(), item.getAlphaThree(),
|
||||||
|
CountryCodeAliasUtils.parseAliasCodes(item.getAliasCodes()))
|
||||||
|
.contains(normalizedCode))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SysCountryCode getByExactCode(String code) {
|
||||||
|
if (StringUtils.isBlank(code)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
int len = code.length();
|
int len = code.length();
|
||||||
boolean isTwo = Objects.equals(len, NumConstant.TWO);
|
boolean isTwo = Objects.equals(len, NumConstant.TWO);
|
||||||
String upperCaseCode = code.toUpperCase();
|
|
||||||
return query()
|
return query()
|
||||||
.eq(isTwo, SysCountryCode::getAlphaTwo, upperCaseCode)
|
.eq(isTwo, SysCountryCode::getAlphaTwo, code)
|
||||||
.eq(!isTwo, SysCountryCode::getAlphaThree, upperCaseCode)
|
.eq(!isTwo, SysCountryCode::getAlphaThree, code)
|
||||||
.last(PageConstant.LIMIT_ONE)
|
.last(PageConstant.LIMIT_ONE)
|
||||||
.getOne();
|
.getOne();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import com.red.circle.other.domain.gateway.user.UserProfileGateway;
|
|||||||
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
|
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
|
||||||
import com.red.circle.other.domain.model.user.UserProfile;
|
import com.red.circle.other.domain.model.user.UserProfile;
|
||||||
import com.red.circle.other.domain.model.user.ability.RegionConfig;
|
import com.red.circle.other.domain.model.user.ability.RegionConfig;
|
||||||
|
import com.red.circle.other.infra.common.sys.CountryCodeAliasSupport;
|
||||||
import com.red.circle.other.infra.convertor.user.UserRegionInfraConvertor;
|
import com.red.circle.other.infra.convertor.user.UserRegionInfraConvertor;
|
||||||
import com.red.circle.other.infra.database.cache.service.user.SysRegionCacheService;
|
import com.red.circle.other.infra.database.cache.service.user.SysRegionCacheService;
|
||||||
import com.red.circle.other.infra.database.cache.service.user.UserRegionCacheService;
|
import com.red.circle.other.infra.database.cache.service.user.UserRegionCacheService;
|
||||||
@ -54,6 +55,7 @@ public class UserRegionGatewayImpl implements UserRegionGateway {
|
|||||||
private final UserRegionInfraConvertor userRegionInfraConvertor;
|
private final UserRegionInfraConvertor userRegionInfraConvertor;
|
||||||
private final SysRegionAssistConfigService sysRegionAssistConfigService;
|
private final SysRegionAssistConfigService sysRegionAssistConfigService;
|
||||||
private final UserRegionCacheService userRegionCacheService;
|
private final UserRegionCacheService userRegionCacheService;
|
||||||
|
private final CountryCodeAliasSupport countryCodeAliasSupport;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* key=用户id, value=区域code 获取一组区域code.
|
* key=用户id, value=区域code 获取一组区域code.
|
||||||
@ -185,9 +187,9 @@ public class UserRegionGatewayImpl implements UserRegionGateway {
|
|||||||
// 2.1 国家匹配
|
// 2.1 国家匹配
|
||||||
if (StringUtils.isNotBlank(userProfile.getCountryCode())) {
|
if (StringUtils.isNotBlank(userProfile.getCountryCode())) {
|
||||||
SysRegionConfig regionConfig = configs.stream()
|
SysRegionConfig regionConfig = configs.stream()
|
||||||
.filter(region -> StringUtils.containsIgnoreCase(region.getCountryCodes(),
|
.filter(region -> countryCodeAliasSupport.containsCode(region.getCountryCodes(),
|
||||||
userProfile.getCountryCode())
|
userProfile.getCountryCode()))
|
||||||
).findFirst().orElse(null);
|
.findFirst().orElse(null);
|
||||||
UserRegionDTO userRegion = createUserRegionDTO(userProfile, regionConfig);
|
UserRegionDTO userRegion = createUserRegionDTO(userProfile, regionConfig);
|
||||||
if (Objects.nonNull(userRegion)) {
|
if (Objects.nonNull(userRegion)) {
|
||||||
userRegions.add(userRegion);
|
userRegions.add(userRegion);
|
||||||
@ -907,8 +909,8 @@ public class UserRegionGatewayImpl implements UserRegionGateway {
|
|||||||
SysRegionConfig sysRegionConfig = configs.stream()
|
SysRegionConfig sysRegionConfig = configs.stream()
|
||||||
.filter(region -> StringUtils.isNotBlank(region.getCountryCodes())
|
.filter(region -> StringUtils.isNotBlank(region.getCountryCodes())
|
||||||
&& StringUtils.isNotBlank(userProfile.getCountryCode())
|
&& StringUtils.isNotBlank(userProfile.getCountryCode())
|
||||||
&& region.getCountryCodes().toLowerCase()
|
&& countryCodeAliasSupport.containsCode(region.getCountryCodes(),
|
||||||
.contains(userProfile.getCountryCode().toLowerCase())).findFirst()
|
userProfile.getCountryCode())).findFirst()
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
|
|
||||||
if (Objects.nonNull(sysRegionConfig)) {
|
if (Objects.nonNull(sysRegionConfig)) {
|
||||||
|
|||||||
64
sql/20260420_mifapay_order_mysql.sql
Normal file
64
sql/20260420_mifapay_order_mysql.sql
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
SET @table_schema = DATABASE();
|
||||||
|
|
||||||
|
SET @ddl = IF(
|
||||||
|
EXISTS(
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = @table_schema
|
||||||
|
AND TABLE_NAME = 'order_user_purchase_pay'
|
||||||
|
AND COLUMN_NAME = 'receipt_type'
|
||||||
|
),
|
||||||
|
'SELECT 1',
|
||||||
|
"ALTER TABLE `order_user_purchase_pay` ADD COLUMN `receipt_type` varchar(32) NOT NULL DEFAULT 'PAYMENT' COMMENT '单据类型 PAYMENT/RECEIPT' AFTER `reference_id`"
|
||||||
|
);
|
||||||
|
PREPARE stmt FROM @ddl;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
SET @ddl = IF(
|
||||||
|
EXISTS(
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = @table_schema
|
||||||
|
AND TABLE_NAME = 'order_user_purchase_pay'
|
||||||
|
AND COLUMN_NAME = 'product_descriptor'
|
||||||
|
),
|
||||||
|
'SELECT 1',
|
||||||
|
"ALTER TABLE `order_user_purchase_pay` ADD COLUMN `product_descriptor` varchar(255) NOT NULL DEFAULT '' COMMENT '商品描述' AFTER `product_content`"
|
||||||
|
);
|
||||||
|
PREPARE stmt FROM @ddl;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
SET @ddl = IF(
|
||||||
|
EXISTS(
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = @table_schema
|
||||||
|
AND TABLE_NAME = 'order_user_purchase_pay'
|
||||||
|
AND COLUMN_NAME = 'reason'
|
||||||
|
),
|
||||||
|
'SELECT 1',
|
||||||
|
"ALTER TABLE `order_user_purchase_pay` ADD COLUMN `reason` varchar(255) NOT NULL DEFAULT '' COMMENT '失败或挂起原因' AFTER `pay_status`"
|
||||||
|
);
|
||||||
|
PREPARE stmt FROM @ddl;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
UPDATE `order_user_purchase_pay`
|
||||||
|
SET `receipt_type` = 'PAYMENT'
|
||||||
|
WHERE `receipt_type` = '';
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `order_user_purchase_pay_notice` (
|
||||||
|
`id` bigint NOT NULL COMMENT '主键ID',
|
||||||
|
`purchase_pay_id` bigint NOT NULL COMMENT '支付预订单ID',
|
||||||
|
`event_id` varchar(128) NOT NULL DEFAULT '' COMMENT '事件标识',
|
||||||
|
`notice_type` varchar(64) NOT NULL DEFAULT '' COMMENT '通知类型',
|
||||||
|
`notice_data` longtext COMMENT '通知内容(JSON)',
|
||||||
|
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
`create_user` bigint DEFAULT NULL COMMENT '创建人',
|
||||||
|
`update_user` bigint DEFAULT NULL COMMENT '更新人',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_purchase_pay_notice_order` (`purchase_pay_id`, `id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Web支付通知明细';
|
||||||
6
sql/20260420_sys_country_code_alias_codes.sql
Normal file
6
sql/20260420_sys_country_code_alias_codes.sql
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
ALTER TABLE `sys_country_code`
|
||||||
|
ADD COLUMN `alias_codes` varchar(255) NOT NULL DEFAULT '' COMMENT '国家code别名集合(JSON数组)' AFTER `alias_name`;
|
||||||
|
|
||||||
|
UPDATE `sys_country_code`
|
||||||
|
SET `alias_codes` = '["SA","KSA"]'
|
||||||
|
WHERE `alpha_two` = 'SA' OR `alpha_three` = 'KSA';
|
||||||
Loading…
x
Reference in New Issue
Block a user