def ValidateConstraint5(person_config, all_dates, assignment_dict, errors): name = person_config.name fixed_total_workdays = 0 off_count = 0 for work_date in all_dates: shift_type = assignment_dict.get((work_date, name)) if shift_type in _WORK_SHIFTS: fixed_total_workdays += 1 elif shift_type == _OFF_SHIFT: off_count += 1 util.ErrorIfLess( len(all_dates) - off_count, person_config.min_total_workdays, errors, _('Worker {person_name} should work for at least {min_total_workdays} days, but is already scheduled to off for {total_off_days} days out of {total_calendar_days} days' ), person_name=name, min_total_workdays=person_config.min_total_workdays, total_off_days=off_count, total_calendar_days=len(all_dates)) util.ErrorIfGreater( fixed_total_workdays, person_config.max_total_workdays, errors, _('Worker {person_name} should work no more than {max_total_workdays} days, but is already scheduled to work for {fixed_total_workdays} days' ), person_name=name, max_total_workdays=person_config.max_total_workdays, fixed_total_workdays=fixed_total_workdays)
def ValidateConstraint4(person_config, all_dates, assignment_dict, errors): name = person_config.name consecutive_nights = 0 start_work_date = None # Adding [None] is a trick to include consecutive nights ending on end_date for work_date in all_dates + [None]: shift_type = assignment_dict.get((work_date, name)) if shift_type == _NIGHT_SHIFT: if start_work_date is None: # Starting a new consecutive nights start_work_date = work_date consecutive_nights += 1 else: util.ErrorIfGreater( consecutive_nights, person_config.max_consecutive_nights, errors, _('Worker {person_name} should work no more than {max_consecutive_nights} consecutive nights, but worked for {actual_consecutive_nights} nights from {start_date}' ), person_name=name, max_consecutive_nights=person_config.max_consecutive_nights, actual_consecutive_nights=consecutive_nights, start_date=start_work_date) consecutive_nights = 0 start_work_date = None
def ValidateConstraint3(person_config, all_dates, assignment_dict, errors): name = person_config.name consecutive_workdays = 0 start_work_date = None # Adding [None] is a trick to include consecutive workdays ending on 'end_date' for work_date in (all_dates + [None]): shift_type = assignment_dict.get((work_date, name)) if shift_type in _WORK_SHIFTS: if start_work_date is None: # Starting a new consecutive workdays start_work_date = work_date consecutive_workdays += 1 # shift_type can be None for barebone input. elif shift_type is None or shift_type == _OFF_SHIFT: util.ErrorIfGreater( consecutive_workdays, person_config.max_consecutive_workdays, errors, _('Worker {person_name} should work no more than {max_consecutive_workdays} consecutive days, but worked for {actual_consecutive_workdays} days from {start_date}' ), person_name=name, max_consecutive_workdays=person_config. max_consecutive_workdays, actual_consecutive_workdays=consecutive_workdays, start_date=start_work_date) consecutive_workdays = 0 start_work_date = None
def ValidateMaximumTotalWorkSlots(person_configs, off_count, date_count, errors): sum_max_workdays = functools.reduce( lambda sum, pc: sum + pc.max_total_workdays, person_configs, 0) non_off_count = len(person_configs) * date_count - off_count util.ErrorIfGreater( non_off_count, sum_max_workdays, errors, _('There are {total_available_slot_count} slots to fill, but the sum of total maximum workdays of all people are {sum_max_total_workdays}' ), total_available_slot_count=non_off_count, sum_max_total_workdays=sum_max_workdays)
def ValidateMinimumTotalWorkSlots(person_configs, off_count, date_count, errors): sum_min_workdays = functools.reduce( lambda sum, pc: sum + pc.min_total_workdays, person_configs, 0) non_off_count = len(person_configs) * date_count - off_count util.ErrorIfGreater( sum_min_workdays, non_off_count, errors, _('Sum of total minimum workdays of all people are {sum_min_total_workdays}, but there are only {total_available_slot_count} available slots to work' ), sum_min_total_workdays=sum_min_workdays, total_available_slot_count=non_off_count)
def ValidateMinimumRequiredWorkers(date_configs, assignment_dict, num_person, errors): for date_config in date_configs: total_required = date_config.num_workers_day + date_config.num_workers_evening + date_config.num_workers_night off_count = util.GetWorkerCount(assignment_dict, date_config.work_date, _OFF_SHIFT) available_workers = num_person - off_count util.ErrorIfGreater( total_required, available_workers, errors, _('{required_count} workers are required on {work_date}, but {off_worker_count} out of {total_worker_count} people already scheduled to off that day' ), required_count=total_required, work_date=date_config.work_date, off_worker_count=off_count, total_worker_count=num_person)