From abfb425b4f2f95a294a37d3457fb43c8155f55d1 Mon Sep 17 00:00:00 2001 From: liuhuayong <995058772@qq.com> Date: Sat, 27 Jun 2026 10:17:26 +0800 Subject: [PATCH] =?UTF-8?q?feat(edu):=20=E7=BC=B4=E8=B4=B9=E8=AE=A1?= =?UTF-8?q?=E5=88=92=20Service=20=E5=AE=9E=E7=8E=B0-=E7=94=9F=E6=88=90/?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2/=E6=94=B9/=E6=94=B6=E6=AC=BE=E8=81=94?= =?UTF-8?q?=E5=8A=A8/=E4=BD=9C=E5=BA=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/EduPaymentPlanServiceImpl.java | 212 ++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 ruoyi-modules/ruoyi-edu/src/main/java/org/dromara/edu/application/service/contract/impl/EduPaymentPlanServiceImpl.java diff --git a/ruoyi-modules/ruoyi-edu/src/main/java/org/dromara/edu/application/service/contract/impl/EduPaymentPlanServiceImpl.java b/ruoyi-modules/ruoyi-edu/src/main/java/org/dromara/edu/application/service/contract/impl/EduPaymentPlanServiceImpl.java new file mode 100644 index 000000000..6476dda5a --- /dev/null +++ b/ruoyi-modules/ruoyi-edu/src/main/java/org/dromara/edu/application/service/contract/impl/EduPaymentPlanServiceImpl.java @@ -0,0 +1,212 @@ +package org.dromara.edu.application.service.contract.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.RequiredArgsConstructor; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.edu.application.dto.EduPaymentPlanBo; +import org.dromara.edu.application.dto.PaymentReceiveBo; +import org.dromara.edu.application.service.contract.IEduPaymentPlanService; +import org.dromara.edu.common.constant.EduConstants; +import org.dromara.edu.common.exception.EduBusinessException; +import org.dromara.edu.domain.model.contract.EduContract; +import org.dromara.edu.domain.model.contract.EduContractLog; +import org.dromara.edu.domain.model.contract.EduContractPaymentPlan; +import org.dromara.edu.infrastructure.persistence.mapper.EduContractLogMapper; +import org.dromara.edu.infrastructure.persistence.mapper.EduContractMapper; +import org.dromara.edu.infrastructure.persistence.mapper.EduContractPaymentPlanMapper; +import org.dromara.edu.interfaces.vo.EduContractPaymentPlanVo; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.temporal.ChronoUnit; +import java.util.Date; +import java.util.List; + +/** + * 合同缴费计划 业务实现 + *
分期合同的应收节点生成 + 收款联动合同账本 + 退费/作废联动作废
+ * + * @author FIGS + */ +@RequiredArgsConstructor +@Service +public class EduPaymentPlanServiceImpl implements IEduPaymentPlanService { + + private final EduContractPaymentPlanMapper paymentPlanMapper; + private final EduContractMapper contractMapper; + private final EduContractLogMapper contractLogMapper; + + /** + * 生成缴费计划(幂等: 先删后建) + *金额: 首期吸收尾差, 保证各期之和精确等于 totalAmount; + * 日期: 首期=签约日, 第N期=签约日+(N-1)*30天
+ */ + @Override + @Transactional(rollbackFor = Exception.class) + public void generatePaymentPlan(Long contractId, int installmentCount) { + EduContract contract = contractMapper.selectById(contractId); + if (contract == null) { + throw new EduBusinessException("CONTRACT_NOT_FOUND", "合同不存在"); + } + if (installmentCount != 2 && installmentCount != 3) { + throw new EduBusinessException("INSTALLMENT_COUNT_INVALID", "分期数必须为 2 或 3"); + } + // 幂等: 先删后建 + paymentPlanMapper.delete(new LambdaQueryWrapper1. 置该期已收, 记 paidAmount/paidDate/paymentMethod; + * 2. 重算合同 paidAmount = SUM(已收期 paidAmount); + * 3. 重算 paymentStatus: 全额=已支付(2), 否则部分支付(1); + * 4. 写合同流水(action=RECEIVE_PAYMENT).
+ */ + @Override + @Transactional(rollbackFor = Exception.class) + public int receivePayment(PaymentReceiveBo bo) { + EduContractPaymentPlan plan = paymentPlanMapper.selectById(bo.getId()); + if (plan == null) { + throw new EduBusinessException("PLAN_NOT_FOUND", "缴费计划不存在"); + } + if (!EduConstants.PaymentPlanStatus.PENDING.equals(plan.getStatus())) { + throw new EduBusinessException("PLAN_STATUS_NOT_RECEIVABLE", "仅待收态计划可收款"); + } + // 1. 更新该期 + EduContractPaymentPlan update = new EduContractPaymentPlan(); + update.setId(plan.getId()); + update.setStatus(EduConstants.PaymentPlanStatus.RECEIVED); + update.setPaidAmount(bo.getPaidAmount()); + update.setPaymentMethod(bo.getPaymentMethod()); + update.setPaidDate(bo.getPaidDate() != null ? bo.getPaidDate() : new Date()); + update.setRemark(bo.getRemark()); + int rows = paymentPlanMapper.updateById(update); + + // 2. 重算合同实收: SUM(已收期 paidAmount), 本期刚置为已收, 库里已为最新值 + List仅把"待收"期置"已作废", "已收"期保留作为历史收款记录
+ */ + @Override + @Transactional(rollbackFor = Exception.class) + public int voidPendingPlans(Long contractId) { + List