use chrono::{DateTime, NaiveDate, Utc};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ClientReport {
pub id: Option<i64>,
pub client_name: String,
pub project_id: Option<i64>,
pub report_period_start: NaiveDate,
pub report_period_end: NaiveDate,
pub total_hours: f64,
pub hourly_rate: Option<f64>,
pub notes: Option<String>,
pub status: ReportStatus,
pub created_at: DateTime<Utc>,
pub sent_at: Option<DateTime<Utc>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ReportStatus {
Draft,
Sent,
Paid,
}
impl std::fmt::Display for ReportStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ReportStatus::Draft => write!(f, "draft"),
ReportStatus::Sent => write!(f, "sent"),
ReportStatus::Paid => write!(f, "paid"),
}
}
}
impl ClientReport {
pub fn new(
client_name: String,
report_period_start: NaiveDate,
report_period_end: NaiveDate,
total_hours: f64,
) -> Self {
Self {
id: None,
client_name,
project_id: None,
report_period_start,
report_period_end,
total_hours,
hourly_rate: None,
notes: None,
status: ReportStatus::Draft,
created_at: Utc::now(),
sent_at: None,
}
}
pub fn total_amount(&self) -> Option<f64> {
self.hourly_rate.map(|rate| rate * self.total_hours)
}
pub fn mark_sent(&mut self) {
self.status = ReportStatus::Sent;
self.sent_at = Some(Utc::now());
}
pub fn mark_paid(&mut self) {
self.status = ReportStatus::Paid;
}
}