# GmwrGenerateDataTask.java

    package cloud.wconnect.workperformance.businesstask.gmwr;

    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.cons.FunctionIdConstant;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.pojo.query.OpenFunctionPropertyQuery;
    import cloud.wconnect.commonlib.service.PropertyInternalService;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.workperformance.entity.gmwr.GmwrWeeks;
    import cloud.wconnect.workperformance.service.gmwr.*;
    import cloud.wconnect.workperformance.service.hotelkpi.internal.IHotelKpiInternalService;
    import com.google.common.collect.Lists;
    import jakarta.annotation.Resource;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.collections4.CollectionUtils;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Component;

    import java.time.DayOfWeek;
    import java.time.LocalDateTime;
    import java.time.ZoneId;
    import java.util.List;
    import java.util.concurrent.TimeUnit;
    import java.util.stream.Collectors;

    /**
     * Task: 生成周报数据
     *
     * @author zc
     * @date 2024/10/15
     */
    @Slf4j
    @Component
    public class GmwrGenerateDataTask {
        @Resource
        private IGmwrWeeksService weeksService;
        @Resource
        private IGmwrMonthEndService monthEndService;
        @Resource
        private IGmwrMonthlyOtbPaceService monthlyOtbPaceService;
        @Resource
        private IGmwrStrDataService strDataService;
        @Resource
        private IGmwrHotelKpiService hotelKpiService;
        @Resource
        private IGmwrSelloutEfficiencyService selloutEfficiencyService;
        @Resource
        private PropertyInternalService propertyInternalService;
        @Resource
        private IHotelKpiInternalService hotelKpiInternalService;
        @Resource
        private RedisTemplate<String, Object> jsonRedisTemplate;

        /**
         * 数据生成时间
         */
        private static final int GENERATE_TIME = 9;

        private static final String PREFIX_KEY_GENERATE = "wconnect:task:weekly-gm-report:generate:";

        /**
         * 生成数据
         *
         * @author zc
         * @date 2024/10/15
         */
        @Scheduled(cron = "${schedule.cron.weekly-gm-report.generate}", zone = "${default.timezone}")
        public void generate() {
            log.info("GmwrGenerateDataTask.generate start...");

            // 获取资产
            List<PropertyDTO> openPropertyList = getPropertyList();
            if (CollectionUtils.isEmpty(openPropertyList)) {
                log.info("GmwrGenerateDataTask.generate end... openPropertyList is empty");
                return;
            }

            for (PropertyDTO propertyDTO : openPropertyList) {
                // 判断 nowDateTime 与配置的周起始日是否一致 且 nowDateTime 等于中午 12 点，若不是则跳过
                LocalDateTime nowDateTime = LocalDateTime.now(ZoneId.of(propertyDTO.getTimezone()));
                DayOfWeek dayOfWeek = hotelKpiInternalService.getWeekStartDay(propertyDTO.getId());
                if (nowDateTime.getDayOfWeek().compareTo(dayOfWeek) != 0
                        || nowDateTime.getHour() != GENERATE_TIME) {
                    continue;
                }

                // 防止并发操作（wconnect:task:weekly-gm-report:generate:250108:2）
                String concurrencyKey = PREFIX_KEY_GENERATE + DateTimeUtils.localDateTimeToStr(nowDateTime,
                        BaseConstant.DATE_FORMAT_YYMMDD) + ":" + propertyDTO.getId();
                if (!preventConcurrency(concurrencyKey)) {
                    // 若某资产当天已执行过，则跳过
                    continue;
                }

                // 生成上一周期的主数据
                GmwrWeeks gmwrWeeks = weeksService.save(propertyDTO, nowDateTime.minusDays(7).toLocalDate());

                // 生成 Month End 数据
                monthEndService.generate(propertyDTO, gmwrWeeks);
                // 生成 Monthly OTB Pace 数据
                monthlyOtbPaceService.generate(propertyDTO, gmwrWeeks);
                // 生成 Str Data 数据
                strDataService.generate(propertyDTO, gmwrWeeks);
                // 生成 Sellout Efficiency 数据
                selloutEfficiencyService.generate(propertyDTO, gmwrWeeks);
                // 生成 Hotel KPI 数据
                hotelKpiService.generate(propertyDTO, gmwrWeeks);
            }
            log.info("GmwrGenerateDataTask.generate end...");
        }

        /**
         * 过滤出有效的资产
         *
         * @return PropertyDTO 资产集合
         * @author zc
         * @date 2025/1/27
         */
        private List<PropertyDTO> getPropertyList() {
            // 过滤出有效的资产
            return propertyInternalService.getOpenFunctionProperty(OpenFunctionPropertyQuery.builder()
                            .openFunctionIds(Lists.newArrayList(FunctionIdConstant.GM_WEEKLY_REPORT)).build()).stream()
                    .filter(PropertyDTO::getStatus).collect(Collectors.toList());
        }

        /**
         * 校验是否并发执行
         *
         * @param key 缓存前缀
         * @return true:是；false:否
         * @author zc
         * @date 2024/10/15
         */
        private Boolean preventConcurrency(String key) {
            return jsonRedisTemplate.opsForValue().setIfAbsent(key, 0, 1, TimeUnit.DAYS);
        }
    }