yuki_cli/cli/mod.rs
1pub mod accounts;
2pub mod admin;
3pub mod check;
4pub mod contacts;
5pub mod documents;
6pub mod init;
7pub mod invoices;
8pub mod projects;
9pub mod upload;
10pub mod vat;
11
12use clap::{Parser, Subcommand};
13
14use crate::client::accounting::AccountingClient;
15use crate::config::{AdminEntry, Config};
16use crate::error::YukiError;
17
18/// Authenticate a client and set the active administration domain.
19///
20/// Returns both the configured client and the resolved `AdminEntry` so callers
21/// can pass `admin_id` to operations that require `administrationID`.
22pub async fn setup_domain(
23 config: &Config,
24 admin: Option<&str>,
25) -> Result<(AccountingClient, AdminEntry), YukiError> {
26 let entry = config.resolve_admin(admin)?;
27 let mut client = AccountingClient::new();
28 client.authenticate(&config.api_key).await?;
29 client.set_current_domain(&entry.domain_id).await?;
30 Ok((client, entry))
31}
32
33/// Top-level CLI entry point for the Yuki bookkeeping API client.
34#[derive(Parser)]
35#[command(
36 name = "yuki",
37 version,
38 about = "CLI client for the Yuki bookkeeping API"
39)]
40pub struct Cli {
41 /// Override the active administration by name.
42 #[arg(long = "admin", global = true)]
43 pub admin: Option<String>,
44
45 /// Output format: table or json.
46 #[arg(long, global = true)]
47 pub format: Option<String>,
48
49 /// Suppress all output except errors.
50 #[arg(long, short, global = true)]
51 pub quiet: bool,
52
53 #[command(subcommand)]
54 pub command: Commands,
55}
56
57#[derive(Subcommand)]
58pub enum Commands {
59 /// Initialize yuki configuration for this machine.
60 Init {
61 /// API key (skips interactive prompt if provided).
62 #[arg(long)]
63 api_key: Option<String>,
64
65 /// Default administration name (auto-selects if only one available).
66 #[arg(long)]
67 default_admin: Option<String>,
68 },
69
70 /// Manage Yuki administrations.
71 Admin {
72 #[command(subcommand)]
73 command: AdminCommands,
74 },
75
76 /// Work with sales invoices.
77 Invoices {
78 #[command(subcommand)]
79 command: InvoiceCommands,
80 },
81
82 /// Work with archived documents.
83 Documents {
84 #[command(subcommand)]
85 command: DocumentCommands,
86 },
87
88 /// Work with contacts (customers and suppliers).
89 Contacts {
90 #[command(subcommand)]
91 command: ContactCommands,
92 },
93
94 /// Work with general ledger accounts.
95 Accounts {
96 #[command(subcommand)]
97 command: AccountCommands,
98 },
99
100 /// Work with VAT returns and codes.
101 Vat {
102 #[command(subcommand)]
103 command: VatCommands,
104 },
105
106 /// Work with projects.
107 Projects {
108 #[command(subcommand)]
109 command: ProjectCommands,
110 },
111
112 /// Run compliance and period checks.
113 Check {
114 #[command(subcommand)]
115 command: CheckCommands,
116 },
117
118 /// Upload documents to the Yuki archive.
119 Upload {
120 #[command(subcommand)]
121 command: UploadCommands,
122 },
123}
124
125#[derive(Subcommand)]
126pub enum AdminCommands {
127 /// List all available administrations.
128 List,
129
130 /// Switch the active administration.
131 Switch {
132 /// Name of the administration to activate.
133 name: String,
134 },
135}
136
137#[derive(Subcommand)]
138pub enum InvoiceCommands {
139 /// List invoices, optionally filtered by period and type.
140 List {
141 /// Accounting period (e.g. 2025-01).
142 #[arg(long)]
143 period: Option<String>,
144
145 /// Invoice type filter (e.g. sales, purchase).
146 #[arg(long)]
147 invoice_type: Option<String>,
148 },
149
150 /// Show details for a single invoice.
151 Show {
152 /// Invoice ID.
153 id: String,
154 },
155
156 /// Show the document linked to a transaction.
157 Document {
158 /// Transaction ID.
159 id: String,
160 },
161}
162
163#[derive(Subcommand)]
164pub enum DocumentCommands {
165 /// List documents in a folder or of a given type.
166 List {
167 /// Archive folder name.
168 #[arg(long)]
169 folder: Option<String>,
170
171 /// Document type filter.
172 #[arg(long)]
173 doc_type: Option<String>,
174 },
175
176 /// Search documents by a query string.
177 Search {
178 /// Search query.
179 query: String,
180 },
181
182 /// Check if an invoice exists in the archive (by amount, date, and optional contact).
183 Exists {
184 /// Invoice amount to search for.
185 #[arg(long)]
186 amount: f64,
187 /// Invoice date (YYYY-MM-DD). Matches within ±7 days.
188 #[arg(long)]
189 date: String,
190 /// Contact/supplier name to narrow the search.
191 #[arg(long)]
192 contact: Option<String>,
193 },
194}
195
196#[derive(Subcommand)]
197pub enum ContactCommands {
198 /// Search contacts by name or other criteria.
199 Search {
200 /// Search query.
201 query: String,
202 },
203
204 /// List contacts filtered by type.
205 List {
206 /// Contact type (e.g. customer, supplier).
207 #[arg(long)]
208 contact_type: Option<String>,
209 },
210}
211
212#[derive(Subcommand)]
213pub enum AccountCommands {
214 /// Show the balance of a general ledger account for a period.
215 Balance {
216 /// GL account code.
217 #[arg(long)]
218 account: Option<String>,
219
220 /// Accounting period (e.g. 2025-01).
221 #[arg(long)]
222 period: Option<String>,
223 },
224
225 /// List transactions for a general ledger account.
226 Transactions {
227 /// GL account code.
228 #[arg(long)]
229 account: Option<String>,
230
231 /// Accounting period (e.g. 2025-01).
232 #[arg(long)]
233 period: Option<String>,
234 },
235
236 /// Show the chart of accounts (GL account scheme).
237 Scheme,
238
239 /// Show net revenue for a period.
240 Revenue {
241 /// Accounting period (e.g. 2025, 2025-Q1, 2025-01).
242 #[arg(long)]
243 period: Option<String>,
244 },
245
246 /// Show opening balances per GL account for a book year.
247 StartBalance {
248 /// Book year (e.g. 2025).
249 #[arg(long)]
250 year: Option<String>,
251 },
252}
253
254#[derive(Subcommand)]
255pub enum ProjectCommands {
256 /// List all projects.
257 List,
258
259 /// Show balance for a project.
260 Balance {
261 /// Project code.
262 project: String,
263
264 /// GL account code filter.
265 #[arg(long)]
266 account: Option<String>,
267
268 /// Accounting period (e.g. 2025, 2025-Q1).
269 #[arg(long)]
270 period: Option<String>,
271 },
272}
273
274#[derive(Subcommand)]
275pub enum VatCommands {
276 /// List VAT returns for a given year.
277 Returns {
278 /// Fiscal year (e.g. 2025).
279 year: Option<String>,
280 },
281
282 /// List active VAT codes.
283 Codes,
284}
285
286#[derive(Subcommand)]
287pub enum CheckCommands {
288 /// Check outstanding BTW (VAT) items for a period.
289 Btw {
290 /// Accounting period (e.g. 2025-01).
291 period: Option<String>,
292 },
293
294 /// Find bank transactions without matching booked invoices.
295 Unmatched {
296 /// Accounting period (e.g. 2025-Q1).
297 #[arg(long)]
298 period: Option<String>,
299 /// GL account code for the bank account (default: 11001).
300 #[arg(long, default_value = "11001")]
301 bank_account: String,
302 },
303
304 /// Check if a specific invoice reference is still outstanding.
305 Outstanding {
306 /// Invoice reference to check.
307 reference: String,
308 },
309}
310
311#[derive(Subcommand)]
312pub enum UploadCommands {
313 /// Upload a document with optional invoice metadata.
314 File {
315 /// Path to the file to upload.
316 file: String,
317
318 /// Target folder: uitzoeken (default), inkoop, verkoop, bank, personeel, belasting, overig-financieel.
319 #[arg(long, default_value = "uitzoeken")]
320 folder: String,
321
322 /// Invoice amount (e.g. 114.27); enables richer metadata upload.
323 #[arg(long)]
324 amount: Option<f64>,
325
326 /// Cost category ID (e.g. 45100).
327 #[arg(long)]
328 category: Option<String>,
329
330 /// Payment method ID (e.g. 4 for pinpas).
331 #[arg(long = "payment-method")]
332 payment_method: Option<String>,
333
334 /// Project ID.
335 #[arg(long)]
336 project: Option<String>,
337
338 /// Remarks or notes.
339 #[arg(long)]
340 remarks: Option<String>,
341
342 /// Currency code (default: EUR).
343 #[arg(long, default_value = "EUR")]
344 currency: String,
345 },
346
347 /// List available cost categories.
348 Categories,
349
350 /// List available payment methods.
351 PaymentMethods,
352}