Skip to main content

use_finance/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4//! Thin facade for `RustUse` practical finance primitive crates.
5//!
6//! `use-finance` describes money, currency, amount, ledger, transaction, payment, receipt,
7//! invoice, bank-account, routing-number, IBAN, BIC, ACH, reconciliation, and BAI2 vocabulary. It is not a
8//! trading system, exchange-rate service, bank integration, payment processor, tax engine,
9//! accounting platform, or market-data provider.
10
11pub use use_ach as ach;
12pub use use_amount as amount;
13pub use use_bai2 as bai2;
14pub use use_bank_account as bank_account;
15pub use use_bic as bic;
16pub use use_currency as currency;
17pub use use_iban as iban;
18pub use use_invoice as invoice;
19pub use use_ledger as ledger;
20pub use use_money as money;
21pub use use_payment as payment;
22pub use use_receipt as receipt;
23pub use use_reconciliation as reconciliation;
24pub use use_routing_number as routing_number;
25pub use use_transaction as transaction;
26
27/// Common practical finance primitive types from the focused crates.
28pub mod prelude {
29    pub use crate::ach::{
30        AchAccountType, AchAddendaIndicator, AchCompanyId, AchEntry, AchEntryDirection, AchError,
31        AchIndividualId, AchStandardEntryClass, AchTraceNumber, AchTransactionCode,
32    };
33    pub use crate::amount::{Amount, AmountError};
34    pub use crate::bai2::{
35        AccountIdentifierRecord, Bai2Error, FileHeaderRecord, FileTrailerRecord, FundsTypeCode,
36        NormalizedTransaction, RawRecord, RecordCode, TransactionDetailRecord, TransactionTypeCode,
37    };
38    pub use crate::bank_account::{
39        AccountHolderName, AccountNumber, AccountType, BankAccount, MaskedAccountNumber,
40    };
41    pub use crate::bic::{Bic, BicError};
42    pub use crate::currency::{AUD, CAD, CurrencyCode, CurrencyCodeError, EUR, GBP, JPY, USD};
43    pub use crate::iban::{Iban, IbanError};
44    pub use crate::invoice::{
45        BalanceDue, DueDate, Invoice, InvoiceLine, InvoiceNumber, InvoiceStatus, Subtotal, Total,
46    };
47    pub use crate::ledger::{Balance, DebitCredit, JournalEntry, LedgerEntry, Posting};
48    pub use crate::money::{CurrencyMismatch, Money, MoneyError};
49    pub use crate::payment::{
50        Payment, PaymentDirection, PaymentMethod, PaymentReference, PaymentStatus,
51    };
52    pub use crate::receipt::{
53        AppliedAmount, Receipt, ReceiptNumber, ReceiptStatus, ReceivedAt, UnappliedAmount,
54    };
55    pub use crate::reconciliation::{
56        ExceptionReason, MatchConfidence, MatchScore, MatchStatus, ReconciliationCandidate,
57        ReconciliationResult,
58    };
59    pub use crate::routing_number::{RoutingNumber, RoutingNumberError};
60    pub use crate::transaction::{
61        EffectiveDate, PostedDate, Transaction, TransactionDate, TransactionDirection,
62        TransactionId, TransactionStatus,
63    };
64}
65
66#[cfg(test)]
67mod tests {
68    use super::{ach, amount, bai2, bic, currency, iban, money, reconciliation, routing_number};
69
70    #[test]
71    fn facade_exposes_composable_finance_primitives() -> Result<(), Box<dyn std::error::Error>> {
72        let usd = currency::CurrencyCode::new("USD")?;
73        let cents = amount::Amount::from_minor_units(12_345, 2)?;
74        let invoice_total = money::Money::new(cents, usd);
75
76        let routing = routing_number::RoutingNumber::new("021000021")?;
77        assert_eq!(routing.as_str(), "021000021");
78
79        let iban = iban::Iban::new("GB82 WEST 1234 5698 7654 32")?;
80        let bic = bic::Bic::new("DEUTDEFF500")?;
81        let ach_entry = ach::AchEntry::new(
82            ach::AchStandardEntryClass::Ppd,
83            ach::AchTransactionCode::CheckingCredit,
84            ach::AchTraceNumber::new("123456780000001")?,
85            ach::AchCompanyId::new("1234567890")?,
86            ach::AchIndividualId::new("EMPLOYEE001")?,
87        );
88
89        let records =
90            bai2::parse_logical_records("16,475,12345,Z,bank-ref,customer-ref,invoice payment/\n")?;
91        let detail = bai2::TransactionDetailRecord::try_from(&records[0])?;
92        let normalized = bai2::NormalizedTransaction::from_detail(&detail)?;
93
94        let candidate = reconciliation::ReconciliationCandidate::new(
95            "bank-ref",
96            "invoice-1001",
97            amount::Amount::zero(2)?,
98            reconciliation::MatchScore::exact(),
99        )?;
100
101        assert_eq!(invoice_total.currency().as_str(), "USD");
102        assert_eq!(iban.country_code(), "GB");
103        assert_eq!(bic.country_code(), "DE");
104        assert_eq!(
105            ach_entry.transaction_code().direction(),
106            ach::AchEntryDirection::Credit
107        );
108        assert_eq!(normalized.amount().minor_units(), 12_345);
109        assert_eq!(candidate.score(), reconciliation::MatchScore::exact());
110        Ok(())
111    }
112}