Skip to main content

schwab_cli/human/
mod.rs

1use anyhow::{Context, Result};
2use inquire::Select;
3
4use crate::config::RuntimeConfig;
5
6pub async fn pick_account_hash(
7    _runtime: &RuntimeConfig,
8    api: &schwab_api::TraderApi,
9) -> Result<String> {
10    let numbers = api
11        .accounts()
12        .account_numbers()
13        .await
14        .context("Failed to list account numbers")?;
15
16    if numbers.is_empty() {
17        anyhow::bail!("No linked accounts found");
18    }
19
20    let labels: Vec<String> = numbers
21        .iter()
22        .map(|n| {
23            format!(
24                "{}  (hash: {}…)",
25                n.account_number,
26                &n.hash_value[..n.hash_value.len().min(8)]
27            )
28        })
29        .collect();
30
31    let choice = Select::new("Select account", labels.clone()).prompt()?;
32    let idx = labels
33        .iter()
34        .position(|l| l == &choice)
35        .context("Invalid selection")?;
36
37    Ok(numbers[idx].hash_value.clone())
38}
39
40pub fn read_order_json(prompt: &str) -> Result<serde_json::Value> {
41    let raw = inquire::Text::new(prompt)
42        .with_help_message("Path to .json file or inline JSON object")
43        .prompt()?;
44    parse_order_input(&raw)
45}
46
47pub fn parse_order_input(raw: &str) -> Result<serde_json::Value> {
48    let path = std::path::Path::new(raw.trim());
49    if path.is_file() {
50        let content = std::fs::read_to_string(path)?;
51        Ok(serde_json::from_str(&content)?)
52    } else {
53        Ok(serde_json::from_str(raw)?)
54    }
55}