feat: include MifaPay orders in admin list

This commit is contained in:
z 2026-05-04 00:39:31 +08:00
parent 8f888c7041
commit 1d724dadd9

View File

@ -1,17 +1,38 @@
package com.red.circle.order.inner.service.impl;
import com.red.circle.order.infra.database.mongo.order.InAppPurchaseDetailsService;
import com.red.circle.order.infra.database.mongo.order.entity.assist.CountUserInAppPurchase;
import com.red.circle.order.inner.convertor.InAppPurchaseDetailsInnerConvert;
import com.red.circle.order.inner.model.cmd.inapp.InAppPurchaseDetailsQryCmd;
import com.red.circle.order.inner.model.dto.inapp.CountUserInAppPurchaseDTO;
import com.red.circle.order.inner.model.dto.inapp.InAppPurchaseDetailsDTO;
import com.red.circle.order.inner.service.InAppPurchaseDetailsClientService;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
package com.red.circle.order.inner.service.impl;
import com.red.circle.framework.mybatis.constant.PageConstant;
import com.red.circle.order.app.common.MiFaPayMysqlOrderSupport;
import com.red.circle.order.infra.database.mongo.order.InAppPurchaseDetailsService;
import com.red.circle.order.infra.database.mongo.order.entity.InAppPurchaseDetails;
import com.red.circle.order.infra.database.mongo.order.entity.assist.CountUserInAppPurchase;
import com.red.circle.order.infra.database.mongo.order.entity.assist.InAppPurchaseEventNotice;
import com.red.circle.order.infra.database.rds.entity.order.OrderUserPurchasePay;
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.order.infra.database.rds.service.order.OrderUserPurchasePayService;
import com.red.circle.order.inner.convertor.InAppPurchaseDetailsInnerConvert;
import com.red.circle.order.inner.model.cmd.inapp.InAppPurchaseDetailsQryCmd;
import com.red.circle.order.inner.model.dto.inapp.CountUserInAppPurchaseDTO;
import com.red.circle.order.inner.model.dto.inapp.InAppPurchaseDetailsDTO;
import com.red.circle.order.inner.model.enums.inapp.InAppPurchaseStatus;
import com.red.circle.order.inner.service.InAppPurchaseDetailsClientService;
import com.red.circle.tool.core.text.StringUtils;
import com.red.circle.tool.core.json.JacksonUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
/**
* 内购详情.
@ -20,32 +41,278 @@ import org.springframework.stereotype.Service;
*/
@Service
@RequiredArgsConstructor
public class InAppPurchaseDetailsClientServiceImpl implements InAppPurchaseDetailsClientService {
private final InAppPurchaseDetailsService inAppPurchaseDetailsService;
private final InAppPurchaseDetailsInnerConvert inAppPurchaseDetailsInnerConvert;
@Override
public InAppPurchaseDetailsDTO getById(String id) {
return inAppPurchaseDetailsInnerConvert.toInAppPurchaseDetailsDTO(
inAppPurchaseDetailsService.getById(id)
);
}
@Override
public List<InAppPurchaseDetailsDTO> list(InAppPurchaseDetailsQryCmd qryCmd) {
return inAppPurchaseDetailsInnerConvert.toListInAppPurchaseDetailsDTO(
inAppPurchaseDetailsService.list(
inAppPurchaseDetailsInnerConvert.toInAppPurchaseDetailsQuery(qryCmd))
);
}
@Override
public Map<String, Object> statistics(InAppPurchaseDetailsQryCmd qryCmd) {
return inAppPurchaseDetailsService.statistics(
inAppPurchaseDetailsInnerConvert.toInAppPurchaseDetailsQuery(qryCmd)
);
}
public class InAppPurchaseDetailsClientServiceImpl implements InAppPurchaseDetailsClientService {
private static final String H5_PLATFORM = "H5";
private final InAppPurchaseDetailsService inAppPurchaseDetailsService;
private final InAppPurchaseDetailsInnerConvert inAppPurchaseDetailsInnerConvert;
private final OrderUserPurchasePayService orderUserPurchasePayService;
private final OrderUserPurchasePayNoticeService orderUserPurchasePayNoticeService;
@Override
public InAppPurchaseDetailsDTO getById(String id) {
InAppPurchaseDetails details = inAppPurchaseDetailsService.getById(id);
if (Objects.isNull(details)) {
details = getMiFaPayDetails(id);
}
return inAppPurchaseDetailsInnerConvert.toInAppPurchaseDetailsDTO(
details
);
}
@Override
public List<InAppPurchaseDetailsDTO> list(InAppPurchaseDetailsQryCmd qryCmd) {
List<InAppPurchaseDetailsDTO> mongoOrders = safeList(
inAppPurchaseDetailsInnerConvert.toListInAppPurchaseDetailsDTO(
inAppPurchaseDetailsService.list(
inAppPurchaseDetailsInnerConvert.toInAppPurchaseDetailsQuery(qryCmd))
));
List<InAppPurchaseDetailsDTO> miFaPayOrders = listMiFaPayOrders(qryCmd, true).stream()
.map(order -> inAppPurchaseDetailsInnerConvert.toInAppPurchaseDetailsDTO(
toMiFaPayDetails(order, false)))
.filter(Objects::nonNull)
.collect(Collectors.toList());
return mergePage(mongoOrders, miFaPayOrders, normalizeLimit(qryCmd.getLimit()));
}
@Override
public Map<String, Object> statistics(InAppPurchaseDetailsQryCmd qryCmd) {
Map<String, Object> result = new HashMap<>(inAppPurchaseDetailsService.statistics(
inAppPurchaseDetailsInnerConvert.toInAppPurchaseDetailsQuery(qryCmd)
));
List<OrderUserPurchasePay> miFaPayOrders = listMiFaPayOrders(qryCmd, false);
if (miFaPayOrders.isEmpty()) {
return result;
}
long totalOrderCount = longValue(result.get("totalOrderCount")) + miFaPayOrders.size();
BigDecimal totalAmount = decimalValue(result.get("totalAmount"))
.add(sum(miFaPayOrders, OrderUserPurchasePay::getPaymentAmount));
BigDecimal totalAmountUsd = decimalValue(result.get("totalAmountUsd"))
.add(sum(miFaPayOrders, OrderUserPurchasePay::getComputeUsdAmount));
result.put("totalOrderCount", totalOrderCount);
result.put("totalAmount", totalAmount);
result.put("totalAmountUsd", totalAmountUsd);
result.put("averageOrderAmount", average(totalAmount, totalOrderCount));
return result;
}
private InAppPurchaseDetails getMiFaPayDetails(String id) {
Long mysqlOrderId = MiFaPayMysqlOrderSupport.parseOrderId(id);
if (Objects.isNull(mysqlOrderId)) {
return null;
}
OrderUserPurchasePay order = orderUserPurchasePayService.getById(mysqlOrderId);
if (Objects.isNull(order) || !MiFaPayMysqlOrderSupport.isMiFaPay(order.getFactoryCode())) {
return null;
}
return toMiFaPayDetails(order, true);
}
private List<OrderUserPurchasePay> listMiFaPayOrders(InAppPurchaseDetailsQryCmd qryCmd,
boolean pageable) {
if (!shouldIncludeMiFaPay(qryCmd)) {
return Collections.emptyList();
}
Long id = parseFilterId(qryCmd.getId());
if (StringUtils.isNotBlank(qryCmd.getId()) && Objects.isNull(id)) {
return Collections.emptyList();
}
Long lastId = parseFilterId(qryCmd.getLastId());
if (pageable && StringUtils.isNotBlank(qryCmd.getLastId()) && Objects.isNull(lastId)) {
return Collections.emptyList();
}
String payStatus = toMiFaPayStatus(qryCmd.getStatus());
if (Objects.nonNull(qryCmd.getStatus()) && Objects.isNull(payStatus)) {
return Collections.emptyList();
}
List<String> sysOrigins = parseSysOrigins(qryCmd.getSysOrigins());
var query = orderUserPurchasePayService.query()
.eq(OrderUserPurchasePay::getFactoryCode, MiFaPayMysqlOrderSupport.FACTORY_CODE)
.eq(Objects.nonNull(id), OrderUserPurchasePay::getId, id)
.eq(Objects.nonNull(qryCmd.getReceiptType()), OrderUserPurchasePay::getReceiptType,
Objects.nonNull(qryCmd.getReceiptType()) ? qryCmd.getReceiptType().name() : null)
.eq(StringUtils.isNotBlank(qryCmd.getTrackId()), OrderUserPurchasePay::getReferenceId,
qryCmd.getTrackId())
.in(!sysOrigins.isEmpty(), OrderUserPurchasePay::getSysOrigin, sysOrigins)
.eq(Objects.nonNull(qryCmd.getAcceptUserId()), OrderUserPurchasePay::getUserId,
qryCmd.getAcceptUserId())
.eq(StringUtils.isNotBlank(qryCmd.getOrderId()), OrderUserPurchasePay::getFactoryOrderId,
qryCmd.getOrderId())
.eq(StringUtils.isNotBlank(qryCmd.getEnv()), OrderUserPurchasePay::getEvn,
qryCmd.getEnv())
.eq(StringUtils.isNotBlank(qryCmd.getCountryCode()), OrderUserPurchasePay::getCountryCode,
qryCmd.getCountryCode())
.eq(Objects.nonNull(payStatus), OrderUserPurchasePay::getPayStatus, payStatus)
.ge(Objects.nonNull(qryCmd.getStartTime()), OrderUserPurchasePay::getCreateTime,
toTimestamp(qryCmd.getStartTime()))
.le(Objects.nonNull(qryCmd.getEndTime()), OrderUserPurchasePay::getCreateTime,
toTimestamp(qryCmd.getEndTime()))
.lt(pageable && Objects.nonNull(lastId), OrderUserPurchasePay::getId, lastId)
.orderByDesc(OrderUserPurchasePay::getId);
if (pageable) {
query.last("LIMIT " + normalizeLimit(qryCmd.getLimit()));
}
return query.list();
}
private boolean shouldIncludeMiFaPay(InAppPurchaseDetailsQryCmd qryCmd) {
if (StringUtils.isNotBlank(qryCmd.getFactoryPlatform())
&& !Objects.equals(H5_PLATFORM, qryCmd.getFactoryPlatform())) {
return false;
}
return StringUtils.isBlank(qryCmd.getSubscribeId());
}
private InAppPurchaseDetails toMiFaPayDetails(OrderUserPurchasePay order, boolean withNotices) {
InAppPurchaseDetails details = MiFaPayMysqlOrderSupport.toInAppPurchaseDetails(order)
.setMetadata(miFaPayMetadata(order))
.setPayNotices(withNotices ? miFaPayNotices(order.getId()) : Collections.emptyList())
.setVersion(0);
return details;
}
private Map<String, String> miFaPayMetadata(OrderUserPurchasePay order) {
Map<String, String> metadata = new HashMap<>();
putMetadata(metadata, "payStatus", order.getPayStatus());
putMetadata(metadata, "refundStatus", order.getRefundStatus());
putMetadata(metadata, "paymentChannel", order.getPaymentChannel());
putMetadata(metadata, "factoryChannel", order.getFactoryChannel());
putMetadata(metadata, "payCountryId", order.getPayCountryId());
putMetadata(metadata, "countryId", order.getCountryId());
putMetadata(metadata, "reason", order.getReason());
return metadata;
}
private void putMetadata(Map<String, String> metadata, String key, Object value) {
if (Objects.nonNull(value) && StringUtils.isNotBlank(Objects.toString(value, ""))) {
metadata.put(key, Objects.toString(value));
}
}
private List<InAppPurchaseEventNotice> miFaPayNotices(Long purchasePayId) {
if (Objects.isNull(purchasePayId)) {
return Collections.emptyList();
}
return orderUserPurchasePayNoticeService.query()
.eq(OrderUserPurchasePayNotice::getPurchasePayId, purchasePayId)
.orderByAsc(OrderUserPurchasePayNotice::getId)
.list()
.stream()
.map(notice -> new InAppPurchaseEventNotice()
.setEventId(notice.getEventId())
.setNoticeType(notice.getNoticeType())
.setNoticeData(parseNoticeData(notice.getNoticeData()))
.setCreateTime(notice.getCreateTime()))
.collect(Collectors.toList());
}
private Object parseNoticeData(String noticeData) {
if (StringUtils.isBlank(noticeData)) {
return "";
}
try {
return JacksonUtils.readValue(noticeData, Object.class);
} catch (Exception ignore) {
return noticeData;
}
}
private List<InAppPurchaseDetailsDTO> mergePage(List<InAppPurchaseDetailsDTO> first,
List<InAppPurchaseDetailsDTO> second, int limit) {
List<InAppPurchaseDetailsDTO> result = new ArrayList<>();
result.addAll(first);
result.addAll(second);
return result.stream()
.filter(Objects::nonNull)
.sorted(Comparator.comparing(InAppPurchaseDetailsDTO::getId,
this::compareIdDesc))
.limit(limit)
.collect(Collectors.toList());
}
private int compareIdDesc(String left, String right) {
Long leftId = parseFilterId(left);
Long rightId = parseFilterId(right);
if (Objects.nonNull(leftId) && Objects.nonNull(rightId)) {
return rightId.compareTo(leftId);
}
return Objects.toString(right, "").compareTo(Objects.toString(left, ""));
}
private List<InAppPurchaseDetailsDTO> safeList(List<InAppPurchaseDetailsDTO> list) {
return Objects.isNull(list) ? Collections.emptyList() : list;
}
private List<String> parseSysOrigins(String sysOrigins) {
if (StringUtils.isBlank(sysOrigins)) {
return Collections.emptyList();
}
return Arrays.stream(sysOrigins.split(","))
.map(String::trim)
.filter(StringUtils::isNotBlank)
.collect(Collectors.toList());
}
private Long parseFilterId(String id) {
return MiFaPayMysqlOrderSupport.parseOrderId(id);
}
private String toMiFaPayStatus(InAppPurchaseStatus status) {
if (Objects.isNull(status)) {
return null;
}
if (Objects.equals(InAppPurchaseStatus.CREATE, status)) {
return MiFaPayMysqlOrderSupport.PAY_STATUS_PREPAYMENT;
}
if (Objects.equals(InAppPurchaseStatus.SUCCESS, status)) {
return MiFaPayMysqlOrderSupport.PAY_STATUS_SUCCESSFUL;
}
if (Objects.equals(InAppPurchaseStatus.FAIL, status)) {
return MiFaPayMysqlOrderSupport.PAY_STATUS_FAIL;
}
return null;
}
private Timestamp toTimestamp(Long value) {
return Objects.isNull(value) ? null : new Timestamp(value);
}
private int normalizeLimit(Integer limit) {
return Objects.isNull(limit) || limit <= 0 ? PageConstant.DEFAULT_LIMIT_SIZE : limit;
}
private long longValue(Object value) {
return Objects.isNull(value) ? 0L : Long.parseLong(Objects.toString(value));
}
private BigDecimal decimalValue(Object value) {
return Objects.isNull(value) ? BigDecimal.ZERO : new BigDecimal(Objects.toString(value));
}
private BigDecimal sum(List<OrderUserPurchasePay> orders,
java.util.function.Function<OrderUserPurchasePay, BigDecimal> mapper) {
return orders.stream()
.map(mapper)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
private BigDecimal average(BigDecimal amount, long count) {
if (count <= 0) {
return BigDecimal.ZERO;
}
return amount.divide(BigDecimal.valueOf(count), 8, RoundingMode.HALF_UP).stripTrailingZeros();
}
@Override
public List<CountUserInAppPurchaseDTO> countUserInAppPurchase(String sysOrigin,