+ // SPDX-FileCopyrightText: 2024 Markus Haug (Korrat)
+ //
+ // SPDX-License-Identifier: EUPL-1.2
+
+ use core::fmt::Display;
+ use core::hash::Hash;
+
+ use beancount_account::Account;
+ 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 Close {
+ pub date: Date,
+
+ pub account: Account,
+
+ pub meta: MetadataMap,
+ }
+
+ impl Close {
+ pub fn new(date: Date, account: impl Into<Account>) -> Self {
+ let (account, meta) = (account.into(), MetadataMap::default());
+ Self {
+ date,
+ account,
+ meta,
+ }
+ }
+ }
+
+ impl Close {
+ #[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_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_date(&mut self, date: Date) -> &mut Self {
+ self.date = date;
+ self
+ }
+
+ #[inline]
+ pub fn set_meta(&mut self, meta: impl Into<MetadataMap>) -> &mut Self {
+ self.meta = meta.into();
+ self
+ }
+ }
+
+ impl Close {
+ #[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 Close {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ let Self {
+ date,
+ account,
+ meta,
+ } = self;
+ write!(f, "{date} close {account}")?;
+
+ for (key, value) in meta {
+ write!(f, "\n {key}: {value}")?;
+ }
+
+ Ok(())
+ }
+ }