244 lines
7.3 KiB
Rust
244 lines
7.3 KiB
Rust
use std::{fs::File, io::Write};
|
|
|
|
use anyhow::Context;
|
|
use docx_rs::{Docx, Paragraph, Run, RunFonts, Table, TableCell, TableRow};
|
|
|
|
use crate::{
|
|
config::UserConfig,
|
|
schedule::MonthlySchedule,
|
|
slot::{month_to_greek, weekday_to_greek, Day, ShiftPosition, Slot},
|
|
workload::WorkloadTracker,
|
|
};
|
|
|
|
#[derive(Debug)]
|
|
pub enum FileType {
|
|
Txt,
|
|
Docx,
|
|
}
|
|
|
|
pub trait Export {
|
|
fn export(
|
|
&self,
|
|
file_type: FileType,
|
|
config: &UserConfig,
|
|
tracker: &WorkloadTracker,
|
|
) -> anyhow::Result<()>;
|
|
}
|
|
|
|
impl Export for MonthlySchedule {
|
|
fn export(
|
|
&self,
|
|
file_type: FileType,
|
|
config: &UserConfig,
|
|
tracker: &WorkloadTracker,
|
|
) -> anyhow::Result<()> {
|
|
match file_type {
|
|
FileType::Txt => self.export_as_txt(config, tracker)?,
|
|
FileType::Docx => self.export_as_doc(config)?,
|
|
};
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl MonthlySchedule {
|
|
pub fn export_as_txt(
|
|
&self,
|
|
config: &UserConfig,
|
|
tracker: &WorkloadTracker,
|
|
) -> anyhow::Result<()> {
|
|
let file = File::create("rota.txt")?;
|
|
let mut writer = std::io::BufWriter::new(file);
|
|
|
|
writer.write_all(self.pretty_print(config).as_bytes())?;
|
|
|
|
writer.write_all(self.report(config, tracker).as_bytes())?;
|
|
|
|
writer.flush()?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn export_as_doc(&self, config: &UserConfig) -> anyhow::Result<()> {
|
|
let path = std::path::Path::new("rota.docx");
|
|
let file = std::fs::File::create(path)?;
|
|
|
|
let header = Table::new(vec![
|
|
TableRow::new(vec![TableCell::new().add_paragraph(
|
|
Paragraph::new()
|
|
.add_run(Run::new().bold().add_text("Εφημερίες Ακτινολογικό"))
|
|
.fonts(RunFonts::new().ascii("Arial")),
|
|
)]),
|
|
TableRow::new(vec![TableCell::new().add_paragraph(
|
|
Paragraph::new()
|
|
.add_run(Run::new().bold().add_text(format!(
|
|
"Μήνας {} {}",
|
|
month_to_greek(config.month.number_from_month()),
|
|
config.year
|
|
)))
|
|
.fonts(RunFonts::new().ascii("Arial")),
|
|
)]),
|
|
TableRow::new(vec![TableCell::new().add_paragraph(
|
|
Paragraph::new()
|
|
.add_run(Run::new().bold().add_text(""))
|
|
.fonts(RunFonts::new().ascii("Arial")),
|
|
)]),
|
|
TableRow::new(vec![TableCell::new().add_paragraph(
|
|
Paragraph::new()
|
|
.add_run(
|
|
Run::new()
|
|
.bold()
|
|
.add_text("ΠΑΝΕΠΙΣΤΗΜΙΑΚΟ ΓΕΝΙΚΟ ΝΟΣΟΚΟΜΕΙΟ ΙΩΑΝΝΙΝΩΝ"),
|
|
)
|
|
.fonts(RunFonts::new().ascii("Arial")),
|
|
)]),
|
|
]);
|
|
|
|
let mut doc = Docx::new().add_table(header);
|
|
|
|
let mut residents_table = Table::new(vec![]);
|
|
|
|
for d in 1..=config.total_days {
|
|
let day = Day(d);
|
|
let is_weekend = day.is_weekend(config.month.number_from_month(), config.year);
|
|
let slot_first = Slot::new(Day(d), ShiftPosition::First);
|
|
let slot_first_res_id = self.get_resident_id(&slot_first);
|
|
let res_name_1 = config
|
|
.residents
|
|
.iter()
|
|
.find(|r| Some(&r.id) == slot_first_res_id)
|
|
.map(|r| r.name.as_str())
|
|
.unwrap_or("-");
|
|
|
|
let res_name_2 = if day.is_open_shift() {
|
|
let slot_second = Slot::new(Day(d), ShiftPosition::Second);
|
|
let slot_second_res_id = self.get_resident_id(&slot_second);
|
|
config
|
|
.residents
|
|
.iter()
|
|
.find(|r| Some(&r.id) == slot_second_res_id)
|
|
.map(|r| r.name.as_str())
|
|
} else {
|
|
None
|
|
};
|
|
|
|
let make_run = |text: &str| {
|
|
let mut run = Run::new().add_text(text);
|
|
if is_weekend {
|
|
run = run.bold();
|
|
}
|
|
run
|
|
};
|
|
|
|
let residents_table_row = TableRow::new(vec![
|
|
TableCell::new().add_paragraph(
|
|
Paragraph::new()
|
|
.add_run(make_run(&format!("{d}")))
|
|
.fonts(RunFonts::new().ascii("Arial")),
|
|
),
|
|
TableCell::new().add_paragraph(
|
|
Paragraph::new()
|
|
.add_run(make_run(weekday_to_greek(
|
|
Day(d).weekday(config.month.number_from_month(), config.year),
|
|
)))
|
|
.fonts(RunFonts::new().ascii("Arial")),
|
|
),
|
|
TableCell::new().add_paragraph(
|
|
Paragraph::new()
|
|
.add_run(make_run(res_name_1))
|
|
.fonts(RunFonts::new().ascii("Arial")),
|
|
),
|
|
TableCell::new().add_paragraph(
|
|
Paragraph::new()
|
|
.add_run(make_run(res_name_2.unwrap_or("")))
|
|
.fonts(RunFonts::new().ascii("Arial")),
|
|
),
|
|
]);
|
|
|
|
residents_table = residents_table.add_row(residents_table_row);
|
|
}
|
|
|
|
doc = doc.add_table(residents_table);
|
|
|
|
doc.build().pack(file)?;
|
|
|
|
tauri_plugin_opener::open_path(path, None::<&str>)
|
|
.context("Created file but failed to open it")?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use anyhow::Ok;
|
|
use rstest::{fixture, rstest};
|
|
|
|
use crate::{
|
|
config::UserConfig,
|
|
export::{Export, FileType},
|
|
resident::Resident,
|
|
schedule::MonthlySchedule,
|
|
scheduler::Scheduler,
|
|
workload::{WorkloadBounds, WorkloadTracker},
|
|
};
|
|
|
|
#[fixture]
|
|
fn schedule() -> MonthlySchedule {
|
|
MonthlySchedule::new()
|
|
}
|
|
|
|
#[fixture]
|
|
fn config() -> UserConfig {
|
|
UserConfig::default().with_residents(vec![
|
|
Resident::new(1, "Στέφανος"),
|
|
Resident::new(2, "Ιορδάνης"),
|
|
Resident::new(3, "Μαρία"),
|
|
Resident::new(4, "Βεατρίκη"),
|
|
Resident::new(5, "Τάκης"),
|
|
Resident::new(6, "Μάκης"),
|
|
])
|
|
}
|
|
|
|
#[fixture]
|
|
fn bounds(config: UserConfig) -> WorkloadBounds {
|
|
WorkloadBounds::new_with_config(&config)
|
|
}
|
|
|
|
#[fixture]
|
|
fn scheduler(config: UserConfig, bounds: WorkloadBounds) -> Scheduler {
|
|
Scheduler::new(config, bounds)
|
|
}
|
|
|
|
#[fixture]
|
|
fn tracker() -> WorkloadTracker {
|
|
WorkloadTracker::default()
|
|
}
|
|
|
|
#[rstest]
|
|
pub fn test_export_as_txt(
|
|
mut schedule: MonthlySchedule,
|
|
mut tracker: WorkloadTracker,
|
|
scheduler: Scheduler,
|
|
) -> anyhow::Result<()> {
|
|
assert!(scheduler.run(&mut schedule, &mut tracker)?);
|
|
|
|
schedule.export(FileType::Txt, &scheduler.config, &tracker)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[rstest]
|
|
pub fn test_export_as_doc(
|
|
mut schedule: MonthlySchedule,
|
|
mut tracker: WorkloadTracker,
|
|
scheduler: Scheduler,
|
|
) -> anyhow::Result<()> {
|
|
assert!(scheduler.run(&mut schedule, &mut tracker)?);
|
|
|
|
schedule.export(FileType::Docx, &scheduler.config, &tracker)?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|