1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
use std::path::PathBuf;
use chrono::NaiveDate;
use clap::{Parser, Subcommand};
/// Pactole command-line interface.
#[derive(Debug, Parser)]
#[command(
name = "pactole",
version,
about = "Tools around the Pactole ledger format"
)]
pub(crate) struct Cli {
#[command(subcommand)]
pub(crate) command: Command,
}
#[derive(Debug, Subcommand)]
pub(crate) enum Command {
/// Parse a `.pactole` file and print the resulting journal entries.
Parse {
/// Path to the `.pactole` file to parse.
file: PathBuf,
},
/// Reformat a `.pactole` file into its canonical form.
Fmt {
/// Path to the `.pactole` file to format, or `-` for stdin.
file: String,
/// Write the result back to `file` instead of printing it.
#[arg(long)]
write: bool,
},
/// Generate shell completion scripts and print them to stdout.
Completions {
/// Shell for which to generate completions.
#[arg(value_enum)]
shell: clap_complete::Shell,
},
/// Check that a `.pactole` file is valid, both grammatically and from a
/// business point of view.
Check {
/// Path to the `.pactole` file to check.
file: PathBuf,
/// Treat warnings as errors.
#[arg(long)]
strict: bool,
},
/// List the transactions of a `.pactole` file with a running balance.
Register {
/// Path to the `.pactole` file to read.
file: PathBuf,
/// Only show postings on this account or one of its sub-accounts.
#[arg(short, long)]
account: Option<String>,
/// Only show transactions on or after this date (`YYYY-MM-DD`).
#[arg(long)]
from: Option<NaiveDate>,
/// Only show transactions on or before this date (`YYYY-MM-DD`).
#[arg(long)]
to: Option<NaiveDate>,
/// Only show transactions whose payee contains this text.
#[arg(long)]
payee: Option<String>,
/// Only show transactions whose narration contains this text.
#[arg(long)]
narration: Option<String>,
/// Only show transactions carrying this tag.
#[arg(long)]
tag: Option<String>,
/// Only show transactions with this status.
#[arg(long, value_enum)]
status: Option<StatusArg>,
},
/// Import transactions from an OFX statement into canonical `.pactole`
/// transaction directives.
ImportOfx {
/// Path to the OFX/QFX file to import.
file: PathBuf,
/// Path to the import configuration file.
#[arg(long, value_name = "PATH")]
config: Option<PathBuf>,
/// Path to an existing `.pactole` file used for deduplication.
#[arg(long, value_name = "PATH")]
into: Option<PathBuf>,
/// Append generated transactions to `--into` instead of printing them.
#[arg(long, requires = "into")]
write: bool,
},
/// Initialize a ledger and, when missing, the OFX import configuration.
Init {
/// Path to the ledger file to create.
#[arg(default_value = "ledger.pactole")]
ledger: PathBuf,
/// Path to the OFX import configuration file.
#[arg(long, value_name = "PATH")]
config: Option<PathBuf>,
/// Main bank account.
#[arg(long, default_value = "Assets:Checking")]
account: String,
/// Initial commodity/currency.
#[arg(long, default_value = "EUR")]
currency: String,
/// Default counter account for uncategorized imports.
#[arg(long, default_value = "Expenses:ToReview")]
counter_account: String,
/// Date for the initial declarations. Defaults to today.
#[arg(long)]
date: Option<NaiveDate>,
/// Print the generated ledger instead of creating the ledger file.
#[arg(long)]
stdout: bool,
/// Do not create the OFX import configuration.
#[arg(long)]
no_config: bool,
/// Do not create the ledger file.
#[arg(long)]
no_ledger: bool,
},
}
/// CLI-facing mirror of [`pactole_core::TransactionStatus`].
#[derive(Debug, Clone, Copy, clap::ValueEnum)]
pub(crate) enum StatusArg {
Uncleared,
Pending,
Cleared,
}
impl From<StatusArg> for pactole_core::TransactionStatus {
fn from(value: StatusArg) -> Self {
match value {
StatusArg::Uncleared => pactole_core::TransactionStatus::Uncleared,
StatusArg::Pending => pactole_core::TransactionStatus::Pending,
StatusArg::Cleared => pactole_core::TransactionStatus::Cleared,
}
}
}