|
|
@@ -1061,7 +1061,7 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
|
|
|
orderItem.setCount(item.getCount());
|
|
|
orderItem.setItemName(item.getItemName());
|
|
|
orderItem.setDescription(StringUtils.isBlank(item.getDescription()) ?
|
|
|
- LocalDateTimeUtil.format(expireDate.with(TemporalAdjusters.firstDayOfMonth()), DatePattern.NORM_DATE_PATTERN) + "至" + LocalDateTimeUtil.format(expireDate, DatePattern.NORM_DATE_PATTERN) + "的" + item.getItemName() :
|
|
|
+ item.getStartTime() + "至" + item.getEndTime() + "的" + item.getItemName() :
|
|
|
item.getDescription());
|
|
|
orderItem.setContractId(item.getContractId());
|
|
|
if (item.getExpenseSource().equals(BusinessConstants.EXPENSE_ITEM)) {
|
|
|
@@ -1127,8 +1127,8 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
|
|
|
orderItem.setExpenseSource(item.getExpenseSource());
|
|
|
orderItem.setCount(item.getCount());
|
|
|
orderItem.setItemName(item.getItemName());
|
|
|
- orderItem.setDescription(StringUtils.isBlank(item.getDescription()) ? LocalDateTimeUtil.format(billYearMonth.atDay(1), DatePattern.NORM_DATE_PATTERN)
|
|
|
- + "至" + LocalDateTimeUtil.format(billYearMonth.atEndOfMonth(), DatePattern.NORM_DATE_PATTERN) + "的" + item.getItemName() :
|
|
|
+ orderItem.setDescription(StringUtils.isBlank(item.getDescription()) ?
|
|
|
+ item.getStartTime() + "至" + item.getEndTime() + "的" + item.getItemName() :
|
|
|
item.getDescription());
|
|
|
orderItem.setPrice(item.getPrice()); //单价
|
|
|
orderItem.setActualPrice(item.getPrice()); //实际单价
|
|
|
@@ -3746,34 +3746,61 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
|
|
|
}
|
|
|
|
|
|
private List<ExpenseItemRespVO> handlerCollectMonthlyExpense(String billingMonth, Long elderId){
|
|
|
- ElderlyTempOutDO elderlyTempOutDO = elderlyTempOutMapper.selectOne(new LambdaQueryWrapperX<ElderlyTempOutDO>()
|
|
|
+ // 离住/返院记录:你方约定为“只存在一条记录”,返院时会把该记录 outStatus 更新为 2 并写入 comeTime
|
|
|
+ ElderlyTempOutDO tempOutRecord = elderlyTempOutMapper.selectOne(new LambdaQueryWrapperX<ElderlyTempOutDO>()
|
|
|
.eq(ElderlyTempOutDO::getElderId, elderId)
|
|
|
- .eq(ElderlyTempOutDO::getOutStatus, 1)
|
|
|
- .le(ElderlyTempOutDO::getOutMonth, billingMonth));
|
|
|
+ .orderByDesc(ElderlyTempOutDO::getOutTime)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+
|
|
|
List<ExpenseItemRespVO> collect = new ArrayList<>();
|
|
|
YearMonth yearMonth = YearMonth.parse(billingMonth, DateTimeFormatter.ofPattern("yyyy-MM"));
|
|
|
- LocalDate yearMonthStartDay = yearMonth.atDay(1);
|
|
|
- // 规则:一旦开始离住(outStatus=1),离住当月按 1 号~离院前一天计固定费;离住后的月份直到返院前均不计固定费
|
|
|
- // 因此:
|
|
|
- // - billingMonth < outMonth:正常整月固定费
|
|
|
- // - billingMonth == outMonth:若离院日>1号,则计 1号~离院前一天;若离院日=1号则当月不计固定费
|
|
|
- // - billingMonth > outMonth:离住期内后续月份不计固定费
|
|
|
- LocalDate fixedEnd = yearMonth.atEndOfMonth();
|
|
|
- if (elderlyTempOutDO != null && elderlyTempOutDO.getOutTime() != null) {
|
|
|
- YearMonth outYm = YearMonth.parse(elderlyTempOutDO.getOutMonth(), DateTimeFormatter.ofPattern("yyyy-MM"));
|
|
|
- if (yearMonth.isAfter(outYm)) {
|
|
|
- return collect;
|
|
|
- }
|
|
|
- if (yearMonth.equals(outYm)) {
|
|
|
- LocalDate outDate = elderlyTempOutDO.getOutTime().toLocalDate();
|
|
|
- if (outDate.isAfter(yearMonthStartDay)) {
|
|
|
- fixedEnd = outDate.minusDays(1);
|
|
|
+ LocalDate monthStart = yearMonth.atDay(1);
|
|
|
+ LocalDate monthEnd = yearMonth.atEndOfMonth();
|
|
|
+
|
|
|
+ // 计费核心:仅当目标月份与“在院区间”有交集才生成固定费用。
|
|
|
+ // 这里的“在院区间”按离住/返院时间截断,避免出现:离住后未返院的月份不应计费,但后续补录返院导致回算。
|
|
|
+ LocalDate actualStart = monthStart;
|
|
|
+ LocalDate actualEnd = monthEnd;
|
|
|
+
|
|
|
+ if (tempOutRecord != null && tempOutRecord.getOutTime() != null) {
|
|
|
+ LocalDate outDate = tempOutRecord.getOutTime().toLocalDate();
|
|
|
+ LocalDate comeDate = tempOutRecord.getComeTime() == null ? null : tempOutRecord.getComeTime().toLocalDate();
|
|
|
+
|
|
|
+ // 规则:
|
|
|
+ // 1) 离住月:计费区间为 月初 ~ 离院前一天(不包含离院当天)
|
|
|
+ // 2) 离住后、返院前:不计固定费
|
|
|
+ // 3) 返院月:计费区间为 返院当天 ~ 月末(包含返院当天)
|
|
|
+ // 4) 返院后月份:整月计费
|
|
|
+
|
|
|
+ // 离住发生在本月内:本月仅计 1号~离住前一天
|
|
|
+ if (!outDate.isBefore(monthStart) && !outDate.isAfter(monthEnd)) {
|
|
|
+ if (outDate.isAfter(monthStart)) {
|
|
|
+ actualEnd = outDate.minusDays(1);
|
|
|
} else {
|
|
|
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;
|
|
|
+ }
|
|
|
+ // 返院后的月份:整月计费(保持 monthStart)
|
|
|
+ }
|
|
|
}
|
|
|
- if (!fixedEnd.isBefore(yearMonthStartDay)) {
|
|
|
+
|
|
|
+ if (!actualEnd.isBefore(actualStart)) {
|
|
|
//如果没有当月订单查询当月未缴费的日常费用和月度费用
|
|
|
Optional<ExpenseDO> optional = expenseMapper.selectList(new LambdaQueryWrapperX<ExpenseDO>()
|
|
|
.eq(ExpenseDO::getElderId, elderId)
|
|
|
@@ -3797,7 +3824,8 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
|
|
|
.le(ExpenseItemDO::getFreeStartTime, queryTime.atDay(1))
|
|
|
.ge(ExpenseItemDO::getFreeEndTime, queryTime.atEndOfMonth()));
|
|
|
expenseItems.addAll(freeGiftItemList);
|
|
|
-
|
|
|
+ LocalDate finalActualStart = actualStart;
|
|
|
+ LocalDate finalActualEnd = actualEnd;
|
|
|
collect = expenseItems.stream().map(item -> {
|
|
|
ExpenseItemRespVO respVO = new ExpenseItemRespVO();
|
|
|
if (item.getIsFreeGift().equals(BooleanEnum.TRUE.getValue())) {
|
|
|
@@ -3807,13 +3835,25 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
|
|
|
}
|
|
|
respVO.setExpenseSource(BusinessConstants.EXPENSE_ITEM);
|
|
|
respVO.setSourceExpenseItemId(item.getId());
|
|
|
- respVO.setPrice(item.getActualAmount());
|
|
|
- respVO.setTotalAmount(item.getTotalAmount());
|
|
|
+ BigDecimal originAmount = item.getActualAmount();
|
|
|
+ BigDecimal originTotal = item.getTotalAmount();
|
|
|
+ if (finalActualStart.isAfter(monthStart) || finalActualEnd.isBefore(monthEnd)) {
|
|
|
+ long monthDays = ChronoUnit.DAYS.between(monthStart, monthEnd) + 1;
|
|
|
+ long actualDays = ChronoUnit.DAYS.between(finalActualStart, finalActualEnd) + 1;
|
|
|
+ if (monthDays > 0 && actualDays > 0) {
|
|
|
+ BigDecimal ratio = BigDecimal.valueOf(actualDays)
|
|
|
+ .divide(BigDecimal.valueOf(monthDays), 8, RoundingMode.HALF_UP);
|
|
|
+ originAmount = originAmount.multiply(ratio).setScale(2, RoundingMode.HALF_UP);
|
|
|
+ originTotal = originTotal.multiply(ratio).setScale(2, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ respVO.setPrice(originAmount);
|
|
|
+ respVO.setTotalAmount(originTotal);
|
|
|
respVO.setItemName(item.getItemName());
|
|
|
respVO.setItemCategory(item.getItemCategoryName());
|
|
|
respVO.setCount(item.getCount() == null ? 1 : item.getCount());
|
|
|
- respVO.setStartTime(yearMonthStartDay.toString());
|
|
|
- respVO.setEndTime(yearMonth.atEndOfMonth().toString());
|
|
|
+ respVO.setStartTime(finalActualStart.toString());
|
|
|
+ respVO.setEndTime(finalActualEnd.toString());
|
|
|
respVO.setType(item.getType());
|
|
|
respVO.setItemCategory(item.getItemCategoryName());
|
|
|
respVO.setContractId(expense.getContractId());
|