# DepCategoryRecommendHourController.java

    package cloud.wconnect.workperformance.controller.sva;

    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.cons.CommonFieldI18nConstant;
    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.pojo.query.PageSizeQuery;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.I18nMessageUtils;
    import cloud.wconnect.workperformance.cons.sva.SvaErrorI18nConstant;
    import cloud.wconnect.workperformance.entity.sva.setting.DepCategoryRecommendHour;
    import cloud.wconnect.workperformance.pojo.dto.sva.recommendhours.RecommendHoursDTO;
    import cloud.wconnect.workperformance.pojo.dto.sva.recommendhours.RecommendHoursHistoryDTO;
    import cloud.wconnect.workperformance.service.sva.setting.IDepCategoryRecommendHourService;
    import cloud.wconnect.workperformance.service.sva.setting.IDepartmentCategoryService;
    import com.google.common.collect.ImmutableMap;
    import com.google.common.collect.Lists;
    import jakarta.annotation.Resource;
    import jakarta.validation.Valid;
    import org.springframework.context.i18n.LocaleContextHolder;
    import org.springframework.util.Assert;
    import org.springframework.web.bind.annotation.*;

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

    /**
     * <p>
     * 控制器类：部门分类推荐时数
     * </p>
     *
     * @author zc
     * @since 2023-03-12
     */
    @RestController
    @RequestMapping("/sva/setting/recommend/hours")
    public class DepCategoryRecommendHourController {
        @Resource
        private IDepCategoryRecommendHourService depCategoryRecommendHourService;
        @Resource
        private IDepartmentCategoryService departmentCategoryService;
        @Resource
        private PropertyI18nRedisService propertyI18nRedisService;
        @Resource
        private SessionContext sessionContext;
        @Resource
        private I18nMessageUtils i18nMessageUtils;

        /**
         * 保存 recommend hours 数据
         *
         * @param property          资产标识
         * @param recommendHoursDTO recommend hours 数据
         * @return recommend hours id
         * @author zc
         * @date 2023/3/12
         */
        @ApiId(88)
        @PostMapping
        public Map<String, Integer> save(@RequestParam String property, @RequestBody @Valid RecommendHoursDTO recommendHoursDTO) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            String timezone = propertyDTO.getTimezone();
            if (Objects.isNull(recommendHoursDTO.getId())) {
                // 选择的开始日期必须是未来日期
                if (!DateTimeUtils.toZonedDateTime(recommendHoursDTO.getStartingDate(), timezone)
                        .isAfter(DateTimeUtils.dateNow(timezone))) {
                    throw new BadRequestException(SvaErrorI18nConstant.DATE_SELECT_MUST_FEATURE,
                            BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                            MessageFormat.format("The starting date must be a future date; startingDate: {0}",
                                    recommendHoursDTO.getStartingDate()));
                }
                // 选择的版本必须是当前版本 或 未来版本
                depCategoryRecommendHourService.checkCategoryVersion(propertyDTO, recommendHoursDTO.getCategoryRecomHours());

                return ImmutableMap.of("id", depCategoryRecommendHourService.insert(propertyDTO.getId(),
                        recommendHoursDTO, sessionContext.getLoginUserId()));
            }

            DepCategoryRecommendHour originRecommendHour = depCategoryRecommendHourService.getById(recommendHoursDTO.getId());
            if (Objects.isNull(originRecommendHour)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_FOUND,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        MessageFormat.format("The recommend hours to be update is not found; recommendHoursId: {0}",
                                recommendHoursDTO.getId()));
            }
            if (!propertyDTO.getId().equals(originRecommendHour.getPropertyId())) {
                throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(),
                        BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(),
                        MessageFormat.format("Cannot update the recommend hours. paramPropertyId: {0}; propertyId: {1}",
                                propertyDTO.getId(), originRecommendHour.getPropertyId()));
            }

            // 增加限制：当前及历史版本不支持编辑
            int updateVersion = Integer.parseInt(DateTimeUtils.localDateToStr(DateTimeUtils.longToLocalDate(recommendHoursDTO.getStartingDate(),
                    timezone), BaseConstant.DATE_FORMAT_YYYYMMDD));
            departmentCategoryService.checkUpdateVersion(propertyDTO.getId(), updateVersion);

            return ImmutableMap.of("id", depCategoryRecommendHourService.update(propertyDTO,
                    sessionContext.getLoginUserId(), originRecommendHour, recommendHoursDTO));
        }

        /**
         * 删除 recommend hours 数据
         *
         * @param property 资产标识
         * @param id       recommend hours id
         * @return empty map
         * @author zc
         * @date 2023/3/13
         */
        @ApiId(90)
        @DeleteMapping("/{id:\\d+}")
        public Map<Object, Object> remove(@RequestParam String property, @PathVariable int id) {
            DepCategoryRecommendHour recommendHour = depCategoryRecommendHourService.getById(id);
            if (Objects.isNull(recommendHour)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_FOUND,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        MessageFormat.format("The recommend hour to be remove is not found; recommendHoursId: {0}",
                                id));
            }
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            if (!propertyDTO.getId().equals(recommendHour.getPropertyId())) {
                throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(),
                        BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(),
                        MessageFormat.format("Cannot remove the recommend hour;paramPropertyId: {0}; propertyId: {1}",
                                propertyDTO.getId(), recommendHour.getPropertyId()));
            }

            // 增加限制：当前及历史版本不支持删除
            int updateVersion = Integer.parseInt(DateTimeUtils.localDateToStr(DateTimeUtils.longToLocalDate(recommendHour.getStartingDate(),
                    propertyDTO.getTimezone()), BaseConstant.DATE_FORMAT_YYYYMMDD));
            departmentCategoryService.checkUpdateVersion(propertyDTO.getId(), updateVersion);

            // 增加限制：若当前版本的 Category 被考勤数据占用，则不能删除
            departmentCategoryService.checkOccupied(recommendHour);

            depCategoryRecommendHourService.removeRecommendHour(recommendHour);

            return Collections.emptyMap();
        }

        /**
         * 获取 recommend hours 历史版本列表
         *
         * @param property 资产标识
         * @param page     当前页码
         * @param size     每页条数
         * @return recommend hours 历史数据
         * @author zc
         * @date 2023/3/13
         */
        @ApiId(91)
        @GetMapping("/history")
        public ListPagedDTO<RecommendHoursHistoryDTO> listByPaged(@RequestParam String property, @RequestParam int page, @RequestParam int size) {
            Assert.isTrue(page > 0, "The page must greater than 0");
            Assert.isTrue(size > 0, "The size must greater than 0");

            int propertyId = sessionContext.getPropertyId(property);
            return depCategoryRecommendHourService.listHistories(propertyId, page, size);
        }

        /**
         * 获取目标日期的 recommend hours 数据
         *
         * @param property   资产标识
         * @param targetDate 目标日期
         * @param isGreater  0: 获取大于目标日期的数据；1: 获取小于目标日期的数据；2: 获取等于目标日期的数据
         * @return recommend hours
         * @author zc
         * @date 2023/3/12
         */
        @ApiId(92)
        @GetMapping
        public RecommendHoursDTO getByTargetDate(@RequestParam String property, @RequestParam long targetDate,
                                                 @RequestParam(required = false) Integer isGreater) {
            int propertyId = sessionContext.getPropertyId(property);

            if (targetDate == 0L) {
                return depCategoryRecommendHourService.getLatest(propertyId);
            }
            if (Objects.isNull(isGreater)) {
                return depCategoryRecommendHourService.getCurrent(propertyId, targetDate);
            }
            if (!Lists.newArrayList(RecommendHoursDTO.LESS_THAN, RecommendHoursDTO.GREATER_THAN,
                    RecommendHoursDTO.EQUAL_TO).contains(isGreater)) {
                throw new BadRequestException(CommonErrorI18nConstant.MUST_IN_LIST,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("isGreater",
                                List.of("less-than", "greater-than", "equal-to")),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The isGreater must be in [0:less than; 1:greater than; 2:equal to]");

            }
            return depCategoryRecommendHourService.getEffective(propertyId, targetDate, isGreater);
        }

        /**
         * 1434 - 新增推荐工时操作可供选择的推荐工时版本列表
         *
         * @param property 资产标识
         * @param query    分页查询参数
         * @return 版本列表
         * @author yyt
         * @date 2025/4/30
         **/
        @ApiId(1434)
        @GetMapping("/new-operations-available")
        public ListPagedDTO<RecommendHoursHistoryDTO> listNewOperationsAvailable(String property, @Valid PageSizeQuery query) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            return depCategoryRecommendHourService.listNewOperationsAvailable(propertyDTO, query);
        }

    }