roboticus-cli 0.11.3

CLI commands and migration engine for the Roboticus agent runtime
Documentation
#[derive(Debug, Default, Clone)]
struct RevenueTaxReconcileHealth {
    submitted_tasks: usize,
    pending_receipts: usize,
    confirmed_repairs: usize,
    failed_repairs: usize,
}

async fn probe_revenue_tax_reconcile(
    base_url: &str,
    repair: bool,
) -> Result<RevenueTaxReconcileHealth, Box<dyn std::error::Error>> {
    let resp = super::http_client()?
        .get(format!("{base_url}/api/services/tax-payouts?limit=200"))
        .send()
        .await?;
    if !resp.status().is_success() {
        return Err(std::io::Error::other(format!(
            "tax payout listing endpoint returned HTTP {}",
            resp.status()
        ))
        .into());
    }
    let body: serde_json::Value = resp.json().await.unwrap_or_default();
    let tasks = body
        .get("tax_tasks")
        .and_then(|v| v.as_array())
        .cloned()
        .unwrap_or_default();
    let mut health = RevenueTaxReconcileHealth::default();
    for task in tasks {
        let status = task
            .get("status")
            .and_then(|v| v.as_str())
            .unwrap_or_default();
        let source = task
            .get("source")
            .cloned()
            .unwrap_or(serde_json::Value::Null);
        let tax_tx_hash = source
            .get("tax_tx_hash")
            .and_then(|v| v.as_str())
            .map(str::trim)
            .filter(|s| !s.is_empty());
        if !status.eq_ignore_ascii_case("in_progress") || tax_tx_hash.is_none() {
            continue;
        }
        health.submitted_tasks += 1;
        if !repair {
            continue;
        }
        let opportunity_id = task
            .get("opportunity_id")
            .and_then(|v| v.as_str())
            .unwrap_or_default();
        if opportunity_id.is_empty() {
            continue;
        }
        let reconcile = super::http_client()?
            .post(format!(
                "{base_url}/api/services/tax-payouts/{}/reconcile",
                opportunity_id
            ))
            .send()
            .await?;
        if !reconcile.status().is_success() {
            continue;
        }
        let reconcile_body: serde_json::Value = reconcile.json().await.unwrap_or_default();
        match reconcile_body
            .get("receipt_status")
            .and_then(|v| v.as_str())
            .unwrap_or_default()
        {
            "confirmed" => health.confirmed_repairs += 1,
            "failed" => health.failed_repairs += 1,
            "pending" => health.pending_receipts += 1,
            _ => {}
        }
    }
    Ok(health)
}