From c9e005475c7364f8d980877b6a488f0ce9600cf5 Mon Sep 17 00:00:00 2001 From: James McDonald Date: Wed, 3 Jun 2026 09:16:05 +0200 Subject: [PATCH] Add filter to transactions command --- src/main.rs | 13 +++++++++++-- src/ynab/client.rs | 12 ++++++++++-- src/ynab/transform.rs | 10 ++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index a52a82c..5c5ae0d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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, }, /// 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,8 +163,11 @@ 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 { diff --git a/src/ynab/client.rs b/src/ynab/client.rs index c9daa75..c2e792e 100644 --- a/src/ynab/client.rs +++ b/src/ynab/client.rs @@ -130,6 +130,7 @@ impl Plan { &self, account_id: Option<&str>, days: i64, + filter: Option<&str>, ) -> Result, 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, Error> { - self.plan.list_transactions(Some(&self.id), days).await + pub async fn list_transactions( + &self, + days: i64, + filter: Option<&str>, + ) -> Result, Error> { + self.plan + .list_transactions(Some(&self.id), days, filter) + .await } pub async fn upload(&self, transactions: &[Transaction]) -> Result<(), Error> { diff --git a/src/ynab/transform.rs b/src/ynab/transform.rs index f1d6b6f..088a2ce 100644 --- a/src/ynab/transform.rs +++ b/src/ynab/transform.rs @@ -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 { 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 {