Skip to main content

raps_cli/commands/acc/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2024-2025 Dmytro Yemelianov
3
4//! ACC Extended Commands
5//!
6//! Commands for ACC modules: Assets, Submittals, Checklists
7
8mod assets;
9mod checklists;
10mod submittals;
11
12use anyhow::Result;
13use clap::Subcommand;
14use std::path::PathBuf;
15
16use crate::output::OutputFormat;
17use raps_acc::AccClient;
18
19#[derive(Debug, Subcommand)]
20pub enum AccCommands {
21    /// Manage project assets
22    #[command(subcommand)]
23    Asset(AssetCommands),
24
25    /// Manage project submittals
26    #[command(subcommand)]
27    Submittal(SubmittalCommands),
28
29    /// Manage project checklists
30    #[command(subcommand)]
31    Checklist(ChecklistCommands),
32}
33
34#[derive(Debug, Subcommand)]
35pub enum AssetCommands {
36    /// List assets in a project
37    List {
38        /// Project ID (without "b." prefix)
39        project_id: String,
40    },
41
42    /// Get a specific asset
43    Get {
44        /// Project ID (without "b." prefix)
45        project_id: String,
46        /// Asset ID
47        asset_id: String,
48    },
49
50    /// Create a new asset
51    Create {
52        /// Project ID (without "b." prefix)
53        project_id: String,
54        /// Asset description
55        #[arg(long)]
56        description: Option<String>,
57        /// Barcode
58        #[arg(long)]
59        barcode: Option<String>,
60        /// Category ID
61        #[arg(long)]
62        category_id: Option<String>,
63    },
64
65    /// Update an existing asset
66    Update {
67        /// Project ID (without "b." prefix)
68        project_id: String,
69        /// Asset ID
70        asset_id: String,
71        /// New description
72        #[arg(long)]
73        description: Option<String>,
74        /// New barcode
75        #[arg(long)]
76        barcode: Option<String>,
77        /// New status ID
78        #[arg(long)]
79        status_id: Option<String>,
80    },
81
82    /// Delete an asset
83    Delete {
84        /// Project ID (without "b." prefix)
85        project_id: String,
86        /// Asset ID
87        asset_id: String,
88    },
89}
90
91#[derive(Debug, Subcommand)]
92pub enum SubmittalCommands {
93    /// List submittals in a project
94    List {
95        /// Project ID (without "b." prefix)
96        project_id: String,
97    },
98
99    /// Get a specific submittal
100    Get {
101        /// Project ID (without "b." prefix)
102        project_id: String,
103        /// Submittal ID
104        submittal_id: String,
105    },
106
107    /// Create a new submittal
108    Create {
109        /// Project ID (without "b." prefix)
110        project_id: String,
111        /// Submittal title
112        #[arg(long)]
113        title: Option<String>,
114        /// Spec section reference
115        #[arg(long)]
116        spec_section: Option<String>,
117        /// Due date (ISO 8601 format)
118        #[arg(long)]
119        due_date: Option<String>,
120        /// Create submittals from CSV file (columns: title, description, spec_id)
121        #[arg(long, value_name = "FILE")]
122        from_csv: Option<PathBuf>,
123    },
124
125    /// Update an existing submittal
126    Update {
127        /// Project ID (without "b." prefix)
128        project_id: String,
129        /// Submittal ID
130        submittal_id: String,
131        /// New title
132        #[arg(long)]
133        title: Option<String>,
134        /// New status
135        #[arg(long)]
136        status: Option<String>,
137        /// New due date
138        #[arg(long)]
139        due_date: Option<String>,
140    },
141
142    /// Delete a submittal
143    Delete {
144        /// Project ID (without "b." prefix)
145        project_id: String,
146        /// Submittal ID
147        submittal_id: String,
148    },
149}
150
151#[derive(Debug, Subcommand)]
152pub enum ChecklistCommands {
153    /// List checklists in a project
154    List {
155        /// Project ID (without "b." prefix)
156        project_id: String,
157    },
158
159    /// Get a specific checklist
160    Get {
161        /// Project ID (without "b." prefix)
162        project_id: String,
163        /// Checklist ID
164        checklist_id: String,
165    },
166
167    /// Create a new checklist
168    Create {
169        /// Project ID (without "b." prefix)
170        project_id: String,
171        /// Checklist title
172        #[arg(long)]
173        title: String,
174        /// Template ID to use
175        #[arg(long)]
176        template_id: Option<String>,
177        /// Location reference
178        #[arg(long)]
179        location: Option<String>,
180        /// Due date (ISO 8601 format)
181        #[arg(long)]
182        due_date: Option<String>,
183        /// Assignee user ID
184        #[arg(long)]
185        assignee_id: Option<String>,
186    },
187
188    /// Update an existing checklist
189    Update {
190        /// Project ID (without "b." prefix)
191        project_id: String,
192        /// Checklist ID
193        checklist_id: String,
194        /// New title
195        #[arg(long)]
196        title: Option<String>,
197        /// New status
198        #[arg(long)]
199        status: Option<String>,
200        /// New location
201        #[arg(long)]
202        location: Option<String>,
203        /// New due date
204        #[arg(long)]
205        due_date: Option<String>,
206    },
207
208    /// List checklist templates
209    Templates {
210        /// Project ID (without "b." prefix)
211        project_id: String,
212    },
213}
214
215// ---------------------------------------------------------------------------
216// Shared helpers
217// ---------------------------------------------------------------------------
218
219pub(super) fn truncate_str(s: &str, max_len: usize) -> String {
220    if s.len() <= max_len {
221        s.to_string()
222    } else {
223        format!("{}...", &s[..max_len - 3])
224    }
225}
226
227// ---------------------------------------------------------------------------
228// Command dispatch
229// ---------------------------------------------------------------------------
230
231impl AccCommands {
232    pub async fn execute(self, client: &AccClient, output_format: OutputFormat) -> Result<()> {
233        match self {
234            AccCommands::Asset(cmd) => cmd.execute(client, output_format).await,
235            AccCommands::Submittal(cmd) => cmd.execute(client, output_format).await,
236            AccCommands::Checklist(cmd) => cmd.execute(client, output_format).await,
237        }
238    }
239}
240
241impl AssetCommands {
242    pub async fn execute(self, client: &AccClient, output_format: OutputFormat) -> Result<()> {
243        match self {
244            AssetCommands::List { project_id } => {
245                assets::list_assets(client, &project_id, output_format).await
246            }
247            AssetCommands::Get {
248                project_id,
249                asset_id,
250            } => assets::get_asset(client, &project_id, &asset_id, output_format).await,
251            AssetCommands::Create {
252                project_id,
253                description,
254                barcode,
255                category_id,
256            } => {
257                assets::create_asset(
258                    client,
259                    &project_id,
260                    description,
261                    barcode,
262                    category_id,
263                    output_format,
264                )
265                .await
266            }
267            AssetCommands::Update {
268                project_id,
269                asset_id,
270                description,
271                barcode,
272                status_id,
273            } => {
274                assets::update_asset(
275                    client,
276                    &project_id,
277                    &asset_id,
278                    description,
279                    barcode,
280                    status_id,
281                    output_format,
282                )
283                .await
284            }
285            AssetCommands::Delete {
286                project_id,
287                asset_id,
288            } => assets::delete_asset(client, &project_id, &asset_id, output_format).await,
289        }
290    }
291}
292
293impl SubmittalCommands {
294    pub async fn execute(self, client: &AccClient, output_format: OutputFormat) -> Result<()> {
295        match self {
296            SubmittalCommands::List { project_id } => {
297                submittals::list_submittals(client, &project_id, output_format).await
298            }
299            SubmittalCommands::Get {
300                project_id,
301                submittal_id,
302            } => submittals::get_submittal(client, &project_id, &submittal_id, output_format).await,
303            SubmittalCommands::Create {
304                project_id,
305                title,
306                spec_section,
307                due_date,
308                from_csv,
309            } => {
310                submittals::create_submittal(
311                    client,
312                    &project_id,
313                    title,
314                    spec_section,
315                    due_date,
316                    from_csv,
317                    output_format,
318                )
319                .await
320            }
321            SubmittalCommands::Update {
322                project_id,
323                submittal_id,
324                title,
325                status,
326                due_date,
327            } => {
328                submittals::update_submittal(
329                    client,
330                    &project_id,
331                    &submittal_id,
332                    title,
333                    status,
334                    due_date,
335                    output_format,
336                )
337                .await
338            }
339            SubmittalCommands::Delete {
340                project_id,
341                submittal_id,
342            } => {
343                submittals::delete_submittal(client, &project_id, &submittal_id, output_format)
344                    .await
345            }
346        }
347    }
348}
349
350impl ChecklistCommands {
351    pub async fn execute(self, client: &AccClient, output_format: OutputFormat) -> Result<()> {
352        match self {
353            ChecklistCommands::List { project_id } => {
354                checklists::list_checklists(client, &project_id, output_format).await
355            }
356            ChecklistCommands::Get {
357                project_id,
358                checklist_id,
359            } => checklists::get_checklist(client, &project_id, &checklist_id, output_format).await,
360            ChecklistCommands::Create {
361                project_id,
362                title,
363                template_id,
364                location,
365                due_date,
366                assignee_id,
367            } => {
368                checklists::create_checklist(
369                    client,
370                    &project_id,
371                    &title,
372                    template_id,
373                    location,
374                    due_date,
375                    assignee_id,
376                    output_format,
377                )
378                .await
379            }
380            ChecklistCommands::Update {
381                project_id,
382                checklist_id,
383                title,
384                status,
385                location,
386                due_date,
387            } => {
388                checklists::update_checklist(
389                    client,
390                    &project_id,
391                    &checklist_id,
392                    title,
393                    status,
394                    location,
395                    due_date,
396                    output_format,
397                )
398                .await
399            }
400            ChecklistCommands::Templates { project_id } => {
401                checklists::list_templates(client, &project_id, output_format).await
402            }
403        }
404    }
405}