Compare commits
4 Commits
e205280176
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| ae543e5edf | |||
| f7b645895d | |||
| 14d0d82719 | |||
| c9e005475c |
Generated
+1
-1
@@ -1963,7 +1963,7 @@ checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
|
||||
|
||||
[[package]]
|
||||
name = "ynabmunger"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ynabmunger"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
edition = "2024"
|
||||
publish = false
|
||||
|
||||
|
||||
+12
-3
@@ -55,6 +55,11 @@ enum Command {
|
||||
/// The number of days to look back for transactions
|
||||
#[arg(short, long, default_value_t = 30)]
|
||||
days: i64,
|
||||
|
||||
/// Filter transactions by a search term in the payee field. This will match any transaction
|
||||
/// whose payee contains the search term, case-insensitive.
|
||||
#[arg(short, long)]
|
||||
filter: Option<String>,
|
||||
},
|
||||
/// Convert from a bank export to a CSV you can import manually to YNAB
|
||||
Convert {
|
||||
@@ -141,6 +146,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
account,
|
||||
account_id,
|
||||
days,
|
||||
filter,
|
||||
} => {
|
||||
let client = Client::new(&token);
|
||||
let plan = match (plan, plan_id) {
|
||||
@@ -157,12 +163,15 @@ async fn main() -> anyhow::Result<()> {
|
||||
};
|
||||
|
||||
let transactions = match account {
|
||||
Some(account) => account.list_transactions(days).await?,
|
||||
None => plan.list_transactions(None, days).await?,
|
||||
Some(account) => account.list_transactions(days, filter.as_deref()).await?,
|
||||
None => {
|
||||
plan.list_transactions(None, days, filter.as_deref())
|
||||
.await?
|
||||
}
|
||||
};
|
||||
println!("Transactions{} in the last 30 days:", accountstr);
|
||||
for t in transactions {
|
||||
println!("{},{},{}", t.date, t.payee, t.amount);
|
||||
println!("{},{},{}", t.date, t.payee, t.format_amount());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
+2
-4
@@ -18,9 +18,7 @@ fn parse_amount_str(amount_str: &str) -> Result<i64, Error> {
|
||||
let frac = format!("{:0<2}", frac);
|
||||
let frac = frac.parse::<i64>()?;
|
||||
|
||||
let mut amount: i64 = 0;
|
||||
amount += whole * 100 * 10;
|
||||
amount += frac * 10;
|
||||
let amount = whole * 100 * 10 + frac * 10;
|
||||
Ok(if negative { -amount } else { amount })
|
||||
}
|
||||
|
||||
@@ -34,7 +32,7 @@ impl Transaction {
|
||||
})
|
||||
}
|
||||
|
||||
fn format_amount(&self) -> String {
|
||||
pub fn format_amount(&self) -> String {
|
||||
let whole = self.amount / 10 / 100;
|
||||
let frac = if self.amount < 0 { -1 } else { 1 } * (self.amount / 10) % 100;
|
||||
format!("{}.{:02}", whole, frac)
|
||||
|
||||
+10
-2
@@ -130,6 +130,7 @@ impl Plan {
|
||||
&self,
|
||||
account_id: Option<&str>,
|
||||
days: i64,
|
||||
filter: Option<&str>,
|
||||
) -> Result<Vec<Transaction>, Error> {
|
||||
let since_date = chrono::Local::now().date_naive() - chrono::Duration::days(days);
|
||||
let since_date = since_date.format("%Y-%m-%d");
|
||||
@@ -139,6 +140,7 @@ impl Plan {
|
||||
Ok(transform::from_ynab_transactions(
|
||||
&res.data.transactions,
|
||||
account_id,
|
||||
filter,
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -175,8 +177,14 @@ impl Account {
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn list_transactions(&self, days: i64) -> Result<Vec<Transaction>, Error> {
|
||||
self.plan.list_transactions(Some(&self.id), days).await
|
||||
pub async fn list_transactions(
|
||||
&self,
|
||||
days: i64,
|
||||
filter: Option<&str>,
|
||||
) -> Result<Vec<Transaction>, Error> {
|
||||
self.plan
|
||||
.list_transactions(Some(&self.id), days, filter)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn upload(&self, transactions: &[Transaction]) -> Result<(), Error> {
|
||||
|
||||
@@ -31,6 +31,7 @@ pub(crate) fn to_ynab_transactions(
|
||||
pub(crate) fn from_ynab_transactions(
|
||||
transactions: &[apitypes::Transaction],
|
||||
account_id: Option<&str>,
|
||||
filter: Option<&str>,
|
||||
) -> Vec<Transaction> {
|
||||
transactions
|
||||
.iter()
|
||||
@@ -38,6 +39,15 @@ pub(crate) fn from_ynab_transactions(
|
||||
Some(id) => t.account_id == id,
|
||||
None => true,
|
||||
})
|
||||
.filter(|t| match filter {
|
||||
Some(filter) => t
|
||||
.payee_name
|
||||
.to_owned()
|
||||
.unwrap_or(String::new())
|
||||
.to_lowercase()
|
||||
.contains(filter.to_lowercase().as_str()),
|
||||
None => true,
|
||||
})
|
||||
.map(|t| Transaction {
|
||||
date: t.date.to_owned(),
|
||||
payee: match &t.payee_name {
|
||||
|
||||
Reference in New Issue
Block a user