|
|
@@ -31,6 +31,7 @@ import javax.annotation.Resource;
|
|
|
import javax.validation.Valid;
|
|
|
|
|
|
import java.util.*;
|
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
import java.math.BigDecimal;
|
|
|
@@ -50,6 +51,8 @@ public class GoViewDataController {
|
|
|
|
|
|
private static final int SCALE_TWO = 2;
|
|
|
|
|
|
+ private static final int SCALE_ZERO = 0;
|
|
|
+
|
|
|
private static BigDecimal scale2(BigDecimal v) {
|
|
|
if (v == null) {
|
|
|
return null;
|
|
|
@@ -188,15 +191,55 @@ public class GoViewDataController {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 获取当前机构的「账单金额单项取整设置」配置值
|
|
|
+ * 「账单金额单项取整设置」配置值缓存:配置为低频变更数据,避免每个报表接口都查库
|
|
|
+ */
|
|
|
+ private static final long AMOUNT_ROUND_CONFIG_CACHE_TTL_MS = 5 * 60 * 1000L;
|
|
|
+ private static final Map<Long, AmountRoundConfigCacheEntry> AMOUNT_ROUND_CONFIG_CACHE = new ConcurrentHashMap<>();
|
|
|
+
|
|
|
+ private static class AmountRoundConfigCacheEntry {
|
|
|
+ private final String value;
|
|
|
+ private final long expireAt;
|
|
|
+
|
|
|
+ AmountRoundConfigCacheEntry(String value, long expireAt) {
|
|
|
+ this.value = value;
|
|
|
+ this.expireAt = expireAt;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取当前机构的「账单金额单项取整设置」配置值(本地短期缓存)
|
|
|
*/
|
|
|
private String getAmountRoundConfigValue(Long tenantId) {
|
|
|
+ if (tenantId == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ long now = System.currentTimeMillis();
|
|
|
+ AmountRoundConfigCacheEntry entry = AMOUNT_ROUND_CONFIG_CACHE.get(tenantId);
|
|
|
+ if (entry != null && entry.expireAt > now) {
|
|
|
+ return entry.value;
|
|
|
+ }
|
|
|
+ String value;
|
|
|
try {
|
|
|
- return businessParamsConfigApi.getConfigValue(tenantId, AMOUNT_ROUND_CONFIG_TITLE, AMOUNT_ROUND_CONFIG_NAME);
|
|
|
+ value = businessParamsConfigApi.getConfigValue(tenantId, AMOUNT_ROUND_CONFIG_TITLE, AMOUNT_ROUND_CONFIG_NAME);
|
|
|
} catch (Exception e) {
|
|
|
- // 配置获取失败时,保持现状,不影响报表查询
|
|
|
+ // 配置获取失败时,保持现状,不影响报表查询;不缓存,下次继续尝试
|
|
|
return null;
|
|
|
}
|
|
|
+ AMOUNT_ROUND_CONFIG_CACHE.put(tenantId, new AmountRoundConfigCacheEntry(value, now + AMOUNT_ROUND_CONFIG_CACHE_TTL_MS));
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 配置值转换为小数保留位数:4-保留两位小数;2-四舍五入取整;其它-不做处理
|
|
|
+ */
|
|
|
+ private static Integer toRoundScale(String configValue) {
|
|
|
+ if (AMOUNT_ROUND_VALUE_TWO_SCALE.equals(configValue)) {
|
|
|
+ return SCALE_TWO;
|
|
|
+ }
|
|
|
+ if (AMOUNT_ROUND_VALUE_INTEGER.equals(configValue)) {
|
|
|
+ return SCALE_ZERO;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
}
|
|
|
|
|
|
private OrderSubListGroupedRespVO loadOrComputeGrouped(Long tenantId, String billingMonth, Integer payStatus) {
|
|
|
@@ -210,7 +253,7 @@ public class GoViewDataController {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- List<OrderItemRespVO> listByMonth = orderApi.getOrderSubListForReport(null, tenantId, billingMonth, payStatus);
|
|
|
+ List<OrderItemRespVO> listByMonth = orderApi.getOrderSubListForReport(1, tenantId, billingMonth, payStatus);
|
|
|
OrderSubListGroupedRespVO grouped = new OrderSubListGroupedRespVO();
|
|
|
if (!CollectionUtils.isEmpty(listByMonth)) {
|
|
|
// 按当前机构的「账单金额单项取整设置」配置,处理金额小数位
|
|
|
@@ -343,9 +386,14 @@ public class GoViewDataController {
|
|
|
@RequestParam(required = false) Map<String, String> params,
|
|
|
@RequestBody(required = false) String body) { // params、body 按照需要去接收,这里仅仅是示例
|
|
|
String billingMonth = params.get("billingMonth");
|
|
|
+ Long tenantId = getTenantId(params);
|
|
|
Integer payStatus = params.get("payStatus") == null ? null : Integer.valueOf(params.get("payStatus"));
|
|
|
- OrderItemTotalRespVO orderItemTotalRespVO = orderApi.getTotalByMonth(null, getTenantId(params), billingMonth,payStatus);
|
|
|
- scale2OrderTotal(orderItemTotalRespVO);
|
|
|
+ // 配置了小数保留位数时:由取数侧先对每项金额处理小数,再进行汇总(一次取数完成,不再二次取数)
|
|
|
+ Integer roundScale = toRoundScale(getAmountRoundConfigValue(tenantId));
|
|
|
+ OrderItemTotalRespVO orderItemTotalRespVO = orderApi.getTotalByMonth(1, tenantId, billingMonth, payStatus, roundScale);
|
|
|
+ if (roundScale == null) {
|
|
|
+ scale2OrderTotal(orderItemTotalRespVO);
|
|
|
+ }
|
|
|
List<OrderItemTotalRespVO> list = new ArrayList<>();
|
|
|
list.add(orderItemTotalRespVO);
|
|
|
return success(list);
|
|
|
@@ -375,9 +423,14 @@ public class GoViewDataController {
|
|
|
String billingMonth = params.get("billingMonth");
|
|
|
List<OrderItemTotalRespVO> list = new ArrayList<>();
|
|
|
if (null == billingMonth) return success(list);
|
|
|
+ Long tenantId = getTenantId(params);
|
|
|
Integer payStatus = params.get("payStatus") == null ? null : Integer.valueOf(params.get("payStatus"));
|
|
|
- OrderItemTotalRespVO orderItemTotalRespVO = orderApi.getOrderReceivableTotal(null, getTenantId(params), billingMonth,payStatus);
|
|
|
- scale2OrderTotal(orderItemTotalRespVO);
|
|
|
+ // 配置了小数保留位数时:由取数侧先对每项金额处理小数,再进行汇总(复用原有取数,不重复遍历月份)
|
|
|
+ Integer roundScale = toRoundScale(getAmountRoundConfigValue(tenantId));
|
|
|
+ OrderItemTotalRespVO orderItemTotalRespVO = orderApi.getOrderReceivableTotal(null, tenantId, billingMonth, payStatus, roundScale);
|
|
|
+ if (roundScale == null) {
|
|
|
+ scale2OrderTotal(orderItemTotalRespVO);
|
|
|
+ }
|
|
|
list.add(orderItemTotalRespVO);
|
|
|
return success(list);
|
|
|
}
|
|
|
@@ -386,6 +439,7 @@ public class GoViewDataController {
|
|
|
// 新增:仅汇总在住(本地缓存聚合)
|
|
|
@RequestMapping("/getOrderSubTotalIn")
|
|
|
@Operation(summary = "查询在住汇总", description = "仅汇总在住记录 (本地缓存聚合)")
|
|
|
+ @TenantIgnore
|
|
|
public CommonResult<List<OrderItemTotalRespVO>> getOrderSubTotalIn(
|
|
|
@RequestParam(required = false) Map<String, String> params,
|
|
|
@RequestBody(required = false) String body) {
|
|
|
@@ -393,14 +447,17 @@ public class GoViewDataController {
|
|
|
Integer payStatus = params.get("payStatus") == null ? null : Integer.valueOf(params.get("payStatus"));
|
|
|
Long tenantId = getTenantId(params);
|
|
|
OrderSubListGroupedRespVO grouped = loadOrComputeGrouped(tenantId, billingMonth, payStatus);
|
|
|
- OrderItemTotalRespVO total = aggregate(grouped.getInList(), billingMonth);
|
|
|
- roundOrderTotalByConfig(total, getAmountRoundConfigValue(tenantId));
|
|
|
+ // 先对每项金额处理小数,再进行汇总
|
|
|
+ String roundConfigValue = getAmountRoundConfigValue(tenantId);
|
|
|
+ OrderItemTotalRespVO total = aggregate(grouped.getInList(), billingMonth, roundConfigValue);
|
|
|
+ roundOrderTotalByConfig(total, roundConfigValue);
|
|
|
return success(java.util.Collections.singletonList(total));
|
|
|
}
|
|
|
|
|
|
// 新增:仅汇总离住
|
|
|
@RequestMapping("/getOrderSubTotalLeave")
|
|
|
@Operation(summary = "查询离住汇总", description = "仅汇总离住记录 (本地缓存聚合)")
|
|
|
+ @TenantIgnore
|
|
|
public CommonResult<List<OrderItemTotalRespVO>> getOrderSubTotalLeave(
|
|
|
@RequestParam(required = false) Map<String, String> params,
|
|
|
@RequestBody(required = false) String body) {
|
|
|
@@ -408,14 +465,17 @@ public class GoViewDataController {
|
|
|
Integer payStatus = params.get("payStatus") == null ? null : Integer.valueOf(params.get("payStatus"));
|
|
|
Long tenantId = getTenantId(params);
|
|
|
OrderSubListGroupedRespVO grouped = loadOrComputeGrouped(tenantId, billingMonth, payStatus);
|
|
|
- OrderItemTotalRespVO total = aggregate(grouped.getLeaveList(), billingMonth);
|
|
|
- roundOrderTotalByConfig(total, getAmountRoundConfigValue(tenantId));
|
|
|
+ // 先对每项金额处理小数,再进行汇总
|
|
|
+ String roundConfigValue = getAmountRoundConfigValue(tenantId);
|
|
|
+ OrderItemTotalRespVO total = aggregate(grouped.getLeaveList(), billingMonth, roundConfigValue);
|
|
|
+ roundOrderTotalByConfig(total, roundConfigValue);
|
|
|
return success(java.util.Collections.singletonList(total));
|
|
|
}
|
|
|
|
|
|
// 新增:仅汇总退住
|
|
|
@RequestMapping("/getOrderSubTotalRetreat")
|
|
|
@Operation(summary = "查询退住汇总", description = "仅汇总退住记录 (本地缓存聚合)")
|
|
|
+ @TenantIgnore
|
|
|
public CommonResult<List<OrderItemTotalRespVO>> getOrderSubTotalRetreat(
|
|
|
@RequestParam(required = false) Map<String, String> params,
|
|
|
@RequestBody(required = false) String body) {
|
|
|
@@ -423,31 +483,40 @@ public class GoViewDataController {
|
|
|
Integer payStatus = params.get("payStatus") == null ? null : Integer.valueOf(params.get("payStatus"));
|
|
|
Long tenantId = getTenantId(params);
|
|
|
OrderSubListGroupedRespVO grouped = loadOrComputeGrouped(tenantId, billingMonth, payStatus);
|
|
|
- OrderItemTotalRespVO total = aggregate(grouped.getRetreatList(), billingMonth);
|
|
|
- roundOrderTotalByConfig(total, getAmountRoundConfigValue(tenantId));
|
|
|
+ // 先对每项金额处理小数,再进行汇总
|
|
|
+ String roundConfigValue = getAmountRoundConfigValue(tenantId);
|
|
|
+ OrderItemTotalRespVO total = aggregate(grouped.getRetreatList(), billingMonth, roundConfigValue);
|
|
|
+ roundOrderTotalByConfig(total, roundConfigValue);
|
|
|
return success(java.util.Collections.singletonList(total));
|
|
|
}
|
|
|
|
|
|
- // Helper:本地聚合
|
|
|
- private OrderItemTotalRespVO aggregate(List<OrderItemRespVO> src, String billingMonth) {
|
|
|
+ /**
|
|
|
+ * Helper:本地聚合
|
|
|
+ * 如果配置了小数保留位数(roundConfigValue),则先对每项金额做小数处理,再进行汇总,
|
|
|
+ * 保证「汇总金额 = 各项金额之和」(而不是先汇总再对合计做小数处理)
|
|
|
+ */
|
|
|
+ private OrderItemTotalRespVO aggregate(List<OrderItemRespVO> src, String billingMonth, String roundConfigValue) {
|
|
|
OrderItemTotalRespVO t = new OrderItemTotalRespVO();
|
|
|
t.setBillingMonth(billingMonth);
|
|
|
if (src == null || src.isEmpty()) {
|
|
|
return t;
|
|
|
}
|
|
|
for (OrderItemRespVO vo : src) {
|
|
|
- t.setBedTotalAmount(t.getBedTotalAmount().add(nz(vo.getBedAmount())));
|
|
|
- t.setMealTotalAmount(t.getMealTotalAmount().add(nz(vo.getMealAmount())));
|
|
|
- t.setNurseTotalAmount(t.getNurseTotalAmount().add(nz(vo.getNurseAmount())));
|
|
|
- t.setServiceTotalAmount(t.getServiceTotalAmount().add(nz(vo.getServiceAmount())));
|
|
|
- t.setTotalAmount(t.getTotalAmount().add(nz(vo.getTotalAmount())));
|
|
|
- t.setAdjustTotalAmount(t.getAdjustTotalAmount().add(nz(vo.getAdjustAmount())));
|
|
|
- t.setBedActualTotalAmount(t.getBedActualTotalAmount().add(nz(vo.getBedActualAmount())));
|
|
|
- t.setMealActualTotalAmount(t.getMealActualTotalAmount().add(nz(vo.getMealActualAmount())));
|
|
|
- t.setNurseActualTotalAmount(t.getNurseActualTotalAmount().add(nz(vo.getNurseActualAmount())));
|
|
|
- t.setServiceActualTotalAmount(t.getServiceActualTotalAmount().add(nz(vo.getServiceActualAmount())));
|
|
|
- t.setTotalActualAmount(t.getTotalActualAmount().add(nz(vo.getTotalActualAmount())));
|
|
|
- t.setExtraServiceAmount(t.getExtraServiceAmount().add(nz(vo.getExtraServiceAmount())));
|
|
|
+ if (vo == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ t.setBedTotalAmount(t.getBedTotalAmount().add(nz(roundByConfig(vo.getBedAmount(), roundConfigValue))));
|
|
|
+ t.setMealTotalAmount(t.getMealTotalAmount().add(nz(roundByConfig(vo.getMealAmount(), roundConfigValue))));
|
|
|
+ t.setNurseTotalAmount(t.getNurseTotalAmount().add(nz(roundByConfig(vo.getNurseAmount(), roundConfigValue))));
|
|
|
+ t.setServiceTotalAmount(t.getServiceTotalAmount().add(nz(roundByConfig(vo.getServiceAmount(), roundConfigValue))));
|
|
|
+ t.setTotalAmount(t.getTotalAmount().add(nz(roundByConfig(vo.getTotalAmount(), roundConfigValue))));
|
|
|
+ t.setAdjustTotalAmount(t.getAdjustTotalAmount().add(nz(roundByConfig(vo.getAdjustAmount(), roundConfigValue))));
|
|
|
+ t.setBedActualTotalAmount(t.getBedActualTotalAmount().add(nz(roundByConfig(vo.getBedActualAmount(), roundConfigValue))));
|
|
|
+ t.setMealActualTotalAmount(t.getMealActualTotalAmount().add(nz(roundByConfig(vo.getMealActualAmount(), roundConfigValue))));
|
|
|
+ t.setNurseActualTotalAmount(t.getNurseActualTotalAmount().add(nz(roundByConfig(vo.getNurseActualAmount(), roundConfigValue))));
|
|
|
+ t.setServiceActualTotalAmount(t.getServiceActualTotalAmount().add(nz(roundByConfig(vo.getServiceActualAmount(), roundConfigValue))));
|
|
|
+ t.setTotalActualAmount(t.getTotalActualAmount().add(nz(roundByConfig(vo.getTotalActualAmount(), roundConfigValue))));
|
|
|
+ t.setExtraServiceAmount(t.getExtraServiceAmount().add(nz(roundByConfig(vo.getExtraServiceAmount(), roundConfigValue))));
|
|
|
}
|
|
|
if (t.getTotalAmount().compareTo(java.math.BigDecimal.ZERO) > 0) {
|
|
|
java.math.BigDecimal p = t.getTotalActualAmount().divide(t.getTotalAmount(),2,java.math.RoundingMode.HALF_UP).multiply(new java.math.BigDecimal("100"));
|