# HkEfficiencySumServiceImpl.java

    package cloud.wconnect.workperformance.service.hkefficiency.impl;

    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.workperformance.cons.hkefficiency.HkEfficiencyConstant;
    import cloud.wconnect.workperformance.entity.hkefficiency.HkEfficiency;
    import cloud.wconnect.workperformance.entity.hkefficiency.HkEfficiencySum;
    import cloud.wconnect.workperformance.mapper.hkefficiency.HkEfficiencySumMapper;
    import cloud.wconnect.workperformance.service.hkefficiency.IHkEfficiencyService;
    import cloud.wconnect.workperformance.service.hkefficiency.IHkEfficiencySumService;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import org.apache.commons.collections.CollectionUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Lazy;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.math.BigDecimal;
    import java.util.*;
    import java.util.function.Function;
    import java.util.stream.Collectors;

    /**
     * <p>
     * 服务实现类：Housekeeping Efficiency 每月统计
     * </p>
     *
     * @author zc
     * @since 2023-03-29
     */
    @Service
    @DS("work_performance")
    public class HkEfficiencySumServiceImpl extends ServiceImpl<HkEfficiencySumMapper, HkEfficiencySum> implements IHkEfficiencySumService {

        @Autowired
        @Lazy
        private IHkEfficiencyService hkEfficiencyService;

        /**
         * 获取指定月的 Housekeeping Efficiency 每月统计数据
         *
         * @param propertyId   property id
         * @param targetMonths 目标月份
         * @return Housekeeping Efficiency 每月统计数据
         * @author zc
         * @date 2023/3/30
         */
        @Override
        public List<HkEfficiencySum> list(int propertyId, List<Long> targetMonths) {
            return list(new QueryWrapper<HkEfficiencySum>().lambda()
                    .eq(HkEfficiencySum::getPropertyId, propertyId)
                    .in(HkEfficiencySum::getStartOfMonth, targetMonths));
        }

        /**
         * 获取月开始日-时间范围的 Housekeeping Efficiency 每月统计数据
         *
         * @param propertyIds             property ids
         * @param startDateByStartOfMonth 开始时间
         * @param endDateByStartOfMonth   结束时间
         * @return Housekeeping Efficiency 每月统计数据
         * @author lichen
         * @date 2025/11/25
         */
        @Override
        public List<HkEfficiencySum> listByStartOfMonthRange(List<Integer> propertyIds, long startDateByStartOfMonth, long endDateByStartOfMonth) {
            if (CollectionUtils.isEmpty(propertyIds)) return Collections.emptyList();
            return list(new QueryWrapper<HkEfficiencySum>().lambda()
                    .in(HkEfficiencySum::getPropertyId, propertyIds)
                    .between(HkEfficiencySum::getStartOfMonth, startDateByStartOfMonth, endDateByStartOfMonth));
        }

        /**
         * 处理汇总数据
         *
         * @param propertyDTOList          资产集合
         * @param propertyId2StartOfMonths 资产对应的月开始日集合
         * @author lichen
         * @date 2025/11/25
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void handleHkEfficiencySum(List<PropertyDTO> propertyDTOList, Map<Integer, List<Long>> propertyId2StartOfMonths) {
            Set<Long> startOfMonths = propertyId2StartOfMonths.values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
            Long minStartOfMonth = Collections.min(startOfMonths);
            Long maxStartOfMonth = Collections.max(startOfMonths);

            Map<Integer, PropertyDTO> propertyId2DTO = propertyDTOList.stream().collect(Collectors.toMap(PropertyDTO::getId, Function.identity()));
            List<Integer> propertyIds = propertyDTOList.stream().map(PropertyDTO::getId).toList();

            // 查询原来的汇总数据
            Map<Integer, Map<Long, HkEfficiencySum>> propertyId2StartOfMonth2OriginData = listByStartOfMonthRange(propertyIds, minStartOfMonth, maxStartOfMonth)
                    .stream().collect(Collectors.groupingBy(HkEfficiencySum::getPropertyId, Collectors.toMap(HkEfficiencySum::getStartOfMonth, Function.identity())));

            // 查询HkEfficiency数据
            Map<Integer, Map<Long, List<HkEfficiency>>> propertyId2StartOfMonth2HkEfficiencys = hkEfficiencyService.listByStartOfMonthRange(propertyIds, minStartOfMonth, maxStartOfMonth)
                    .stream().collect(Collectors.groupingBy(HkEfficiency::getPropertyId, Collectors.groupingBy(HkEfficiency::getStartOfMonth)));

            List<HkEfficiencySum> insertBatch = new ArrayList<>();
            List<HkEfficiencySum> updateBatch = new ArrayList<>();

            propertyId2StartOfMonths.forEach((propertyId, startOfMonthsByPropertyId) -> {
                PropertyDTO propertyDTO = propertyId2DTO.get(propertyId);
                // 获取指定资产的汇总数据
                Map<Long, HkEfficiencySum> startOfMonth2OriginData = propertyId2StartOfMonth2OriginData.getOrDefault(propertyId, Collections.emptyMap());
                // 获取指定资产的HkEfficiency数据
                Map<Long, List<HkEfficiency>> startOfMonth2HkEfficiencys = propertyId2StartOfMonth2HkEfficiencys.getOrDefault(propertyId, Collections.emptyMap());

                for (Long startOfMonth : startOfMonthsByPropertyId) {
                    // 获取指定资产指定月开始日的汇总数据
                    HkEfficiencySum originData = startOfMonth2OriginData.get(startOfMonth);
                    // 获取指定资产指定月开始日的HkEfficiency数据
                    List<HkEfficiency> hkEfficiencys = startOfMonth2HkEfficiencys.getOrDefault(startOfMonth, Collections.emptyList());

                    Integer totalRoomsRented = null;
                    BigDecimal totalHours = null;
                    for (HkEfficiency existHkEfficiency : hkEfficiencys) {
                        // 如果当天信息完整、入住房间数有值且实际工时有值，则当天的数据参与统计计算
                        Map<String, Object> map = hkEfficiencyService.checkAndCumulative(existHkEfficiency);
                        if (!map.isEmpty()) {
                            totalRoomsRented = Objects.isNull(totalRoomsRented) ? 0 : totalRoomsRented;
                            totalRoomsRented += Integer.parseInt(map.get(HkEfficiencyConstant.ROOMS_RENTED).toString());

                            totalHours = Objects.isNull(totalHours) ? BigDecimal.ZERO : totalHours;
                            totalHours = totalHours.add(new BigDecimal(map.get(HkEfficiencyConstant.TOTAL_HOURS).toString()));
                        }
                    }

                    if (Objects.isNull(originData)) {
                        // 新增
                        HkEfficiencySum hkEfficiencySum = new HkEfficiencySum();
                        hkEfficiencySum.setPropertyId(propertyId);
                        hkEfficiencySum.setTheYear(DateTimeUtils.longToLocalDate(startOfMonth, propertyDTO.getTimezone()).getYear());
                        hkEfficiencySum.setStartOfMonth(startOfMonth);
                        hkEfficiencySum.setRoomsRentedTotal(totalRoomsRented);
                        hkEfficiencySum.setHourTotal(totalHours);
                        insertBatch.add(hkEfficiencySum);
                    } else {
                        // 修改
                        originData.setRoomsRentedTotal(totalRoomsRented);
                        originData.setHourTotal(totalHours);
                        updateBatch.add(originData);
                    }
                }
            });
            saveBatch(insertBatch);
            if(CollectionUtils.isNotEmpty(updateBatch)){
                baseMapper.batchUpdateWithNull(updateBatch);
            }
        }

    }