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 /// Generate shell completions
125 Completions {
126 /// Shell to generate completions for
127 shell: clap_complete::Shell,
128 },
129
130 /// Output JSON schema for agent integration
131 Schema,
132}
133
134#[derive(Subcommand)]
135pub enum AdminCommands {
136 /// List all available administrations.
137 List,
138
139 /// Switch the active administration.
140 Switch {
141 /// Name of the administration to activate.
142 name: String,
143 },
144}
145
146#[derive(Subcommand)]
147pub enum InvoiceCommands {
148 /// List invoices, optionally filtered by period and type.
149 List {
150 /// Accounting period (e.g. 2025-01).
151 #[arg(long)]
152 period: Option<String>,
153
154 /// Invoice type filter (e.g. sales, purchase).
155 #[arg(long)]
156 invoice_type: Option<String>,
157 },
158
159 /// Show details for a single invoice.
160 Show {
161 /// Invoice ID.
162 id: String,
163 },
164
165 /// Show the document linked to a transaction.
166 Document {
167 /// Transaction ID.
168 id: String,
169 },
170}
171
172#[derive(Subcommand)]
173pub enum DocumentCommands {
174 /// List documents in a folder or of a given type.
175 List {
176 /// Archive folder name.
177 #[arg(long)]
178 folder: Option<String>,
179
180 /// Document type filter.
181 #[arg(long)]
182 doc_type: Option<String>,
183 },
184
185 /// Search documents by a query string.
186 Search {
187 /// Search query.
188 query: String,
189 },
190
191 /// Check if an invoice exists in the archive (by amount, date, and optional contact).
192 Exists {
193 /// Invoice amount to search for.
194 #[arg(long)]
195 amount: f64,
196 /// Invoice date (YYYY-MM-DD). Matches within ±7 days.
197 #[arg(long)]
198 date: String,
199 /// Contact/supplier name to narrow the search.
200 #[arg(long)]
201 contact: Option<String>,
202 },
203}
204
205#[derive(Subcommand)]
206pub enum ContactCommands {
207 /// Search contacts by name or other criteria.
208 Search {
209 /// Search query.
210 query: String,
211 },
212
213 /// List contacts filtered by type.
214 List {
215 /// Contact type (e.g. customer, supplier).
216 #[arg(long)]
217 contact_type: Option<String>,
218 },
219}
220
221#[derive(Subcommand)]
222pub enum AccountCommands {
223 /// Show the balance of a general ledger account for a period.
224 Balance {
225 /// GL account code.
226 #[arg(long)]
227 account: Option<String>,
228
229 /// Accounting period (e.g. 2025-01).
230 #[arg(long)]
231 period: Option<String>,
232 },
233
234 /// List transactions for a general ledger account.
235 Transactions {
236 /// GL account code.
237 #[arg(long)]
238 account: Option<String>,
239
240 /// Accounting period (e.g. 2025-01).
241 #[arg(long)]
242 period: Option<String>,
243 },
244
245 /// Show the chart of accounts (GL account scheme).
246 Scheme,
247
248 /// Show net revenue for a period.
249 Revenue {
250 /// Accounting period (e.g. 2025, 2025-Q1, 2025-01).
251 #[arg(long)]
252 period: Option<String>,
253 },
254
255 /// Show opening balances per GL account for a book year.
256 StartBalance {
257 /// Book year (e.g. 2025).
258 #[arg(long)]
259 year: Option<String>,
260 },
261}
262
263#[derive(Subcommand)]
264pub enum ProjectCommands {
265 /// List all projects.
266 List,
267
268 /// Show balance for a project.
269 Balance {
270 /// Project code.
271 project: String,
272
273 /// GL account code filter.
274 #[arg(long)]
275 account: Option<String>,
276
277 /// Accounting period (e.g. 2025, 2025-Q1).
278 #[arg(long)]
279 period: Option<String>,
280 },
281}
282
283#[derive(Subcommand)]
284pub enum VatCommands {
285 /// List VAT returns for a given year.
286 Returns {
287 /// Fiscal year (e.g. 2025).
288 year: Option<String>,
289 },
290
291 /// List active VAT codes.
292 Codes,
293}
294
295#[derive(Subcommand)]
296pub enum CheckCommands {
297 /// Check outstanding BTW (VAT) items for a period.
298 Btw {
299 /// Accounting period (e.g. 2025-01).
300 period: Option<String>,
301 },
302
303 /// Find bank transactions without matching booked invoices.
304 Unmatched {
305 /// Accounting period (e.g. 2025-Q1).
306 #[arg(long)]
307 period: Option<String>,
308 /// GL account code for the bank account (default: 11001).
309 #[arg(long, default_value = "11001")]
310 bank_account: String,
311 },
312
313 /// Check if a specific invoice reference is still outstanding.
314 Outstanding {
315 /// Invoice reference to check.
316 reference: String,
317 },
318}
319
320#[derive(Subcommand)]
321pub enum UploadCommands {
322 /// Upload a document with optional invoice metadata.
323 File {
324 /// Path to the file to upload.
325 file: String,
326
327 /// Target folder: uitzoeken (default), inkoop, verkoop, bank, personeel, belasting, overig-financieel.
328 #[arg(long, default_value = "uitzoeken")]
329 folder: String,
330
331 /// Invoice amount (e.g. 114.27); enables richer metadata upload.
332 #[arg(long)]
333 amount: Option<f64>,
334
335 /// Cost category ID (e.g. 45100).
336 #[arg(long)]
337 category: Option<String>,
338
339 /// Payment method ID (e.g. 4 for pinpas).
340 #[arg(long = "payment-method")]
341 payment_method: Option<String>,
342
343 /// Project ID.
344 #[arg(long)]
345 project: Option<String>,
346
347 /// Remarks or notes.
348 #[arg(long)]
349 remarks: Option<String>,
350
351 /// Currency code (default: EUR).
352 #[arg(long, default_value = "EUR")]
353 currency: String,
354 },
355
356 /// List available cost categories.
357 Categories,
358
359 /// List available payment methods.
360 PaymentMethods,
361}