Move valid_residents to the scheduler impl and simplify it

This commit is contained in:
2026-01-14 21:15:57 +02:00
parent 2febcb7344
commit 1ce55675db
4 changed files with 63 additions and 118 deletions

View File

@@ -3,8 +3,7 @@ use serde::{Deserialize, Serialize};
use crate::{
resident::{Resident, ResidentDTO},
schedule::{MonthlySchedule, ShiftType},
slot::{Day, ShiftPosition, Slot},
slot::Day
};
const YEAR: i32 = 2026;
@@ -80,54 +79,6 @@ impl UserConfig {
|| self.holidays.contains(&(day.0 as usize))
}
/// Return all possible candidates for the next slot
/// TODO: move this to another file, UserConfig should only hold the info set from GUI
///
/// @slot
/// @schedule
pub fn candidates(
&self,
slot: Slot,
schedule: &MonthlySchedule,
) -> Vec<(&Resident, &ShiftType)> {
let mut candidates = vec![];
let is_open = slot.is_open_shift();
let other_position = match slot.position {
ShiftPosition::First => ShiftPosition::Second,
ShiftPosition::Second => ShiftPosition::First,
};
let other_slot = Slot::new(slot.day, other_position);
let already_on_duty = schedule.get_resident_id(&other_slot);
for resident in &self.residents {
if let Some(on_duty_id) = &already_on_duty {
if &&resident.id == on_duty_id {
continue;
}
}
if resident.negative_shifts.contains(&slot.day) {
continue;
}
for shift_type in &resident.allowed_types {
match (shift_type, is_open, slot.position) {
(ShiftType::OpenFirst, true, ShiftPosition::First) => {
candidates.push((resident, shift_type))
}
(ShiftType::OpenSecond, true, ShiftPosition::Second) => {
candidates.push((resident, shift_type))
}
(ShiftType::Closed, false, _) => candidates.push((resident, shift_type)),
_ => continue,
}
}
}
candidates
}
pub fn default() -> Self {
Self {
month: Month::try_from(2).unwrap(),
@@ -155,12 +106,7 @@ impl From<UserConfigDTO> for UserConfig {
mod tests {
use rstest::{fixture, rstest};
use crate::{
config::UserConfig,
resident::Resident,
schedule::{MonthlySchedule, ShiftType},
slot::{Day, ShiftPosition, Slot},
};
use crate::{config::UserConfig, resident::Resident, schedule::MonthlySchedule};
#[fixture]
fn setup() -> (UserConfig, MonthlySchedule) {
@@ -175,38 +121,6 @@ mod tests {
(config, schedule)
}
#[rstest]
fn test_candidates_prevents_double_booking_on_open_day(setup: (UserConfig, MonthlySchedule)) {
let (config, mut schedule) = setup;
let slot_1 = Slot::new(Day(1), ShiftPosition::First);
let slot_2 = Slot::new(Day(1), ShiftPosition::Second);
let stefanos = &config.residents[0];
let iordanis = &config.residents[1];
schedule.insert(slot_1, stefanos);
let candidates = config.candidates(slot_2, &schedule);
let stefanos_is_candidate = candidates.iter().any(|(r, _)| r.id == stefanos.id);
assert!(!stefanos_is_candidate);
let iordanis_is_candidate = candidates.iter().any(|(r, _)| r.id == iordanis.id);
assert!(iordanis_is_candidate);
}
#[rstest]
fn test_candidates_respects_shift_type_position(setup: (UserConfig, MonthlySchedule)) {
let (config, schedule) = setup;
let slot_1 = Slot::new(Day(1), ShiftPosition::First);
let candidates = config.candidates(slot_1, &schedule);
for (_, shift_type) in candidates {
assert_eq!(shift_type, &ShiftType::OpenFirst);
}
}
#[rstest]
fn test_total_holiday_slots() {
let config = UserConfig::default().with_holidays(vec![2, 3, 4]);