use crate::{
api::si::Si,
db::{pauses::Pauses, workdays::Workdays},
libs::{
config::Config,
messages::Message,
summary::{DailySummary, SummaryCalculator, SummaryFormatter},
view::View,
},
msg_error, msg_print,
};
use anyhow::Result;
use chrono::{Datelike, Duration, Local, NaiveDate};
use clap::Args;
use std::collections::HashSet;
#[derive(Debug, Args)]
pub struct SumArgs {
#[arg(long, help = "Send report")]
send: bool,
}
pub async fn cmd(_sum_args: SumArgs) -> Result<()> {
let now = Local::now();
let config = Config::read()?;
let monitor_config = config.monitor.clone().unwrap_or_default();
msg_print!(Message::WorkingHoursForMonth(now.format("%B, %Y").to_string()), true);
let mut rest_dates: HashSet<NaiveDate> = HashSet::new();
if let Some(si_config) = config.si {
match Si::new(&si_config).rest_dates(now.date_naive()).await {
Ok(dates) => {
rest_dates = dates.into_iter().filter(|d| d.month() == now.month()).collect();
}
Err(e) => {
msg_error!(Message::ErrorRequestingRestDates(e.to_string()));
}
}
}
let workdays = Workdays::new()?.fetch_month(now.date_naive())?;
let workdays_count = workdays.len() as f64;
let mut daily_summaries = Vec::new();
let mut total_productivity = 0.0;
for workday in workdays {
let workday_pauses = Pauses::new()?.get_workday_pauses(&workday)?;
let end_time = crate::libs::report::workday_end_time(&workday, &workday_pauses);
let gross_duration = end_time.signed_duration_since(workday.start);
let long_breaks_duration = Pauses::new()?
.set_min_duration(monitor_config.min_pause_duration)
.get_workday_pauses(&workday)?
.iter()
.filter_map(|b| b.duration)
.fold(Duration::zero(), |acc, d| acc + d);
let gross_work_time_minus_long_breaks = gross_duration - long_breaks_duration;
let productivity = crate::libs::productivity::Productivity::new(&workday)
.map(|p| p.calculate_productivity())
.unwrap_or(0.0);
total_productivity += productivity;
daily_summaries.push(DailySummary {
date: workday.date,
duration: gross_work_time_minus_long_breaks, productivity,
});
}
let event_summary = daily_summaries
.add_rest_dates(rest_dates, Duration::hours(8)) .calculate_totals()
.format_summary();
View::sum(&event_summary)?;
if total_productivity > 0.0 && workdays_count > 0.0 {
let average_productivity = total_productivity / workdays_count;
msg_print!(Message::MonthlyProductivity(average_productivity), true);
}
Ok(())
}