M9: kvitt-import Splitwise importer (SPEC §10.8, FR-17)

CLI per §10.8 with --help, --dry-run and a summary; English and Swedish
headers with member columns matched by name; CSV quoting; payments as
settlements with one allocation; trailing totals row used to reconcile
the account balance (mismatch rolls back, exit 4); non-SEK rows abort
unless --fx; committed category table data/splitwise_categories.csv;
idempotent re-runs through import_key; rows validated with the server's
push checks, audited with source import, no pushes; one BEGIN IMMEDIATE
transaction. Tests over synthetic fixtures only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
This commit is contained in:
2026-10-18 07:45:32 +02:00
parent d9dd5848fe
commit 50339aef6d
21 changed files with 3097 additions and 13 deletions
+2 -12
View File
@@ -1,20 +1,10 @@
//! `kvitt-import`: the Splitwise CSV importer (SPEC §10.8). M9 owns this crate; in M2a it prints its usage and
//! exits 2.
//! `kvitt-import`: the Splitwise CSV importer (SPEC §10.8). The work is in the library (`kvitt_import`).
// No unwrap/expect outside tests (CLAUDE.md server rule); integration tests are separate crates and may use them.
#![cfg_attr(not(test), deny(clippy::unwrap_used, clippy::expect_used))]
use std::process::ExitCode;
// The importer reuses the server crate for database access and audit writing and the domain crate for the money
// rules (SPEC §6.3); referenced here so the dependency edges exist from the start.
use kvitt_domain as _;
use kvitt_server as _;
const USAGE: &str =
"usage: kvitt-import <options> (Splitwise CSV importer, SPEC §10.8; not implemented in M2a)";
fn main() -> ExitCode {
eprintln!("{USAGE}");
ExitCode::from(2)
kvitt_import::cli::main()
}