# ExpenseServiceImpl.java

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

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.workperformance.cons.monthlyreport.AreaEnum;
    import cloud.wconnect.workperformance.entity.monthlyreport.*;
    import cloud.wconnect.workperformance.mapper.monthlyreport.ExpenseMapper;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.expenses.ExpenseCategoryDTO;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.expenses.ExpenseCategoryItemDTO;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.expenses.ExpenseDetailDTO;
    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.google.common.collect.Lists;
    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.util.*;
    import java.util.function.Function;
    import java.util.stream.Collectors;

    /**
     * <p>
     * 月报EXPENSES（花费）区域，参数表 服务实现类
     * </p>
     *
     * @author lichen
     * @since 2023-09-01
     */
    @Service
    @DS("monthly_report")
    public class ExpenseServiceImpl extends ServiceImpl<ExpenseMapper, Expense> implements IExpenseService, IHandlePropertySettingChange {

        @Lazy
        @Autowired
        private IMonthlyReportService monthlyReportService;
        @Autowired
        private IAreaTypeConfigService areaTypeConfigService;
        @Autowired
        private IExpenseCategoryService expenseCategoryService;
        @Autowired
        private IExpenseCategoryItemService expenseCategoryItemService;
        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        private ExpenseMapper expenseMapper;

        /**
         * 查询花费区域详情
         *
         * @param monthlyReport 月报
         * @param propertyDTO   资产DTO
         * @return cloud.wconnect.workperformance.pojo.dto.monthlyreport.expenses.ExpensesDetailDTO
         * @author lichen
         * @date 2023/9/4
         */
        @Override
        public ExpenseDetailDTO getExpenses(MonthlyReport monthlyReport, PropertyDTO propertyDTO) {
            //查询link链接
            Expense expense = getOne(new LambdaQueryWrapper<Expense>()
                    .eq(Expense::getReportId, monthlyReport.getId())
                    .eq(Expense::getPropertyId, propertyDTO.getId()));
            String link = Objects.isNull(expense) ? "" : expense.getLink();

            //查询花销分类集合
            List<ExpenseCategory> expenseCategories = expenseCategoryService.listByReportId(propertyDTO.getId(), monthlyReport.getId());
            //查询花销分类明细集合
            List<ExpenseCategoryItem> expenseCategoryItems = expenseCategoryItemService.listByReportId(propertyDTO.getId(), monthlyReport.getId());
            Map<Integer, List<ExpenseCategoryItemDTO>> categoryId2ExpenseCategoryItemDTOS = expenseCategoryItems.stream()
                    .map(item -> beanMapper.map(item, ExpenseCategoryItemDTO.class))
                    .collect(Collectors.groupingBy(ExpenseCategoryItemDTO::getCategoryId));

            List<ExpenseCategoryDTO> expenseCategoryDTOS = beanMapper.mapList(expenseCategories, ExpenseCategoryDTO.class, (entity, dto) -> {
                dto.setExpenseCategoryItems(categoryId2ExpenseCategoryItemDTOS.getOrDefault(dto.getCategoryId(), Collections.emptyList()));
            });

            //校验是否历史月报
            Boolean isHistoryMonthlyReport = monthlyReportService.checkIsHistoryMonthlyReport(monthlyReport, propertyDTO);
            /**
             * 历史月报：按照区域表存储的数据，返回
             * 当前正在使用或未来的数据：按照最新的区域类型配置 组装返回对象
             */
            if (isHistoryMonthlyReport) {
                return new ExpenseDetailDTO(link, expenseCategoryDTOS);
            }

            Map<Integer, ExpenseCategoryDTO> categoryId2DTO = expenseCategoryDTOS.stream().collect(Collectors.toMap(ExpenseCategoryDTO::getCategoryId, Function.identity()));
            //区域类型集合
            List<AreaTypeConfig> areaTypeConfigs = areaTypeConfigService.listByAreaId(propertyDTO.getId(), Lists.newArrayList(AreaEnum.EXPENSES.getAreaId()));
            List<ExpenseCategoryDTO> resultList = Lists.newArrayListWithCapacity(areaTypeConfigs.size());
            for (AreaTypeConfig areaTypeConfig : areaTypeConfigs) {
                ExpenseCategoryDTO expenseCategoryDTO = categoryId2DTO.get(areaTypeConfig.getId());
                if (Objects.isNull(expenseCategoryDTO)) {
                    resultList.add(ExpenseCategoryDTO.builder()
                            .categoryId(areaTypeConfig.getId())
                            .categoryName(areaTypeConfig.getName())
                            .expenseCategoryItems(Collections.emptyList())
                            .build());
                } else {
                    resultList.add(expenseCategoryDTO);
                }
            }
            return new ExpenseDetailDTO(link, resultList);
        }

        /**
         * 保存花费区域数据
         *
         * @param monthlyReport    月报
         * @param propertyDTO      资产DTO
         * @param expenseDetailDTO 区域数据
         * @param loginUserId      登录用户id
         * @return void
         * @author lichen
         * @date 2023/9/4
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void save(MonthlyReport monthlyReport, PropertyDTO propertyDTO, ExpenseDetailDTO expenseDetailDTO, int loginUserId) {
            Integer propertyId = propertyDTO.getId();
            Integer tenantId = propertyDTO.getTenantId();
            //保存链接
            Expense expense = Expense.builder()
                    .tenantId(tenantId)
                    .propertyId(propertyId)
                    .reportId(monthlyReport.getId())
                    .link(expenseDetailDTO.getLink())
                    .updateId(loginUserId)
                    .updateTime(DateTimeUtils.nowTimestamp()).build();
            expenseMapper.saveOrUpdateByUnique(expense);

            //删除花销分类信息
            expenseCategoryService.remove(new LambdaQueryWrapper<ExpenseCategory>()
                    .eq(ExpenseCategory::getReportId, monthlyReport.getId())
                    .eq(ExpenseCategory::getPropertyId, propertyId));
            //删除花销分类明细信息
            expenseCategoryItemService.remove(new LambdaQueryWrapper<ExpenseCategoryItem>()
                    .eq(ExpenseCategoryItem::getReportId, monthlyReport.getId())
                    .eq(ExpenseCategoryItem::getPropertyId, propertyId));

            List<ExpenseCategoryDTO> expenseCategoryDTOS = expenseDetailDTO.getExpenseCategorys();
            if (CollectionUtils.isNotEmpty(expenseCategoryDTOS)) {
                List<ExpenseCategory> expenseCategorys = beanMapper.mapList(expenseCategoryDTOS, ExpenseCategory.class, (dto, entity) -> {
                    entity.setTenantId(tenantId);
                    entity.setPropertyId(propertyId);
                    entity.setReportId(monthlyReport.getId());
                    entity.setUpdateId(loginUserId);
                    entity.setUpdateTime(DateTimeUtils.nowTimestamp());
                });
                //批量新增花费分类数据
                expenseCategoryService.saveBatch(expenseCategorys);

                List<ExpenseCategoryItem> itemList = Lists.newArrayList();
                for (ExpenseCategoryDTO expenseCategoryDTO : expenseCategoryDTOS) {
                    List<ExpenseCategoryItemDTO> expenseCategoryItemDTOS = expenseCategoryDTO.getExpenseCategoryItems();
                    if (CollectionUtils.isNotEmpty(expenseCategoryItemDTOS)) {
                        List<ExpenseCategoryItem> expenseCategoryItems = beanMapper.mapList(expenseCategoryItemDTOS, ExpenseCategoryItem.class, (dto, entity) -> {
                            entity.setTenantId(tenantId);
                            entity.setPropertyId(propertyId);
                            entity.setReportId(monthlyReport.getId());
                            entity.setCategoryId(expenseCategoryDTO.getCategoryId());
                            entity.setCategoryName(expenseCategoryDTO.getCategoryName());
                            entity.setUpdateId(loginUserId);
                            entity.setUpdateTime(DateTimeUtils.nowTimestamp());
                        });
                        itemList.addAll(expenseCategoryItems);
                    }
                }
                //批量新增花费分类明细数据
                expenseCategoryItemService.saveBatch(itemList);

            }
        }

        /**
         * 删除区域数据
         *
         * @param propertyDTO    资产DTO
         * @param monthlyReports 月报集合
         * @return void
         * @author lichen
         * @date 2023/9/5
         */
        @Override
        public void delete(PropertyDTO propertyDTO, List<MonthlyReport> monthlyReports) {
            List<Long> reportIds = monthlyReports.stream().map(MonthlyReport::getId).toList();
            if (CollectionUtils.isEmpty(reportIds)) return;
            remove(new LambdaQueryWrapper<Expense>()
                    .in(Expense::getReportId, reportIds)
                    .eq(Expense::getPropertyId, propertyDTO.getId()));
        }
    }