|
@@ -59,10 +59,72 @@ public class OrderApiImpl implements OrderApi {
|
|
|
private final ConcurrentHashMap<String, CacheEntry> receivableCache = new ConcurrentHashMap<>();
|
|
private final ConcurrentHashMap<String, CacheEntry> receivableCache = new ConcurrentHashMap<>();
|
|
|
private static final long RECEIVABLE_CACHE_TTL_MS = 1 * 60 * 1000L; // 1 分钟
|
|
private static final long RECEIVABLE_CACHE_TTL_MS = 1 * 60 * 1000L; // 1 分钟
|
|
|
|
|
|
|
|
|
|
+ private static final Set<String> REPORT_EXTRA_NURSING_ITEMS = buildNormalizedSet(Arrays.asList(
|
|
|
|
|
+ "陪护费", "换尿管", "换胃管", "一次性护理费", "开塞露通便", "血糖测量", "压疮护理", "吸氧", "鼻饲喂养", "全辅助进食"
|
|
|
|
|
+ ));
|
|
|
|
|
+
|
|
|
|
|
+ private static final Set<String> REPORT_EXTRA_SERVICE_ITEMS = buildNormalizedSet(Arrays.asList(
|
|
|
|
|
+ "代开药", "陪同就医", "收视费", "紧急送医服务", "生活用品", "外出"
|
|
|
|
|
+ ));
|
|
|
|
|
+
|
|
|
|
|
+ private static final Set<String> REPORT_OTHER_INCOME_ITEMS = buildNormalizedSet(Arrays.asList(
|
|
|
|
|
+ "一次性安置品", "差额补收", "物品损坏赔偿费", "临终关怀", "一口价费用", "大门损坏赔偿"
|
|
|
|
|
+ ));
|
|
|
|
|
+
|
|
|
private String buildReceivableCacheKey(Integer orgType, Long tenantId, String normalizedMonth) {
|
|
private String buildReceivableCacheKey(Integer orgType, Long tenantId, String normalizedMonth) {
|
|
|
return orgType + "|" + tenantId + "|" + normalizedMonth;
|
|
return orgType + "|" + tenantId + "|" + normalizedMonth;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private static Set<String> buildNormalizedSet(List<String> items) {
|
|
|
|
|
+ if (items == null || items.isEmpty()) {
|
|
|
|
|
+ return Collections.emptySet();
|
|
|
|
|
+ }
|
|
|
|
|
+ LinkedHashSet<String> set = new LinkedHashSet<>();
|
|
|
|
|
+ for (String s : items) {
|
|
|
|
|
+ String k = normalizeProjectKey(s);
|
|
|
|
|
+ if (k != null && !k.isEmpty()) {
|
|
|
|
|
+ set.add(k);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return Collections.unmodifiableSet(set);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static String normalizeProjectKey(String s) {
|
|
|
|
|
+ if (s == null) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ String trimmed = s.trim();
|
|
|
|
|
+ if (trimmed.isEmpty()) {
|
|
|
|
|
+ return "";
|
|
|
|
|
+ }
|
|
|
|
|
+ StringBuilder sb = new StringBuilder(trimmed.length());
|
|
|
|
|
+ for (int i = 0; i < trimmed.length(); i++) {
|
|
|
|
|
+ char c = trimmed.charAt(i);
|
|
|
|
|
+ if (Character.isWhitespace(c) || c == ' ') {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ sb.append(c);
|
|
|
|
|
+ }
|
|
|
|
|
+ return sb.toString();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static void mergeAmount(Map<String, BigDecimal> map, String key, BigDecimal amount) {
|
|
|
|
|
+ if (map == null) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (amount == null || amount.compareTo(BigDecimal.ZERO) == 0) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (key == null) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ String k = key.trim();
|
|
|
|
|
+ if (k.isEmpty()) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ map.merge(k, amount, BigDecimal::add);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private String normalizeMonth(String queryFlag, String billingMonth) {
|
|
private String normalizeMonth(String queryFlag, String billingMonth) {
|
|
|
if (StringUtil.isEmptyORNull(billingMonth)) return null;
|
|
if (StringUtil.isEmptyORNull(billingMonth)) return null;
|
|
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(FORMAT_YEAR_MONTH_DAY);
|
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(FORMAT_YEAR_MONTH_DAY);
|
|
@@ -236,7 +298,15 @@ public class OrderApiImpl implements OrderApi {
|
|
|
dto.setNurseActualAmount(BigDecimal.ZERO);
|
|
dto.setNurseActualAmount(BigDecimal.ZERO);
|
|
|
dto.setServiceActualAmount(BigDecimal.ZERO);
|
|
dto.setServiceActualAmount(BigDecimal.ZERO);
|
|
|
dto.setExtraServiceAmount(BigDecimal.ZERO);
|
|
dto.setExtraServiceAmount(BigDecimal.ZERO);
|
|
|
|
|
+ dto.setOrderFoodAmount(BigDecimal.ZERO);
|
|
|
|
|
+ dto.setOrderShopAmount(BigDecimal.ZERO);
|
|
|
|
|
+ dto.setOrderNursingAmount(BigDecimal.ZERO);
|
|
|
|
|
+ dto.setOrderServiceAmount(BigDecimal.ZERO);
|
|
|
dto.setOrderWaterElectricityAmount(BigDecimal.ZERO);
|
|
dto.setOrderWaterElectricityAmount(BigDecimal.ZERO);
|
|
|
|
|
+ dto.setOrderOtherIncomeAmount(BigDecimal.ZERO);
|
|
|
|
|
+ dto.setOrderNursingItemStats(new LinkedHashMap<>());
|
|
|
|
|
+ dto.setOrderServiceItemStats(new LinkedHashMap<>());
|
|
|
|
|
+ dto.setOrderOtherIncomeItemStats(new LinkedHashMap<>());
|
|
|
dto.setTotalAmount(BigDecimal.ZERO);
|
|
dto.setTotalAmount(BigDecimal.ZERO);
|
|
|
dto.setTotalActualAmount(BigDecimal.ZERO);
|
|
dto.setTotalActualAmount(BigDecimal.ZERO);
|
|
|
dto.setAdjustAmount(BigDecimal.ZERO);
|
|
dto.setAdjustAmount(BigDecimal.ZERO);
|
|
@@ -423,22 +493,23 @@ public class OrderApiImpl implements OrderApi {
|
|
|
/** 处理非外出/变更的日常费用(增值、点餐、护理、服务等) */
|
|
/** 处理非外出/变更的日常费用(增值、点餐、护理、服务等) */
|
|
|
private void handleOtherDailyExpenses(OrderItemRespDTO dto, DailyExpensesDO dailyExpensesDO) {
|
|
private void handleOtherDailyExpenses(OrderItemRespDTO dto, DailyExpensesDO dailyExpensesDO) {
|
|
|
String itemName = dailyExpensesDO.getItemName();
|
|
String itemName = dailyExpensesDO.getItemName();
|
|
|
- if (itemName != null) {
|
|
|
|
|
- BigDecimal roundAmount = dailyExpensesDO.getAmount() == null ? BigDecimal.ZERO : dailyExpensesDO.getAmount();
|
|
|
|
|
- if ("点餐".equals(itemName)) {
|
|
|
|
|
- BigDecimal currentAmount = dto.getOrderFoodAmount() == null ? BigDecimal.ZERO : dto.getOrderFoodAmount();
|
|
|
|
|
- dto.setOrderFoodAmount(currentAmount.add(roundAmount));
|
|
|
|
|
- }
|
|
|
|
|
- if (itemName.contains("生命体征") || itemName.contains("医疗护理")) {
|
|
|
|
|
- BigDecimal currentAmount = dto.getOrderNursingAmount() == null ? BigDecimal.ZERO : dto.getOrderNursingAmount();
|
|
|
|
|
- dto.setOrderNursingAmount(currentAmount.add(roundAmount));
|
|
|
|
|
|
|
+ BigDecimal extraAmount = dailyExpensesDO.getAmount() == null ? BigDecimal.ZERO : dailyExpensesDO.getAmount();
|
|
|
|
|
+ String normalizedName = normalizeProjectKey(itemName);
|
|
|
|
|
+ if (normalizedName != null && !normalizedName.isEmpty()) {
|
|
|
|
|
+ if ("点餐".equals(normalizedName)) {
|
|
|
|
|
+ dto.setOrderFoodAmount(nz(dto.getOrderFoodAmount()).add(extraAmount));
|
|
|
}
|
|
}
|
|
|
- if (itemName.contains("身体护理")) {
|
|
|
|
|
- BigDecimal currentAmount = dto.getOrderServiceAmount() == null ? BigDecimal.ZERO : dto.getOrderServiceAmount();
|
|
|
|
|
- dto.setOrderServiceAmount(currentAmount.add(roundAmount));
|
|
|
|
|
|
|
+ if (REPORT_EXTRA_NURSING_ITEMS.contains(normalizedName)) {
|
|
|
|
|
+ dto.setOrderNursingAmount(nz(dto.getOrderNursingAmount()).add(extraAmount));
|
|
|
|
|
+ mergeAmount(dto.getOrderNursingItemStats(), itemName, extraAmount);
|
|
|
|
|
+ } else if (REPORT_EXTRA_SERVICE_ITEMS.contains(normalizedName)) {
|
|
|
|
|
+ dto.setOrderServiceAmount(nz(dto.getOrderServiceAmount()).add(extraAmount));
|
|
|
|
|
+ mergeAmount(dto.getOrderServiceItemStats(), itemName, extraAmount);
|
|
|
|
|
+ } else if (REPORT_OTHER_INCOME_ITEMS.contains(normalizedName)) {
|
|
|
|
|
+ dto.setOrderOtherIncomeAmount(nz(dto.getOrderOtherIncomeAmount()).add(extraAmount));
|
|
|
|
|
+ mergeAmount(dto.getOrderOtherIncomeItemStats(), itemName, extraAmount);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- BigDecimal extraAmount = dailyExpensesDO.getAmount() == null ? BigDecimal.ZERO : dailyExpensesDO.getAmount();
|
|
|
|
|
if (isWaterElectricityItem(itemName)) {
|
|
if (isWaterElectricityItem(itemName)) {
|
|
|
BigDecimal currentAmount = dto.getOrderWaterElectricityAmount() == null ? BigDecimal.ZERO : dto.getOrderWaterElectricityAmount();
|
|
BigDecimal currentAmount = dto.getOrderWaterElectricityAmount() == null ? BigDecimal.ZERO : dto.getOrderWaterElectricityAmount();
|
|
|
dto.setOrderWaterElectricityAmount(currentAmount.add(extraAmount));
|
|
dto.setOrderWaterElectricityAmount(currentAmount.add(extraAmount));
|
|
@@ -446,7 +517,12 @@ public class OrderApiImpl implements OrderApi {
|
|
|
dto.setExtraServiceAmount(dto.getExtraServiceAmount().add(extraAmount));
|
|
dto.setExtraServiceAmount(dto.getExtraServiceAmount().add(extraAmount));
|
|
|
}
|
|
}
|
|
|
dto.setAdjustAmount(dto.getAdjustAmount().add(extraAmount));
|
|
dto.setAdjustAmount(dto.getAdjustAmount().add(extraAmount));
|
|
|
- dto.setRemark((dto.getRemark() == null ? "" : dto.getRemark()) + (dailyExpensesDO.getRemarks() == null ? "" : dailyExpensesDO.getRemarks()) + itemName + ":" + dailyExpensesDO.getAmount().setScale(2,RoundingMode.HALF_UP) + ";");
|
|
|
|
|
|
|
+ dto.setRemark((dto.getRemark() == null ? "" : dto.getRemark())
|
|
|
|
|
+ + (dailyExpensesDO.getRemarks() == null ? "" : dailyExpensesDO.getRemarks())
|
|
|
|
|
+ + (itemName == null ? "" : itemName)
|
|
|
|
|
+ + ":"
|
|
|
|
|
+ + extraAmount.setScale(2, RoundingMode.HALF_UP)
|
|
|
|
|
+ + ";");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/** 判断是否为水电费相关项目 */
|
|
/** 判断是否为水电费相关项目 */
|
|
@@ -1040,6 +1116,7 @@ public class OrderApiImpl implements OrderApi {
|
|
|
.eq(ElderlyAskLeaveDO::getElderId, elderId)
|
|
.eq(ElderlyAskLeaveDO::getElderId, elderId)
|
|
|
.eq(ElderlyAskLeaveDO::getOutboundRefundConfigId, outboundConfig.getId())
|
|
.eq(ElderlyAskLeaveDO::getOutboundRefundConfigId, outboundConfig.getId())
|
|
|
.eq(ElderlyAskLeaveDO::getStatus, 0) // 0表示正常状态
|
|
.eq(ElderlyAskLeaveDO::getStatus, 0) // 0表示正常状态
|
|
|
|
|
+ .and(w -> w.ne(ElderlyAskLeaveDO::getLeaveStatus, 0).or().isNull(ElderlyAskLeaveDO::getLeaveStatus))
|
|
|
.le(ElderlyAskLeaveDO::getOutDate, monthEndDate) // 外出时间不能晚于月末
|
|
.le(ElderlyAskLeaveDO::getOutDate, monthEndDate) // 外出时间不能晚于月末
|
|
|
.and(wrapper -> wrapper
|
|
.and(wrapper -> wrapper
|
|
|
// 返回时间>=月初 或 返回时间为空(还在外出中)
|
|
// 返回时间>=月初 或 返回时间为空(还在外出中)
|
|
@@ -1096,6 +1173,7 @@ public class OrderApiImpl implements OrderApi {
|
|
|
.eq(ElderlyAskLeaveDO::getElderId, elderId)
|
|
.eq(ElderlyAskLeaveDO::getElderId, elderId)
|
|
|
.eq(ElderlyAskLeaveDO::getOutboundRefundConfigId, outboundConfig.getId())
|
|
.eq(ElderlyAskLeaveDO::getOutboundRefundConfigId, outboundConfig.getId())
|
|
|
.eq(ElderlyAskLeaveDO::getStatus, 0)
|
|
.eq(ElderlyAskLeaveDO::getStatus, 0)
|
|
|
|
|
+ .and(w -> w.ne(ElderlyAskLeaveDO::getLeaveStatus, 0).or().isNull(ElderlyAskLeaveDO::getLeaveStatus))
|
|
|
// 有时间交集:外出开始<=月底,返回时间>=月初或为空
|
|
// 有时间交集:外出开始<=月底,返回时间>=月初或为空
|
|
|
.le(ElderlyAskLeaveDO::getOutDate, monthEndDate)
|
|
.le(ElderlyAskLeaveDO::getOutDate, monthEndDate)
|
|
|
.and(w -> w.ge(ElderlyAskLeaveDO::getUpdateDate, monthStartDate).or().isNull(ElderlyAskLeaveDO::getUpdateDate))
|
|
.and(w -> w.ge(ElderlyAskLeaveDO::getUpdateDate, monthStartDate).or().isNull(ElderlyAskLeaveDO::getUpdateDate))
|
|
@@ -1490,6 +1568,15 @@ public class OrderApiImpl implements OrderApi {
|
|
|
vo.setNurseActualAmount(BigDecimal.ZERO);
|
|
vo.setNurseActualAmount(BigDecimal.ZERO);
|
|
|
vo.setServiceActualAmount(BigDecimal.ZERO);
|
|
vo.setServiceActualAmount(BigDecimal.ZERO);
|
|
|
vo.setTotalActualAmount(BigDecimal.ZERO);
|
|
vo.setTotalActualAmount(BigDecimal.ZERO);
|
|
|
|
|
+ vo.setOrderFoodAmount(BigDecimal.ZERO);
|
|
|
|
|
+ vo.setOrderShopAmount(BigDecimal.ZERO);
|
|
|
|
|
+ vo.setOrderNursingAmount(BigDecimal.ZERO);
|
|
|
|
|
+ vo.setOrderServiceAmount(BigDecimal.ZERO);
|
|
|
|
|
+ vo.setOrderWaterElectricityAmount(BigDecimal.ZERO);
|
|
|
|
|
+ vo.setOrderOtherIncomeAmount(BigDecimal.ZERO);
|
|
|
|
|
+ vo.setOrderNursingItemStats(new LinkedHashMap<>());
|
|
|
|
|
+ vo.setOrderServiceItemStats(new LinkedHashMap<>());
|
|
|
|
|
+ vo.setOrderOtherIncomeItemStats(new LinkedHashMap<>());
|
|
|
vo.setExtraServiceAmount(BigDecimal.ZERO);
|
|
vo.setExtraServiceAmount(BigDecimal.ZERO);
|
|
|
vo.setActualProportion("0%");
|
|
vo.setActualProportion("0%");
|
|
|
|
|
|
|
@@ -1531,6 +1618,15 @@ public class OrderApiImpl implements OrderApi {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
vo.setAdjustAmount(BigDecimal.ZERO);
|
|
vo.setAdjustAmount(BigDecimal.ZERO);
|
|
|
|
|
+ vo.setOrderFoodAmount(BigDecimal.ZERO);
|
|
|
|
|
+ vo.setOrderShopAmount(BigDecimal.ZERO);
|
|
|
|
|
+ vo.setOrderNursingAmount(BigDecimal.ZERO);
|
|
|
|
|
+ vo.setOrderServiceAmount(BigDecimal.ZERO);
|
|
|
|
|
+ vo.setOrderWaterElectricityAmount(BigDecimal.ZERO);
|
|
|
|
|
+ vo.setOrderOtherIncomeAmount(BigDecimal.ZERO);
|
|
|
|
|
+ vo.setOrderNursingItemStats(Collections.emptyMap());
|
|
|
|
|
+ vo.setOrderServiceItemStats(Collections.emptyMap());
|
|
|
|
|
+ vo.setOrderOtherIncomeItemStats(Collections.emptyMap());
|
|
|
vo.setExtraServiceAmount(BigDecimal.ZERO);
|
|
vo.setExtraServiceAmount(BigDecimal.ZERO);
|
|
|
BigDecimal total = nz(vo.getBedAmount()).add(nz(vo.getMealAmount())).add(nz(vo.getNurseAmount())).add(nz(vo.getServiceAmount()));
|
|
BigDecimal total = nz(vo.getBedAmount()).add(nz(vo.getMealAmount())).add(nz(vo.getNurseAmount())).add(nz(vo.getServiceAmount()));
|
|
|
vo.setTotalAmount(total);
|
|
vo.setTotalAmount(total);
|
|
@@ -1594,6 +1690,7 @@ public class OrderApiImpl implements OrderApi {
|
|
|
.in(ElderlyAskLeaveDO::getElderId, elderIds)
|
|
.in(ElderlyAskLeaveDO::getElderId, elderIds)
|
|
|
.eq(ElderlyAskLeaveDO::getOutboundRefundConfigId, outboundConfig.getId())
|
|
.eq(ElderlyAskLeaveDO::getOutboundRefundConfigId, outboundConfig.getId())
|
|
|
.eq(ElderlyAskLeaveDO::getStatus, 0)
|
|
.eq(ElderlyAskLeaveDO::getStatus, 0)
|
|
|
|
|
+ .and(w -> w.ne(ElderlyAskLeaveDO::getLeaveStatus, 0).or().isNull(ElderlyAskLeaveDO::getLeaveStatus))
|
|
|
.le(ElderlyAskLeaveDO::getOutDate, monthEndDate)
|
|
.le(ElderlyAskLeaveDO::getOutDate, monthEndDate)
|
|
|
.and(w -> w.ge(ElderlyAskLeaveDO::getUpdateDate, monthStartDate).or().isNull(ElderlyAskLeaveDO::getUpdateDate))
|
|
.and(w -> w.ge(ElderlyAskLeaveDO::getUpdateDate, monthStartDate).or().isNull(ElderlyAskLeaveDO::getUpdateDate))
|
|
|
.orderByAsc(ElderlyAskLeaveDO::getElderId, ElderlyAskLeaveDO::getOutDate)
|
|
.orderByAsc(ElderlyAskLeaveDO::getElderId, ElderlyAskLeaveDO::getOutDate)
|