fix(lease): 修复仓库出租率导出总面积、日租率计算错误

导出时总面积被算成全系统所有仓库库区面积之和(6168),日租率因此也错误(0.16)。
根因:导出方法调用 warehouseOccupancyRate(),该方法在不传 warehouseId 时
totalArea 会累加所有仓库面积。

- 导出方法不再调用 warehouseOccupancyRate(),改为自行按(业务日期+仓库)维度计算
- 总面积按仓库单独累加库区面积(通宇关务测试仓库 100,不再 6168)
- 整租/散租面积按(日期+仓库)聚合
- 日租率 = (整租+散租)/该仓库总面积×100,直接输出百分比(10.00)
- 增加总面积为0的除零保护
- 查询接口 warehouseOccupancyRate() 不受影响
This commit is contained in:
rcx
2026-08-13 17:43:44 +08:00
parent e35fa7d48e
commit 3240e57c3e
@@ -508,24 +508,53 @@ public class LeaseApplicationService {
* 参数与 /warehouseOccupancyRate、/list 一致
*/
public void exportOccupancyRate(HttpServletResponse response, ShipperLeaseDetailsDO shipperLeaseDetailsDO) throws IOException {
// ===== 1. 查出租率(注意:方法内部会修改传入的 DO,所以先查它)=====
List<WarehouseOccupancyRate> rateList = warehouseOccupancyRate(shipperLeaseDetailsDO);
// 注意:方法不调用 warehouseOccupancyRate(),因为该方法在不传 warehouseId 时
// totalArea 会算成全系统所有仓库库区面积之和(如 6168),导致导出面积/日租率错误。
// 这里自行按 (业务日期 + 仓库) 维度计算,保证多仓库导出时每个仓库的面积/日租率正确。
// ===== 2. 用副本查明细,避免被上面改过的 DO 影响 =====
// ===== 1. 查全部明细(用副本 DO,避免影响外部)=====
ShipperLeaseDetailsDO detailDO = new ShipperLeaseDetailsDO();
BeanUtils.copyProperties(shipperLeaseDetailsDO, detailDO);
List<ShipperLeaseDetailsPO> detailList = shipperLeaseDetailsService.queryList(detailDO);
// ===== 3. 出租率按 (业务日期 + 仓库ID) 建映射,方便明细行查汇总 =====
SimpleDateFormat keySdf = new SimpleDateFormat("yyyy-MM-dd");
Map<String, WarehouseOccupancyRate> rateMap = new HashMap<>();
for (WarehouseOccupancyRate r : rateList) {
String key = (r.getBusinessDate() == null ? "" : keySdf.format(r.getBusinessDate()))
+ "_" + r.getWarehouseId();
rateMap.put(key, r);
if (detailList == null) {
detailList = new ArrayList<>();
}
// ===== 4. 明细为主,每行拼上对应仓库当天的汇总 =====
// ===== 2. 预算每个仓库的总面积(启用库区的 storageRegion 累加),建 warehouseId -> totalArea 映射 =====
Set<Long> warehouseIds = detailList.stream()
.map(ShipperLeaseDetailsPO::getWarehouseId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
Map<Long, BigDecimal> warehouseTotalAreaMap = new HashMap<>();
for (Long wid : warehouseIds) {
StorageSectionDO storageSectionDO = new StorageSectionDO();
storageSectionDO.setWarehouseId(wid);
storageSectionDO.setOpeningUp(1);
List<StorageSectionPO> sections = storageSectionApplicationService.queryList(storageSectionDO);
BigDecimal area = BigDecimal.ZERO;
for (StorageSectionPO s : sections) {
area = area.add(s.getStorageRegion() == null ? BigDecimal.ZERO : s.getStorageRegion());
}
warehouseTotalAreaMap.put(wid, area);
}
// ===== 3. 按 (业务日期 + 仓库ID) 聚合,算每个仓库当天的整租/散租面积 =====
// summaryMap: key -> [整租面积, 散租面积]
SimpleDateFormat keySdf = new SimpleDateFormat("yyyy-MM-dd");
Map<String, BigDecimal[]> summaryMap = new HashMap<>();
for (ShipperLeaseDetailsPO d : detailList) {
String key = (d.getBusinessDate() == null ? "" : keySdf.format(d.getBusinessDate()))
+ "_" + d.getWarehouseId();
BigDecimal[] arr = summaryMap.computeIfAbsent(key, k -> new BigDecimal[]{BigDecimal.ZERO, BigDecimal.ZERO});
BigDecimal leaseArea = d.getLeaseArea() == null ? BigDecimal.ZERO : d.getLeaseArea();
if ("整租".equals(d.getLeaseType())) {
arr[0] = arr[0].add(leaseArea);
} else {
arr[1] = arr[1].add(leaseArea);
}
}
// ===== 4. 明细为主,每行拼上对应仓库当天的汇总(总面积/日租率按仓库单独算)=====
List<WarehouseLeaseExportVO> exportList = new ArrayList<>();
for (ShipperLeaseDetailsPO d : detailList) {
WarehouseLeaseExportVO vo = new WarehouseLeaseExportVO();
@@ -536,20 +565,27 @@ public class LeaseApplicationService {
vo.setCargoOwnerName(d.getCargoOwnerName());
vo.setLeaseType(d.getLeaseType());
vo.setLeaseArea(d.getLeaseArea());
// 汇总列(从映射取,找不到就留空)
// 汇总列
String key = (d.getBusinessDate() == null ? "" : keySdf.format(d.getBusinessDate()))
+ "_" + d.getWarehouseId();
WarehouseOccupancyRate r = rateMap.get(key);
if (r != null) {
vo.setEntireLeaseArea(r.getEntireLeaseArea());
vo.setFractionalLeaseArea(r.getFractionalLeaseArea());
vo.setTotalArea(r.getTotalArea());
vo.setDailyRentalRate(r.getDailyRentalRate());
}
BigDecimal[] arr = summaryMap.get(key);
BigDecimal entireLeaseArea = (arr != null) ? arr[0] : BigDecimal.ZERO;
BigDecimal fractionalLeaseArea = (arr != null) ? arr[1] : BigDecimal.ZERO;
vo.setEntireLeaseArea(entireLeaseArea);
vo.setFractionalLeaseArea(fractionalLeaseArea);
// 该仓库的总面积(按仓库单独算,不再用全局总和)
BigDecimal widTotalArea = warehouseTotalAreaMap.getOrDefault(d.getWarehouseId(), BigDecimal.ZERO);
vo.setTotalArea(widTotalArea);
// 日租率 = (整租+散租) / 总面积 × 100,保留2位小数(直接输出百分比值,如 10.00)
BigDecimal leaseSum = entireLeaseArea.add(fractionalLeaseArea);
BigDecimal dailyRate = widTotalArea.compareTo(BigDecimal.ZERO) == 0
? BigDecimal.ZERO
: leaseSum.multiply(new BigDecimal("100")).divide(widTotalArea, 2, BigDecimal.ROUND_HALF_UP);
vo.setDailyRentalRate(dailyRate);
exportList.add(vo);
}
// ===== 5. 按业务日期降序排序(null 排最后)=====
// ===== 5. 按业务日期降序、仓库名升序排序(null 排最后)=====
exportList.sort(Comparator
.comparing(WarehouseLeaseExportVO::getBusinessDate, Comparator.nullsLast(Comparator.reverseOrder()))
.thenComparing(WarehouseLeaseExportVO::getWarehouseName, Comparator.nullsLast(Comparator.naturalOrder())));