My personal project and infrastructure archive
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
nomicon/apps/koffice/libko/src/invoice.rs

95 lines
2.7 KiB

use crate::Io;
use chrono::{NaiveDate, Utc};
use serde::{Deserialize, Serialize};
use std::{fs::File, io::Read, path::Path, string::ToString};
/// A specification to build invoice IDs with
#[derive(Serialize, Deserialize)]
pub enum InvoiceId {
YearMonthId(u16, u8, usize),
}
impl InvoiceId {
pub(crate) fn date() -> Self {
let now = Utc::now().naive_local().date();
let year = now.format("%Y").to_string();
let month = now.format("%m").to_string();
Self::YearMonthId(
str::parse(&year).unwrap_or_else(|_| {
fatal!(
"Current year doesn't fit into u16. WHEN ARE YOU USING THIS CODE???????? (have you abolished capitalism yet? uwu)"
)
}),
str::parse(&month)
.unwrap_or_else(|_| fatal!("Invalid month value (doesn't fit in u8)")),
0,
)
}
/// Utility to find the next invoice ID in a sequence
///
/// Start with an InvoiceID that only has the correct date
/// (`date()`), then call this function for each existing invoice
/// in your collection. If the current ID is lower or equal than
/// the one given, take the given ID and increment it by one.
///
/// Once this has been done for all invoices in the collection,
/// you are guaranteed to have the latest invoice ID.
pub(crate) fn find_next(mut self, i: &Invoice) -> Self {
if self.numeric() <= i.id.numeric() {
self.update_numeric(i.id.numeric() + 1);
}
self
}
fn update_numeric(&mut self, id: usize) {
match self {
Self::YearMonthId(_, _, ref mut _id) => {
*_id = id;
}
}
}
/// A valid invoice ID needs to have a numeric element
pub(crate) fn numeric(&self) -> usize {
match self {
Self::YearMonthId(_, _, id) => *id,
}
}
}
impl ToString for InvoiceId {
fn to_string(&self) -> String {
match self {
Self::YearMonthId(yr, mo, id) => format!("#{}-{:02}-{:04}", yr, mo, id),
}
}
}
/// An invoice for a specific project
#[derive(Serialize, Deserialize)]
pub struct Invoice {
id: InvoiceId,
client: String,
project: String,
date: NaiveDate,
amount: usize,
currency: String,
vat: u8,
}
impl Invoice {
pub fn load(path: &Path) -> Option<Self> {
let mut buf = String::new();
let mut f = File::open(path).ok()?;
f.read_to_string(&mut buf).ok()?;
Some(Self::from_yaml(buf))
}
}
#[test]
fn invoice_id_fmt() {
let inv_id = InvoiceId::YearMonthId(2020, 06, 0055);
assert_eq!(inv_id.to_string(), "#2020-06-0055".to_string());
}