新增用户红包手续费字段

This commit is contained in:
tianfeng 2026-01-09 18:27:15 +08:00
parent d2a3c8e6e1
commit cc5fbde032
7 changed files with 47 additions and 13 deletions

View File

@ -5,7 +5,6 @@ import com.red.circle.other.app.convertor.UserRedPacketAppConvertor;
import com.red.circle.other.app.dto.clientobject.UserRedPacketCO; import com.red.circle.other.app.dto.clientobject.UserRedPacketCO;
import com.red.circle.other.app.dto.cmd.SendUserRedPacketCmd; import com.red.circle.other.app.dto.cmd.SendUserRedPacketCmd;
import com.red.circle.other.domain.gateway.UserRedPacketGateway; import com.red.circle.other.domain.gateway.UserRedPacketGateway;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.redpacket.RoomRedPacketType; import com.red.circle.other.domain.redpacket.RoomRedPacketType;
import com.red.circle.other.domain.redpacket.UserRedPacket; import com.red.circle.other.domain.redpacket.UserRedPacket;
import com.red.circle.other.domain.redpacket.UserRedPacketStatus; import com.red.circle.other.domain.redpacket.UserRedPacketStatus;
@ -39,6 +38,11 @@ public class SendUserRedPacketCmdExe {
private final UserRedPacketCacheService userRedPacketCacheService; private final UserRedPacketCacheService userRedPacketCacheService;
private final WalletGoldClient walletGoldClient; private final WalletGoldClient walletGoldClient;
/**
* 手续费比例10%
*/
private static final double HANDLING_FEE_RATE = 0.1;
/** /**
* 执行发用户红包 * 执行发用户红包
*/ */
@ -55,36 +59,44 @@ public class SendUserRedPacketCmdExe {
LocalDateTime expireTime = LocalDateTime.now().plusHours(24); LocalDateTime expireTime = LocalDateTime.now().plusHours(24);
UserRedPacket redPacket = buildRedPacket(cmd, senderUserId, receiverUserId, packetId, expireTime); Long handlingFee = calculateHandlingFee(cmd.getTotalAmount());
UserRedPacket redPacket = buildRedPacket(cmd, senderUserId, receiverUserId, packetId, expireTime, handlingFee);
userRedPacketGateway.save(redPacket); userRedPacketGateway.save(redPacket);
deductUserGold(senderUserId, cmd, packetId); deductUserGold(senderUserId, cmd, packetId, handlingFee);
cacheRedPacketData(redPacket); cacheRedPacketData(redPacket);
log.info("发用户红包成功 senderUserId={} receiverUserId={} packetId={} amount={}",
senderUserId, receiverUserId, packetId, cmd.getTotalAmount());
return UserRedPacketAppConvertor.toCO(redPacket); return UserRedPacketAppConvertor.toCO(redPacket);
} }
/**
* 计算手续费10%
*/
private Long calculateHandlingFee(Long totalAmount) {
return (long) Math.ceil(totalAmount * HANDLING_FEE_RATE);
}
/** /**
* 参数校验 * 参数校验
*/ */
private void validateParams(SendUserRedPacketCmd cmd) { private void validateParams(SendUserRedPacketCmd cmd) {
if (cmd.getTotalAmount() < 100 || cmd.getTotalAmount() > 50000) { if (cmd.getTotalAmount() < 500 || cmd.getTotalAmount() > 250000) {
throw new RuntimeException(OtherErrorCode.RED_PACKET_AMOUNT_ERROR.getMessage()); throw new RuntimeException(OtherErrorCode.RED_PACKET_AMOUNT_ERROR.getMessage());
} }
} }
/** /**
* 扣除用户金币 * 扣除用户金币红包金额 + 手续费
*/ */
private void deductUserGold(Long userId, SendUserRedPacketCmd cmd, String packetId) { private void deductUserGold(Long userId, SendUserRedPacketCmd cmd, String packetId, Long handlingFee) {
Long totalDeduct = cmd.getTotalAmount() + handlingFee;
GoldReceiptCmd build = GoldReceiptCmd.builder() GoldReceiptCmd build = GoldReceiptCmd.builder()
.appExpenditure() .appExpenditure()
.userId(userId) .userId(userId)
.amount(PennyAmount.ofDollar(cmd.getTotalAmount())) .amount(PennyAmount.ofDollar(totalDeduct))
.eventId(packetId) .eventId(packetId)
.sysOrigin(cmd.getReqSysOrigin().getOrigin()) .sysOrigin(cmd.getReqSysOrigin().getOrigin())
.origin(GoldOrigin.USER_RED_PACKET) .origin(GoldOrigin.USER_RED_PACKET)
@ -93,7 +105,7 @@ public class SendUserRedPacketCmdExe {
try { try {
walletGoldClient.changeBalance(build); walletGoldClient.changeBalance(build);
} catch (Exception e) { } catch (Exception e) {
log.error("扣除金币失败 userId={} amount={} packetId={}", userId, cmd.getTotalAmount(), packetId, e); log.error("扣除金币失败 userId={} totalDeduct={} packetId={}", userId, totalDeduct, packetId, e);
ResponseAssert.isTrue(WalletErrorCode.INSUFFICIENT_BALANCE, false); ResponseAssert.isTrue(WalletErrorCode.INSUFFICIENT_BALANCE, false);
} }
} }
@ -102,13 +114,15 @@ public class SendUserRedPacketCmdExe {
* 构建红包对象 * 构建红包对象
*/ */
private UserRedPacket buildRedPacket(SendUserRedPacketCmd cmd, Long senderUserId, private UserRedPacket buildRedPacket(SendUserRedPacketCmd cmd, Long senderUserId,
Long receiverUserId, String packetId, LocalDateTime expireTime) { Long receiverUserId, String packetId, LocalDateTime expireTime,
Long handlingFee) {
return UserRedPacket.builder() return UserRedPacket.builder()
.packetId(packetId) .packetId(packetId)
.senderUserId(senderUserId) .senderUserId(senderUserId)
.receiverUserId(receiverUserId) .receiverUserId(receiverUserId)
.packetType(RoomRedPacketType.FIXED.getCode()) .packetType(RoomRedPacketType.FIXED.getCode())
.totalAmount(cmd.getTotalAmount()) .totalAmount(cmd.getTotalAmount())
.handlingFee(handlingFee)
.expireTime(expireTime) .expireTime(expireTime)
.status(UserRedPacketStatus.PENDING.getCode()) .status(UserRedPacketStatus.PENDING.getCode())
.refundStatus(0) .refundStatus(0)
@ -125,6 +139,7 @@ public class SendUserRedPacketCmdExe {
packetData.put("senderUserId", redPacket.getSenderUserId()); packetData.put("senderUserId", redPacket.getSenderUserId());
packetData.put("receiverUserId", redPacket.getReceiverUserId()); packetData.put("receiverUserId", redPacket.getReceiverUserId());
packetData.put("totalAmount", redPacket.getTotalAmount()); packetData.put("totalAmount", redPacket.getTotalAmount());
packetData.put("handlingFee", redPacket.getHandlingFee());
packetData.put("expireTime", redPacket.getExpireTime().toString()); packetData.put("expireTime", redPacket.getExpireTime().toString());
packetData.put("status", redPacket.getStatus()); packetData.put("status", redPacket.getStatus());

View File

@ -5,7 +5,6 @@ import com.red.circle.other.app.dto.clientobject.SimpleUserInfoCO;
import com.red.circle.other.app.dto.clientobject.UserRedPacketCO; import com.red.circle.other.app.dto.clientobject.UserRedPacketCO;
import com.red.circle.other.domain.redpacket.UserRedPacket; import com.red.circle.other.domain.redpacket.UserRedPacket;
import java.sql.Time;
import java.sql.Timestamp; import java.sql.Timestamp;
/** /**
@ -22,6 +21,7 @@ public class UserRedPacketAppConvertor {
.senderUserId(domain.getSenderUserId()) .senderUserId(domain.getSenderUserId())
.receiverUserId(domain.getReceiverUserId()) .receiverUserId(domain.getReceiverUserId())
.totalAmount(domain.getTotalAmount()) .totalAmount(domain.getTotalAmount())
.handlingFee(domain.getHandlingFee())
.status(domain.getStatus()) .status(domain.getStatus())
.expireTime(domain.getExpireTime() != null ? Timestamp.valueOf(domain.getExpireTime()) : null) .expireTime(domain.getExpireTime() != null ? Timestamp.valueOf(domain.getExpireTime()) : null)
.grabbedAt(domain.getGrabbedAt() != null ? Timestamp.valueOf(domain.getGrabbedAt()) : null) .grabbedAt(domain.getGrabbedAt() != null ? Timestamp.valueOf(domain.getGrabbedAt()) : null)
@ -40,6 +40,7 @@ public class UserRedPacketAppConvertor {
.senderInfo(senderInfo) .senderInfo(senderInfo)
.receiverInfo(receiverInfo) .receiverInfo(receiverInfo)
.totalAmount(domain.getTotalAmount()) .totalAmount(domain.getTotalAmount())
.handlingFee(domain.getHandlingFee())
.status(domain.getStatus()) .status(domain.getStatus())
.expireTime(domain.getExpireTime() != null ? Timestamp.valueOf(domain.getExpireTime()) : null) .expireTime(domain.getExpireTime() != null ? Timestamp.valueOf(domain.getExpireTime()) : null)
.grabbedAt(domain.getGrabbedAt() != null ? Timestamp.valueOf(domain.getGrabbedAt()) : null) .grabbedAt(domain.getGrabbedAt() != null ? Timestamp.valueOf(domain.getGrabbedAt()) : null)

View File

@ -47,6 +47,11 @@ public class UserRedPacketCO {
*/ */
private Long totalAmount; private Long totalAmount;
/**
* 手续费金币10%
*/
private Long handlingFee;
/** /**
* 状态1-待领取 2-已领取 3-已过期 * 状态1-待领取 2-已领取 3-已过期
*/ */

View File

@ -46,6 +46,11 @@ public class UserRedPacket {
*/ */
private Long totalAmount; private Long totalAmount;
/**
* 手续费10%
*/
private Long handlingFee;
/** /**
* 过期时间 * 过期时间
*/ */

View File

@ -19,6 +19,7 @@ public class UserRedPacketConvertor {
.receiverUserId(entity.getReceiverUserId()) .receiverUserId(entity.getReceiverUserId())
.packetType(entity.getPacketType()) .packetType(entity.getPacketType())
.totalAmount(entity.getTotalAmount()) .totalAmount(entity.getTotalAmount())
.handlingFee(entity.getHandlingFee())
.expireTime(entity.getExpireTime()) .expireTime(entity.getExpireTime())
.status(entity.getStatus()) .status(entity.getStatus())
.refundStatus(entity.getRefundStatus()) .refundStatus(entity.getRefundStatus())
@ -39,6 +40,7 @@ public class UserRedPacketConvertor {
entity.setReceiverUserId(domain.getReceiverUserId()); entity.setReceiverUserId(domain.getReceiverUserId());
entity.setPacketType(domain.getPacketType()); entity.setPacketType(domain.getPacketType());
entity.setTotalAmount(domain.getTotalAmount()); entity.setTotalAmount(domain.getTotalAmount());
entity.setHandlingFee(domain.getHandlingFee());
entity.setExpireTime(domain.getExpireTime()); entity.setExpireTime(domain.getExpireTime());
entity.setStatus(domain.getStatus()); entity.setStatus(domain.getStatus());
entity.setRefundStatus(domain.getRefundStatus()); entity.setRefundStatus(domain.getRefundStatus());

View File

@ -45,6 +45,11 @@ public class UserRedPacketEntity {
*/ */
private Long totalAmount; private Long totalAmount;
/**
* 手续费10%
*/
private Long handlingFee;
/** /**
* 过期时间 * 过期时间
*/ */

View File

@ -9,6 +9,7 @@
<result column="receiver_user_id" property="receiverUserId"/> <result column="receiver_user_id" property="receiverUserId"/>
<result column="packet_type" property="packetType"/> <result column="packet_type" property="packetType"/>
<result column="total_amount" property="totalAmount"/> <result column="total_amount" property="totalAmount"/>
<result column="handling_fee" property="handlingFee"/>
<result column="expire_time" property="expireTime"/> <result column="expire_time" property="expireTime"/>
<result column="status" property="status"/> <result column="status" property="status"/>
<result column="refund_status" property="refundStatus"/> <result column="refund_status" property="refundStatus"/>