|
|
@@ -25,6 +25,7 @@ import java.time.LocalDate;
|
|
|
import java.time.YearMonth;
|
|
|
import java.time.ZoneId;
|
|
|
import java.time.format.DateTimeFormatter;
|
|
|
+import java.time.temporal.ChronoUnit;
|
|
|
import java.util.*;
|
|
|
import java.util.stream.Collectors;
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
@@ -160,8 +161,8 @@ public class OrderApiImpl implements OrderApi {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- // 月度费用类(expenseSource=EXPENSE_ITEM):一次遍历同时计算“标准应收”和“实际应收”
|
|
|
- applyMonthlyItems(dto, expenseOrderItemDOS, expenseItemMap);
|
|
|
+ // 月度费用类(expenseSource=EXPENSE_ITEM):按账单月区间计算“标准应收”和“实际应收”
|
|
|
+ applyMonthlyItems(dto, expenseOrderItemDOS, expenseItemMap, billMonth);
|
|
|
|
|
|
// 3) 日常费用的外出/变更等调整:叠加到“实际应收”
|
|
|
applyDailyAdjustments(dto, expenseOrderItemDOS, dailyExpenseMap, remarkBuilder);
|
|
|
@@ -244,7 +245,19 @@ public class OrderApiImpl implements OrderApi {
|
|
|
* - 费用分类:按 ExpenseItemDO.type 划分床/膳/护/服务
|
|
|
*/
|
|
|
private void applyMonthlyItems(OrderItemRespDTO dto, List<ExpenseOrderItemDO> items,
|
|
|
- Map<Long, ExpenseItemDO> expenseItemMap) {
|
|
|
+ Map<Long, ExpenseItemDO> expenseItemMap,
|
|
|
+ String billMonth) {
|
|
|
+ YearMonth billYm = null;
|
|
|
+ if (StringUtil.isNotEmptyORNull(billMonth)) {
|
|
|
+ try {
|
|
|
+ billYm = YearMonth.parse(billMonth);
|
|
|
+ } catch (Exception ignore) {
|
|
|
+ billYm = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ LocalDate billStart = billYm == null ? null : billYm.atDay(1);
|
|
|
+ LocalDate billEnd = billYm == null ? null : billYm.atEndOfMonth();
|
|
|
+
|
|
|
for (ExpenseOrderItemDO expenseOrderItemDO : items) {
|
|
|
if (!BusinessConstants.EXPENSE_ITEM.equals(expenseOrderItemDO.getExpenseSource())) {
|
|
|
continue;
|
|
|
@@ -259,20 +272,57 @@ public class OrderApiImpl implements OrderApi {
|
|
|
BigDecimal actualAmount = expenseOrderItemDO.getTotalAmount() == null
|
|
|
? BigDecimal.ZERO : expenseOrderItemDO.getTotalAmount();
|
|
|
|
|
|
+ BigDecimal billedStandardAmount = standardAmount;
|
|
|
+ BigDecimal billedActualAmount = actualAmount;
|
|
|
+
|
|
|
+ if (billYm != null) {
|
|
|
+ int daysInBillMonth = billYm.lengthOfMonth();
|
|
|
+ LocalDate changeStartDate = expenseItemDO.getChangeStartDate();
|
|
|
+ LocalDate changeEndDate = expenseItemDO.getChangeEndDate();
|
|
|
+
|
|
|
+ // 费用生效区间与账单月做交集:
|
|
|
+ // - 无开始日:视为本月月初
|
|
|
+ // - 无结束日:视为本月月末
|
|
|
+ LocalDate periodStart = changeStartDate == null ? billStart : changeStartDate;
|
|
|
+ LocalDate periodEnd = changeEndDate == null ? billEnd : changeEndDate;
|
|
|
+
|
|
|
+ LocalDate overlapStart = periodStart.isAfter(billStart) ? periodStart : billStart;
|
|
|
+ LocalDate overlapEnd = periodEnd.isBefore(billEnd) ? periodEnd : billEnd;
|
|
|
+
|
|
|
+ if (overlapEnd.isBefore(overlapStart)) {
|
|
|
+ // 该费用在账单月无覆盖,跳过
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ long actualDays = ChronoUnit.DAYS.between(overlapStart, overlapEnd) + 1;
|
|
|
+ if (daysInBillMonth > 0 && actualDays > 0 && actualDays != daysInBillMonth) {
|
|
|
+ BigDecimal dayStandard = standardAmount
|
|
|
+ .divide(BigDecimal.valueOf(daysInBillMonth), 8, RoundingMode.DOWN);
|
|
|
+ BigDecimal dayActual = actualAmount
|
|
|
+ .divide(BigDecimal.valueOf(daysInBillMonth), 8, RoundingMode.DOWN);
|
|
|
+ billedStandardAmount = dayStandard
|
|
|
+ .multiply(BigDecimal.valueOf(actualDays))
|
|
|
+ .setScale(2, RoundingMode.DOWN);
|
|
|
+ billedActualAmount = dayActual
|
|
|
+ .multiply(BigDecimal.valueOf(actualDays))
|
|
|
+ .setScale(2, RoundingMode.DOWN);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
Integer type = expenseItemDO.getType();
|
|
|
if ((type != null && 1 == type) || expenseItemDO.getItemName().contains("床位费")) {
|
|
|
dto.setBedItemName(expenseItemDO.getItemName());
|
|
|
- dto.setBedAmount(dto.getBedAmount().add(standardAmount));
|
|
|
- dto.setBedActualAmount(dto.getBedActualAmount().add(actualAmount));
|
|
|
+ dto.setBedAmount(dto.getBedAmount().add(billedStandardAmount));
|
|
|
+ dto.setBedActualAmount(dto.getBedActualAmount().add(billedActualAmount));
|
|
|
} else if ((type != null && 2 == type) || expenseItemDO.getItemName().contains("护理费")) {
|
|
|
- dto.setNurseAmount(dto.getNurseAmount().add(standardAmount));
|
|
|
- dto.setNurseActualAmount(dto.getNurseActualAmount().add(actualAmount));
|
|
|
+ dto.setNurseAmount(dto.getNurseAmount().add(billedStandardAmount));
|
|
|
+ dto.setNurseActualAmount(dto.getNurseActualAmount().add(billedActualAmount));
|
|
|
} else if ((type != null && 3 == type) || expenseItemDO.getItemName().contains("餐饮费")) {
|
|
|
- dto.setMealAmount(dto.getMealAmount().add(standardAmount));
|
|
|
- dto.setMealActualAmount(dto.getMealActualAmount().add(actualAmount));
|
|
|
+ dto.setMealAmount(dto.getMealAmount().add(billedStandardAmount));
|
|
|
+ dto.setMealActualAmount(dto.getMealActualAmount().add(billedActualAmount));
|
|
|
} else if ((type != null && 7 == type) || expenseItemDO.getItemName().contains("服务费")) {
|
|
|
- dto.setServiceAmount(dto.getServiceAmount().add(standardAmount));
|
|
|
- dto.setServiceActualAmount(dto.getServiceActualAmount().add(actualAmount));
|
|
|
+ dto.setServiceAmount(dto.getServiceAmount().add(billedStandardAmount));
|
|
|
+ dto.setServiceActualAmount(dto.getServiceActualAmount().add(billedActualAmount));
|
|
|
}
|
|
|
}
|
|
|
}
|