Improve ebase importer to handle currency conversions in sales
Dependencies
- [2]
3VXVY2YUUse Self instead of typename - [3]
5XUAFMCKEnforce decimal precision for ebase importer - [4]
RQIRG5BDAdd english variant of decimal parser - [5]
D6LJRTWXAdd importers for ebase accounts - [6]
UO34MAAGRefactor CSV-based Importers
Change contents
- edit in importers/ebase/src/transactions.rs at line 10
use beancount_types::Balance; - edit in importers/ebase/src/transactions.rs at line 27
use tap::prelude::Tap; - edit in importers/ebase/src/transactions.rs at line 32
pub mod opt {pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<time::Date>, D::Error>whereD: serde::Deserializer<'de>,{struct Visitor;impl<'de> serde::de::Visitor<'de> for Visitor {type Value = Option<time::Date>;fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {formatter.write_str("a date in dd.mm.yy format")}fn visit_none<E>(self) -> Result<Self::Value, E>whereE: serde::de::Error,{Ok(None)}fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>whereD: serde::Deserializer<'de>,{super::deserialize(deserializer).map(Some)}}deserializer.deserialize_option(Visitor)}} - replacement in importers/ebase/src/transactions.rs at line 87
parsed.parse_items(v.as_bytes(), DATE_FORMAT).unwrap();parsed.parse_items(v.as_bytes(), DATE_FORMAT).map_err(E::custom)?; - edit in importers/ebase/src/transactions.rs at line 282[4.7826]→[4.7826:7827](∅→∅),[4.7827]→[4.13524:13648](∅→∅),[4.13648]→[4.8058:8059](∅→∅),[4.8058]→[4.8058:8059](∅→∅),[4.8059]→[4.13649:13718](∅→∅),[4.13718]→[4.8131:8132](∅→∅),[4.8131]→[4.8131:8132](∅→∅),[4.8132]→[4.13719:13808](∅→∅),[4.13808]→[4.8422:8423](∅→∅),[4.8422]→[4.8422:8423](∅→∅),[4.8423]→[4.13809:13924](∅→∅)
let fund_currency = record.fund_currency;let share_price = Amount::new(record.share_price, fund_currency);let shares_amount = Amount::new(record.shares, record.isin);let payment_amount = Amount::new(record.payment_amount, record.payment_curreny);let investment_amount_payment =Amount::new(record.investment_amount, record.payment_curreny); - replacement in importers/ebase/src/transactions.rs at line 283
let investment_amount_fund = record.exchange_rate.map(|rate| {let mut amount = investment_amount_payment.amount * rate;amount.rescale(2);Amount::new(amount, fund_currency)});let mut directives = Vec::new(); - edit in importers/ebase/src/transactions.rs at line 292
TransactionKind::Distribution => {let distribution_amount =Amount::new(record.distribution_total, record.payment_currency);let balance_date = record.balance_date.unwrap();let main_account = self.config.account_template.render(&context);let balance_amount = Amount::new(record.balance_shares, record.isin);directives.push(Directive::from(Balance::new(balance_date,main_account,balance_amount,)));transaction.build_posting(self.config.reference_account.render(&context),|posting| {if record.payment_currency.as_ref() == "EUR" {posting.set_amount(distribution_amount);} else {let rate = record.exchange_rate_eur_payment.unwrap();let distribution_amount_eur = {let amount_eur =(distribution_amount.amount / rate).tap_mut(|amount| {amount.rescale(2);});Amount::new(amount_eur, Commodity::try_from("EUR").unwrap())};posting.set_amount(distribution_amount_eur).set_price(Amount::new(rate, record.payment_currency));}},);transaction.build_posting(self.config.distributions_template.render(&context),|posting| {posting.set_amount(-distribution_amount);},);}TransactionKind::LumpSumTaxAdvance => {// No interesting informationreturn Ok(vec![]);} - edit in importers/ebase/src/transactions.rs at line 342
let fund_currency = record.fund_currency.unwrap();let share_price = Amount::new(record.share_price, fund_currency);let shares_amount = Amount::new(record.shares, record.isin);let payment_currency = record.payment_currency;let payment_amount = Amount::new(record.payment_amount, payment_currency);let investment_amount_payment =Amount::new(record.investment_amount, payment_currency);let investment_amount_fund = record.exchange_rate_payment_fund.map(|rate| {let mut amount = investment_amount_payment.amount * rate;amount.rescale(2);Amount::new(amount, fund_currency)}); - replacement in importers/ebase/src/transactions.rs at line 367
let fees = Amount::new(record.fees, record.payment_curreny);let fees = Amount::new(record.fees, payment_currency); - replacement in importers/ebase/src/transactions.rs at line 391
let currency: &str = &record.payment_curreny;let currency: &str = &payment_currency; - edit in importers/ebase/src/transactions.rs at line 419
let fund_currency = record.fund_currency.unwrap();let share_price = Amount::new(record.share_price, fund_currency);let shares_amount = Amount::new(record.shares, record.isin);let payment_currency = record.payment_currency;let sale_amount_payment = Amount::new(record.fees, payment_currency);let sale_amount_fund = record.exchange_rate_payment_fund.map(|rate| {let mut amount = sale_amount_payment.amount * rate;amount.rescale(2);Amount::new(amount, fund_currency)}); - replacement in importers/ebase/src/transactions.rs at line 442
posting.set_amount(Amount::new(record.fees, record.payment_curreny));posting.set_amount(sale_amount_payment); - edit in importers/ebase/src/transactions.rs at line 449
if let Some(sale_amount_fund) = sale_amount_fund {transaction.build_posting(self.config.currency_account.render(&CurrencyTemplateContext {currency: {let currency: &str = &payment_currency;<&Seg>::try_from(currency).expect("commodities are valid segments")},}),|posting| {posting.set_amount(-sale_amount_payment);},).build_posting(self.config.currency_account.render(&CurrencyTemplateContext {currency: {let currency: &str = &fund_currency;<&Seg>::try_from(currency).expect("commodities are valid segments")},}),|posting| {posting.set_amount(sale_amount_fund);},);} - edit in importers/ebase/src/transactions.rs at line 484
let fund_currency = record.fund_currency.unwrap();let share_price = Amount::new(record.share_price, fund_currency);let shares_amount = Amount::new(record.shares, record.isin);let payment_currency = record.payment_currency;let investment_amount_payment =Amount::new(record.investment_amount, payment_currency); - replacement in importers/ebase/src/transactions.rs at line 504
let fees = Amount::new(record.fees, record.payment_curreny);let fees = Amount::new(record.fees, payment_currency); - replacement in importers/ebase/src/transactions.rs at line 516
self.config.distributions_template.render(&context),self.config.reference_account.render(&context), - replacement in importers/ebase/src/transactions.rs at line 520
if record.payment_curreny != fund_currency {if payment_currency != fund_currency { - replacement in importers/ebase/src/transactions.rs at line 523
.exchange_rate.exchange_rate_payment_fund - edit in importers/ebase/src/transactions.rs at line 532
let fund_currency = record.fund_currency.unwrap();let share_price = Amount::new(record.share_price, fund_currency);let shares_amount = Amount::new(record.shares, record.isin);let payment_currency = record.payment_currency;let investment_amount_payment =Amount::new(record.investment_amount, payment_currency); - replacement in importers/ebase/src/transactions.rs at line 552
let fees = Amount::new(record.fees, record.payment_curreny);let fees = Amount::new(record.fees, payment_currency); - replacement in importers/ebase/src/transactions.rs at line 568
if record.payment_curreny != fund_currency {if payment_currency != fund_currency { - replacement in importers/ebase/src/transactions.rs at line 571
.exchange_rate.exchange_rate_payment_fund - edit in importers/ebase/src/transactions.rs at line 580
let fund_currency = record.fund_currency.unwrap();let share_price = Amount::new(record.share_price, fund_currency);let shares_amount = Amount::new(record.shares, record.isin);let payment_currency = record.payment_currency;let payment_amount = Amount::new(record.payment_amount, payment_currency);let investment_amount_payment =Amount::new(record.investment_amount, payment_currency);let investment_amount_fund = record.exchange_rate_payment_fund.map(|rate| {let mut amount = investment_amount_payment.amount * rate;amount.rescale(2);Amount::new(amount, fund_currency)}); - replacement in importers/ebase/src/transactions.rs at line 606
let fees = Amount::new(record.fees, record.payment_curreny);let fees = Amount::new(record.fees, payment_currency); - replacement in importers/ebase/src/transactions.rs at line 630
let currency: &str = &record.payment_curreny;let currency: &str = &payment_currency; - replacement in importers/ebase/src/transactions.rs at line 657[4.18504]→[4.18504:18526](∅→∅),[4.18526]→[4.15736:15833](∅→∅),[4.15833]→[4.18654:18665](∅→∅),[4.18654]→[4.18654:18665](∅→∅)
let price = {let date = record.price_date;Price::new(date, record.isin, share_price)};directives.push(Directive::from(transaction));if let Some(date) = record.price_date {let share_price = Amount::new(record.share_price, record.fund_currency.unwrap());directives.push(Directive::from(Price::new(date, record.isin, share_price)));} - replacement in importers/ebase/src/transactions.rs at line 663
Ok(vec![Directive::from(transaction), Directive::from(price)])Ok(directives) - edit in importers/ebase/src/transactions.rs at line 730
#[serde(rename = "Bestandsdatum", with = "dmy_short::opt")]balance_date: Option<Date>,#[serde(rename = "Anteile zum Bestandsdatum",with = "decimal_parsers::german::serde::with_precision::<6>")]balance_shares: Decimal, - edit in importers/ebase/src/transactions.rs at line 748
#[serde(rename = "Ertragswährung (EW)")]distribution_currency: Option<Commodity>, - edit in importers/ebase/src/transactions.rs at line 752
rename = "Barausschüttung/Steuerliquidität in ZW",with = "decimal_parsers::german::serde::with_precision::<2>")]distribution_total: Decimal,#[serde( - replacement in importers/ebase/src/transactions.rs at line 761
exchange_rate: Option<Decimal>,exchange_rate_payment_fund: Option<Decimal>,#[serde(rename = "Devisenkurs (EUR/ZW)",with = "decimal_parsers::german::serde::opt::with_precision::<6>")]exchange_rate_eur_payment: Option<Decimal>, - replacement in importers/ebase/src/transactions.rs at line 776
fund_currency: Commodity,fund_currency: Option<Commodity>, - replacement in importers/ebase/src/transactions.rs at line 797
payment_curreny: Commodity,payment_currency: Commodity, - replacement in importers/ebase/src/transactions.rs at line 799
#[serde(rename = "Kursdatum", with = "dmy_short")]price_date: Date,#[serde(rename = "Kursdatum", with = "dmy_short::opt")]price_date: Option<Date>, - edit in importers/ebase/src/transactions.rs at line 883
#[serde(rename = "Fondsertrag (Ausschüttung)")]Distribution, - edit in importers/ebase/src/transactions.rs at line 887
#[serde(rename = "Vorabpauschale")]LumpSumTaxAdvance, - edit in importers/ebase/src/transactions.rs at line 904
Self::Distribution => format!("Distribution of {fund}"), - edit in importers/ebase/src/transactions.rs at line 906
Self::LumpSumTaxAdvance => format!("Lump-sum tax advance for {fund}"), - edit in importers/ebase/src/transactions.rs at line 923
"Fondsertrag (Ausschüttung)" => Self::Distribution, - edit in importers/ebase/src/transactions.rs at line 927
"Vorabpauschale" => Self::LumpSumTaxAdvance,