修复多处问题
This commit was merged in pull request #46.
This commit is contained in:
+8
@@ -34,6 +34,14 @@ public interface MemberStoredCardRepository extends R2dbcRepository<MemberStored
|
||||
"WHERE member_id = :memberId AND deleted_at IS NULL")
|
||||
Mono<Integer> rechargeBalance(Long memberId, BigDecimal addAmount);
|
||||
|
||||
/**
|
||||
* 储值卡返还 - 增加余额(用于取消预约退款)
|
||||
*/
|
||||
@Modifying
|
||||
@Query("UPDATE member_stored_card SET balance = balance + :addAmount, updated_at = NOW() " +
|
||||
"WHERE member_id = :memberId AND deleted_at IS NULL")
|
||||
Mono<Integer> refundBalance(Long memberId, BigDecimal addAmount);
|
||||
|
||||
/**
|
||||
* 储值卡消费 - 扣减余额
|
||||
*/
|
||||
|
||||
+11
@@ -52,6 +52,17 @@ public interface IMemberStoredCardService {
|
||||
*/
|
||||
Mono<PayResult> payWithStoredCard(Long memberId, String password, BigDecimal amount);
|
||||
|
||||
/**
|
||||
* 储值卡返还(取消预约退款,仅增加余额不修改充值总额)
|
||||
*/
|
||||
Mono<PayResult> refundToStoredCard(Long memberId, String password, BigDecimal amount, long cancelCount);
|
||||
|
||||
/**
|
||||
* 储值卡返还(内部调用,无需密码,含手续费逻辑)
|
||||
* @return 实际返还金额
|
||||
*/
|
||||
Mono<BigDecimal> refundBalanceWithFee(Long memberId, BigDecimal amount, long cancelCount);
|
||||
|
||||
/**
|
||||
* 查询会员的充值记录列表
|
||||
*/
|
||||
|
||||
+5
-5
@@ -213,9 +213,9 @@ public class MemberCardRecordServiceImpl implements IMemberCardRecordService {
|
||||
.filter(record -> record.getMemberCardType() == null ||
|
||||
!record.getMemberCardType().equals("STORED_VALUE_CARD"))
|
||||
.collectList()
|
||||
.map(records -> {
|
||||
.flatMap(records -> {
|
||||
if (records.isEmpty()) {
|
||||
return null;
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
// 优先找临期卡(剩余1-3天)
|
||||
@@ -230,7 +230,7 @@ public class MemberCardRecordServiceImpl implements IMemberCardRecordService {
|
||||
.orElse(null);
|
||||
|
||||
if (expiringCard != null) {
|
||||
return expiringCard;
|
||||
return Mono.just(expiringCard);
|
||||
}
|
||||
|
||||
// 再找普通有效卡(剩余>3天)
|
||||
@@ -245,11 +245,11 @@ public class MemberCardRecordServiceImpl implements IMemberCardRecordService {
|
||||
.orElse(null);
|
||||
|
||||
if (activeCard != null) {
|
||||
return activeCard;
|
||||
return Mono.just(activeCard);
|
||||
}
|
||||
|
||||
// 最后返回第一张卡
|
||||
return records.get(0);
|
||||
return Mono.just(records.get(0));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+87
-1
@@ -5,6 +5,7 @@ import cn.novalon.gym.manage.member.entity.MemberStoredCardRecharge;
|
||||
import cn.novalon.gym.manage.member.repository.MemberStoredCardRechargeRepository;
|
||||
import cn.novalon.gym.manage.member.repository.MemberStoredCardRepository;
|
||||
import cn.novalon.gym.manage.member.service.IMemberStoredCardService;
|
||||
import cn.novalon.gym.manage.sys.core.service.ISysConfigService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -22,12 +23,15 @@ public class MemberStoredCardServiceImpl implements IMemberStoredCardService {
|
||||
|
||||
private final MemberStoredCardRepository memberStoredCardRepository;
|
||||
private final MemberStoredCardRechargeRepository memberStoredCardRechargeRepository;
|
||||
private final ISysConfigService sysConfigService;
|
||||
private final BCryptPasswordEncoder passwordEncoder;
|
||||
|
||||
public MemberStoredCardServiceImpl(MemberStoredCardRepository memberStoredCardRepository,
|
||||
MemberStoredCardRechargeRepository memberStoredCardRechargeRepository) {
|
||||
MemberStoredCardRechargeRepository memberStoredCardRechargeRepository,
|
||||
ISysConfigService sysConfigService) {
|
||||
this.memberStoredCardRepository = memberStoredCardRepository;
|
||||
this.memberStoredCardRechargeRepository = memberStoredCardRechargeRepository;
|
||||
this.sysConfigService = sysConfigService;
|
||||
this.passwordEncoder = new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@@ -137,12 +141,94 @@ public class MemberStoredCardServiceImpl implements IMemberStoredCardService {
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<PayResult> refundToStoredCard(Long memberId, String password, BigDecimal amount, long cancelCount) {
|
||||
// 从系统配置读取免手续费次数阈值,默认3次
|
||||
Mono<Long> freeLimitMono = sysConfigService.getConfigValue("group_course.cancel_free_limit")
|
||||
.map(Long::parseLong)
|
||||
.defaultIfEmpty(3L);
|
||||
|
||||
return freeLimitMono.flatMap(freeLimit ->
|
||||
memberStoredCardRepository.findByMemberId(memberId)
|
||||
.flatMap(card -> {
|
||||
// 验证密码
|
||||
if (card.getPayPassword() == null || card.getPayPassword().isEmpty()) {
|
||||
log.warn("[储值卡退款] 未设置支付密码: memberId={}", memberId);
|
||||
return Mono.just(PayResult.fail("请先设置支付密码"));
|
||||
}
|
||||
|
||||
if (!passwordEncoder.matches(password, card.getPayPassword())) {
|
||||
log.warn("[储值卡退款] 密码错误: memberId={}", memberId);
|
||||
return Mono.just(PayResult.fail("支付密码错误"));
|
||||
}
|
||||
|
||||
// 前N次取消不扣手续费,超出后扣除10%
|
||||
BigDecimal refundAmount = amount;
|
||||
BigDecimal fee = BigDecimal.ZERO;
|
||||
if (cancelCount >= freeLimit) {
|
||||
fee = amount.multiply(new BigDecimal("0.1")).setScale(2, java.math.RoundingMode.HALF_UP);
|
||||
refundAmount = amount.subtract(fee);
|
||||
log.info("[储值卡退款] 第{}次取消,已超出免手续费阈值({}次),扣除10%手续费: 原额={}, 手续费={}, 退款={}",
|
||||
cancelCount + 1, freeLimit, amount, fee, refundAmount);
|
||||
} else {
|
||||
log.info("[储值卡退款] 第{}次取消,在免手续费阈值({}次)内,全额退款: 原额={}",
|
||||
cancelCount + 1, freeLimit, amount);
|
||||
}
|
||||
|
||||
// 执行退款
|
||||
BigDecimal finalRefundAmount = refundAmount;
|
||||
return memberStoredCardRepository.refundBalance(memberId, refundAmount)
|
||||
.flatMap(rows -> {
|
||||
if (rows > 0) {
|
||||
return memberStoredCardRepository.findByMemberId(memberId)
|
||||
.map(updatedCard -> PayResult.success(
|
||||
updatedCard.getBalance() != null ? updatedCard.getBalance() : BigDecimal.ZERO));
|
||||
} else {
|
||||
log.warn("[储值卡退款] 退款失败: memberId={}, amount={}", memberId, finalRefundAmount);
|
||||
return Mono.just(PayResult.fail("退款失败,请稍后重试"));
|
||||
}
|
||||
});
|
||||
})
|
||||
.switchIfEmpty(Mono.defer(() -> {
|
||||
log.warn("[储值卡退款] 储值卡不存在: memberId={}", memberId);
|
||||
return Mono.just(PayResult.fail("储值卡不存在"));
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<MemberStoredCardRecharge> getRechargeRecords(Long memberId, int page, int size) {
|
||||
int offset = (page - 1) * size;
|
||||
return memberStoredCardRechargeRepository.findByMemberId(memberId, size, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<BigDecimal> refundBalanceWithFee(Long memberId, BigDecimal amount, long cancelCount) {
|
||||
return sysConfigService.getConfigValue("group_course.cancel_free_limit")
|
||||
.map(Long::parseLong)
|
||||
.defaultIfEmpty(3L)
|
||||
.flatMap(freeLimit -> {
|
||||
BigDecimal refundAmount;
|
||||
if (cancelCount >= freeLimit) {
|
||||
BigDecimal fee = amount.multiply(new BigDecimal("0.1")).setScale(2, java.math.RoundingMode.HALF_UP);
|
||||
refundAmount = amount.subtract(fee);
|
||||
log.info("[储值卡退款-内部] 第{}次取消,超出免手续费阈值({}次),扣除10%: 原额={}, 手续费={}, 退款={}",
|
||||
cancelCount + 1, freeLimit, amount, fee, refundAmount);
|
||||
} else {
|
||||
refundAmount = amount;
|
||||
log.info("[储值卡退款-内部] 第{}次取消,在免手续费阈值({}次)内,全额退款: {}",
|
||||
cancelCount + 1, freeLimit, amount);
|
||||
}
|
||||
return memberStoredCardRepository.refundBalance(memberId, refundAmount)
|
||||
.flatMap(rows -> {
|
||||
if (rows > 0) {
|
||||
return Mono.just(refundAmount);
|
||||
}
|
||||
return Mono.error(new RuntimeException("储值卡退款失败"));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Long> countRechargeRecords(Long memberId) {
|
||||
return memberStoredCardRechargeRepository.countByMemberIdAndDeletedAtIsNull(memberId);
|
||||
|
||||
Reference in New Issue
Block a user