# PropertyMonthlyReportSetServiceImpl.java

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

    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.cons.CommonErrorI18nConstant;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.util.JsonUtils;
    import cloud.wconnect.commonlib.util.S3Utils;
    import cloud.wconnect.commonlib.util.TransactionUtils;
    import cloud.wconnect.workperformance.cons.S3BucketFunctionCons;
    import cloud.wconnect.workperformance.cons.monthlyreport.AreaEnum;
    import cloud.wconnect.workperformance.entity.monthlyreport.*;
    import cloud.wconnect.workperformance.mapper.monthlyreport.PropertyMonthlyReportSetMapper;
    import cloud.wconnect.workperformance.service.monthlyreport.*;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.google.common.collect.Lists;
    import org.apache.commons.collections.CollectionUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.Lazy;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.text.MessageFormat;
    import java.util.*;
    import java.util.concurrent.Executor;

    /**
     * <p>
     * 资产月报配置表 服务实现类
     * </p>
     *
     * @author lichen
     * @since 2023-09-01
     */
    @Service
    @DS("monthly_report")
    public class PropertyMonthlyReportSetServiceImpl extends ServiceImpl<PropertyMonthlyReportSetMapper, PropertyMonthlyReportSet> implements IPropertyMonthlyReportSetService {

        @Autowired
        private ObjectMapper objectMapper;
        @Lazy
        @Autowired
        private IMonthlyReportService monthlyReportService;
        @Autowired
        private ApplicationContext applicationContext;
        @Autowired
        private IReportAttachmentService reportAttachmentService;
        @Autowired
        private IReportRemarkService reportRemarkService;
        @Value("${aws-s3.region}")
        private String region;
        @Value("#{${aws-s3.function-bucket}}")
        private Map<String, Map<String, Object>> bucketMap;
        @Autowired
        private Executor executor;

        /**
         * 校验资产是否配置区域
         *
         * @param propertyId 资产id
         * @return cloud.wconnect.workperformance.entity.monthlyreport.PropertyMonthlyReportSet
         * @author lichen
         * @date 2023/9/2
         */
        @Override
        public PropertyMonthlyReportSet checkSettingExist(Integer propertyId) {
            PropertyMonthlyReportSet propertyMonthlyReportSet = getOne(new LambdaQueryWrapper<PropertyMonthlyReportSet>()
                    .eq(PropertyMonthlyReportSet::getPropertyId, propertyId));
            if (Objects.isNull(propertyMonthlyReportSet)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_FOUND, BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        MessageFormat.format("The property monthly report area setting not found, propertyId:{0}", propertyId));
            }
            return propertyMonthlyReportSet;
        }

        /**
         * 保存资产配置区域
         *
         * @param propertyDTO 资产DTO
         * @param areaIds     区域id集合
         * @param loginUserId 登录用户id
         * @return void
         * @author lichen
         * @date 2023/9/5
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void savePropertySetting(PropertyDTO propertyDTO, List<Integer> areaIds, int loginUserId) {
            //查询原来的配置
            PropertyMonthlyReportSet oriPropertyMonthlyReportSet = getOne(new LambdaQueryWrapper<PropertyMonthlyReportSet>()
                    .eq(PropertyMonthlyReportSet::getPropertyId, propertyDTO.getId()));
            if (Objects.isNull(oriPropertyMonthlyReportSet)) {
                //新增
                save(PropertyMonthlyReportSet.builder()
                        .tenantId(propertyDTO.getTenantId())
                        .propertyId(propertyDTO.getId())
                        .areaIds(JsonUtils.convertObjListToString(objectMapper, areaIds))
                        .build());
            } else {
                List<Integer> oriAreaIds = JsonUtils.convertStringToList(objectMapper, oriPropertyMonthlyReportSet.getAreaIds(), Integer.class);
                //修改
                updateById(PropertyMonthlyReportSet.builder()
                        .id(oriPropertyMonthlyReportSet.getId())
                        .areaIds(JsonUtils.convertObjListToString(objectMapper, areaIds))
                        .build());
                /**
                 * 资产配置区域发生变化后，只影响当前使用（上个月）和未来的月报，历史的月报不影响
                 */
                List<MonthlyReport> monthlyReports = monthlyReportService.listUsingAndFuture(propertyDTO.getId(), propertyDTO.getTimezone());
                if (CollectionUtils.isEmpty(monthlyReports)) return;

                //批量修改月报的区域id
                monthlyReports.forEach(item -> item.setAreaIds(JsonUtils.convertObjListToString(objectMapper, areaIds)));
                monthlyReportService.updateBatchById(monthlyReports);

                //计算出删除的区域id(删除的区域id集合 = 原来设置的区域id集合 删除掉 新设置的区域id集合)
                List<Integer> delAreaIds = Lists.newArrayList(oriAreaIds);
                delAreaIds.removeAll(areaIds);
                if (CollectionUtils.isNotEmpty(delAreaIds)) {
                    //删除区域的数据
                    deleteAreaData(delAreaIds, monthlyReports, propertyDTO);
                }

                //计算出新增的区域id(新增的区域id集合 = 新设置的区域id集合 删除掉 原来设置的区域id集合)
                List<Integer> insertAreaIds = Lists.newArrayList(areaIds);
                insertAreaIds.removeAll(oriAreaIds);
                if (CollectionUtils.isNotEmpty(insertAreaIds)) {
                    //新增区域时，初始化区域对应的数据
                    monthlyReportService.initAreaData(insertAreaIds, monthlyReports, propertyDTO);
                }
            }
        }

        /**
         * 根据资产id查询资产配置区域
         *
         * @param propertyId 资产id
         * @return cloud.wconnect.workperformance.entity.monthlyreport.PropertyMonthlyReportSet
         * @author lichen
         * @date 2025/12/30
         */
        @Override
        public PropertyMonthlyReportSet getByPropertyId(int propertyId) {
            return getOne(new LambdaQueryWrapper<PropertyMonthlyReportSet>()
                    .eq(PropertyMonthlyReportSet::getPropertyId, propertyId));
        }

        /**
         * 删除区域数据
         *
         * @param delAreaIds     删除的区域id集合
         * @param monthlyReports 月报集合
         * @param propertyDTO    资产DTO
         * @return void
         * @author lichen
         * @date 2023/9/5
         */
        private void deleteAreaData(List<Integer> delAreaIds, List<MonthlyReport> monthlyReports, PropertyDTO propertyDTO) {
            List<Long> monthlyReportIds = monthlyReports.stream().map(MonthlyReport::getId).toList();
            //过滤出要删除的区域对应的业务层
            List<String> delServiceImpls = Arrays.stream(AreaEnum.values())
                    .filter(areaEnum -> delAreaIds.contains(areaEnum.getAreaId()) && StringUtils.isNotBlank(areaEnum.getDelServiceImpls()))
                    .map(AreaEnum::getDelServiceImpls)
                    .flatMap(item -> Arrays.stream(item.split(",")))
                    .toList();
            delServiceImpls.forEach(serviceImpl -> {
                IHandlePropertySettingChange handlePropertySettingChange = (IHandlePropertySettingChange) applicationContext.getBean(serviceImpl);
                //删除区域对应的数据
                handlePropertySettingChange.delete(propertyDTO, monthlyReports);
            });

            //查询要删除的附件s3key集合
            List<ReportAttachment> reportAttachments = reportAttachmentService.list(new LambdaQueryWrapper<ReportAttachment>()
                    .in(ReportAttachment::getReportId, monthlyReportIds)
                    .in(ReportAttachment::getAreaId, delAreaIds)
                    .eq(ReportAttachment::getPropertyId, propertyDTO.getId()));
            List<Long> reportAttachmentIds = reportAttachments.stream().map(ReportAttachment::getId).toList();
            List<String> delS3Keys = reportAttachments.stream().map(ReportAttachment::getFileKey).toList();
            //刪除附件
            reportAttachmentService.removeByIds(reportAttachmentIds);
            //刪除备注
            reportRemarkService.remove(new LambdaQueryWrapper<ReportRemark>()
                    .in(ReportRemark::getReportId, monthlyReportIds)
                    .in(ReportRemark::getAreaId, delAreaIds)
                    .eq(ReportRemark::getPropertyId, propertyDTO.getId()));

            /**
             * 事务提交后删除s3附件
             */
            TransactionUtils.afterCommitAsyncExecute(executor, () -> {
                S3Utils.batchDeleteFile(region, bucketMap.get(S3BucketFunctionCons.MONTHLY_REPORT), delS3Keys);
            });
        }
    }