use chrono::{Months, Utc};
use polars::prelude::*;
use rust_ynab::{Client, IntoDataFrame, PlanId};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let token = std::env::var("YNAB_TOKEN")?;
let client = Client::new(&token)?;
let plan_id_str = std::env::var("YNAB_TEST_PLAN_ID")?;
let plan_id = PlanId::Id(plan_id_str.parse()?);
let cutoff = Utc::now().date_naive() - Months::new(12);
let (month_summaries, _) = client.get_months(plan_id).send().await?;
let mut per_month = Vec::new();
for summary in month_summaries.iter().filter(|s| s.month >= cutoff) {
let m = client.get_month(plan_id, summary.month).await?;
per_month.push(
m.categories
.into_dataframe()
.lazy()
.with_column(lit(m.month).cast(DataType::Date).alias("month")),
);
}
let result = concat(&per_month, UnionArgs::default())?
.filter(col("hidden").eq(lit(false)))
.filter(col("deleted").eq(lit(false)))
.with_column(((col("budgeted") + col("activity")) / lit(1000.0)).alias("variance"))
.select([
col("month"),
col("name").alias("category"),
(col("budgeted") / lit(1000.0)).alias("budgeted"),
(col("activity") / lit(-1000.0)).alias("spent"),
col("variance"),
])
.sort(["variance"], SortMultipleOptions::default())
.collect()?;
println!("{result}");
Ok(())
}