shiftloop_fb.drl 12.1 KB
package com.bsth.service.schedule.shiftloop;

import org.joda.time.*;
import java.util.*;

import com.bsth.service.schedule.rules.shiftloop.ScheduleCalcuParam_input;
import com.bsth.service.schedule.rules.shiftloop.ScheduleRule_input;
import com.bsth.service.schedule.rules.shiftloop.ScheduleResult_output;
import com.bsth.service.schedule.rules.shiftloop.ScheduleResults_output;

import org.slf4j.Logger;

global Logger log;

/*
    存在(翻班格式)
*/

//------------------------- 第一阶段、计算规则准备数据(天数) ----------------------------//

declare Calcu_days_result
    ruleId : String // 规则Id
    qyrq_days : Integer // 开始日期离启用日期的天数
    sdays : Integer // 总共需要排班的天数
    calcu_start_date : DateTime // 开始计算日期
    calcu_end_date : DateTime // 结束计算日期
end

/*
    计算启用日期,开始计算日期,结束计算日期,相差天数
    1、规则启用日期小于开始计算日期
    2、规则启用日期大于等于开始日期,小于等于结束日期
*/
rule "calcu_days_1"
    salience 100
    when
        ScheduleCalcuParam_input(
            fromDate.isBefore(toDate) || fromDate.isEqual(toDate),
            $fromDate : fromDate,
            $toDate : toDate
        )
        ScheduleRule_input($ruleId : ruleId, $qyrq : qyrq)
        eval($qyrq.isBefore($fromDate))
    then
        // 构造Calcu_days_result对象,进行下一阶段计算
        Calcu_days_result cdr = new Calcu_days_result();
        cdr.setRuleId($ruleId);
        Period p1 = new Period($qyrq, $fromDate, PeriodType.days());
        cdr.setQyrq_days(p1.getDays());
        Period p2 = new Period($fromDate, $toDate, PeriodType.days());
        cdr.setSdays(p2.getDays() + 1);
        cdr.setCalcu_start_date($fromDate);
        cdr.setCalcu_end_date($toDate);

        log.info("开始日期离启用日期的天数 qyrq_days={}", p1.getDays());
        log.info("总共需要排班的天数 sdays={}", (p2.getDays() + 1));

        insert(cdr); // 插入fact数据,进入下一个阶段
end

rule "calcu_days_2"
    salience 100
    when
        ScheduleCalcuParam_input(
            fromDate.isBefore(toDate) || fromDate.isEqual(toDate),
            $fromDate : fromDate,
            $toDate : toDate
        )
        ScheduleRule_input($ruleId : ruleId, $qyrq : qyrq)
        eval((!$qyrq.isBefore($fromDate)) && (!$qyrq.isAfter($toDate)))
    then
        // 构造Calcu_days_result对象,进行下一阶段计算
        Calcu_days_result cdr = new Calcu_days_result();
        cdr.setRuleId($ruleId);
        cdr.setQyrq_days(0);
        Period p2 = new Period($qyrq, $toDate, PeriodType.days());
        cdr.setSdays(Integer.valueOf(p2.getDays() + 1));
        cdr.setCalcu_start_date($qyrq);
        cdr.setCalcu_end_date($toDate);

        log.info("开始日期离启用日期的天数 qyrq_days=0");
        log.info("总共需要排班的天数 sdays={}", (p2.getDays() + 1));

        insert(cdr); // 插入fact数据,进入下一个阶段
end

//------------------------- 第二阶段、计算规则准备数据2(起始索引) ----------------------------//

//----------------------- 路牌范围循环计算 ------------------------//

declare Calcu_guideboard_index_result
    ruleId : String // 规则Id
    calcu_index : Integer // 计算之后的起始索引
end

// 启用日期等于开始日期
rule "calcu_guideboard_index_qyrq_eq_startrq"
    when
        $calcu_days_result : Calcu_days_result(
            qyrq_days == 0,
            $ruleId: ruleId
        )
        $scheduleRule_input : ScheduleRule_input(
            ruleId == $ruleId,
            $oindex : startGbdIndex
        )
    then
        Calcu_guideboard_index_result cgir = new Calcu_guideboard_index_result();
        cgir.setRuleId($ruleId);
        cgir.setCalcu_index($oindex);

        log.info("calcu_guideboard_index_qyrq_eq_startrq ruleId={}, calcu_index={}", $ruleId, cgir.getCalcu_index());

        insert(cgir);
end

// 开始日期大于启用日期
rule "calcu_guideboard_index_startrq_gt_qyrq"
    when
        $calcu_days_result : Calcu_days_result(
            qyrq_days > 0,
            $ruleId: ruleId, $qyrq_days: qyrq_days,
            $calcu_start_date: calcu_start_date
        )
        $scheduleRule_input : ScheduleRule_input(
            ruleId == $ruleId,
            $qyrq: qyrq,
            $rangesize : guideboardIds.size(),
            $oindex : startGbdIndex,
            $weekdays: weekdays
        )
    then
        // 开始时间
        DateTime initDate = $qyrq;
        int index = $oindex;
        int resultIndex = index;

        while (!initDate.isAfter($calcu_start_date)) {
            if (((Boolean) $weekdays.get(initDate.getDayOfWeek() - 1)).booleanValue()) {
                resultIndex = index;
                index = (index + 1) % $rangesize;
            }
            initDate = initDate.plusDays(1);
        }

        Calcu_guideboard_index_result cgir = new Calcu_guideboard_index_result();
        cgir.setRuleId($ruleId);
        cgir.setCalcu_index(resultIndex);

        log.info("calcu_guideboard_index_startrq_gt_qyrq ruleId={}, calcu_index={}", $ruleId, cgir.getCalcu_index());

        insert(cgir);
end

//----------------------- 人员范围循环计算 ------------------------//

declare Calcu_employee_index_result
    ruleId : String // 规则Id
    calcu_index : Integer // 计算之后的起始索引
end

// 启用日期等于开始日期
rule "calcu_employee_index_qyrq_eq_startrq"
    when
        $calcu_days_result : Calcu_days_result(
            qyrq_days == 0,
            $ruleId: ruleId)
        $scheduleRule_input : ScheduleRule_input(
            ruleId == $ruleId,
            $oindex : startEIndex)
    then
        Calcu_employee_index_result cgir = new Calcu_employee_index_result();
        cgir.setRuleId($ruleId);
        cgir.setCalcu_index($oindex);

        log.info("calcu_employee_index_qyrq_eq_startrq ruleId={}, calcu_index={}", $ruleId, cgir.getCalcu_index());

        insert(cgir);
end

// 开始日期大于启用日期
rule "calcu_employee_index_startrq_gt_qyrq"
    when
        $calcu_days_result : Calcu_days_result(
            qyrq_days > 0,
            $ruleId: ruleId, $qyrq_days: qyrq_days,
            $calcu_start_date: calcu_start_date
        )
        $scheduleRule_input : ScheduleRule_input(
            ruleId == $ruleId,
            $qyrq: qyrq,
            $rangesize : employeeConfigIds.size(),
            $oindex : startEIndex,
            $weekdays: weekdays
        )
    then
        // 开始时间
        DateTime initDate = $qyrq;
        int index = $oindex;
        int resultIndex = index;

        while (!initDate.isAfter($calcu_start_date)) {
            if (((Boolean) $weekdays.get(initDate.getDayOfWeek() - 1)).booleanValue()) {
                resultIndex = index;
                index = (index + 1) % $rangesize;
            }
            initDate = initDate.plusDays(1);
        }

        Calcu_employee_index_result cgir = new Calcu_employee_index_result();
        cgir.setRuleId($ruleId);
        cgir.setCalcu_index(resultIndex);

        log.info("calcu_employee_index_startrq_gt_qyrq ruleId={}, calcu_index={}", $ruleId, cgir.getCalcu_index());

        insert(cgir);

end

//------------------------- 第三阶段、循环计算 ------------------------//

//----------------------- 路牌范围循环计算 ------------------------//
declare loop_guideboard_result
    ruleId : String // 规则id
    go_list : List // 路牌循环的列表
end

// 循环路牌计算
rule "Calcu_loop_guideboard_result"
    when
        Calcu_days_result(
            $ruleId: ruleId,
            $startDate : calcu_start_date,
            $calcu_end_date: calcu_end_date
        )
        $ruleData : ScheduleRule_input(
            ruleId == $ruleId,
            $rangesize : guideboardIds.size(),
            $weekdays: weekdays
        )
        $indexData : Calcu_guideboard_index_result(
            ruleId == $ruleId
        )
    then
        DateTime initDate = $startDate; // 开始时间
        DateTime endDate = $calcu_end_date; // 结束实际
        List<ScheduleResult_output> scheduleResult_outputs =
            new ArrayList<ScheduleResult_output>();

        int i = $indexData.getCalcu_index();
        if (((Boolean) $weekdays.get(initDate.getDayOfWeek() - 1)).booleanValue() == false) {
            i = (i + 1) % $rangesize;
        }

        while (!initDate.isAfter(endDate)) {
            if (((Boolean) $weekdays.get(initDate.getDayOfWeek() - 1)).booleanValue()) {
                ScheduleResult_output ro = new ScheduleResult_output();
                ro.setRuleId($ruleId);
                ro.setSd(initDate);
                ro.setGuideboardId($ruleData.getGuideboardIds().get(i));
                ro.setCarConfigId($ruleData.getCarConfigId());
                scheduleResult_outputs.add(ro);

                i = (i + 1) % $rangesize;
            }

            initDate = initDate.plusDays(1);
        }

        loop_guideboard_result clgr = new loop_guideboard_result();
        clgr.setRuleId($ruleId);
        clgr.setGo_list(scheduleResult_outputs);

        log.info(String.valueOf(scheduleResult_outputs.size()));

        insert(clgr);

end

//----------------------- 人员范围循环计算 ------------------------//
declare loop_employee_result
    ruleId : String // 规则id
    eo_list : List // 人员循环的列表
end

// 循环人员计算
rule "Calcu_loop_employee_result"
    when
        Calcu_days_result(
            $ruleId: ruleId,
            $startDate : calcu_start_date,
            $calcu_end_date: calcu_end_date
        )
        $ruleData : ScheduleRule_input(
            ruleId == $ruleId,
            $rangesize : employeeConfigIds.size(),
            $weekdays: weekdays
        )
        $indexData : Calcu_employee_index_result(
            ruleId == $ruleId
        )
    then
        DateTime initDate = $startDate; // 开始时间
        DateTime endDate = $calcu_end_date; // 结束实际
        List<ScheduleResult_output> scheduleResult_outputs =
            new ArrayList<ScheduleResult_output>();

        int i = $indexData.getCalcu_index();
        if (((Boolean) $weekdays.get(initDate.getDayOfWeek() - 1)).booleanValue() == false) {
            i = (i + 1) % $rangesize;
        }

        while (!initDate.isAfter(endDate)) {
            if (((Boolean) $weekdays.get(initDate.getDayOfWeek() - 1)).booleanValue()) {
                ScheduleResult_output ro = new ScheduleResult_output();
                ro.setRuleId($ruleId);
                ro.setSd(initDate);
                ro.setEmployeeConfigId($ruleData.getEmployeeConfigIds().get(i));
                ro.setCarConfigId($ruleData.getCarConfigId());
                scheduleResult_outputs.add(ro);

                i = (i + 1) % $rangesize;
            }

            initDate = initDate.plusDays(1);
        }

        loop_employee_result clgr = new loop_employee_result();
        clgr.setRuleId($ruleId);
        clgr.setEo_list(scheduleResult_outputs);

        log.info(String.valueOf(scheduleResult_outputs.size()));

        insert(clgr);
end

//------------------------- 第四阶段、范围组循环计算 ----------------------------//

global ScheduleResults_output scheduleResult;

rule "output"
    when
        loop_guideboard_result(
            go_list.size() > 0,
            $ruleId : ruleId, $go_list : go_list
        )
        loop_employee_result(
            ruleId == $ruleId,
            eo_list.size() == $go_list.size(),
            $eo_list : eo_list
        )
    then
        for (int i = 0; i < $go_list.size(); i++) {
            ScheduleResult_output go = (ScheduleResult_output) $go_list.get(i);
            ScheduleResult_output eo = (ScheduleResult_output) $eo_list.get(i);
            go.setEmployeeConfigId(eo.getEmployeeConfigId());
            scheduleResult.getResults().add(go);
        }

end