1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
//! data contains fundamental types used in Ledger data.
//! Note the structure is quite similar to repl module,
//! however, repl is for textual representation while
//! data is more for understanding.
use std::cmp::Ordering;
use rust_decimal::Decimal;
/// Represents a transaction where the money transfered across the accounts.
#[derive(Debug, PartialEq, Eq)]
pub struct Transaction {
/// Date when the transaction issued.
pub date: chrono::NaiveDate,
/// Date when the transaction got effective, optional.
pub effective_date: Option<chrono::NaiveDate>,
/// Indiacates clearing state of the entire transaction.
pub clear_state: ClearState,
/// Transaction code (not necessarily unique).
pub code: Option<String>,
/// Label of the transaction, often the opposite party of the transaction.
pub payee: String,
/// Postings of the transaction, could be empty.
pub posts: Vec<Posting>,
}
impl Transaction {
/// Constructs minimal transaction.
pub fn new(date: chrono::NaiveDate, payee: String) -> Transaction {
Transaction {
date,
effective_date: None,
clear_state: ClearState::Uncleared,
code: None,
payee,
posts: Vec::new(),
}
}
}
/// Represents a clearing state, often combined with the ambiguity.
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
pub enum ClearState {
/// No specific meaning.
#[default]
Uncleared,
/// Useful to declare that the transaction / post is confirmed.
Cleared,
/// Useful to declare that the transaction / post is still pending.
Pending,
}
/// Posting in a transaction to represent a particular account amount increase / decrease.
#[derive(Debug, PartialEq, Eq)]
pub struct Posting {
/// Account of the post target.
pub account: String,
/// Posting specific ClearState.
pub clear_state: ClearState,
/// Amount of the posting.
pub amount: Option<ExchangedAmount>,
/// Balance after the transaction of the specified account.
pub balance: Option<Amount>,
/// Overwrites the payee.
pub payee: Option<String>,
}
/// Cost of the posting.
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ExchangedAmount {
/// Amount that posting account was increased by.
pub amount: Amount,
/// Exchange rate information to balance with other postings.
pub exchange: Option<Exchange>,
}
/// Commodity exchange information.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Exchange {
/// Represents the amount equals to the `ExchangedAmount.amount`.
Total(Amount),
/// Represents te amount equals to 1 `ExchangedAmount.amount.commodity`.
Rate(Amount),
}
/// Amount of posting, balance, ...
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Amount {
/// Numerical value.
pub value: Decimal,
/// Commodity aka currency.
pub commodity: String,
}
impl Amount {
/// Returns `true` if the amount is zero.
pub fn is_zero(&self) -> bool {
self.value.is_zero()
}
/// Returns `true` if the amount is positive.
pub fn is_sign_positive(&self) -> bool {
self.value.is_sign_positive()
}
/// Returns `true` if the amount is negative.
pub fn is_sign_negative(&self) -> bool {
self.value.is_sign_negative()
}
}
/// # Examples
///
/// ```
/// # use rust_decimal_macros::dec;
/// let x = okane_core::datamodel::Amount{
/// value: dec!(-5),
/// commodity: "JPY".to_string(),
/// };
/// let y = -x.clone();
/// assert_eq!(x.value, dec!(-5));
/// assert_eq!(x.commodity, "JPY");
/// assert_eq!(y.value, dec!(5));
/// assert_eq!(y.commodity, "JPY");
/// ```
impl std::ops::Neg for Amount {
type Output = Amount;
fn neg(self) -> Amount {
Amount {
value: -self.value,
commodity: self.commodity,
}
}
}
impl PartialOrd for Amount {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
if self.commodity != other.commodity {
None
} else {
Some(self.value.cmp(&other.value))
}
}
}