def schedule(self, totalDayNum): scheduleResult = ScheduleResult() totalDayNum = int(totalDayNum) if self.workerNum < self.dailyRequiredWorkerNum: print('worker number less than workload, cannot schedule') scheduleResult.message = u'总员工人数小于每天出勤人数,无法排班' return scheduleResult if self.workerNum == self.dailyRequiredWorkerNum: print('worker number equals to workload, don\'t need to schedule at all') scheduleResult.message = u'总员工人数等于每天出勤人数,无需排班' return scheduleResult if self.MIN_WORK_DAY > self.maxWorkDay: print('min day > max day') scheduleResult.message = u'最大连续出勤天数设置无法保证连续出勤' return scheduleResult if self.MIN_WORK_DAY == self.maxWorkDay: if self.workerNum < self.dailyRequiredWorkerNum * 2: print('min=max but workers < workload * 2, not enough worker to handle the workload') scheduleResult.message = u'最大最小连续出勤数相等且总员工数小于每天出勤人数的两倍,人手不足' return scheduleResult else: # 固定班次的话,则误差可能为固定连续出勤数 self.MAX_DELTA_DAY = self.MIN_WORK_DAY # 这种情况包含了上一种情况 if self.workerNum < self.dailyRequiredWorkerNum * 2: if self.maxWorkDay < self.MIN_WORK_DAY * 2: print('min * 2 > max while workers < workload * 2, not enough worker to handle the workload') scheduleResult.message = u'总员工数小于每天出勤人数的两倍,且最大连续出勤天数小于最小连续出勤天数的两倍,人手不足' return scheduleResult workerNum = self.workerNum # 平均工时每人(天),向上取整 targetTotalWorkDay = int(totalDayNum * self.dailyRequiredWorkerNum + workerNum - 1) / workerNum if self.MIN_WORK_DAY > targetTotalWorkDay: scheduleResult.message = u'最小连续工时大于平均工时,不能平均安排工时' return scheduleResult retryCnt = 0 minDelta = 99999 unBalancedResult = dict() while retryCnt < self.MAX_RETRY_TIME: retryCnt += 1 [resultCalendar, workStats] = self.doSchedule(totalDayNum) if self.validateSchedule(resultCalendar): currentDelta = self.getMaxDelta(resultCalendar, totalDayNum) if currentDelta <= self.MAX_DELTA_DAY: logging.debug('after %d time\'s retry', retryCnt) scheduleResult.message = u'排班成功且工时较为平均' scheduleResult.workCalendar = resultCalendar scheduleResult.personalTotalWorkDay = self.calculateWorkDayPerWorker(resultCalendar) scheduleResult.restCalendar = self.getRestCalendar(resultCalendar) return scheduleResult else: # 如果不够平均,则取目前最平均的排班返回 logging.debug('minDelta %d current %d', minDelta, currentDelta) if minDelta > currentDelta: unBalancedResult = resultCalendar minDelta = currentDelta logging.debug('Cannot meet min delta requirement after %d retries', self.MAX_RETRY_TIME) if unBalancedResult: scheduleResult.message = u'排班成功但没有找到工时最平均方案' scheduleResult.workCalendar = unBalancedResult scheduleResult.personalTotalWorkDay = self.calculateWorkDayPerWorker(unBalancedResult) scheduleResult.restCalendar = self.getRestCalendar(unBalancedResult) self.printFormatedCalendar(unBalancedResult) logging.debug(self.getMaxDelta(unBalancedResult, totalDayNum)) else: logging.debug('empty unbalanceResult') scheduleResult.message = u'没有找到符合条件的排班方案,建议调整参数' return scheduleResult
def schedule(self, totalScheduleDays): scheduleResult = ScheduleResult() totalScheduleDays = int(totalScheduleDays) if totalScheduleDays % 7 != 0: print('totalScheduleDays % 7 != 0') scheduleResult.message = u'排班周期必须为7的倍数' return scheduleResult if self.totalWorkerNum < self.workerNumRequired: print('worker number less than workload, cannot schedule') scheduleResult.message = u'总员工人数小于每天休息人数,无法排班' return scheduleResult if self.totalWorkerNum == self.workerNumRequired: print('worker number equals to workload, don\'t need to schedule at all') scheduleResult.message = u'总员工人数等于每天休息人数,无需排班' return scheduleResult if self.minRestDay > self.maxRestDay: print('min day > max day') scheduleResult.message = u'最小连续休息天数大于最大连续休息天数,无法排班' return scheduleResult try: [restCalendar, workStats] = self.doSchedule(totalScheduleDays) if not self.validateSchedule(restCalendar): scheduleResult.message = u'没有找到符合条件的排班方案,请调整参数' else: scheduleResult.restCalendar = restCalendar scheduleResult.workCalendar = self.getWorkCalendar(restCalendar) scheduleResult.personalTotalWorkDay = self.calculateWorkDayPerWorker(scheduleResult.workCalendar) scheduleResult.message = u'排班成功' except: scheduleResult.message = u'遇到未知错误,没有找到符合条件的排班方案,请调整参数' return scheduleResult
def schedule(self, targetDays): scheduleResult = ScheduleResult() targetDays = int(targetDays) if len(self.workers) < self.workload: print('worker number less than workload, cannot schedule') scheduleResult.message = u'总员工人数小于每天出勤人数,无法排班' return scheduleResult if len(self.workers) == self.workload: print('worker number equals to workload, don\'t need to schedule at all') scheduleResult.message = u'总员工人数等于每天出勤人数,无需排班' return scheduleResult if self.minWorkDay > self.maxWorkDay: print('min day > max day') scheduleResult.message = u'最小连续出勤天数大于最大连续出勤天数,无法排班' return scheduleResult if self.minWorkDay == self.maxWorkDay: if len(self.workers) < self.workload * 2: print('min=max but workers < workload * 2, not enough worker to handle the workload') scheduleResult.message = u'最大最小连续出勤数相等且总员工数小于每天出勤人数的两倍,人手不足' return scheduleResult else: # 固定班次的话,则误差可能为固定连续出勤数 self.MAX_DELTA_DAY = self.minWorkDay # 这种情况包含了上一种情况 if len(self.workers) < self.workload * 2: if self.maxWorkDay < self.minWorkDay * 2: print('min * 2 > max while workers < workload * 2, not enough worker to handle the workload') scheduleResult.message = u'总员工数小于每天出勤人数的两倍,且最大连续出勤天数小于最小连续出勤天数的两倍,人手不足' return scheduleResult workerNum = len(self.workers) # 平均工时每人(天),向上取整 targetTotalWorkDay = int(targetDays * self.workload + workerNum - 1) / workerNum if self.minWorkDay > targetTotalWorkDay: scheduleResult.message = u'最小连续工时大于平均工时,不能平均安排工时' return scheduleResult retryCnt = 0 minDelta = 99999 unBalancedResult = dict() while retryCnt < self.MAX_RETRY_TIME: retryCnt += 1 [resultCalendar, workStats] = self.doSchedule(targetDays) # self.printSchedule(resultCalendar) if self.validateSchedule(resultCalendar): currentDelta = self.getMaxDelta(resultCalendar, targetDays) if currentDelta <= self.MAX_DELTA_DAY: print('after', retryCnt, 'time\'s retry') self.printSchedule(resultCalendar) scheduleResult.message = u'排班成功且工时较为平均' scheduleResult.workCalendar = resultCalendar scheduleResult.personalTotalWorkDay = self.calculateWorkDayPerWorker(resultCalendar) scheduleResult.restCalendar = self.getRestCalendar(resultCalendar) # scheduleResult.workStats = workStats return scheduleResult else: # 如果不够平均,则取目前最平均的排班返回 print('minDelta', minDelta, 'current', currentDelta) if minDelta > currentDelta: unBalancedResult = resultCalendar unBalancedWorkStats = workStats minDelta = currentDelta print('fail to schedule after', self.MAX_RETRY_TIME, 'retries') if unBalancedResult: # print('before rebalance' # print('delta', self.getMaxDelta(unBalancedResult, targetDays) # print(self.calculateWorkDayPerWorker(unBalancedResult) # self.printSchedule(unBalancedResult) newUnBalancedResult = self.rebalance(unBalancedResult, unBalancedWorkStats) # print('revalidate', self.validateSchedule(newUnBalancedResult) # print('after rebalance' # print('new delta', self.getMaxDelta(newUnBalancedResult, targetDays) # print(self.calculateWorkDayPerWorker(newUnBalancedResult) # self.printSchedule(newUnBalancedResult) if (self.validateSchedule(newUnBalancedResult)): scheduleResult.message = u'排班成功但没有找到工时最平均方案' scheduleResult.workCalendar = newUnBalancedResult scheduleResult.personalTotalWorkDay = self.calculateWorkDayPerWorker(newUnBalancedResult) scheduleResult.restCalendar = self.getRestCalendar(newUnBalancedResult) # scheduleResult.workStats = unBalancedWorkStats else: scheduleResult.message = u'尝试重新平衡化工时失败,如果不满意请重试' scheduleResult.workCalendar = unBalancedResult scheduleResult.personalTotalWorkDay = self.calculateWorkDayPerWorker(unBalancedResult) scheduleResult.restCalendar = self.getRestCalendar(unBalancedResult) # scheduleResult.workStats = unBalancedWorkStats else: print('empty unbalanceResult') scheduleResult.message = u'没有找到符合条件的排班方案,请调整参数' self.printFormatedCalendar(scheduleResult.workCalendar) self.getMaxDelta(scheduleResult.workCalendar, targetDays) return scheduleResult