|
|
@@ -1009,171 +1009,54 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
|
|
|
expenseOrder.setOrgType(elderlyInfo.getOrgType());
|
|
|
expenseOrder.setTenantId(saveVO.getTenantId());
|
|
|
expenseOrderMapper.insert(expenseOrder);
|
|
|
+ //生成账单费用项
|
|
|
+ BigDecimal totalAmount = BigDecimal.ZERO;
|
|
|
+ List<ExpenseItemRespVO> items = saveVO.getItems();
|
|
|
+ for (ExpenseItemRespVO item : items) {
|
|
|
+ ExpenseOrderItemDO orderItem = new ExpenseOrderItemDO();
|
|
|
+ orderItem.setExpenseOrderId(expenseOrder.getId());
|
|
|
+ orderItem.setSourceExpenseItemId(item.getSourceExpenseItemId());
|
|
|
+ orderItem.setExpenseSource(item.getExpenseSource());
|
|
|
+ orderItem.setCount(item.getCount());
|
|
|
+ orderItem.setItemName(item.getItemName());
|
|
|
+ orderItem.setDescription(StringUtils.isBlank(item.getDescription()) ?
|
|
|
+ item.getStartTime() + "至" + item.getEndTime() + "的" + item.getItemName() :
|
|
|
+ item.getDescription());
|
|
|
+ orderItem.setPrice(item.getPrice()); //单价
|
|
|
+ orderItem.setActualPrice(item.getPrice()); //实际单价
|
|
|
+ orderItem.setTotalAmount(item.getTotalAmount()); //总金额
|
|
|
+ orderItem.setRoundAmount(orderItem.getTotalAmount().setScale(0, RoundingMode.HALF_UP));
|
|
|
+ orderItem.setRoundTwoDecimalAmount(orderItem.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
|
|
|
+ orderItem.setCreatedTime(new Date());
|
|
|
+ orderItem.setType(item.getType());
|
|
|
+ orderItem.setItemCategoryName(item.getItemCategory());
|
|
|
+ orderItem.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
|
|
|
+ orderItem.setTenantId(saveVO.getTenantId());
|
|
|
+ orderItem.setStartDate(item.getStartTime() == null ? null : LocalDate.parse(item.getStartTime()));
|
|
|
+ orderItem.setEndDate(item.getEndTime() == null ? null : LocalDate.parse(item.getEndTime()));
|
|
|
+ orderItem.setContractId(item.getContractId());
|
|
|
+ expenseOrderItemMapper.insert(orderItem);
|
|
|
+ if (item.getExpenseSource().equals(BusinessConstants.DISCOUNT_DEDUCTION)) {
|
|
|
+ addDiscountRecord(saveVO.getElderId(), saveVO.getBillingMonth(), item);
|
|
|
+ }
|
|
|
+ //判断是否生成过账单(用于标记那些生成账单后再生成的费用项)
|
|
|
+ DailyExpensesDO dailyExpenses = dailyExpensesMapper.selectById(item.getSourceExpenseItemId());
|
|
|
+ if (dailyExpenses != null) {
|
|
|
+ dailyExpenses.setIsGenerateBill(BooleanEnum.TRUE.getValue());
|
|
|
+ dailyExpenses.setExpenseOrderNumber(expenseOrder.getBillOrderNumber());
|
|
|
+ dailyExpensesMapper.updateById(dailyExpenses);
|
|
|
+ }
|
|
|
|
|
|
- // 获取进行中的合同
|
|
|
- List<ElderlyContractDO> elderlyContractList = elderlyContractMapper.selectList(new LambdaQueryWrapperX<ElderlyContractDO>()
|
|
|
- .eq(ElderlyContractDO::getElderId, saveVO.getElderId())
|
|
|
- .in(ElderlyContractDO::getStatus, 1,2)
|
|
|
- .orderByDesc(ElderlyContractDO::getCreatedTime));
|
|
|
-
|
|
|
- if (CollectionUtil.isEmpty(elderlyContractList)) {
|
|
|
- return; // 没有合同则跳过
|
|
|
- }
|
|
|
-
|
|
|
- ElderlyContractDO elderlyContractDO = elderlyContractList.get(0); // 获取最新的合同
|
|
|
- Date expireTime = elderlyContractDO.getExpireTime();
|
|
|
-
|
|
|
- if (expireTime == null) {
|
|
|
- return; // 没有设置过期时间则跳过
|
|
|
- }
|
|
|
-
|
|
|
- // 将账单月份和合同过期时间转换为 YearMonth 进行比较
|
|
|
- YearMonth billYearMonth = YearMonth.parse(saveVO.getBillingMonth(), DateTimeFormatter.ofPattern("yyyy-MM"));
|
|
|
- YearMonth expireYearMonth = YearMonth.from(expireTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
|
|
|
-
|
|
|
- // 如果合同在当前账单月之前就已经过期,则跳过生成账单
|
|
|
- if (expireYearMonth.isBefore(billYearMonth)) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- if (!elderlyContractList.isEmpty()) {
|
|
|
- if (expireTime != null) {
|
|
|
- // 判断合同是否在账单月份过期
|
|
|
-// String billingMonth = saveVO.getBillingMonth();
|
|
|
-// YearMonth billYearMonth = YearMonth.parse(billingMonth, DateTimeFormatter.ofPattern("yyyy-MM"));
|
|
|
-// YearMonth expireYearMonth = YearMonth.from(expireTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
|
|
|
-
|
|
|
- if (billYearMonth.equals(expireYearMonth)) {
|
|
|
- LocalDate expireDate = expireTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
|
|
|
- int dayOfMonth = expireDate.getDayOfMonth(); // 过期日期是当月第几天
|
|
|
- int lengthOfMonth = expireDate.lengthOfMonth(); // 当月总天数
|
|
|
-
|
|
|
- // 遍历所有账单明细,调整金额
|
|
|
- // 如果合同在账单月份过期
|
|
|
- BigDecimal newTotalAmount = BigDecimal.ZERO;
|
|
|
- List<ExpenseItemRespVO> items = saveVO.getItems();
|
|
|
- for (ExpenseItemRespVO item : items) {
|
|
|
- ExpenseOrderItemDO orderItem = new ExpenseOrderItemDO();
|
|
|
- orderItem.setExpenseOrderId(expenseOrder.getId());
|
|
|
- orderItem.setSourceExpenseItemId(item.getSourceExpenseItemId() == null ? null : item.getSourceExpenseItemId());
|
|
|
- orderItem.setExpenseSource(item.getExpenseSource());
|
|
|
- orderItem.setCount(item.getCount());
|
|
|
- orderItem.setItemName(item.getItemName());
|
|
|
- orderItem.setDescription(StringUtils.isBlank(item.getDescription()) ?
|
|
|
- item.getStartTime() + "至" + item.getEndTime() + "的" + item.getItemName() :
|
|
|
- item.getDescription());
|
|
|
- orderItem.setContractId(item.getContractId());
|
|
|
- if (item.getExpenseSource().equals(BusinessConstants.EXPENSE_ITEM)) {
|
|
|
- //计算单价
|
|
|
- orderItem.setPrice(item.getPrice()); //单价
|
|
|
- orderItem.setActualPrice(item.getPrice()); //实际单价
|
|
|
- BigDecimal itemTotalAmount = item.getTotalAmount();
|
|
|
- BigDecimal dayPrice = itemTotalAmount.divide(BigDecimal.valueOf(lengthOfMonth), 8, RoundingMode.DOWN);
|
|
|
- BigDecimal actualPrice = dayPrice.multiply(BigDecimal.valueOf(dayOfMonth)).setScale(8, RoundingMode.DOWN);
|
|
|
- orderItem.setTotalAmount(actualPrice); //总金额
|
|
|
- orderItem.setRoundAmount(orderItem.getTotalAmount().setScale(0, RoundingMode.HALF_UP));
|
|
|
- orderItem.setRoundTwoDecimalAmount(orderItem.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
|
|
|
- } else {
|
|
|
- orderItem.setPrice(item.getPrice()); //单价
|
|
|
- orderItem.setActualPrice(item.getPrice()); //实际单价
|
|
|
- orderItem.setTotalAmount(item.getTotalAmount()); //总金额
|
|
|
- orderItem.setRoundAmount(orderItem.getTotalAmount().setScale(0, RoundingMode.HALF_UP));
|
|
|
- orderItem.setRoundTwoDecimalAmount(orderItem.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
|
|
|
- if (item.getExpenseSource().equals(BusinessConstants.DISCOUNT_DEDUCTION)) {
|
|
|
- addDiscountRecord(saveVO.getElderId(), saveVO.getBillingMonth(), item);
|
|
|
- }
|
|
|
- }
|
|
|
- orderItem.setStartDate(item.getStartTime() == null ? null : LocalDate.parse(item.getStartTime()));
|
|
|
- orderItem.setEndDate(expireDate);
|
|
|
- orderItem.setCreatedTime(new Date());
|
|
|
- orderItem.setType(item.getType());
|
|
|
- orderItem.setItemCategoryName(item.getItemCategory());
|
|
|
- orderItem.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
|
|
|
- orderItem.setTenantId(expenseOrder.getTenantId());
|
|
|
- expenseOrderItemMapper.insert(orderItem);
|
|
|
-
|
|
|
- //判断是否生成过账单(用于标记那些生成账单后再生成的费用项)
|
|
|
- DailyExpensesDO dailyExpenses = dailyExpensesMapper.selectById(item.getSourceExpenseItemId());
|
|
|
- if (dailyExpenses != null) {
|
|
|
- dailyExpenses.setIsGenerateBill(BooleanEnum.TRUE.getValue());
|
|
|
- dailyExpenses.setExpenseOrderNumber(expenseOrder.getBillOrderNumber());
|
|
|
- dailyExpensesMapper.updateById(dailyExpenses);
|
|
|
- }
|
|
|
-
|
|
|
- ExpenseSubsidyDO expenseSubsidyDO = expenseSubsidyMapper.selectById(item.getSourceExpenseItemId());
|
|
|
- if (expenseSubsidyDO != null) {
|
|
|
- expenseSubsidyDO.setStatus(BooleanEnum.TRUE.getValue());
|
|
|
- expenseSubsidyMapper.updateById(expenseSubsidyDO);
|
|
|
- }
|
|
|
- newTotalAmount = newTotalAmount.add(orderItem.getTotalAmount().setScale(2, RoundingMode.DOWN));
|
|
|
- }
|
|
|
-
|
|
|
-// List<ExpenseSubsidyDO> expenseSubsidList = expenseSubsidyMapper.selectList(new LambdaQueryWrapperX<ExpenseSubsidyDO>()
|
|
|
-// .eq(ExpenseSubsidyDO::getElderId, expenseOrder.getElderId())
|
|
|
-// .eq(ExpenseSubsidyDO::getDeductionBillMonth, expenseOrder.getBillingMonth()));
|
|
|
-
|
|
|
-// newTotalAmount = updateExpenseSubsidy(expenseSubsidList, expenseOrder, newTotalAmount);
|
|
|
- expenseOrder.setActualAmount(newTotalAmount);
|
|
|
- expenseOrderMapper.updateById(expenseOrder);
|
|
|
- } else {
|
|
|
- //生成账单费用项
|
|
|
- BigDecimal totalAmount = BigDecimal.ZERO;
|
|
|
- List<ExpenseItemRespVO> items = saveVO.getItems();
|
|
|
- for (ExpenseItemRespVO item : items) {
|
|
|
- ExpenseOrderItemDO orderItem = new ExpenseOrderItemDO();
|
|
|
- orderItem.setExpenseOrderId(expenseOrder.getId());
|
|
|
- orderItem.setSourceExpenseItemId(item.getSourceExpenseItemId());
|
|
|
- orderItem.setExpenseSource(item.getExpenseSource());
|
|
|
- orderItem.setCount(item.getCount());
|
|
|
- orderItem.setItemName(item.getItemName());
|
|
|
- orderItem.setDescription(StringUtils.isBlank(item.getDescription()) ?
|
|
|
- item.getStartTime() + "至" + item.getEndTime() + "的" + item.getItemName() :
|
|
|
- item.getDescription());
|
|
|
- orderItem.setPrice(item.getPrice()); //单价
|
|
|
- orderItem.setActualPrice(item.getPrice()); //实际单价
|
|
|
- orderItem.setTotalAmount(item.getTotalAmount()); //总金额
|
|
|
- orderItem.setRoundAmount(orderItem.getTotalAmount().setScale(0, RoundingMode.HALF_UP));
|
|
|
- orderItem.setRoundTwoDecimalAmount(orderItem.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
|
|
|
- orderItem.setCreatedTime(new Date());
|
|
|
- orderItem.setType(item.getType());
|
|
|
- orderItem.setItemCategoryName(item.getItemCategory());
|
|
|
- orderItem.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
|
|
|
- orderItem.setTenantId(saveVO.getTenantId());
|
|
|
- orderItem.setStartDate(item.getStartTime() == null ? null : LocalDate.parse(item.getStartTime()));
|
|
|
- orderItem.setEndDate(item.getEndTime() == null ? null : LocalDate.parse(item.getEndTime()));
|
|
|
- orderItem.setContractId(item.getContractId());
|
|
|
- expenseOrderItemMapper.insert(orderItem);
|
|
|
- if (item.getExpenseSource().equals(BusinessConstants.DISCOUNT_DEDUCTION)) {
|
|
|
- addDiscountRecord(saveVO.getElderId(), saveVO.getBillingMonth(), item);
|
|
|
- }
|
|
|
- //判断是否生成过账单(用于标记那些生成账单后再生成的费用项)
|
|
|
- DailyExpensesDO dailyExpenses = dailyExpensesMapper.selectById(item.getSourceExpenseItemId());
|
|
|
- if (dailyExpenses != null) {
|
|
|
- dailyExpenses.setIsGenerateBill(BooleanEnum.TRUE.getValue());
|
|
|
- dailyExpenses.setExpenseOrderNumber(expenseOrder.getBillOrderNumber());
|
|
|
- dailyExpensesMapper.updateById(dailyExpenses);
|
|
|
- }
|
|
|
-
|
|
|
- ExpenseSubsidyDO expenseSubsidyDO = expenseSubsidyMapper.selectById(item.getSourceExpenseItemId());
|
|
|
- if (expenseSubsidyDO != null) {
|
|
|
- expenseSubsidyDO.setStatus(BooleanEnum.TRUE.getValue());
|
|
|
- expenseSubsidyMapper.updateById(expenseSubsidyDO);
|
|
|
- }
|
|
|
-
|
|
|
- totalAmount = totalAmount.add(orderItem.getTotalAmount().setScale(2, RoundingMode.DOWN));
|
|
|
- }
|
|
|
-
|
|
|
-// List<ExpenseSubsidyDO> expenseSubsidList = expenseSubsidyMapper.selectList(new LambdaQueryWrapperX<ExpenseSubsidyDO>()
|
|
|
-// .eq(ExpenseSubsidyDO::getElderId, expenseOrder.getElderId())
|
|
|
-// .eq(ExpenseSubsidyDO::getDeductionBillMonth, expenseOrder.getBillingMonth()));
|
|
|
-//
|
|
|
-// totalAmount = updateExpenseSubsidy(expenseSubsidList, expenseOrder, totalAmount);
|
|
|
- expenseOrder.setActualAmount(totalAmount);
|
|
|
- expenseOrderMapper.updateById(expenseOrder);
|
|
|
- }
|
|
|
+ ExpenseSubsidyDO expenseSubsidyDO = expenseSubsidyMapper.selectById(item.getSourceExpenseItemId());
|
|
|
+ if (expenseSubsidyDO != null) {
|
|
|
+ expenseSubsidyDO.setStatus(BooleanEnum.TRUE.getValue());
|
|
|
+ expenseSubsidyMapper.updateById(expenseSubsidyDO);
|
|
|
}
|
|
|
+
|
|
|
+ totalAmount = totalAmount.add(orderItem.getTotalAmount().setScale(2, RoundingMode.DOWN));
|
|
|
}
|
|
|
+ expenseOrder.setActualAmount(totalAmount);
|
|
|
+ expenseOrderMapper.updateById(expenseOrder);
|
|
|
} else {
|
|
|
BigDecimal amount = BigDecimal.ZERO;
|
|
|
List<ExpenseItemRespVO> items = saveVO.getItems();
|
|
|
@@ -2994,18 +2877,50 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ markBillsPaid(expenseOrders);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ @TenantIgnore
|
|
|
+ public void markSupportElderlyBillsPaid(MarkSupportElderlyBillsPaidReqVO reqVO) {
|
|
|
+ // 1. 先查询该机构下供养长者(照护类型=1)
|
|
|
+ List<ElderlyInfoDO> supportElders = elderlyInfoMapper.selectList(new LambdaQueryWrapperX<ElderlyInfoDO>()
|
|
|
+ .eq(ElderlyInfoDO::getTenantId, reqVO.getTenantId())
|
|
|
+ .eq(ElderlyInfoDO::getCareType, 1));
|
|
|
+ if (CollectionUtil.isEmpty(supportElders)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ Set<Long> supportElderIds = supportElders.stream().map(ElderlyInfoDO::getId).collect(Collectors.toSet());
|
|
|
+
|
|
|
+ // 2. 查询账单月+机构下,未缴清的账单
|
|
|
+ List<ExpenseOrderDO> expenseOrders = expenseOrderMapper.selectList(new LambdaQueryWrapperX<ExpenseOrderDO>()
|
|
|
+ .eq(ExpenseOrderDO::getBillingMonth, reqVO.getBillingMonth())
|
|
|
+ .eq(ExpenseOrderDO::getTenantId, reqVO.getTenantId())
|
|
|
+ .in(ExpenseOrderDO::getElderId, supportElderIds)
|
|
|
+ .ne(ExpenseOrderDO::getPayStatus, BooleanEnum.TRUE.getValue()));
|
|
|
+
|
|
|
+ if (CollectionUtil.isEmpty(expenseOrders)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ markBillsPaid(expenseOrders);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 批量将账单置为已缴费(系统补缴)
|
|
|
+ */
|
|
|
+ private void markBillsPaid(List<ExpenseOrderDO> expenseOrders) {
|
|
|
Date payTime = new Date();
|
|
|
String payeeName = SecurityFrameworkUtils.getLoginUserNickname();
|
|
|
|
|
|
- // 2. 逐单处理:补齐 payOrder/payOrderItem + 明细 payStatus/payOrderId + 主单 payStatus/payType/payTime/payableAmount
|
|
|
for (ExpenseOrderDO expenseOrder : expenseOrders) {
|
|
|
- // 2.1 取该账单“需要置为已缴费”的明细:当前未缴费且展示的条目(跟 payOrder 后续判断口径保持一致)
|
|
|
List<ExpenseOrderItemDO> toPayItems = expenseOrderItemMapper.selectList(new LambdaQueryWrapperX<ExpenseOrderItemDO>()
|
|
|
.eq(ExpenseOrderItemDO::getExpenseOrderId, expenseOrder.getId())
|
|
|
.eq(ExpenseOrderItemDO::getPayStatus, BooleanEnum.FALSE.getValue()));
|
|
|
|
|
|
if (CollectionUtil.isEmpty(toPayItems)) {
|
|
|
- // 已无未缴费明细(可能已被其他流程补齐),直接跳过
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
@@ -3015,7 +2930,6 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
|
|
|
.reduce(BigDecimal.ZERO, BigDecimal::add)
|
|
|
.setScale(2, RoundingMode.HALF_UP);
|
|
|
|
|
|
- // 2.2 创建缴费单(模拟一次“系统补缴”),注意 round 字段与 payOrder 保持一致
|
|
|
ExpensePayOrderDO payOrder = new ExpensePayOrderDO();
|
|
|
payOrder.setPayAmount(payAmount);
|
|
|
payOrder.setRoundPayAmount(payAmount.setScale(0, RoundingMode.HALF_UP));
|
|
|
@@ -3027,7 +2941,6 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
|
|
|
payOrder.setTenantId(expenseOrder.getTenantId());
|
|
|
expensePayOrderMapper.insert(payOrder);
|
|
|
|
|
|
- // 2.3 创建缴费方式明细:用一个固定 payType 表示“系统补缴”,并沿用 payOrder 的金额
|
|
|
ExpensePayOrderItemDO payOrderItem = new ExpensePayOrderItemDO();
|
|
|
payOrderItem.setPayOrderId(payOrder.getId());
|
|
|
payOrderItem.setPayType("system");
|
|
|
@@ -3039,7 +2952,6 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
|
|
|
payOrderItem.setTenantId(expenseOrder.getTenantId());
|
|
|
expensePayOrderItemMapper.insert(payOrderItem);
|
|
|
|
|
|
- // 2.4 更新账单明细:缴费状态 + 缴费时间 + 关联 payOrderId,并补齐押金入账(参考 payOrder)
|
|
|
for (ExpenseOrderItemDO item : toPayItems) {
|
|
|
ExpenseOrderItemDO updateItem = new ExpenseOrderItemDO();
|
|
|
updateItem.setId(item.getId());
|
|
|
@@ -3048,10 +2960,6 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
|
|
|
updateItem.setPayOrderId(payOrder.getId());
|
|
|
expenseOrderItemMapper.updateById(updateItem);
|
|
|
|
|
|
- // 押金处理:
|
|
|
- // 1) 日常费用押金(DailyExpenses itemName/itemCategory 包含押金/风险金/预备金 等)
|
|
|
- // 2) 月度费用押金(ExpenseItem isDeposit=TRUE)
|
|
|
- // 说明:markCheckinBillsPaid 没有票据号入参,因此 receiptNumber 不回填。
|
|
|
DailyExpensesDO dailyExpenses = null;
|
|
|
if (Objects.equals(item.getExpenseSource(), BusinessConstants.DAILY_EXPENSES)) {
|
|
|
dailyExpenses = dailyExpensesMapper.selectById(item.getSourceExpenseItemId());
|
|
|
@@ -3076,7 +2984,6 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
|
|
|
boolean isMonthlyDeposit = expenseItemDO != null && Objects.equals(expenseItemDO.getIsDeposit(), BooleanEnum.TRUE.getValue());
|
|
|
|
|
|
if (isDailyDeposit || isMonthlyDeposit) {
|
|
|
- // 幂等保护:如果该账单明细已经生成过押金缴费记录(用 itemId + type=1 + elderId 判断),则跳过
|
|
|
Long recordItemId = isDailyDeposit ? dailyExpenses.getId() : expenseItemDO.getItemId();
|
|
|
DepositRecordDO existed = depositRecordMapper.selectOne(new LambdaQueryWrapperX<DepositRecordDO>()
|
|
|
.eq(DepositRecordDO::getElderId, expenseOrder.getElderId())
|
|
|
@@ -3086,7 +2993,6 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- // 获取押金账户(payOrder 中:日常押金按 elderId+tenantId 查询,月度押金仅按 elderId 查询;这里统一按 elderId+tenantId 优先)
|
|
|
DepositDO dbDeposit = depositMapper.selectOne(new LambdaQueryWrapperX<DepositDO>()
|
|
|
.eq(DepositDO::getElderId, expenseOrder.getElderId())
|
|
|
.eq(DepositDO::getTenantId, expenseOrder.getTenantId()));
|
|
|
@@ -3115,7 +3021,6 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
|
|
|
dbDeposit.setAmount((dbDeposit.getAmount() == null ? BigDecimal.ZERO : dbDeposit.getAmount()).add(depositAmount));
|
|
|
depositMapper.updateById(dbDeposit);
|
|
|
|
|
|
- // 日常费用押金:同步把日常费用置为已缴费并回填账单号(跟 payOrder 一致)
|
|
|
if (dailyExpenses != null) {
|
|
|
dailyExpenses.setStatus(BooleanEnum.TRUE.getValue());
|
|
|
dailyExpenses.setExpenseOrderNumber(expenseOrder.getBillOrderNumber());
|
|
|
@@ -3124,8 +3029,6 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 2.5 更新账单主表:该接口语义为“系统强制缴清”,因此直接将主单置为已缴清
|
|
|
- // 注意:此处字段 payableAmount 在现有代码中被当作“已缴金额”累加使用;这里强制将其置为账单实际金额。
|
|
|
ExpenseOrderDO updateOrder = new ExpenseOrderDO();
|
|
|
updateOrder.setId(expenseOrder.getId());
|
|
|
updateOrder.setPayTime(payTime);
|
|
|
@@ -3757,6 +3660,24 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
|
|
|
LocalDate monthStart = yearMonth.atDay(1);
|
|
|
LocalDate monthEnd = yearMonth.atEndOfMonth();
|
|
|
|
|
|
+ // 合同到期规则:
|
|
|
+ // 1) 到期月只计 1号~到期日(包含到期日)
|
|
|
+ // 2) 到期后月份不再计固定费用
|
|
|
+ // 3) 与离住规则同时命中时,实际结束时间优先采用合同到期时间
|
|
|
+ LocalDate contractExpireDate = null;
|
|
|
+ ElderlyContractDO latestContract = elderlyContractMapper.selectOne(new LambdaQueryWrapperX<ElderlyContractDO>()
|
|
|
+ .eq(ElderlyContractDO::getElderId, elderId)
|
|
|
+ .orderByDesc(ElderlyContractDO::getCreatedTime)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ boolean isContractExpireInBillingMonth = false;
|
|
|
+ if (latestContract != null && latestContract.getExpireTime() != null) {
|
|
|
+ contractExpireDate = latestContract.getExpireTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
|
|
|
+ if (contractExpireDate.isBefore(monthStart)) {
|
|
|
+ return collect;
|
|
|
+ }
|
|
|
+ isContractExpireInBillingMonth = !contractExpireDate.isBefore(monthStart) && !contractExpireDate.isAfter(monthEnd);
|
|
|
+ }
|
|
|
+
|
|
|
// 计费核心:仅当目标月份与“在院区间”有交集才生成固定费用。
|
|
|
// 这里的“在院区间”按离住/返院时间截断,避免出现:离住后未返院的月份不应计费,但后续补录返院导致回算。
|
|
|
LocalDate actualStart = monthStart;
|
|
|
@@ -3777,29 +3698,45 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
|
|
|
if (outDate.isAfter(monthStart)) {
|
|
|
actualEnd = outDate.minusDays(1);
|
|
|
} else {
|
|
|
- return collect;
|
|
|
+ // 原离住规则在“月初离住”会直接不计费;
|
|
|
+ // 但若本月合同到期,需像离住按区间计费(1号~到期日),故不提前 return
|
|
|
+ if (!isContractExpireInBillingMonth) {
|
|
|
+ return collect;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 离住后的月份(本月月初在离院日之后)
|
|
|
if (monthStart.isAfter(outDate)) {
|
|
|
if (comeDate == null) {
|
|
|
- // 仍处于离住中:离院后月份不计费
|
|
|
- return collect;
|
|
|
- }
|
|
|
- YearMonth comeYm = YearMonth.from(comeDate);
|
|
|
- if (yearMonth.isBefore(comeYm)) {
|
|
|
- // 返院发生在未来月份:本月仍不计费
|
|
|
- return collect;
|
|
|
- }
|
|
|
- if (yearMonth.equals(comeYm)) {
|
|
|
- // 返院当月:从返院日开始计费(包含当天)
|
|
|
- actualStart = comeDate.isAfter(monthStart) ? comeDate : monthStart;
|
|
|
+ // 仍处于离住中:离院后月份不计费;
|
|
|
+ // 但若本月合同到期,仍需生成 1号~到期日费用
|
|
|
+ if (!isContractExpireInBillingMonth) {
|
|
|
+ return collect;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ YearMonth comeYm = YearMonth.from(comeDate);
|
|
|
+ if (yearMonth.isBefore(comeYm)) {
|
|
|
+ // 返院发生在未来月份:本月仍不计费;
|
|
|
+ // 但若本月合同到期,仍需生成 1号~到期日费用
|
|
|
+ if (!isContractExpireInBillingMonth) {
|
|
|
+ return collect;
|
|
|
+ }
|
|
|
+ } else if (yearMonth.equals(comeYm)) {
|
|
|
+ // 返院当月:从返院日开始计费(包含当天)
|
|
|
+ actualStart = comeDate.isAfter(monthStart) ? comeDate : monthStart;
|
|
|
+ }
|
|
|
+ // 返院后的月份:整月计费(保持 monthStart)
|
|
|
}
|
|
|
- // 返院后的月份:整月计费(保持 monthStart)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // 合同到期月处理:像离住一样按天折算,只保留月初到到期日区间;
|
|
|
+ // 若与离住规则同时命中,结束时间优先取合同到期时间
|
|
|
+ if (contractExpireDate != null && !contractExpireDate.isBefore(monthStart) && !contractExpireDate.isAfter(monthEnd)) {
|
|
|
+ actualEnd = contractExpireDate;
|
|
|
+ }
|
|
|
+
|
|
|
if (!actualEnd.isBefore(actualStart)) {
|
|
|
//如果没有当月订单查询当月未缴费的日常费用和月度费用
|
|
|
Optional<ExpenseDO> optional = expenseMapper.selectList(new LambdaQueryWrapperX<ExpenseDO>()
|