# OvertimeController.java

    package cloud.wconnect.workperformance.controller.mor.overtime;

    import cloud.wconnect.commonlib.annotation.ApiId;
    import cloud.wconnect.commonlib.component.SessionContext;
    import cloud.wconnect.commonlib.cons.BaseConstant;
    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.ListPagedDTO;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.I18nMessageUtils;
    import cloud.wconnect.workperformance.entity.mor.MorDepartment;
    import cloud.wconnect.workperformance.pojo.dto.mor.MorDepartmentDTO;
    import cloud.wconnect.workperformance.pojo.dto.mor.MorDepartmentSummaryDTO;
    import cloud.wconnect.workperformance.pojo.dto.mor.overtime.OvertimeDailyDTO;
    import cloud.wconnect.workperformance.pojo.dto.mor.overtime.OvertimeSumForPropertyViewDTO;
    import cloud.wconnect.workperformance.pojo.dto.mor.overtime.OvertimeTotalDTO;
    import cloud.wconnect.workperformance.pojo.query.mor.MorDepartmentQuery;
    import cloud.wconnect.workperformance.pojo.query.mor.overtime.*;
    import cloud.wconnect.workperformance.service.mor.IMorDepartmentService;
    import cloud.wconnect.workperformance.service.mor.IMorOvertimeDailyService;
    import cloud.wconnect.workperformance.service.mor.IOvertimeService;
    import com.google.common.collect.Sets;
    import jakarta.annotation.Resource;
    import jakarta.validation.Valid;
    import org.springframework.web.bind.annotation.*;

    import java.math.BigDecimal;
    import java.time.LocalDate;
    import java.util.Collections;
    import java.util.List;
    import java.util.Map;
    import java.util.Objects;

    /**
     * <p>
     * 控制器类：加班信息
     * </p>
     *
     * @author zc
     * @since 2023-04-01
     */
    @RestController
    @RequestMapping("/mor/overtime")
    public class OvertimeController {
        @Resource
        private IOvertimeService overtimeService;
        @Resource
        private IMorDepartmentService morDepartmentService;
        @Resource
        private PropertyI18nRedisService propertyI18nRedisService;
        @Resource
        private SessionContext sessionContext;
        @Resource
        private IMorOvertimeDailyService morOvertimeDailyService;
        @Resource
        private I18nMessageUtils i18nMessageUtils;

        /**
         * 获取 Overtime 列表数据
         *
         * @param property 资产标识
         * @param query    查询条件
         * @return OvertimeTotalDTO
         * @author zc
         * @date 2023/4/1
         */
        @ApiId(248)
        @GetMapping
        public OvertimeTotalDTO getOvertimeTotal(@RequestParam String property, @Valid OvertimeQuery query) {
            int tenantId = sessionContext.getTenantSymbolBO().getId();
            int propertyId = sessionContext.getPropertyId(property);
            return overtimeService.getOvertimeTotal(tenantId, propertyId, sessionContext.getLoginUserId(), query);
        }

        /**
         * 获取资产下 Overtime Details 年份，月份，部门对应的金额
         *
         * @param query 查询条件
         * @return OvertimeSumForPropertyViewDTO 集合
         * @author zc
         * @date 2023/4/1
         */
        @ApiId(249)
        @GetMapping("/year-month-department/sum")
        public List<OvertimeSumForPropertyViewDTO> listSumInfoForPropertyYears(@Valid OvertimeSumQuery query) {
            if (!Sets.newHashSet(sessionContext.getPropertyIds()).containsAll(query.getPropertyIds())) {
                throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(),
                        BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(),
                        "Cannot be operated others property data; propertyIdRange: " + query.getPropertyIds());
            }
            List<PropertyDTO> propertyDTOList = propertyI18nRedisService.list(query.getPropertyIds());
            return overtimeService.listSumInfoForPropertyYears(propertyDTOList, query);
        }

        /**
         * 获取部门
         *
         * @param property 资产标识
         * @param query    查询条件
         * @return MorDepartmentDTO 集合
         * @author zc
         * @date 2023/11/24
         */
        @ApiId(914)
        @GetMapping("/department")
        public List<MorDepartmentDTO> listDepartment(@RequestParam String property, MorDepartmentQuery query) {
            int propertyId = sessionContext.getPropertyId(property);
            return morDepartmentService.list(propertyId, query);
        }

        /**
         * 保存部门
         *
         * @param property         资产标识
         * @param morDepartmentDTO 保存内容
         * @return empty map
         * @author zc
         * @date 2023/11/24
         */
        @ApiId(915)
        @PostMapping("/department")
        public Map<Object, Object> saveDepartment(@RequestParam String property, @Valid @RequestBody MorDepartmentDTO morDepartmentDTO) {
            int propertyId = sessionContext.getPropertyId(property);
            if (Objects.isNull(morDepartmentDTO.getId())) {
                // 校验 code 是否重复
                morDepartmentService.checkRepeat(propertyId, morDepartmentDTO, null);
                // 保存部门
                morDepartmentService.saveDepartment(propertyId, sessionContext.getLoginUserId(), morDepartmentDTO);
                return Collections.emptyMap();
            }
            // 校验数据是否存在
            MorDepartment originDepartment = morDepartmentService.checkExist(propertyId, morDepartmentDTO.getId());
            // 校验 code 是否重复
            morDepartmentService.checkRepeat(propertyId, morDepartmentDTO, originDepartment.getId());
            // 编辑部门
            morDepartmentService.updateDepartment(sessionContext.getLoginUserId(), originDepartment, morDepartmentDTO);
            return Collections.emptyMap();
        }

        /**
         * 获取指定日期范围的Overtime Daily数据
         *
         * @param property 资产标识
         * @param query    查询条件
         * @return OvertimeTotalDTO
         * @author zc
         * @date 2023/4/1
         */
        @ApiId(1614)
        @GetMapping("/daily")
        public ListPagedDTO<OvertimeDailyDTO> pageListDateRange(String property, @Valid OvertimeDailyQuery query) {
            //校验日期
            checkDateRange(query.getStartDate(), query.getEndDate());

            int tenantId = sessionContext.getTenantSymbolBO().getId();
            int propertyId = sessionContext.getPropertyId(property);
            return morOvertimeDailyService.pageListDateRange(tenantId, propertyId, sessionContext.getLoginUserId(), query);
        }

        /**
         * 获取指定日期范围的Overtime Daily汇总数据
         *
         * @param property 资产标识
         * @param query    查询条件
         * @return OvertimeTotalDTO
         * @author zc
         * @date 2023/4/1
         */
        @ApiId(1615)
        @GetMapping("/daily/summary")
        public Map<String, BigDecimal> dailySummary(String property, @Valid OvertimeDailySummaryQuery query) {
            //校验日期
            checkDateRange(query.getStartDate(), query.getEndDate());

            int tenantId = sessionContext.getTenantSymbolBO().getId();
            int propertyId = sessionContext.getPropertyId(property);
            return morOvertimeDailyService.dailySummary(tenantId, propertyId, query);
        }

        /**
         * 获取指定日期范围的Overtime Daily部门汇总数据
         *
         * @param property 资产标识
         * @param query    查询条件
         * @return cloud.wconnect.workperformance.pojo.dto.mor.MorDepartmentSummaryDTO
         * @author lichen
         * @date 2025/10/22
         */
        @ApiId(1616)
        @GetMapping("/department/summary")
        public MorDepartmentSummaryDTO listDepartmentSummary(String property, @Valid MorDepartmentSummaryQuery query) {
            //校验日期
            checkDateRange(query.getStartDate(), query.getEndDate());

            int propertyId = sessionContext.getPropertyId(property);
            return morOvertimeDailyService.listDepartmentSummary(propertyId, query);
        }

        /**
         * 校验日期
         *
         * @param startDate 开始日期
         * @param endDate   结束日期
         * @author zc
         * @date 2023/4/1
         */
        private void checkDateRange(String startDate, String endDate) {
            LocalDate startLocalDate = DateTimeUtils.strToLocalDate(startDate, BaseConstant.DATE_FORMAT_YYYYMMDD);
            LocalDate endLocalDate = DateTimeUtils.strToLocalDate(endDate, BaseConstant.DATE_FORMAT_YYYYMMDD);
            //校验开始日期不能大于结束日期
            if (startLocalDate.isAfter(endLocalDate)) {
                throw new BadRequestException(CommonErrorI18nConstant.START_DATE_CANNOT_GREATER_THAN_END_DATE,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The endDate must be greater than or equal to the startDate");
            }
            long numberOfDays = DateTimeUtils.numberOfDays(startLocalDate, endLocalDate);
            if (numberOfDays > 93) {
                throw new BadRequestException(CommonErrorI18nConstant.SELECT_DATE_LIMIT,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate(31),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The date range is over 93 days. startDate: " + startDate
                                + ", endDate: " + endDate);
            }
        }

    }