Skip to main content

yuki_cli/cli/
invoices.rs

1use crate::cli::setup_domain;
2use crate::client::accounting_info::AccountingInfoClient;
3use crate::client::sales::SalesClient;
4use crate::config::Config;
5use crate::error::YukiError;
6use crate::output::{OutputFormat, format_json, format_table, is_tty};
7
8pub async fn list(
9    config: &Config,
10    admin: Option<&str>,
11    _period: Option<&str>,
12    invoice_type: Option<&str>,
13    format: Option<&str>,
14) -> Result<(), YukiError> {
15    let fmt = OutputFormat::from_flag(format, is_tty());
16
17    match invoice_type {
18        Some("purchase") | Some("creditor") => {
19            let (client, entry) = setup_domain(config, admin).await?;
20            let items = client.outstanding_creditor_items(&entry.admin_id).await?;
21
22            let headers = vec![
23                "Contact".into(),
24                "Description".into(),
25                "Date".into(),
26                "Amount".into(),
27                "Open".into(),
28            ];
29            let rows: Vec<Vec<String>> = items
30                .iter()
31                .map(|i| {
32                    vec![
33                        i.contact_name.clone(),
34                        i.description.clone(),
35                        i.date.clone(),
36                        i.amount.clone(),
37                        i.open_amount.clone(),
38                    ]
39                })
40                .collect();
41
42            match fmt {
43                OutputFormat::Table => println!("{}", format_table(&headers, &rows)),
44                OutputFormat::Json => println!("{}", format_json(&headers, &rows)),
45            }
46        }
47
48        // Default to sales invoices when type is "sales", "debtor", or unspecified
49        _ => {
50            let mut client = SalesClient::new();
51            client.authenticate(&config.api_key).await?;
52            let items = client.get_sales_items().await?;
53
54            let headers = vec!["ID".into(), "Description".into()];
55            let rows: Vec<Vec<String>> = items
56                .iter()
57                .map(|i| vec![i.id.clone(), i.description.clone()])
58                .collect();
59
60            match fmt {
61                OutputFormat::Table => println!("{}", format_table(&headers, &rows)),
62                OutputFormat::Json => println!("{}", format_json(&headers, &rows)),
63            }
64        }
65    }
66
67    Ok(())
68}
69
70pub async fn document(
71    config: &Config,
72    admin: Option<&str>,
73    id: &str,
74    format: Option<&str>,
75) -> Result<(), YukiError> {
76    let entry = config.resolve_admin(admin)?;
77    let mut client = AccountingInfoClient::new();
78    client.authenticate(&config.api_key).await?;
79    let xml = client.get_transaction_document(&entry.admin_id, id).await?;
80
81    let result = crate::client::soap_client::SoapClient::parse_single_result(
82        &xml,
83        "GetTransactionDocumentResult",
84    )
85    .unwrap_or(xml);
86
87    let headers = vec!["Transaction".into(), "Document".into()];
88    let rows = vec![vec![id.to_string(), result]];
89
90    let fmt = OutputFormat::from_flag(format, is_tty());
91    match fmt {
92        OutputFormat::Table => println!("{}", format_table(&headers, &rows)),
93        OutputFormat::Json => println!("{}", format_json(&headers, &rows)),
94    }
95    Ok(())
96}
97
98pub async fn show(
99    config: &Config,
100    _admin: Option<&str>,
101    id: &str,
102    format: Option<&str>,
103) -> Result<(), YukiError> {
104    let mut client = AccountingInfoClient::new();
105    client.authenticate(&config.api_key).await?;
106    let details = client.get_transaction_details(id).await?;
107
108    let headers = vec![
109        "ID".into(),
110        "Date".into(),
111        "Amount".into(),
112        "Currency".into(),
113        "GL Account".into(),
114        "Description".into(),
115    ];
116    let rows: Vec<Vec<String>> = details
117        .iter()
118        .map(|d| {
119            vec![
120                d.id.clone(),
121                d.date.clone(),
122                d.amount.clone(),
123                d.currency.clone(),
124                d.gl_account_code.clone(),
125                d.description.clone(),
126            ]
127        })
128        .collect();
129
130    let fmt = OutputFormat::from_flag(format, is_tty());
131    match fmt {
132        OutputFormat::Table => println!("{}", format_table(&headers, &rows)),
133        OutputFormat::Json => println!("{}", format_json(&headers, &rows)),
134    }
135    Ok(())
136}