|
@@ -1,14 +1,18 @@
|
|
|
package com.etotem.cfc.service.impl;
|
|
package com.etotem.cfc.service.impl;
|
|
|
|
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
|
|
+import com.etotem.cfc.config.ConfigService;
|
|
|
|
|
+import com.etotem.cfc.constant.CfConfigKeys;
|
|
|
import com.etotem.cfc.dto.CfEarnResult;
|
|
import com.etotem.cfc.dto.CfEarnResult;
|
|
|
import com.etotem.cfc.entity.*;
|
|
import com.etotem.cfc.entity.*;
|
|
|
import com.etotem.cfc.mapper.*;
|
|
import com.etotem.cfc.mapper.*;
|
|
|
import com.etotem.cfc.service.CfGrowthPathwayEarnService;
|
|
import com.etotem.cfc.service.CfGrowthPathwayEarnService;
|
|
|
|
|
+import com.etotem.cfc.service.CfSpendDispatchService;
|
|
|
import com.etotem.cfc.service.PurchaseService;
|
|
import com.etotem.cfc.service.PurchaseService;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
import javax.annotation.Resource;
|
|
|
import java.util.*;
|
|
import java.util.*;
|
|
@@ -21,6 +25,10 @@ public class PurchaseServiceImpl implements PurchaseService {
|
|
|
@Autowired private FamilyMembershipMapper membershipMapper;
|
|
@Autowired private FamilyMembershipMapper membershipMapper;
|
|
|
@Autowired private FamilyMemberMapper memberMapper;
|
|
@Autowired private FamilyMemberMapper memberMapper;
|
|
|
@Resource private CfGrowthPathwayEarnService cfGrowthPathwayEarnService;
|
|
@Resource private CfGrowthPathwayEarnService cfGrowthPathwayEarnService;
|
|
|
|
|
+ /** F-5 消费侧:会员续费 CF 值抵扣改投统一账本 cf_balance(支付人 member 维度) */
|
|
|
|
|
+ @Resource private CfSpendDispatchService cfSpendDispatchService;
|
|
|
|
|
+ /** F-5 消费侧数值/开关读 L2 service_config(不写死业务常量) */
|
|
|
|
|
+ @Resource private ConfigService configService;
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public Map<String, Object> checkPurchase(Long userId) {
|
|
public Map<String, Object> checkPurchase(Long userId) {
|
|
@@ -150,44 +158,55 @@ public class PurchaseServiceImpl implements PurchaseService {
|
|
|
@Override
|
|
@Override
|
|
|
public Map<String, Object> getRenewalInfo(Long userId) {
|
|
public Map<String, Object> getRenewalInfo(Long userId) {
|
|
|
Map<String, Object> result = new HashMap<>();
|
|
Map<String, Object> result = new HashMap<>();
|
|
|
-
|
|
|
|
|
- LambdaQueryWrapper<FamilyMember> qw = new LambdaQueryWrapper<>();
|
|
|
|
|
- qw.select(FamilyMember::getSystemPoints, FamilyMember::getFamilyId)
|
|
|
|
|
- .eq(FamilyMember::getUserId, userId)
|
|
|
|
|
- .last("LIMIT 1");
|
|
|
|
|
- FamilyMember member = memberMapper.selectOne(qw);
|
|
|
|
|
-
|
|
|
|
|
- int cfBalance = member != null && member.getSystemPoints() != null ? member.getSystemPoints() : 0;
|
|
|
|
|
- int discount = Math.min(cfBalance, 19900);
|
|
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // F-5:续费可用余额改读统一账本 cf_balance(个人维度),不再读 family_members.system_points
|
|
|
|
|
+ int cfBalance = cfSpendDispatchService.getAvailableForUser(userId);
|
|
|
|
|
+ int maxDeduct = configService.getIntConfig(CfConfigKeys.SPEND_MEMBERSHIP_MAX_DEDUCT, 19900);
|
|
|
|
|
+ int price = configService.getIntConfig(CfConfigKeys.SPEND_MEMBERSHIP_PRICE_CENT, 199900);
|
|
|
|
|
+ int discount = Math.min(cfBalance, maxDeduct);
|
|
|
|
|
+
|
|
|
result.put("success", true);
|
|
result.put("success", true);
|
|
|
result.put("cfBalance", cfBalance);
|
|
result.put("cfBalance", cfBalance);
|
|
|
result.put("discount", discount);
|
|
result.put("discount", discount);
|
|
|
- result.put("payAmount", 199900 - discount);
|
|
|
|
|
- result.put("discountPercent", cfBalance >= 19900 ? 100 : Math.round((double)discount / 19900 * 100));
|
|
|
|
|
-
|
|
|
|
|
|
|
+ result.put("payAmount", price - discount);
|
|
|
|
|
+ result.put("discountPercent", cfBalance >= maxDeduct ? 100 : Math.round((double) discount / maxDeduct * 100));
|
|
|
|
|
+
|
|
|
return result;
|
|
return result;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public Map<String, Object> processRenewal(Long userId, Long familyId, Integer amount) {
|
|
public Map<String, Object> processRenewal(Long userId, Long familyId, Integer amount) {
|
|
|
|
|
+ return processRenewal(userId, familyId, amount, null);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 处理续费(真实支付 + 可选 CF 值抵扣)。
|
|
|
|
|
+ *
|
|
|
|
|
+ * <p>F-5:CF 抵扣改投统一账本 {@code cf_balance}(支付人 member 维度),幂等 refId = 续费订单 ID。
|
|
|
|
|
+ * 抵扣上限取 {@code service_config.cf.spend.membership.max_deduct},余额不足由账本抛业务异常并回滚整单。</p>
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param cfUsed 本次使用的 CF 值数量(可为空/0 = 不使用抵扣)
|
|
|
|
|
+ */
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public Map<String, Object> processRenewal(Long userId, Long familyId, Integer amount, Integer cfUsed) {
|
|
|
Map<String, Object> result = new HashMap<>();
|
|
Map<String, Object> result = new HashMap<>();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
LambdaQueryWrapper<PurchaseOrder> qw = new LambdaQueryWrapper<>();
|
|
LambdaQueryWrapper<PurchaseOrder> qw = new LambdaQueryWrapper<>();
|
|
|
qw.eq(PurchaseOrder::getUserId, userId)
|
|
qw.eq(PurchaseOrder::getUserId, userId)
|
|
|
.eq(PurchaseOrder::getStatus, "paid")
|
|
.eq(PurchaseOrder::getStatus, "paid")
|
|
|
.last("LIMIT 1");
|
|
.last("LIMIT 1");
|
|
|
PurchaseOrder existingOrder = orderMapper.selectOne(qw);
|
|
PurchaseOrder existingOrder = orderMapper.selectOne(qw);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (existingOrder == null) {
|
|
if (existingOrder == null) {
|
|
|
result.put("success", false);
|
|
result.put("success", false);
|
|
|
result.put("message", "无有效购买记录");
|
|
result.put("message", "无有效购买记录");
|
|
|
return result;
|
|
return result;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
existingOrder.setIsEarlyRenewal(1);
|
|
existingOrder.setIsEarlyRenewal(1);
|
|
|
orderMapper.updateById(existingOrder);
|
|
orderMapper.updateById(existingOrder);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
String orderNo = "HR" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 6).toUpperCase();
|
|
String orderNo = "HR" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 6).toUpperCase();
|
|
|
PurchaseOrder renewalOrder = new PurchaseOrder();
|
|
PurchaseOrder renewalOrder = new PurchaseOrder();
|
|
|
renewalOrder.setOrderNo(orderNo);
|
|
renewalOrder.setOrderNo(orderNo);
|
|
@@ -201,11 +220,22 @@ public class PurchaseServiceImpl implements PurchaseService {
|
|
|
renewalOrder.setEndDate(java.sql.Timestamp.valueOf(endDate));
|
|
renewalOrder.setEndDate(java.sql.Timestamp.valueOf(endDate));
|
|
|
renewalOrder.setIsEarlyRenewal(1);
|
|
renewalOrder.setIsEarlyRenewal(1);
|
|
|
orderMapper.insert(renewalOrder);
|
|
orderMapper.insert(renewalOrder);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // F-5:CF 值抵扣(先落订单拿到 ID 作为幂等 refId,再扣统一账本)
|
|
|
|
|
+ int usedCf = cfUsed == null ? 0 : cfUsed;
|
|
|
|
|
+ if (usedCf > 0) {
|
|
|
|
|
+ int maxDeduct = configService.getIntConfig(CfConfigKeys.SPEND_MEMBERSHIP_MAX_DEDUCT, 19900);
|
|
|
|
|
+ if (usedCf > maxDeduct) {
|
|
|
|
|
+ throw new IllegalStateException("CF 值抵扣超出上限:本次 " + usedCf + ",上限 " + maxDeduct);
|
|
|
|
|
+ }
|
|
|
|
|
+ cfSpendDispatchService.spendForUser(userId, usedCf, "membership_renewal_cf", renewalOrder.getId(),
|
|
|
|
|
+ "会员续费 CF 值抵扣: " + orderNo);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
LambdaQueryWrapper<FamilyMembership> memQw = new LambdaQueryWrapper<>();
|
|
LambdaQueryWrapper<FamilyMembership> memQw = new LambdaQueryWrapper<>();
|
|
|
memQw.eq(FamilyMembership::getFamilyId, familyId);
|
|
memQw.eq(FamilyMembership::getFamilyId, familyId);
|
|
|
FamilyMembership membership = membershipMapper.selectOne(memQw);
|
|
FamilyMembership membership = membershipMapper.selectOne(memQw);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (membership == null) {
|
|
if (membership == null) {
|
|
|
membership = new FamilyMembership();
|
|
membership = new FamilyMembership();
|
|
|
membership.setFamilyId(familyId);
|
|
membership.setFamilyId(familyId);
|
|
@@ -215,10 +245,15 @@ public class PurchaseServiceImpl implements PurchaseService {
|
|
|
membership.setEndDate(java.sql.Timestamp.valueOf(endDate));
|
|
membership.setEndDate(java.sql.Timestamp.valueOf(endDate));
|
|
|
membership.setPaymentStatus("paid");
|
|
membership.setPaymentStatus("paid");
|
|
|
membership.setOrderNo(orderNo);
|
|
membership.setOrderNo(orderNo);
|
|
|
- membershipMapper.insert(membership);
|
|
|
|
|
-
|
|
|
|
|
|
|
+ if (membership.getId() == null) {
|
|
|
|
|
+ membershipMapper.insert(membership);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ membershipMapper.updateById(membership);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
result.put("success", true);
|
|
result.put("success", true);
|
|
|
result.put("orderNo", orderNo);
|
|
result.put("orderNo", orderNo);
|
|
|
|
|
+ result.put("cfUsed", usedCf);
|
|
|
result.put("membershipValid", true);
|
|
result.put("membershipValid", true);
|
|
|
return result;
|
|
return result;
|
|
|
}
|
|
}
|