221 lines
6.1 KiB
Rust
221 lines
6.1 KiB
Rust
use chrono::{Datelike, NaiveDate, Weekday};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
#[derive(Serialize, Deserialize, PartialEq, PartialOrd, Ord, Eq, Debug, Hash, Clone, Copy)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct Slot {
|
|
pub day: Day,
|
|
pub position: ShiftPosition,
|
|
}
|
|
|
|
impl Slot {
|
|
pub fn new(day: Day, position: ShiftPosition) -> Self {
|
|
Self { day, position }
|
|
}
|
|
|
|
pub fn is_open_shift(&self) -> bool {
|
|
self.day.is_open_shift()
|
|
}
|
|
|
|
pub fn is_first(&self) -> bool {
|
|
self.day == Day(1) && self.position == ShiftPosition::First
|
|
}
|
|
|
|
pub fn is_open_first(&self) -> bool {
|
|
self.is_open_shift() && self.position == ShiftPosition::First
|
|
}
|
|
|
|
pub fn is_open_second(&self) -> bool {
|
|
self.is_open_shift() && self.position == ShiftPosition::Second
|
|
}
|
|
|
|
pub fn shift_type_str(&self) -> String {
|
|
match (self.day.is_open_shift(), self.position) {
|
|
(true, ShiftPosition::First) => "Ανοιχτή(1)".to_string(),
|
|
(true, ShiftPosition::Second) => "Ανοιχτή(2)".to_string(),
|
|
_ => "Κλειστή".to_string(),
|
|
}
|
|
}
|
|
|
|
pub fn next(&self) -> Self {
|
|
match self.position {
|
|
ShiftPosition::First if self.is_open_shift() => Self {
|
|
day: self.day,
|
|
position: ShiftPosition::Second,
|
|
},
|
|
_ => Self {
|
|
day: self.day.next(),
|
|
position: ShiftPosition::First,
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn previous(&self) -> Self {
|
|
match self.position {
|
|
ShiftPosition::First => {
|
|
let past_day = self.day.previous();
|
|
if past_day.is_open_shift() {
|
|
Self {
|
|
day: past_day,
|
|
position: ShiftPosition::Second,
|
|
}
|
|
} else {
|
|
Self {
|
|
day: past_day,
|
|
position: ShiftPosition::First,
|
|
}
|
|
}
|
|
}
|
|
ShiftPosition::Second => Self {
|
|
day: self.day,
|
|
position: ShiftPosition::First,
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn greater_than(&self, limit: u8) -> bool {
|
|
self.day.greater_than(&Day(limit))
|
|
}
|
|
|
|
pub fn default() -> Self {
|
|
Self {
|
|
day: Day(1),
|
|
position: ShiftPosition::First,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, PartialEq, PartialOrd, Ord, Eq, Debug, Hash, Clone, Copy)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct Day(pub u8);
|
|
|
|
impl Day {
|
|
pub fn is_open_shift(&self) -> bool {
|
|
!self.0.is_multiple_of(2)
|
|
}
|
|
|
|
pub fn next(&self) -> Self {
|
|
Self(self.0 + 1)
|
|
}
|
|
|
|
pub fn previous(&self) -> Self {
|
|
if self.0 <= 1 {
|
|
Self(1)
|
|
} else {
|
|
Self(self.0 - 1)
|
|
}
|
|
}
|
|
|
|
pub fn greater_than(&self, other: &Day) -> bool {
|
|
self.0 > other.0
|
|
}
|
|
|
|
pub fn is_weekend(&self, month: u32, year: i32) -> bool {
|
|
let date = NaiveDate::from_ymd_opt(year, month, self.0 as u32).unwrap();
|
|
let weekday = date.weekday();
|
|
weekday == Weekday::Sat || weekday == Weekday::Sun
|
|
}
|
|
|
|
pub fn weekday(&self, month: u32, year: i32) -> Weekday {
|
|
let date = NaiveDate::from_ymd_opt(year, month, self.0 as u32).unwrap();
|
|
date.weekday()
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, PartialEq, PartialOrd, Ord, Eq, Debug, Hash, Clone, Copy)]
|
|
pub enum ShiftPosition {
|
|
First,
|
|
Second,
|
|
}
|
|
|
|
pub fn weekday_to_greek(weekday: Weekday) -> &'static str {
|
|
match weekday {
|
|
Weekday::Mon => "Δευτέρα",
|
|
Weekday::Tue => "Τρίτη",
|
|
Weekday::Wed => "Τετάρτη",
|
|
Weekday::Thu => "Πέμπτη",
|
|
Weekday::Fri => "Παρασκευή",
|
|
Weekday::Sat => "Σάββατο",
|
|
Weekday::Sun => "Κυριακή",
|
|
}
|
|
}
|
|
|
|
pub fn month_to_greek(month: u32) -> &'static str {
|
|
match month {
|
|
1 => "Ιανουάριος",
|
|
2 => "Φεβρουάριος",
|
|
3 => "Μάρτιος",
|
|
4 => "Απρίλιος",
|
|
5 => "Μάιος",
|
|
6 => "Ιούνιος",
|
|
7 => "Ιούλιος",
|
|
8 => "Αύγουστος",
|
|
9 => "Σεπτέμβριος",
|
|
10 => "Οκτώβριος",
|
|
11 => "Νοέμβριος",
|
|
12 => "Δεκέμβριος",
|
|
_ => panic!("Unable to find translation for month {}", month),
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use rstest::rstest;
|
|
|
|
use crate::slot::{Day, ShiftPosition, Slot};
|
|
|
|
#[rstest]
|
|
fn test_slot() {
|
|
let slot_1 = Slot::new(Day(1), ShiftPosition::First);
|
|
let slot_2 = Slot::new(Day(1), ShiftPosition::Second);
|
|
let slot_3 = Slot::new(Day(2), ShiftPosition::First);
|
|
|
|
assert!(slot_1.is_open_shift());
|
|
assert!(slot_2.is_open_shift());
|
|
assert!(!slot_3.is_open_shift());
|
|
|
|
assert!(slot_1.is_first());
|
|
assert!(!slot_2.is_first());
|
|
assert!(!slot_3.is_first());
|
|
|
|
assert!(!slot_1.is_open_second());
|
|
assert!(slot_2.is_open_second());
|
|
assert!(!slot_3.is_open_second());
|
|
|
|
assert_eq!(slot_1.next(), slot_2);
|
|
assert_eq!(slot_2.next(), slot_3);
|
|
|
|
assert_eq!(slot_3.previous(), slot_2);
|
|
assert_eq!(slot_2.previous(), slot_1);
|
|
|
|
assert!(!slot_1.greater_than(1));
|
|
assert!(!slot_2.greater_than(1));
|
|
assert!(slot_3.greater_than(1));
|
|
}
|
|
|
|
#[rstest]
|
|
fn test_day() {
|
|
let day_1 = Day(1);
|
|
let day_2 = Day(2);
|
|
let day_3 = Day(3);
|
|
|
|
assert!(day_1.is_open_shift());
|
|
assert!(!day_2.is_open_shift());
|
|
assert!(day_3.is_open_shift());
|
|
|
|
assert_eq!(day_1.next(), day_2);
|
|
assert_eq!(day_2.next(), day_3);
|
|
|
|
assert_eq!(day_3.previous(), day_2);
|
|
assert_eq!(day_2.previous(), day_1);
|
|
|
|
assert!(!day_1.greater_than(&day_1));
|
|
assert!(day_2.greater_than(&day_1));
|
|
assert!(day_3.greater_than(&day_1));
|
|
|
|
assert!(day_1.is_weekend(2, 2026));
|
|
assert!(!day_2.is_weekend(2, 2026));
|
|
assert!(!day_3.is_weekend(2, 2026));
|
|
}
|
|
}
|