Add feature batch 2, subscription/recurring sync, smooth charts, and app icon
- Implement subscriptions view with bidirectional recurring transaction sync - Add cascade delete/pause/resume between subscriptions and recurring - Fix foreign key constraints when deleting recurring transactions - Add cross-view instant refresh via callback pattern - Replace Bezier chart smoothing with Fritsch-Carlson monotone Hermite interpolation - Smooth budget sparklines using shared monotone_subdivide function - Add vertical spacing to budget rows - Add app icon (receipt on GNOME blue) in all sizes for desktop, web, and AppImage - Add calendar, credit cards, forecast, goals, insights, and wishlist views - Add date picker, numpad, quick-add, category combo, and edit dialog components - Add import/export for CSV, JSON, OFX, QIF formats - Add NLP transaction parsing, OCR receipt scanning, expression evaluator - Add notification support, Sankey chart, tray icon - Add demo data seeder with full DB wipe - Expand database schema with subscriptions, goals, credit cards, and more
This commit is contained in:
59
outlay-core/src/import_json.rs
Normal file
59
outlay-core/src/import_json.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
use crate::db::Database;
|
||||
use crate::export_json::ExportData;
|
||||
use crate::models::{NewCategory, NewTransaction};
|
||||
use std::path::Path;
|
||||
|
||||
pub fn import_json(db: &Database, path: &Path, merge: bool) -> Result<usize, Box<dyn std::error::Error>> {
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
let data: ExportData = serde_json::from_str(&content)?;
|
||||
|
||||
if !merge {
|
||||
db.reset_all_data()?;
|
||||
}
|
||||
|
||||
for cat in &data.categories {
|
||||
let existing = db.list_categories(Some(cat.transaction_type))?;
|
||||
if !existing.iter().any(|c| c.name == cat.name) {
|
||||
let new_cat = NewCategory {
|
||||
name: cat.name.clone(),
|
||||
icon: cat.icon.clone(),
|
||||
color: cat.color.clone(),
|
||||
transaction_type: cat.transaction_type,
|
||||
sort_order: cat.sort_order,
|
||||
parent_id: None,
|
||||
};
|
||||
db.insert_category(&new_cat)?;
|
||||
}
|
||||
}
|
||||
|
||||
let mut count = 0;
|
||||
for txn in &data.transactions {
|
||||
let categories = db.list_categories(Some(txn.transaction_type))?;
|
||||
let original_cat = data.categories.iter().find(|c| c.id == txn.category_id);
|
||||
let category_id = match original_cat {
|
||||
Some(oc) => categories.iter().find(|c| c.name == oc.name).map(|c| c.id),
|
||||
None => None,
|
||||
};
|
||||
let Some(category_id) = category_id else { continue };
|
||||
|
||||
if merge && db.find_duplicate_transaction(txn.amount, txn.transaction_type, category_id, txn.date)? {
|
||||
continue;
|
||||
}
|
||||
|
||||
let new_txn = NewTransaction {
|
||||
amount: txn.amount,
|
||||
transaction_type: txn.transaction_type,
|
||||
category_id,
|
||||
currency: txn.currency.clone(),
|
||||
exchange_rate: txn.exchange_rate,
|
||||
note: txn.note.clone(),
|
||||
date: txn.date,
|
||||
recurring_id: None,
|
||||
payee: txn.payee.clone(),
|
||||
};
|
||||
db.insert_transaction(&new_txn)?;
|
||||
count += 1;
|
||||
}
|
||||
|
||||
Ok(count)
|
||||
}
|
||||
Reference in New Issue
Block a user