# MonthlyReportAreaController.java

    package cloud.wconnect.workperformance.controller.monthlyreport;

    import cloud.wconnect.commonlib.annotation.ApiId;
    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.component.SessionContext;
    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.cons.CommonErrorI18nConstant;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.exception.ForbiddenException;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.pojo.dto.UserDTO;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.service.UserInternalService;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.I18nMessageUtils;
    import cloud.wconnect.commonlib.util.JsonUtils;
    import cloud.wconnect.workperformance.cons.monthlyreport.AreaEnum;
    import cloud.wconnect.workperformance.cons.monthlyreport.MonthlyReportErrorI18nConstant;
    import cloud.wconnect.workperformance.entity.monthlyreport.*;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.AttachmentDTO;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.MeetingMinutesDTO;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.actionplans.ActionPlanDTO;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.actionplans.CategoryId2ActionPlanDTO;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.customersatisfaction.CustomerSatisfactionDetailDTO;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.expenses.ExpenseCategoryDTO;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.expenses.ExpenseDetailDTO;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.forecast.ForecastDTO;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.forecast.ForecastDetailDTO;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.managerscorecard.ManagersScorecardDetailDTO;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.managerscorecard.MarketSegmentDetailDTO;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.profit.ProfitDTO;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.profit.ProfitDetailDTO;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.roomrevenue.RoomRevenueDTO;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.roomrevenue.RoomRevenueDetailDTO;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.soldoutmanagement.SoldOutManagementDTO;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.strreport.STRReportDetailDTO;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.weeklysalesplan.WeeklySalesPlanStatisticsDTO;
    import cloud.wconnect.workperformance.service.monthlyreport.*;
    import cloud.wconnect.workperformance.service.monthlyreport.impl.MonthlyReportWeeklySalesPlanServiceImpl;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.google.common.collect.Sets;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.*;

    import jakarta.validation.Valid;

    import java.text.MessageFormat;
    import java.util.Collections;
    import java.util.List;
    import java.util.Map;
    import java.util.Objects;
    import java.util.stream.Collectors;

    /**
     * 月报区域信息控制层
     *
     * @author lichen
     * @date 2023/9/1
     */
    @Validated
    @RestController
    @RequestMapping("/monthly-report")
    public class MonthlyReportAreaController {

        @Autowired
        private IRoomRevenueService roomRevenueService;
        @Autowired
        private IMonthlyReportService monthlyReportService;
        @Autowired
        private IProfitService profitService;
        @Autowired
        private IMarketSegmentService marketSegmentService;
        @Autowired
        private IForecastService forecastService;
        @Autowired
        private SessionContext sessionContext;
        @Autowired
        private ObjectMapper objectMapper;
        @Autowired
        private ISTRReportService strReportService;
        @Autowired
        private IReportAttachmentService reportAttachmentService;
        @Autowired
        private ICustomerSatisfactionService customerSatisfactionService;
        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        private IExpenseService expenseService;
        @Autowired
        private ISoldOutManagementService soldOutManagementService;
        @Autowired
        private ISupportTeamReportService supportTeamReportService;
        @Autowired
        private IActionPlanService actionPlanService;
        @Autowired
        private IManagersScorecardService managersScorecardService;
        @Autowired
        private IMonthlyReportMeetingMinutesService meetingMinutesService;
        @Autowired
        private MonthlyReportWeeklySalesPlanServiceImpl monthlyReportWeeklySalesPlanServiceImpl;
        @Autowired
        private UserInternalService userInternalService;
        @Autowired
        private PropertyI18nRedisService propertyI18nRedisService;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;

        /**
         * 查询Room Revenue区域详情
         *
         * @param reportId 报告id
         * @param property 资产标识
         * @return void
         * @author lichen
         * @date 2023/9/1
         */
        @ApiId(602)
        @GetMapping("/{reportId:\\d+}/room-revenue")
        public RoomRevenueDetailDTO getRoomRevenue(@PathVariable long reportId, String property) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            MonthlyReport monthlyReport = monthlyReportService.checkExist(reportId);
            checkBelong(monthlyReport, propertyId);
            return roomRevenueService.getRoomRevenue(monthlyReport, propertyDTO);
        }

        /**
         * 保存Room Revenue区域数据
         *
         * @param reportId 报告id
         * @param property 资产标识
         * @return java.util.Map
         * @author lichen
         * @date 2023/9/1
         */
        @ApiId(603)
        @PutMapping("/{reportId:\\d+}/room-revenue")
        public Map saveRoomRevenue(@PathVariable long reportId, String property, @RequestBody @Valid RoomRevenueDetailDTO roomRevenueDetailDTO) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            int loginUserId = sessionContext.getLoginUserId();
            //有效性校验
            MonthlyReport monthlyReport = validityCheck(reportId, propertyId, AreaEnum.ROOM_REVENUE.getAreaId());

            //校验分类id是否重复
            List<Integer> categoryIds = roomRevenueDetailDTO.getList().stream().map(RoomRevenueDTO::getCategoryId).toList();
            if (categoryIds.size() != Sets.newHashSet(categoryIds).size()) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_CANNOT_REPEAT,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("categoryId"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The categoryId cannot repeat");
            }

            //保存区域信息
            roomRevenueService.save(monthlyReport, propertyDTO, roomRevenueDetailDTO, loginUserId);
            return Collections.emptyMap();
        }

        /**
         * 查询Profit区域详情
         *
         * @param reportId 报告id
         * @param property 资产标识
         * @return cloud.wconnect.workperformance.pojo.dto.monthlyreport.profit.ProfitDetailDTO
         * @author lichen
         * @date 2023/9/2
         */
        @ApiId(604)
        @GetMapping("/{reportId:\\d+}/profit")
        public ProfitDetailDTO getProfit(@PathVariable long reportId, String property) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            MonthlyReport monthlyReport = monthlyReportService.checkExist(reportId);
            checkBelong(monthlyReport, propertyId);
            return profitService.getProfit(monthlyReport, propertyDTO);
        }

        /**
         * 保存Profit区域数据
         *
         * @param reportId        月报id
         * @param property        资产标识
         * @param profitDetailDTO profit数据
         * @return java.util.Map
         * @author lichen
         * @date 2023/9/2
         */
        @ApiId(605)
        @PutMapping("/{reportId:\\d+}/profit")
        public Map saveProfit(@PathVariable long reportId, String property, @RequestBody @Valid ProfitDetailDTO profitDetailDTO) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            int loginUserId = sessionContext.getLoginUserId();
            //有效性校验
            MonthlyReport monthlyReport = validityCheck(reportId, propertyId, AreaEnum.PROFIT.getAreaId());

            //校验分类id是否重复
            List<Integer> categoryIds = profitDetailDTO.getList().stream().map(ProfitDTO::getCategoryId).toList();
            if (categoryIds.size() != Sets.newHashSet(categoryIds).size()) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_CANNOT_REPEAT,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("categoryId"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The categoryId cannot repeat");
            }

            //保存区域信息
            profitService.save(monthlyReport, propertyDTO, profitDetailDTO, loginUserId);
            return Collections.emptyMap();
        }

        /**
         * 查询Market Mix区域详情
         *
         * @param reportId 月报id
         * @param property 资产标识
         * @return cloud.wconnect.workperformance.pojo.dto.monthlyreport.managerscorecard.MarketSegmentDetailDTO
         * @author lichen
         * @date 2023/9/2
         */
        @ApiId(606)
        @GetMapping("/{reportId:\\d+}/market-mix")
        public MarketSegmentDetailDTO getMarketMix(@PathVariable long reportId, String property) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            MonthlyReport monthlyReport = monthlyReportService.checkExist(reportId);
            checkBelong(monthlyReport, propertyId);
            return marketSegmentService.getMarketMix(monthlyReport, propertyDTO);
        }

        /**
         * 保持Market Mix区域数据
         *
         * @param reportId               月报id
         * @param property               资产标识
         * @param marketSegmentDetailDTO 区域数据
         * @return java.util.Map
         * @author lichen
         * @date 2023/9/2
         */
        @ApiId(607)
        @PutMapping("/{reportId:\\d+}/market-mix")
        public Map saveMarketMix(@PathVariable long reportId, String property, @RequestBody @Valid MarketSegmentDetailDTO marketSegmentDetailDTO) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            int loginUserId = sessionContext.getLoginUserId();
            //有效性校验
            MonthlyReport monthlyReport = validityCheck(reportId, propertyId, AreaEnum.MARKET_MIX.getAreaId());
            //保存区域信息
            marketSegmentService.save(monthlyReport, propertyDTO, marketSegmentDetailDTO, loginUserId);
            return Collections.emptyMap();
        }

        /**
         * 查询Forecast区域详情
         *
         * @param reportId 报告id
         * @param property 资产标识
         * @return cloud.wconnect.workperformance.pojo.dto.monthlyreport.forecast.ForecastDetailDTO
         * @author lichen
         * @date 2023/9/2
         */
        @ApiId(608)
        @GetMapping("/{reportId:\\d+}/forecast")
        public ForecastDetailDTO getForecast(@PathVariable long reportId, String property) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            MonthlyReport monthlyReport = monthlyReportService.checkExist(reportId);
            checkBelong(monthlyReport, propertyId);
            return forecastService.getForecast(monthlyReport, propertyDTO);
        }

        /**
         * 保存Forecast区域数据
         *
         * @param reportId          报告id
         * @param property          资产标识
         * @param forecastDetailDTO 区域数据
         * @return java.util.Map
         * @author lichen
         * @date 2023/9/2
         */
        @ApiId(609)
        @PutMapping("/{reportId:\\d+}/forecast")
        public Map saveForecast(@PathVariable long reportId, String property, @RequestBody @Valid ForecastDetailDTO forecastDetailDTO) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            //有效性校验
            MonthlyReport monthlyReport = validityCheck(reportId, propertyId, AreaEnum.FORECAST.getAreaId());

            //校验分类id是否重复
            Map<Integer, List<ForecastDTO>> date2List = forecastDetailDTO.getList().stream().collect(Collectors.groupingBy(ForecastDTO::getDate));
            for (List<ForecastDTO> list : date2List.values()) {
                List<Integer> categoryIds = list.stream().map(ForecastDTO::getCategoryId).toList();
                if (categoryIds.size() != Sets.newHashSet(categoryIds).size()) {
                    throw new BadRequestException(CommonErrorI18nConstant.DATA_CANNOT_REPEAT,
                            i18nMessageUtils.getErrorParamMapNotNeedTranslate("categoryId"),
                            BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                            "The categoryId cannot repeat");
                }
            }

            //保存区域信息
            forecastService.save(monthlyReport, propertyDTO, forecastDetailDTO, sessionContext.getLoginUserId());
            return Collections.emptyMap();
        }

        /**
         * 查询STR Report区域详情
         *
         * @param reportId 报告id
         * @param property 资产标识
         * @return cloud.wconnect.workperformance.pojo.dto.monthlyreport.STRReportDTO
         * @author lichen
         * @date 2023/9/4
         */
        @ApiId(610)
        @GetMapping("/{reportId:\\d+}/str-report")
        public STRReportDetailDTO getSTRReport(@PathVariable long reportId, String property) {
            int propertyId = sessionContext.getPropertyId(property);
            MonthlyReport monthlyReport = monthlyReportService.checkExist(reportId);
            checkBelong(monthlyReport, propertyId);
            return strReportService.getSTRReport(monthlyReport, propertyId);
        }

        /**
         * 保存STR Report区域数据
         *
         * @param reportId           月报id
         * @param property           资产标识
         * @param strReportDetailDTO STR Report区域数据
         * @return java.util.Map
         * @author lichen
         * @date 2023/9/4
         */
        @ApiId(611)
        @PutMapping("/{reportId:\\d+}/str-report")
        public Map saveSTRReport(@PathVariable long reportId, String property, @RequestBody @Valid STRReportDetailDTO strReportDetailDTO) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            //有效性校验
            MonthlyReport monthlyReport = validityCheck(reportId, propertyId, AreaEnum.STR_REPORT.getAreaId());
            //保存区域信息
            strReportService.save(monthlyReport, propertyDTO, strReportDetailDTO);
            return Collections.emptyMap();
        }

        /**
         * 查询Support Team Report区域详情
         *
         * @param reportId 月报id
         * @param property 资产标识
         * @return java.util.List<cloud.wconnect.workperformance.pojo.dto.monthlyreport.AttachmentDTO>
         * @author lichen
         * @date 2023/9/4
         */
        @ApiId(612)
        @GetMapping("/{reportId:\\d+}/support-team-report")
        public List<AttachmentDTO> getSupportTeamReport(@PathVariable long reportId, String property) {
            int propertyId = sessionContext.getPropertyId(property);
            MonthlyReport monthlyReport = monthlyReportService.checkExist(reportId);
            checkBelong(monthlyReport, propertyId);
            List<ReportAttachment> reportAttachments = reportAttachmentService.listByReportIdAndAreaId(propertyId, monthlyReport.getId(), AreaEnum.SUPPORT_TEAM_REPORT.getAreaId());
            return beanMapper.mapList(reportAttachments, AttachmentDTO.class);
        }

        /**
         * 保存Support Team Report区域数据
         *
         * @param reportId    月报id
         * @param property    资产标识
         * @param attachments 附件集合
         * @return java.util.Map
         * @author lichen
         * @date 2023/9/4
         */
        @ApiId(613)
        @PutMapping("/{reportId:\\d+}/support-team-report")
        public Map saveSupportTeamReport(@PathVariable long reportId, String property, @RequestBody List<@Valid AttachmentDTO> attachments) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            //有效性校验
            MonthlyReport monthlyReport = validityCheck(reportId, propertyId, AreaEnum.SUPPORT_TEAM_REPORT.getAreaId());
            //保存区域信息
            supportTeamReportService.save(monthlyReport, propertyDTO, attachments);
            return Collections.emptyMap();
        }

        /**
         * 查询Customer Satisfaction区域详情
         *
         * @param property 资产标识
         * @return cloud.wconnect.workperformance.pojo.dto.monthlyreport.CustomerSatisfactionDTO
         * @author lichen
         * @date 2023/9/4
         */
        @ApiId(614)
        @GetMapping("/{year:\\d+}/{month:\\d+}/customer-satisfaction")
        public CustomerSatisfactionDetailDTO getCustomerSatisfaction(String property, @PathVariable int year, @PathVariable int month) {
            int propertyId = sessionContext.getPropertyId(property);

            MonthlyReport monthlyReport = monthlyReportService.getMonthlyReportByYearAndMonth(propertyId, year, month);
            if (Objects.isNull(monthlyReport)) {
                return null;
            }
            checkBelong(monthlyReport, propertyId);
            return customerSatisfactionService.getCustomerSatisfaction(monthlyReport, propertyId);
        }

        /**
         * 保存Customer Satisfaction区域数据
         *
         * @param property                      资产标识
         * @param reportId                      月报id
         * @param customerSatisfactionDetailDTO 客户满意度数据
         * @return java.util.Map
         * @author lichen
         * @date 2023/9/4
         */
        @ApiId(615)
        @PutMapping("/{reportId:\\d+}/customer-satisfaction")
        public Map saveCustomerSatisfaction(String property, @PathVariable long reportId, @RequestBody @Valid CustomerSatisfactionDetailDTO customerSatisfactionDetailDTO) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            int loginUserId = sessionContext.getLoginUserId();
            //有效性校验
            MonthlyReport monthlyReport = validityCheck(reportId, propertyId, AreaEnum.CUSTOMER_SATISFACTION.getAreaId());
            //保存区域信息
            customerSatisfactionService.save(monthlyReport, propertyDTO, customerSatisfactionDetailDTO, loginUserId);
            return Collections.emptyMap();
        }

        /**
         * 查询Expenses区域详情
         *
         * @param reportId 月报id
         * @param property 资产标识
         * @return cloud.wconnect.workperformance.pojo.dto.monthlyreport.expenses.ExpensesDetailDTO
         * @author lichen
         * @date 2023/9/4
         */
        @ApiId(616)
        @GetMapping("/{reportId:\\d+}/expenses")
        public ExpenseDetailDTO getExpenses(@PathVariable long reportId, String property) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            MonthlyReport monthlyReport = monthlyReportService.checkExist(reportId);
            checkBelong(monthlyReport, propertyId);
            return expenseService.getExpenses(monthlyReport, propertyDTO);
        }

        /**
         * 保存Expenses区域数据
         *
         * @param reportId         月报id
         * @param property         资产标识
         * @param expenseDetailDTO 区域数据
         * @return java.util.Map
         * @author lichen
         * @date 2023/9/4
         */
        @ApiId(617)
        @PutMapping("/{reportId:\\d+}/expenses")
        public Map saveExpenses(@PathVariable long reportId, String property, @RequestBody @Valid ExpenseDetailDTO expenseDetailDTO) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            //有效性校验
            MonthlyReport monthlyReport = validityCheck(reportId, propertyId, AreaEnum.EXPENSES.getAreaId());

            //校验分类id是否重复
            List<Integer> categoryIds = expenseDetailDTO.getExpenseCategorys().stream().map(ExpenseCategoryDTO::getCategoryId).toList();
            if (categoryIds.size() != Sets.newHashSet(categoryIds).size()) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_CANNOT_REPEAT,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("categoryId"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The categoryId cannot repeat");
            }

            //保存区域信息
            expenseService.save(monthlyReport, propertyDTO, expenseDetailDTO, sessionContext.getLoginUserId());
            return Collections.emptyMap();
        }

        /**
         * 查询售罄管理区域详情
         *
         * @return cloud.wconnect.workperformance.pojo.dto.monthlyreport.soldoutmanagement.SoldOutManagementDTO
         * @author lichen
         * @date 2023/9/4
         */
        @ApiId(618)
        @GetMapping("/{reportId:\\d+}/sold-out-management")
        public SoldOutManagementDTO getSoldOutManagement(@PathVariable long reportId, String property) {
            int propertyId = sessionContext.getPropertyId(property);
            MonthlyReport monthlyReport = monthlyReportService.checkExist(reportId);
            checkBelong(monthlyReport, propertyId);

            SoldOutManagement soldOutManagement = soldOutManagementService.getByReportId(propertyId, reportId);

            if (Objects.isNull(soldOutManagement)) {
                return new SoldOutManagementDTO();
            }
            return new SoldOutManagementDTO(soldOutManagement.getOooRooms(), soldOutManagement.getOcc());
        }

        /**
         * 保存售罄管理区域数据
         *
         * @param reportId             月报id
         * @param property             资产标识
         * @param soldOutManagementDTO 售罄管理区域数据
         * @return java.util.Map
         * @author lichen
         * @date 2023/9/4
         */
        @ApiId(619)
        @PutMapping("/{reportId:\\d+}/sold-out-management")
        public Map saveSoldOutManagement(@PathVariable long reportId, String property,
                                         @RequestBody @Valid SoldOutManagementDTO soldOutManagementDTO) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            int loginUserId = sessionContext.getLoginUserId();
            //有效性校验
            MonthlyReport monthlyReport = validityCheck(reportId, propertyId, AreaEnum.SOLD_OUT_MANAGEMENT.getAreaId());
            //保存区域信息
            soldOutManagementService.save(monthlyReport, propertyDTO, soldOutManagementDTO, loginUserId);
            return Collections.emptyMap();
        }

        /**
         * 查询Action Plan区域详情
         *
         * @param reportId 报告id
         * @param property 资产标识
         * @return java.util.List<cloud.wconnect.workperformance.pojo.vo.monthlyreport.CategoryId2ActionPlanVO>
         * @author lichen
         * @date 2023/9/5
         */
        @ApiId(620)
        @GetMapping("/{reportId:\\d+}/action-plans")
        public List<CategoryId2ActionPlanDTO> getActionPlan(@PathVariable long reportId, String property) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            MonthlyReport monthlyReport = monthlyReportService.checkExist(reportId);
            checkBelong(monthlyReport, propertyId);
            return actionPlanService.getActionPlan(monthlyReport, propertyDTO);
        }

        /**
         * 保持Action Plan区域数据
         *
         * @param reportId          报告id
         * @param property          资产标识
         * @param actionPlanDTOList 区域数据集合
         * @return java.util.Map
         * @author lichen
         * @date 2023/9/5
         */
        @ApiId(621)
        @PutMapping("/{reportId:\\d+}/action-plans")
        public Map saveActionPlan(@PathVariable long reportId, String property,
                                  @RequestBody List<@Valid ActionPlanDTO> actionPlanDTOList) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            int loginUserId = sessionContext.getLoginUserId();
            //有效性校验
            MonthlyReport monthlyReport = validityCheck(reportId, propertyId, AreaEnum.ACTION_PLANS.getAreaId());
            //保存区域信息
            actionPlanService.save(monthlyReport, propertyDTO, actionPlanDTOList, loginUserId);
            return Collections.emptyMap();
        }

        /**
         * 获取Managers’ Scorecard区域详情
         *
         * @param reportId 月报id
         * @param property 资产标识
         * @return cloud.wconnect.workperformance.pojo.dto.monthlyreport.managerscorecard.ManagersScorecardDetailDTO
         * @author lichen
         * @date 2023/9/5
         */
        @ApiId(622)
        @GetMapping("/{reportId:\\d+}/managers-scorecard")
        public ManagersScorecardDetailDTO getManagersScorecard(@PathVariable long reportId, String property) {
            int propertyId = sessionContext.getPropertyId(property);
            MonthlyReport monthlyReport = monthlyReportService.checkExist(reportId);
            checkBelong(monthlyReport, propertyId);
            return managersScorecardService.getManagersScorecard(monthlyReport, propertyId);
        }

        /**
         * 保存Managers’ Scorecard区域数据
         *
         * @param reportId    月报id
         * @param property    资产标识
         * @param attachments 附件集合
         * @return java.util.Map
         * @author lichen
         * @date 2023/9/5
         */
        @ApiId(623)
        @PutMapping("/{reportId:\\d+}/managers-scorecard")
        public Map saveManagersScorecard(@PathVariable long reportId, String property, @RequestBody List<@Valid AttachmentDTO> attachments) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            //有效性校验
            MonthlyReport monthlyReport = validityCheck(reportId, propertyId, AreaEnum.MANAGERS_SCORECARD.getAreaId());
            //保存区域信息
            managersScorecardService.save(monthlyReport, propertyDTO, attachments);
            return Collections.emptyMap();
        }

        /**
         * 查询会议纪要
         *
         * @param reportId 月报Id
         * @param property 资产
         * @return java.util.Map
         * @author lichen
         * @date 2024/3/22
         */
        @ApiId(1100)
        @GetMapping("/{reportId:\\d+}/meeting-minutes")
        public MeetingMinutesDTO getMeettingMinutes(@PathVariable long reportId, String property) {
            int propertyId = sessionContext.getPropertyId(property);
            Integer tenantId = sessionContext.getTenantSymbolBO().getId();
            MonthlyReport monthlyReport = monthlyReportService.checkExist(reportId);
            checkBelong(monthlyReport, propertyId);
            //查询会议纪要
            MonthlyReportMeetingMinutes monthlyReportMeetingMinutes = meetingMinutesService.getByReportId(monthlyReport.getId());
            if (Objects.isNull(monthlyReportMeetingMinutes)) return new MeetingMinutesDTO();
            //查询更新人
            UserDTO userDTO = userInternalService.getOne(tenantId, monthlyReportMeetingMinutes.getUpdateId());
            return beanMapper.map(monthlyReportMeetingMinutes, MeetingMinutesDTO.class, dto -> {
                if (Objects.nonNull(userDTO)) dto.setUpdateName(userDTO.getName());
            });
        }

        /**
         * 保存会议纪要
         *
         * @param reportId           月报Id
         * @param property           资产
         * @param meettingMinutesDTO 会议纪要DTO
         * @return java.util.Map
         * @author lichen
         * @date 2024/3/22
         */
        @ApiId(1101)
        @PutMapping("/{reportId:\\d+}/meeting-minutes")
        public Map saveMeettingMinutes(@PathVariable long reportId, String property, @RequestBody MeetingMinutesDTO meettingMinutesDTO) {
            int propertyId = sessionContext.getPropertyId(property);
            Integer tenantId = sessionContext.getTenantSymbolBO().getId();
            MonthlyReport monthlyReport = monthlyReportService.checkExist(reportId);
            checkBelong(monthlyReport, propertyId);

            //查询会议纪要
            MonthlyReportMeetingMinutes monthlyReportMeetingMinutes = meetingMinutesService.getByReportId(monthlyReport.getId());

            if (Objects.isNull(monthlyReportMeetingMinutes)) {//新增
                monthlyReportMeetingMinutes = new MonthlyReportMeetingMinutes();
                monthlyReportMeetingMinutes.setTenantId(tenantId);
                monthlyReportMeetingMinutes.setPropertyId(propertyId);
                monthlyReportMeetingMinutes.setReportId(reportId);
                monthlyReportMeetingMinutes.setMeetingMinutes(meettingMinutesDTO.getMeetingMinutes());
                monthlyReportMeetingMinutes.setUpdateId(sessionContext.getLoginUserId());
                monthlyReportMeetingMinutes.setUpdateTime(DateTimeUtils.nowTimestamp());
                meetingMinutesService.save(monthlyReportMeetingMinutes);
            } else {//修改
                monthlyReportMeetingMinutes.setMeetingMinutes(meettingMinutesDTO.getMeetingMinutes());
                monthlyReportMeetingMinutes.setUpdateId(sessionContext.getLoginUserId());
                monthlyReportMeetingMinutes.setUpdateTime(DateTimeUtils.nowTimestamp());
                meetingMinutesService.updateById(monthlyReportMeetingMinutes);
            }
            return Collections.emptyMap();
        }

        /**
         * 查询Weekly Sales Plan信息
         *
         * @param reportId      月报id
         * @param property      资产标识
         * @param isRecalculate 是否重新计算
         * @return java.util.List<cloud.wconnect.workperformance.pojo.dto.monthlyreport.weeklysalesplan.WeeklySalesPlanDTO>
         * @author lichen
         * @date 2024/12/9
         */
        @ApiId(1313)
        @RequestMapping("/{reportId:\\d+}/weekly-sales-plan")
        public WeeklySalesPlanStatisticsDTO getWeeklySalesPlan(@PathVariable long reportId, String property, Boolean isRecalculate) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            int loginUserId = sessionContext.getLoginUserId();
            MonthlyReport monthlyReport = monthlyReportService.checkExist(reportId);
            checkBelong(monthlyReport, propertyId);

            if (isRecalculate) {
                //重新计算数据
                monthlyReportWeeklySalesPlanServiceImpl.init(propertyDTO, Collections.singletonList(monthlyReport),
                        Collections.emptyMap());
            }

            //查询Weekly Sales Plan数据
            return monthlyReportWeeklySalesPlanServiceImpl.listByReportId(propertyDTO, monthlyReport.getId());
        }

        /**
         * 有效性校验
         *
         * @param reportId   报告id
         * @param propertyId 资产id
         * @param areaId     区域id
         * @return cloud.wconnect.workperformance.entity.monthlyreport.MonthlyReport
         * @author lichen
         * @date 2023/9/2
         */
        private MonthlyReport validityCheck(long reportId, int propertyId, int areaId) {
            //校验月报是否存在
            MonthlyReport monthlyReport = monthlyReportService.checkExist(reportId);
            //校验月报归属当前资产
            checkBelong(monthlyReport, propertyId);
            //校验月报是否开通此区域
            checkIsOpenArea(monthlyReport, areaId);

            return monthlyReport;
        }

        /**
         * 校验月报是否开通某区域
         *
         * @param monthlyReport 月报
         * @param areaId        区域id
         * @return void
         * @author lichen
         * @date 2023/9/2
         */
        private void checkIsOpenArea(MonthlyReport monthlyReport, int areaId) {
            List<Integer> areaIds = JsonUtils.convertStringToList(objectMapper, monthlyReport.getAreaIds(), Integer.class);
            if (!areaIds.contains(areaId)) {
                throw new BadRequestException(MonthlyReportErrorI18nConstant.PROPERTY_NOT_OPEN_AREA,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        MessageFormat.format("The monthly report does not open this area, monthlyReportId:{0}, areaName:{1}",
                                monthlyReport.getId(), AreaEnum.getDesc(areaId)));
            }
        }

        /**
         * 校验月报是否归属于当前资产
         *
         * @param monthlyReport 月报
         * @param propertyId    资产id
         * @return void
         * @author lichen
         * @date 2023/9/1
         */
        private void checkBelong(MonthlyReport monthlyReport, Integer propertyId) {
            if (!monthlyReport.getPropertyId().equals(propertyId)) {
                throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(), BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(),
                        MessageFormat.format("The monthly report not belong to current property, monthlyReportId:{0}, currentPropertyId:{1}",
                                monthlyReport.getId(), propertyId));
            }
        }

    }