# BudgetDatabaseSchedulerJobController.java

    package cloud.wconnect.rateshop.controller.budgetdatabase;

    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.cons.CommonFieldI18nConstant;
    import cloud.wconnect.commonlib.cons.SchedulerCons;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.util.CronRuleUtil;
    import cloud.wconnect.commonlib.util.I18nMessageUtils;
    import cloud.wconnect.rateshop.cons.budgetdatabase.BudgetDatabaseNotifyCons;
    import cloud.wconnect.rateshop.entity.budgetdatabase.BudgetDatabaseConfigSchedulerJob;
    import cloud.wconnect.rateshop.pojo.dto.budgetdatabase.BudgetDatabaseSchedulerDTO;
    import cloud.wconnect.rateshop.service.budgetdatabase.IBudgetDatabaseConfigSchedulerJobService;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.google.common.collect.ImmutableMap;
    import com.google.common.collect.Lists;
    import jakarta.validation.Valid;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;

    import java.util.List;
    import java.util.Map;

    /**
     * <p>
     * 前端控制器
     * </p>
     *
     * @author yyt
     * @since 2025-08-16
     */
    @RestController
    @RequestMapping("/budget-database/scheduler")
    public class BudgetDatabaseSchedulerJobController {

        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        private SessionContext sessionContext;
        @Autowired
        private IBudgetDatabaseConfigSchedulerJobService schedulerJobService;
        @Autowired
        private ObjectMapper objectMapper;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;

        /**
         * 1568 - 查询定时任务
         *
         * @param property 资产标识
         * @param category 分类 (1：到期通知)
         * @return 定时任务
         * @author yyt
         * @date 2025/8/16
         */
        @ApiId(1568)
        @GetMapping("/{category:\\d+}")
        public List<BudgetDatabaseSchedulerDTO> get(String property, @PathVariable int category) {
            int propertyId = sessionContext.getPropertyId(property);

            // 查询非删除中的定时任务
            List<BudgetDatabaseConfigSchedulerJob> schedulers = schedulerJobService.list(propertyId, category);
            return beanMapper.mapList(schedulers, BudgetDatabaseSchedulerDTO.class);
        }

        /**
         * 1569 - 保存定时任务
         *
         * @param property     资产标识
         * @param id           定时任务 id
         * @param schedulerDTO 定时任务
         * @return {}
         * @author yyt
         * @date 2025/8/16
         */
        @ApiId(1569)
        @PostMapping("/{id}")
        public Map<String, String> save(String property, @PathVariable String id, @Valid @RequestBody BudgetDatabaseSchedulerDTO schedulerDTO) {
            // 校验定时规则
            checkScheduler(schedulerDTO);
            Integer propertyId = sessionContext.getPropertyId(property);
            int loginUserId = sessionContext.getLoginUserId();

            if (schedulerDTO.getCategory() == BudgetDatabaseNotifyCons.EXPIRATION_NOTICE) {
                schedulerDTO.setParameters("{}");
            }

            if (id.equals("0")) {
                // 校验分类下最大可配置调度任务的数量
                schedulerJobService.checkMaxNum(propertyId, schedulerDTO.getCategory(), 1);

                id = schedulerJobService.save(propertyId, schedulerDTO, loginUserId);
            } else {
                //校验调度任务是否存在
                BudgetDatabaseConfigSchedulerJob scheduler = schedulerJobService.checkExist(id);

                //校验是否归属于资产
                schedulerJobService.checkBelong(scheduler, propertyId);

                if (scheduler.getStatus() == SchedulerCons.STATUS_DELETING) {
                    throw new BadRequestException(CommonErrorI18nConstant.SCHEDULER_CANNOT_UPDATE_DELETING,
                            BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),  "deleting scheduler do not support update; schedulerId:" + id);
                }
                if (!scheduler.getCategory().equals(schedulerDTO.getCategory())) {
                    throw new BadRequestException(CommonErrorI18nConstant.CANNOT_MODIFIED,
                            i18nMessageUtils.getErrorParamMapNeedTranslate(CommonFieldI18nConstant.CATEGORY),
                            BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "scheduler category do not support update; schedulerId:" + id);
                }

                id = schedulerJobService.update(propertyId, scheduler, schedulerDTO, loginUserId);
            }

            return ImmutableMap.of("id", id);
        }

        /**
         * 校验定时规则
         *
         * @param schedulerDTO 定时
         * @author yyt
         * @date 2025/8/16
         **/
        private void checkScheduler(BudgetDatabaseSchedulerDTO schedulerDTO) {
            switch (schedulerDTO.getCategory()) {
                case BudgetDatabaseNotifyCons.EXPIRATION_NOTICE -> {
                    // 检查 scheduler json 格式是否合法，目前支持配置按天执行；
                    CronRuleUtil.validateCronRuleForScheduler(objectMapper, List.of(SchedulerCons.EVERY_DAY), schedulerDTO.getScheduler());
                }

                default -> throw new BadRequestException(CommonErrorI18nConstant.MUST_IN_LIST,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate(CommonFieldI18nConstant.CATEGORY, Lists.newArrayList(BudgetDatabaseNotifyCons.EXPIRATION_NOTICE)),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "category parameter error");
            }
        }

    }