use crate::{
database::{Database, Error, Result},
entities::{Billable, Client, Company, DateTime, Invoice, Job, NaiveDate, Tag, Worker},
jobber::*,
};
impl JobberCreate for Database {
fn create_company<T>(&mut self, f: impl FnOnce(&mut Company) -> Result<T>) -> Result<T> {
let mut company = self.company.clone().unwrap_or_default();
let result = f(&mut company)?;
self.company = Some(company);
Ok(result)
}
fn create_worker<T>(
&mut self,
id: &str,
f: impl FnOnce(&mut Worker) -> Result<T>,
) -> Result<T> {
let mut worker = self.workers.get(id).cloned().unwrap_or_default();
let result = f(&mut worker)?;
if self.workers.contains_key(id) {
return Err(Error::WorkerExists(id.to_string()));
}
self.workers.insert(id.to_string(), worker);
Ok(result)
}
fn create_client<T>(
&mut self,
id: &str,
f: impl FnOnce(&mut Client) -> Result<T>,
) -> Result<T> {
let mut client = self.clients.get(id).cloned().unwrap_or_default();
if let Some(company) = &self.company {
client.scheme = company.scheme.clone();
}
let result = f(&mut client)?;
if self.clients.contains_key(id) {
return Err(Error::ClientExists(id.to_string()));
}
self.clients.insert(id.to_string(), client);
Ok(result)
}
fn create_job<T>(
&mut self,
pos: Option<usize>,
f: impl FnOnce(&mut Job) -> Result<T>,
) -> Result<T> {
let mut job = if let Some(pos) = pos {
self.jobs.get(pos).cloned().unwrap_or_default()
} else {
Job::default()
};
let result = f(&mut job)?;
if !self.workers.contains_key(&job.worker) {
return Err(Error::UnknownWorker(job.worker));
}
if !self.clients.contains_key(&job.client) {
return Err(Error::UnknownClient(job.client));
}
self.jobs.push(job);
Ok(result)
}
fn create_tag<T>(&mut self, name: &str, f: impl FnOnce(&mut Tag) -> Result<T>) -> Result<T> {
let mut tag = self.tags.get(name).cloned().unwrap_or_default();
let result = f(&mut tag)?;
if self.tags.contains_key(name) {
return Err(Error::TagExists(name.to_string()));
}
self.tags.insert(name.to_string(), tag);
Ok(result)
}
fn create_invoice(
&mut self,
job_ids: impl Iterator<Item = usize>,
subject: Option<String>,
until: Option<NaiveDate>,
) -> Result<usize> {
let until = until.map(DateTime::from_naive_date);
let mut bills: Vec<_> = Vec::new();
let mut client = None;
let mut currency = None;
for job_id in job_ids {
let job = &mut self.jobs[job_id];
if let Some(c) = client
&& c != job.client
{
todo!("error different clients")
} else {
client = Some(job.client.clone())
}
if let Some(p) = &job.scheme(job_id)?.rate {
let c1 = p.amount.currency();
if let Some(c0) = ¤cy
&& c0 != &c1
{
todo!("error different currencies")
} else {
currency = Some(c1);
}
}
bills.push(job.bill(job_id, until)?)
}
if let Some(client) = client {
self.invoices.push(Invoice {
client,
subject,
bills,
date: DateTime::now(),
deleted: false,
});
}
Ok(self.invoices.len() - 1)
}
}