use crate::models::{AccountName, CommodityName};
use chrono::NaiveDate;
use rust_decimal::Decimal;
use thiserror::Error;
#[derive(Error, Debug, Clone, PartialEq, Eq)]
pub enum ModelError {
#[error(
"invalid account name `{0}`: expected colon-separated segments, the first one starting \
with an uppercase letter, each made of letters, digits, `_` or `-`"
)]
InvalidAccountName(String),
#[error(
"invalid commodity name `{0}`: expected 2 to 24 characters, starting with an uppercase \
letter, ending with an uppercase letter or digit, made of uppercase letters, digits, \
`'`, `.`, `_` or `-` in between"
)]
InvalidCommodityName(String),
#[error("invalid metadata key `{0}`: expected only lowercase letters, `_` or `-`")]
InvalidMetadataKey(String),
}
#[derive(Error, Debug, Clone, PartialEq, Eq)]
pub enum ValidationError {
#[error("account `{account}` is already open on {date}")]
AccountAlreadyOpen {
account: AccountName,
date: NaiveDate,
},
#[error("account `{account}` is not open on {date}")]
AccountNotOpen {
account: AccountName,
date: NaiveDate,
},
#[error("commodity `{commodity}` is already declared on {date}")]
CommodityAlreadyDeclared {
commodity: CommodityName,
date: NaiveDate,
},
#[error("commodity `{commodity}` is not declared on {date}")]
CommodityNotDeclared {
commodity: CommodityName,
date: NaiveDate,
},
#[error("payee `{payee}` is already declared")]
PayeeAlreadyDeclared {
payee: String,
},
#[error("payee `{payee}` is not declared (transaction on {date})")]
PayeeNotDeclared {
payee: String,
date: NaiveDate,
},
#[error(
"transaction on {date} has {count} postings without an amount, but at most one posting \
can be left without an amount for auto-balancing"
)]
TooManyPostingsWithoutAmount {
count: usize,
date: NaiveDate,
},
#[error(
"cannot auto-balance transaction: unable to determine a single commodity for the \
missing amount from the other postings on {date} (commodities found: {commodities:?})"
)]
AmbiguousAutoBalanceCommodity {
commodities: Vec<String>,
date: NaiveDate,
},
#[error(
"transaction on {date} is not balanced: postings for commodity `{commodity}` sum to \
`{sum}` instead of zero"
)]
TransactionNotBalanced {
commodity: String,
sum: Decimal,
date: NaiveDate,
},
#[error(
"commodity `{commodity}` is not allowed on account `{account}` (posting on {date}): the \
account was opened with a restricted list of commodities that does not include it"
)]
CommodityNotAllowed {
account: AccountName,
commodity: CommodityName,
date: NaiveDate,
},
#[error(
"balance assertion failed on {date}: account `{account}` has a balance of `{actual}` \
{commodity}, expected `{expected}` {commodity} (tolerance ~ {tolerance})"
)]
BalanceAssertionFailed {
account: AccountName,
commodity: CommodityName,
date: NaiveDate,
expected: Decimal,
actual: Decimal,
tolerance: Decimal,
},
}