首冲奖励
This commit is contained in:
parent
8e37a3d333
commit
e897d635ea
@ -0,0 +1,36 @@
|
|||||||
|
package com.red.circle.mq.business.model.event.pay;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用充值成功事件。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class RechargeSuccessEvent implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private String eventId;
|
||||||
|
private String sysOrigin;
|
||||||
|
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
|
private Long amountCents;
|
||||||
|
|
||||||
|
private String amountUsd;
|
||||||
|
private String currency;
|
||||||
|
private String payPlatform;
|
||||||
|
private String paymentMethod;
|
||||||
|
private String sourceOrderId;
|
||||||
|
private String orderId;
|
||||||
|
private String occurredAt;
|
||||||
|
private Map<String, Object> payload;
|
||||||
|
}
|
||||||
@ -17,13 +17,18 @@ public interface QueueNameConstant {
|
|||||||
*/
|
*/
|
||||||
String LOGIN_REGISTER = "LOGIN_REGISTER";
|
String LOGIN_REGISTER = "LOGIN_REGISTER";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 购买成功
|
* 购买成功
|
||||||
*/
|
*/
|
||||||
String BUY_SUCCESS = "BUY_SUCCESS";
|
String BUY_SUCCESS = "BUY_SUCCESS";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 视频语音房间会话
|
* 通用充值成功。
|
||||||
|
*/
|
||||||
|
String RECHARGE_SUCCESS = "RECHARGE_SUCCESS";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频语音房间会话
|
||||||
*/
|
*/
|
||||||
String LIVE_VOICE_SESSION = "LIVE_VOICE_SESSION";
|
String LIVE_VOICE_SESSION = "LIVE_VOICE_SESSION";
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,12 @@
|
|||||||
|
package com.red.circle.mq.rocket.business.streams;
|
||||||
|
|
||||||
|
import com.red.circle.mq.rocket.business.constant.QueueNameConstant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用充值成功事件。
|
||||||
|
*/
|
||||||
|
public interface RechargeSuccessSink {
|
||||||
|
|
||||||
|
String INPUT = QueueNameConstant.RECHARGE_SUCCESS;
|
||||||
|
String TAG = "recharge_success_v1";
|
||||||
|
}
|
||||||
@ -8,8 +8,9 @@ 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.ResultResponse;
|
import com.red.circle.framework.dto.ResultResponse;
|
||||||
import com.red.circle.framework.web.props.EnvProperties;
|
import com.red.circle.framework.web.props.EnvProperties;
|
||||||
import com.red.circle.mq.business.model.event.pay.BuySuccessEvent;
|
import com.red.circle.mq.business.model.event.pay.BuySuccessEvent;
|
||||||
import com.red.circle.order.app.command.pay.web.strategy.PayEnv;
|
import com.red.circle.order.app.common.task.RechargeSuccessEventPublisher;
|
||||||
|
import com.red.circle.order.app.command.pay.web.strategy.PayEnv;
|
||||||
import com.red.circle.order.domain.gateway.UserRechargeCountGateway;
|
import com.red.circle.order.domain.gateway.UserRechargeCountGateway;
|
||||||
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.InAppPurchaseDetailsService;
|
||||||
@ -76,9 +77,10 @@ public class InAppPurchaseCommon {
|
|||||||
private final OrderPurchaseHistoryService orderPurchaseHistoryService;
|
private final OrderPurchaseHistoryService orderPurchaseHistoryService;
|
||||||
private final InAppPurchaseCollectionReceiptService inAppPurchaseCollectionReceiptService;
|
private final InAppPurchaseCollectionReceiptService inAppPurchaseCollectionReceiptService;
|
||||||
private final UserLevelClient userLevelClient;
|
private final UserLevelClient userLevelClient;
|
||||||
private final PropsActivityClient propsActivityClient;
|
private final PropsActivityClient propsActivityClient;
|
||||||
private final UserOneTimeTaskClient userOneTimeTaskClient;
|
private final UserOneTimeTaskClient userOneTimeTaskClient;
|
||||||
private final UserProfileClient userProfileClient;
|
private final UserProfileClient userProfileClient;
|
||||||
|
private final RechargeSuccessEventPublisher rechargeSuccessEventPublisher;
|
||||||
|
|
||||||
public void inAppPurchaseReceipt(InAppPurchaseDetails order) {
|
public void inAppPurchaseReceipt(InAppPurchaseDetails order) {
|
||||||
inAppPurchaseReceipt(order,
|
inAppPurchaseReceipt(order,
|
||||||
@ -192,13 +194,15 @@ public class InAppPurchaseCommon {
|
|||||||
userSvipClient.incrIntegral(order.getAcceptUserId(),
|
userSvipClient.incrIntegral(order.getAcceptUserId(),
|
||||||
amount.longValue());
|
amount.longValue());
|
||||||
|
|
||||||
// 被邀请人充值邀请人获得佣金
|
// 被邀请人充值邀请人获得佣金
|
||||||
inviteUserClient.processRechargeCommission(amount,
|
inviteUserClient.processRechargeCommission(amount,
|
||||||
order.getSysOrigin(), order.getAcceptUserId());
|
order.getSysOrigin(), order.getAcceptUserId());
|
||||||
|
|
||||||
// 发送首充奖励
|
rechargeSuccessEventPublisher.reportPaymentRecharge(order);
|
||||||
completedFirstCharge(order.getAcceptUserId(), order.getSysOrigin());
|
|
||||||
}
|
// 发送首充奖励
|
||||||
|
completedFirstCharge(order.getAcceptUserId(), order.getSysOrigin());
|
||||||
|
}
|
||||||
|
|
||||||
private void completedFirstCharge(Long userId, String sysOrigin) {
|
private void completedFirstCharge(Long userId, String sysOrigin) {
|
||||||
UserProfileDTO userProfileDTO = userProfileClient.getByUserId(userId).getBody();
|
UserProfileDTO userProfileDTO = userProfileClient.getByUserId(userId).getBody();
|
||||||
|
|||||||
@ -0,0 +1,214 @@
|
|||||||
|
package com.red.circle.order.app.common.task;
|
||||||
|
|
||||||
|
import com.red.circle.component.mq.MessageEvent;
|
||||||
|
import com.red.circle.mq.business.model.event.pay.BuySuccessEvent;
|
||||||
|
import com.red.circle.mq.business.model.event.pay.RechargeSuccessEvent;
|
||||||
|
import com.red.circle.mq.rocket.business.service.MessageSenderService;
|
||||||
|
import com.red.circle.mq.rocket.business.streams.RechargeSuccessSink;
|
||||||
|
import com.red.circle.order.infra.database.mongo.order.entity.InAppPurchaseDetails;
|
||||||
|
import com.red.circle.order.infra.database.mongo.order.entity.assist.InAppPurchaseProduct;
|
||||||
|
import com.red.circle.order.inner.model.enums.PayApplicationCommodityType;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class RechargeSuccessEventPublisher {
|
||||||
|
|
||||||
|
private static final String GOOGLE = "GOOGLE";
|
||||||
|
private static final String APPLE = "APPLE";
|
||||||
|
private static final String THIRD_PARTY = "THIRD_PARTY";
|
||||||
|
private static final String UNKNOWN = "UNKNOWN";
|
||||||
|
|
||||||
|
private final ObjectProvider<MessageSenderService> messageSenderServiceProvider;
|
||||||
|
|
||||||
|
@Value("${recharge.success.mq.enabled:true}")
|
||||||
|
private boolean mqEnabled;
|
||||||
|
|
||||||
|
@Value("${recharge.success.mq.topic:RC_DEFAULT_APP_ORDINARY}")
|
||||||
|
private String mqTopic;
|
||||||
|
|
||||||
|
@Value("${recharge.success.mq.tag:" + RechargeSuccessSink.TAG + "}")
|
||||||
|
private String mqTag;
|
||||||
|
|
||||||
|
public RechargeSuccessEventPublisher(ObjectProvider<MessageSenderService> messageSenderServiceProvider) {
|
||||||
|
this.messageSenderServiceProvider = messageSenderServiceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reportAppPurchaseRecharge(BuySuccessEvent event) {
|
||||||
|
if (Objects.isNull(event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Long userId = event.getAcceptUserId();
|
||||||
|
Long purchaseHistoryId = event.getPurchaseHistoryId();
|
||||||
|
BigDecimal amountUsd = Objects.nonNull(event.getProductConfig())
|
||||||
|
? event.getProductConfig().getUnitPrice()
|
||||||
|
: null;
|
||||||
|
Long amountCents = toCents(amountUsd);
|
||||||
|
if (Objects.isNull(userId) || Objects.isNull(purchaseHistoryId) || !positive(amountCents)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> payload = new HashMap<>();
|
||||||
|
payload.put("payerUserId", event.getUserId());
|
||||||
|
payload.put("acceptUserId", userId);
|
||||||
|
payload.put("purchaseHistoryId", purchaseHistoryId);
|
||||||
|
payload.put("candyQuantity", event.getCandyQuantity());
|
||||||
|
payload.put("platform", event.getPlatform());
|
||||||
|
payload.put("payPlatform", event.getPayPlatform());
|
||||||
|
|
||||||
|
String sourceOrderId = String.valueOf(purchaseHistoryId);
|
||||||
|
String payPlatform = normalizePayPlatform(defaultIfBlank(event.getPayPlatform(), event.getPlatform()));
|
||||||
|
String paymentMethod = classifyPaymentMethod(payPlatform);
|
||||||
|
publish(new RechargeSuccessEvent()
|
||||||
|
.setEventId("RECHARGE_SUCCESS:" + paymentMethod + ":" + sourceOrderId)
|
||||||
|
.setSysOrigin(event.getSysOrigin())
|
||||||
|
.setUserId(userId)
|
||||||
|
.setAmountCents(amountCents)
|
||||||
|
.setAmountUsd(formatAmount(amountUsd))
|
||||||
|
.setCurrency("USD")
|
||||||
|
.setPayPlatform(payPlatform)
|
||||||
|
.setPaymentMethod(paymentMethod)
|
||||||
|
.setSourceOrderId(sourceOrderId)
|
||||||
|
.setOrderId(sourceOrderId)
|
||||||
|
.setOccurredAt(toInstantString(event.getBuyDateTime()))
|
||||||
|
.setPayload(payload));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reportPaymentRecharge(InAppPurchaseDetails order) {
|
||||||
|
if (Objects.isNull(order) || !order.receiptTypeEqPayment()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
InAppPurchaseProduct product = order.firstProduct();
|
||||||
|
if (Objects.isNull(product) || !PayApplicationCommodityType.GOLD.eq(product.getCode())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String payPlatform = normalizePayPlatform(Objects.nonNull(order.getFactory()) ? order.getFactory().getFactoryCode() : "");
|
||||||
|
String paymentMethod = classifyPaymentMethod(payPlatform);
|
||||||
|
|
||||||
|
BigDecimal amountUsd = firstPositive(order.getAmountUsd(), product.getAmountUsd());
|
||||||
|
Long amountCents = toCents(amountUsd);
|
||||||
|
if (Objects.isNull(order.getAcceptUserId()) || isBlank(order.getId()) || !positive(amountCents)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> payload = new HashMap<>();
|
||||||
|
payload.put("trackId", order.getTrackId());
|
||||||
|
payload.put("sourceOrderId", order.getId());
|
||||||
|
payload.put("orderId", order.getOrderId());
|
||||||
|
payload.put("factoryCode", payPlatform);
|
||||||
|
payload.put("factoryChannelCode", Objects.nonNull(order.getFactory()) ? order.getFactory().getFactoryChannelCode() : null);
|
||||||
|
payload.put("platform", Objects.nonNull(order.getFactory()) ? order.getFactory().getPlatform() : null);
|
||||||
|
payload.put("productCode", product.getCode());
|
||||||
|
payload.put("productContent", product.getContent());
|
||||||
|
|
||||||
|
publish(new RechargeSuccessEvent()
|
||||||
|
.setEventId("RECHARGE_SUCCESS:" + paymentMethod + ":" + payPlatform + ":" + order.getId())
|
||||||
|
.setSysOrigin(order.getSysOrigin())
|
||||||
|
.setUserId(order.getAcceptUserId())
|
||||||
|
.setAmountCents(amountCents)
|
||||||
|
.setAmountUsd(formatAmount(amountUsd))
|
||||||
|
.setCurrency(defaultIfBlank(order.getCurrency(), "USD"))
|
||||||
|
.setPayPlatform(payPlatform)
|
||||||
|
.setPaymentMethod(paymentMethod)
|
||||||
|
.setSourceOrderId(order.getId())
|
||||||
|
.setOrderId(defaultIfBlank(order.getOrderId(), order.getId()))
|
||||||
|
.setOccurredAt(firstTime(order.getPurchaseDateMs(), order.getUpdateTime(), order.getCreateTime()))
|
||||||
|
.setPayload(payload));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void publish(RechargeSuccessEvent event) {
|
||||||
|
if (!mqEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
MessageSenderService senderService = messageSenderServiceProvider.getIfAvailable();
|
||||||
|
if (Objects.isNull(senderService)) {
|
||||||
|
log.warn("Recharge success mq sender missing, skip event report. eventId={}", event.getEventId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
senderService.sendEventMessage(MessageEvent.builder()
|
||||||
|
.consumeId(event.getEventId())
|
||||||
|
.topicString(defaultIfBlank(mqTopic, "RC_DEFAULT_APP_ORDINARY"))
|
||||||
|
.tag(defaultIfBlank(mqTag, RechargeSuccessSink.TAG))
|
||||||
|
.body(event)
|
||||||
|
.build());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Recharge success mq report error. eventId={}", event.getEventId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizePayPlatform(String value) {
|
||||||
|
String normalized = Objects.toString(value, "").trim().toUpperCase();
|
||||||
|
return normalized.isEmpty() ? UNKNOWN : normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String classifyPaymentMethod(String payPlatform) {
|
||||||
|
if (Objects.equals(GOOGLE, payPlatform)) {
|
||||||
|
return GOOGLE;
|
||||||
|
}
|
||||||
|
if (Objects.equals(APPLE, payPlatform)) {
|
||||||
|
return APPLE;
|
||||||
|
}
|
||||||
|
if (Objects.equals(UNKNOWN, payPlatform)) {
|
||||||
|
return UNKNOWN;
|
||||||
|
}
|
||||||
|
return THIRD_PARTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long toCents(BigDecimal amount) {
|
||||||
|
if (Objects.isNull(amount) || amount.compareTo(BigDecimal.ZERO) <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return amount.multiply(BigDecimal.valueOf(100)).setScale(0, RoundingMode.HALF_UP).longValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal firstPositive(BigDecimal first, BigDecimal second) {
|
||||||
|
if (Objects.nonNull(first) && first.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
return second;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean positive(Long value) {
|
||||||
|
return Objects.nonNull(value) && value > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toInstantString(Timestamp timestamp) {
|
||||||
|
return Objects.nonNull(timestamp) ? timestamp.toInstant().toString() : Instant.now().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String firstTime(Timestamp first, Timestamp second, Timestamp third) {
|
||||||
|
if (Objects.nonNull(first)) {
|
||||||
|
return first.toInstant().toString();
|
||||||
|
}
|
||||||
|
if (Objects.nonNull(second)) {
|
||||||
|
return second.toInstant().toString();
|
||||||
|
}
|
||||||
|
if (Objects.nonNull(third)) {
|
||||||
|
return third.toInstant().toString();
|
||||||
|
}
|
||||||
|
return Instant.now().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatAmount(BigDecimal amount) {
|
||||||
|
return Objects.isNull(amount) ? null : amount.stripTrailingZeros().toPlainString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String defaultIfBlank(String value, String fallback) {
|
||||||
|
return isBlank(value) ? fallback : value.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBlank(String value) {
|
||||||
|
return Objects.toString(value, "").trim().isEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -17,6 +17,7 @@ import com.red.circle.framework.dto.ResultResponse;
|
|||||||
import com.red.circle.mq.business.model.event.pay.BuySuccessEvent;
|
import com.red.circle.mq.business.model.event.pay.BuySuccessEvent;
|
||||||
import com.red.circle.mq.business.model.event.pay.PurchaseProductEvent;
|
import com.red.circle.mq.business.model.event.pay.PurchaseProductEvent;
|
||||||
import com.red.circle.mq.rocket.business.streams.BuySuccessSink;
|
import com.red.circle.mq.rocket.business.streams.BuySuccessSink;
|
||||||
|
import com.red.circle.order.app.common.task.RechargeSuccessEventPublisher;
|
||||||
import com.red.circle.order.app.common.task.TaskCenterGoClient;
|
import com.red.circle.order.app.common.task.TaskCenterGoClient;
|
||||||
import com.red.circle.other.inner.endpoint.activity.CumulativeRechargeClient;
|
import com.red.circle.other.inner.endpoint.activity.CumulativeRechargeClient;
|
||||||
import com.red.circle.other.inner.endpoint.activity.PropsActivityClient;
|
import com.red.circle.other.inner.endpoint.activity.PropsActivityClient;
|
||||||
@ -71,6 +72,7 @@ public class BuySuccessListener implements MessageListener {
|
|||||||
private final CumulativeRechargeClient cumulativeRechargeClient;
|
private final CumulativeRechargeClient cumulativeRechargeClient;
|
||||||
private final RedisService redisService;
|
private final RedisService redisService;
|
||||||
private final TaskCenterGoClient taskCenterGoClient;
|
private final TaskCenterGoClient taskCenterGoClient;
|
||||||
|
private final RechargeSuccessEventPublisher rechargeSuccessEventPublisher;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Action consume(ConsumerMessage message) {
|
public Action consume(ConsumerMessage message) {
|
||||||
@ -133,6 +135,7 @@ public class BuySuccessListener implements MessageListener {
|
|||||||
eventBody.getPlatform(),
|
eventBody.getPlatform(),
|
||||||
eventBody.getPayPlatform(),
|
eventBody.getPayPlatform(),
|
||||||
Objects.nonNull(eventBody.getBuyDateTime()) ? eventBody.getBuyDateTime().toInstant() : null);
|
Objects.nonNull(eventBody.getBuyDateTime()) ? eventBody.getBuyDateTime().toInstant() : null);
|
||||||
|
rechargeSuccessEventPublisher.reportAppPurchaseRecharge(eventBody);
|
||||||
|
|
||||||
userExpandClient.updatePurchasingToTrue(eventBody.getUserId());
|
userExpandClient.updatePurchasingToTrue(eventBody.getUserId());
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user