Skip to main content

invoice_cli/commands/
issuers.rs

1use crate::cli::IssuerCmd;
2use crate::db::{self, Issuer};
3use crate::error::{AppError, Result};
4use crate::output::{print_success, Ctx};
5use crate::tax::Jurisdiction;
6
7pub fn run(cmd: IssuerCmd, ctx: Ctx) -> Result<()> {
8    let conn = db::open()?;
9    match cmd {
10        IssuerCmd::Add {
11            slug,
12            name,
13            legal_name,
14            jurisdiction,
15            tax_registered,
16            tax_id,
17            company_no,
18            address,
19            email,
20            phone,
21            bank_name,
22            bank_iban,
23            bank_bic,
24            template,
25            logo,
26        } => {
27            let jur = Jurisdiction::from_str(&jurisdiction).ok_or_else(|| {
28                AppError::InvalidInput(format!(
29                    "unknown jurisdiction '{jurisdiction}' — use one of: sg, uk, us, eu, custom"
30                ))
31            })?;
32            let profile = jur.profile();
33            let issuer = Issuer {
34                id: 0,
35                slug,
36                name,
37                legal_name,
38                jurisdiction: jur,
39                tax_registered,
40                tax_id,
41                company_no,
42                tagline: None,
43                address: address.split('\n').map(|s| s.to_string()).collect(),
44                email,
45                phone,
46                bank_name,
47                bank_iban,
48                bank_bic,
49                default_template: template,
50                currency: Some(profile.currency.to_string()),
51                symbol: Some(profile.symbol.to_string()),
52                number_format: "{year}-{seq:04}".into(),
53                logo_path: logo,
54            };
55            let id = db::issuer_create(&conn, &issuer)?;
56            let mut out = issuer.clone();
57            out.id = id;
58            print_success(ctx, &out, |i| println!("added issuer '{}' (id {})", i.slug, i.id));
59            Ok(())
60        }
61        IssuerCmd::List => {
62            let list = db::issuer_list(&conn)?;
63            print_success(ctx, &list, |list| {
64                if list.is_empty() {
65                    println!("no issuers. add one: invoice issuer add <slug> --name ...");
66                }
67                for i in list {
68                    println!(
69                        "{:<16}  {:<24}  {} ({})",
70                        i.slug,
71                        i.name,
72                        i.jurisdiction.as_str(),
73                        if i.tax_registered { "tax-registered" } else { "-" }
74                    );
75                }
76            });
77            Ok(())
78        }
79        IssuerCmd::Show { slug } => {
80            let i = db::issuer_by_slug(&conn, &slug)?;
81            print_success(ctx, &i, |i| println!("{:#?}", i));
82            Ok(())
83        }
84        IssuerCmd::Delete { slug } => {
85            db::issuer_delete(&conn, &slug)?;
86            print_success(ctx, &slug, |s| println!("deleted issuer '{s}'"));
87            Ok(())
88        }
89        IssuerCmd::Edit {
90            slug,
91            name,
92            legal_name,
93            jurisdiction,
94            tax_registered,
95            tax_id,
96            company_no,
97            tagline,
98            address,
99            email,
100            phone,
101            bank_name,
102            bank_iban,
103            bank_bic,
104            template,
105            currency,
106            symbol,
107            number_format,
108            logo,
109        } => {
110            let mut issuer = db::issuer_by_slug(&conn, &slug)?;
111            if let Some(v) = name {
112                issuer.name = v;
113            }
114            if let Some(v) = legal_name {
115                issuer.legal_name = Some(v);
116            }
117            if let Some(v) = jurisdiction {
118                let jur = Jurisdiction::from_str(&v).ok_or_else(|| {
119                    AppError::InvalidInput(format!(
120                        "unknown jurisdiction '{v}' — use one of: sg, uk, us, eu, custom"
121                    ))
122                })?;
123                issuer.jurisdiction = jur;
124            }
125            if let Some(v) = tax_registered {
126                issuer.tax_registered = v;
127            }
128            if let Some(v) = tax_id {
129                issuer.tax_id = Some(v);
130            }
131            if let Some(v) = company_no {
132                issuer.company_no = Some(v);
133            }
134            if let Some(v) = tagline {
135                issuer.tagline = Some(v);
136            }
137            if let Some(v) = address {
138                issuer.address = v.split('\n').map(|s| s.to_string()).collect();
139            }
140            if let Some(v) = email {
141                issuer.email = Some(v);
142            }
143            if let Some(v) = phone {
144                issuer.phone = Some(v);
145            }
146            if let Some(v) = bank_name {
147                issuer.bank_name = Some(v);
148            }
149            if let Some(v) = bank_iban {
150                issuer.bank_iban = Some(v);
151            }
152            if let Some(v) = bank_bic {
153                issuer.bank_bic = Some(v);
154            }
155            if let Some(v) = template {
156                issuer.default_template = v;
157            }
158            if let Some(v) = currency {
159                issuer.currency = Some(v);
160            }
161            if let Some(v) = symbol {
162                issuer.symbol = Some(v);
163            }
164            if let Some(v) = number_format {
165                issuer.number_format = v;
166            }
167            if let Some(v) = logo {
168                issuer.logo_path = Some(v);
169            }
170            db::issuer_update(&conn, &issuer)?;
171            print_success(ctx, &issuer, |i| {
172                println!("updated issuer '{}' (id {})", i.slug, i.id)
173            });
174            Ok(())
175        }
176        IssuerCmd::SetTemplate { slug, template } => {
177            if !crate::typst_assets::has_template(&template)? {
178                let available = crate::typst_assets::list_templates()?.join(", ");
179                return Err(AppError::InvalidInput(format!(
180                    "unknown template '{template}' — available: {available}"
181                )));
182            }
183            let mut issuer = db::issuer_by_slug(&conn, &slug)?;
184            issuer.default_template = template;
185            db::issuer_update(&conn, &issuer)?;
186            print_success(ctx, &issuer, |i| {
187                println!(
188                    "set template for issuer '{}' to '{}'",
189                    i.slug, i.default_template
190                )
191            });
192            Ok(())
193        }
194    }
195}