contract_cli/commands/
issuers.rs1use crate::cli::IssuerCmd;
2use crate::db::{self, Issuer};
3use crate::error::{AppError, Result};
4use crate::output::{print_success, Ctx};
5use crate::tax::Jurisdiction;
6
7use super::split_multiline_arg;
8
9pub fn run(cmd: IssuerCmd, ctx: Ctx) -> Result<()> {
10 let conn = db::open()?;
11 match cmd {
12 IssuerCmd::Add {
13 slug,
14 name,
15 legal_name,
16 jurisdiction,
17 tax_id,
18 company_no,
19 address,
20 email,
21 phone,
22 logo,
23 output_dir,
24 } => {
25 let jur = Jurisdiction::from_str(&jurisdiction).ok_or_else(|| {
26 AppError::InvalidInput(format!("unknown jurisdiction '{jurisdiction}'"))
27 })?;
28 let issuer = Issuer {
29 id: 0,
30 slug: slug.clone(),
31 name,
32 legal_name,
33 jurisdiction: jur,
34 tax_registered: false,
35 tax_id,
36 company_no,
37 tagline: None,
38 address: split_multiline_arg(&address),
39 email,
40 phone,
41 bank_details: None,
42 default_template: "helvetica-nera".into(),
43 currency: None,
44 symbol: None,
45 number_format: "{issuer}-{year}-{seq:04}".into(),
46 logo_path: logo,
47 default_output_dir: output_dir,
48 default_notes: None,
49 };
50 let id = db::issuer_create(&conn, &issuer)?;
51 let mut saved = issuer;
52 saved.id = id;
53 print_success(ctx, &saved, |i| {
54 println!("added issuer '{}' (#{})", i.slug, i.id)
55 });
56 Ok(())
57 }
58 IssuerCmd::Edit {
59 slug,
60 name,
61 legal_name,
62 jurisdiction,
63 tax_id,
64 company_no,
65 address,
66 email,
67 phone,
68 logo,
69 logo_clear,
70 output_dir,
71 } => {
72 let mut existing = db::issuer_by_slug(&conn, &slug)?;
73 if let Some(v) = name { existing.name = v; }
74 if let Some(v) = legal_name { existing.legal_name = Some(v); }
75 if let Some(v) = jurisdiction {
76 existing.jurisdiction = Jurisdiction::from_str(&v).ok_or_else(|| {
77 AppError::InvalidInput(format!("unknown jurisdiction '{v}'"))
78 })?;
79 }
80 if let Some(v) = tax_id { existing.tax_id = Some(v); }
81 if let Some(v) = company_no { existing.company_no = Some(v); }
82 if let Some(v) = address { existing.address = split_multiline_arg(&v); }
83 if let Some(v) = email { existing.email = Some(v); }
84 if let Some(v) = phone { existing.phone = Some(v); }
85 if logo_clear { existing.logo_path = None; }
86 if let Some(v) = logo { existing.logo_path = Some(v); }
87 if let Some(v) = output_dir { existing.default_output_dir = Some(v); }
88 db::issuer_update(&conn, &existing)?;
89 print_success(ctx, &existing, |i| println!("updated issuer '{}'", i.slug));
90 Ok(())
91 }
92 IssuerCmd::List => {
93 let list = db::issuer_list(&conn)?;
94 print_success(ctx, &list, |rows| {
95 if rows.is_empty() {
96 println!("(no issuers — add one with: contract issuer add <slug> --name X --address ...)");
97 } else {
98 for i in rows {
99 println!(
100 " {:<14} {:<24} {}",
101 i.slug,
102 i.name,
103 i.legal_name.clone().unwrap_or_default()
104 );
105 }
106 }
107 });
108 Ok(())
109 }
110 IssuerCmd::Show { slug } => {
111 let i = db::issuer_by_slug(&conn, &slug)?;
112 print_success(ctx, &i, |i| println!("{:#?}", i));
113 Ok(())
114 }
115 IssuerCmd::Delete { slug } => {
116 db::issuer_delete(&conn, &slug)?;
117 print_success(ctx, &slug, |s| println!("deleted issuer '{s}'"));
118 Ok(())
119 }
120 }
121}