- Fix `simple_test_analysis` template in E2E test setup to align with Orchestrator's data fetch logic.
- Implement and verify additional E2E scenarios:
- Scenario C: Partial Provider Failure (verified error propagation fix in Orchestrator).
- Scenario D: Invalid Symbol input.
- Scenario E: Analysis Module failure.
- Update `WorkflowStateMachine::handle_report_failed` to correctly scope error broadcasting to the specific task instead of failing effectively silently or broadly.
- Update testing strategy documentation to reflect completed Phase 4 testing.
- Skip Scenario B (Orchestrator Restart) as persistence is not yet implemented (decision made to defer persistence).
73 lines
2.1 KiB
Rust
73 lines
2.1 KiB
Rust
use std::collections::{BTreeMap, HashSet};
|
|
use common_contracts::dtos::TimeSeriesFinancialDto;
|
|
use chrono::Datelike;
|
|
|
|
/// Formats a list of TimeSeriesFinancialDto into a Markdown table.
|
|
/// The table columns are years (sorted descending), and rows are metrics.
|
|
pub fn format_financials_to_markdown(financials: &[TimeSeriesFinancialDto]) -> String {
|
|
if financials.is_empty() {
|
|
return "No financial data available.".to_string();
|
|
}
|
|
|
|
// 1. Group by Year and Metric
|
|
// Map<MetricName, Map<Year, Value>>
|
|
let mut data_map: BTreeMap<String, BTreeMap<i32, f64>> = BTreeMap::new();
|
|
let mut years_set: HashSet<i32> = HashSet::new();
|
|
|
|
for item in financials {
|
|
let year = item.period_date.year();
|
|
years_set.insert(year);
|
|
|
|
data_map
|
|
.entry(item.metric_name.clone())
|
|
.or_default()
|
|
.insert(year, item.value);
|
|
}
|
|
|
|
// 2. Sort years descending (recent first)
|
|
let mut sorted_years: Vec<i32> = years_set.into_iter().collect();
|
|
sorted_years.sort_by(|a, b| b.cmp(a));
|
|
|
|
// Limit to recent 5 years to keep table readable
|
|
let display_years = if sorted_years.len() > 5 {
|
|
&sorted_years[..5]
|
|
} else {
|
|
&sorted_years
|
|
};
|
|
|
|
// 3. Build Markdown Table
|
|
let mut markdown = String::new();
|
|
|
|
// Header
|
|
markdown.push_str("| Metric |");
|
|
for year in display_years {
|
|
markdown.push_str(&format!(" {} |", year));
|
|
}
|
|
markdown.push('\n');
|
|
|
|
// Separator
|
|
markdown.push_str("| :--- |");
|
|
for _ in display_years {
|
|
markdown.push_str(" ---: |");
|
|
}
|
|
markdown.push('\n');
|
|
|
|
// Rows
|
|
for (metric, year_values) in data_map {
|
|
markdown.push_str(&format!("| {} |", metric));
|
|
for year in display_years {
|
|
if let Some(value) = year_values.get(year) {
|
|
// Format large numbers or percentages intelligently if needed.
|
|
// For now, simple float formatting.
|
|
markdown.push_str(&format!(" {:.2} |", value));
|
|
} else {
|
|
markdown.push_str(" - |");
|
|
}
|
|
}
|
|
markdown.push('\n');
|
|
}
|
|
|
|
markdown
|
|
}
|
|
|