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}