Add a type for Beancount open directives

korrat
Apr 8, 2024, 6:07 PM
JFZHDHYO37SH3JVVFEHAD4YWBDQXKA5EODH4SRHVTLMRCJZHKWLAC

Dependencies

  • [2] OAOH3QOZ Extract metadata into separate crate
  • [3] DYRM6NNX Update licensing information
  • [4] 72AIO2FZ Upgrade dependencies
  • [5] 6A5YLGWV Add an importer for the VR-Bank CSV format
  • [6] PUJBHX7C Add importer for ECUS transactions
  • [7] XWHISGCP Extract Amount into separate crate
  • [8] UZFKS57S Allow expense account overrides by content type for Apple Store transactions
  • [9] XQHYMSDY Add importer for Union Investment transactions
  • [10] 2JBFREZG enable additional warnings
  • [11] 362NCCMX Add importer for Apple Store
  • [12] YDK6X6PP add a library of important types for beancount
  • [13] PCHAKXNM Add an importer for Fidor account statements
  • [*] 576M5IPA Add type for raw price specs
  • [*] NG5QXPZH Extract Account into separate crate
  • [*] I2P2FTLE add basic parser for german decimals
  • [*] 5S4MZHL5 pretty print decimals using icu
  • [*] QRIJE4AQ add a simple pretty printer for beancount directives

Change contents

  • replacement in importers/vr-bank/src/lib.rs at line 51
    [5.1311][4.15:71]()
    #[builder(field(ty = "HashMap<String, Account>"))]
    [5.1311]
    [5.1368]
    #[builder(field(ty = "HashMap<String, Account>"))]
  • replacement in importers/uniondepot/src/lib.rs at line 49
    [5.1366][4.76:148]()
    #[builder(field(ty = "HashMap<String, Commodity>"), setter(into))]
    [5.1366]
    [5.1439]
    #[builder(field(ty = "HashMap<String, Commodity>"), setter(into))]
  • replacement in importers/uniondepot/src/lib.rs at line 62
    [5.1769][4.149:221]()
    #[builder(field(ty = "HashMap<String, Commodity>"), setter(into))]
    [5.1769]
    [5.1842]
    #[builder(field(ty = "HashMap<String, Commodity>"), setter(into))]
  • replacement in importers/fidor/src/lib.rs at line 70
    [5.1861][4.416:472]()
    #[builder(field(ty = "HashMap<String, Account>"))]
    [5.1861]
    [5.1918]
    #[builder(field(ty = "HashMap<String, Account>"))]
  • replacement in importers/ecus/src/lib.rs at line 33
    [5.1009][4.477:545]()
    #[builder(field(ty = "HashMap<String, LocationInformation>"))]
    [5.1009]
    [5.1078]
    #[builder(field(ty = "HashMap<String, LocationInformation>"))]
  • replacement in importers/ecus/src/lib.rs at line 36
    [5.1136][4.546:620]()
    #[builder(field(ty = "Option<String>"), setter(into, strip_option))]
    [5.1136]
    [5.1211]
    #[builder(field(ty = "Option<String>"), setter(into, strip_option))]
  • replacement in importers/apple/src/transaction_history.rs at line 45
    [5.48][4.908:964]()
    #[builder(field(ty = "HashMap<String, Account>"))]
    [5.48]
    [5.105]
    #[builder(field(ty = "HashMap<String, Account>"))]
  • edit in common/beancount-types/src/lib.rs at line 20
    [2.236]
    [15.424]
    pub use beancount_open::Open;
  • edit in common/beancount-types/Cargo.toml at line 31
    [2.319]
    [2.319]
    beancount-open.path = "../../beancount/open"
  • file addition: open (d--r------)
    [16.1]
  • file addition: src (d--r------)
    [0.553]
  • file addition: lib.rs (----------)
    [0.570]
    // SPDX-FileCopyrightText: 2024 Markus Haug (Korrat)
    //
    // SPDX-License-Identifier: EUPL-1.2
    extern crate alloc;
    use core::fmt::Display;
    use core::hash::Hash;
    use alloc::collections::BTreeSet;
    use beancount_account::Account;
    use beancount_commodity::Commodity;
    use beancount_metadata::MetadataKey;
    use beancount_metadata::MetadataMap;
    use beancount_metadata::MetadataValue;
    use time::Date;
    use time::OffsetDateTime;
    use time_tz::PrimitiveDateTimeExt;
    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
    pub struct Open {
    pub date: Date,
    pub account: Account,
    pub commodities: BTreeSet<Commodity>,
    pub booking: Option<String>,
    pub meta: MetadataMap,
    }
    impl Open {
    pub fn new(date: Date, account: impl Into<Account>, commodities: BTreeSet<Commodity>) -> Self {
    let (account, booking, meta) = (account.into(), None, MetadataMap::default());
    Self {
    date,
    account,
    commodities,
    booking,
    meta,
    }
    }
    }
    impl Open {
    #[inline]
    pub fn add_commodity(&mut self, commodity: impl Into<Commodity>) -> &mut Self {
    self.commodities.insert(commodity.into());
    self
    }
    #[inline]
    pub fn add_meta(
    &mut self,
    key: impl Into<MetadataKey>,
    value: impl Into<MetadataValue>,
    ) -> &mut Self {
    self.meta.insert(key.into(), value.into());
    self
    }
    #[inline]
    pub fn clear_commodities(&mut self) -> &mut Self {
    self.commodities.clear();
    self
    }
    #[inline]
    pub fn clear_booking(&mut self) -> &mut Self {
    self.booking = None;
    self
    }
    #[inline]
    pub fn clear_meta(&mut self) -> &mut Self {
    self.meta.clear();
    self
    }
    #[inline]
    pub fn set_account(&mut self, account: impl Into<Account>) -> &mut Self {
    self.account = account.into();
    self
    }
    #[inline]
    pub fn set_booking(&mut self, booking: String) -> &mut Self {
    self.booking = Some(booking);
    self
    }
    #[inline]
    pub fn set_date(&mut self, date: Date) -> &mut Self {
    self.date = date;
    self
    }
    #[inline]
    pub fn set_commodities(&mut self, commodities: impl Into<BTreeSet<Commodity>>) -> &mut Self {
    self.commodities = commodities.into();
    self
    }
    #[inline]
    pub fn set_meta(&mut self, meta: impl Into<MetadataMap>) -> &mut Self {
    self.meta = meta.into();
    self
    }
    }
    impl Open {
    #[inline]
    #[must_use]
    pub fn timestamp(&self) -> Option<OffsetDateTime> {
    // Balance statements occur first thing in the day
    let local_timestamp = self.date.midnight();
    let timezone = time_tz::system::get_timezone().ok()?;
    local_timestamp.assume_timezone(timezone).take_first()
    }
    }
    impl Display for Open {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
    let Self {
    date,
    account,
    commodities,
    booking,
    meta,
    } = self;
    write!(f, "{date} open {account}")?;
    for commodity in commodities {
    write!(f, " {commodity}")?;
    }
    if let Some(booking) = booking {
    write!(f, " {booking:?}")?;
    }
    for (key, value) in meta {
    write!(f, "\n {key}: {value}")?;
    }
    Ok(())
    }
    }
  • file addition: Cargo.toml (----------)
    [0.553]
    # SPDX-FileCopyrightText: 2024 Markus Haug (Korrat)
    #
    # SPDX-License-Identifier: EUPL-1.2
    [package]
    name = "beancount-open"
    authors.workspace = true
    edition.workspace = true
    publish.workspace = true
    rust-version.workspace = true
    version.workspace = true
    [dependencies]
    # Inherited dependencies
    time.workspace = true
    time-tz.workspace = true
    # Workspace dependencies
    beancount-account.path = "../account"
    beancount-commodity.path = "../commodity"
    beancount-metadata.path = "../metadata"
    [lints]
    workspace = true
  • edit in beancount/amount/src/lib.rs at line 7
    [5.2082][3.204:205]()
  • edit in Cargo.lock at line 362
    [18.3914]
    [19.5470]
    name = "beancount-open"
    version = "0.0.0-dev.0"
    dependencies = [
    "beancount-account",
    "beancount-commodity",
    "beancount-metadata",
    "time 0.3.34",
    "time-tz",
    ]
    [[package]]
  • edit in Cargo.lock at line 431
    [2.1483]
    [15.1965]
    "beancount-open",