diff --git a/crates/engine/src/cmd/pivot.rs b/crates/engine/src/cmd/pivot.rs index 38ea4bf..7026486 100644 --- a/crates/engine/src/cmd/pivot.rs +++ b/crates/engine/src/cmd/pivot.rs @@ -1860,6 +1860,24 @@ mod tests { assert!(s.execute("pivot.moveField", json!({"field": "Σ Values", "from": "rows", "to": "columns"})).is_err()); } + #[test] + fn collapsed_item_puts_values_in_the_values_column() { + let mut s = sales(); + s.execute("insert.pivotTable", json!({"rows": ["Region", "Product"], "values": ["Sales", "Units"]})).unwrap(); + s.execute("pivot.moveField", json!({"field": "Σ Values", "from": "columns", "to": "rows"})).unwrap(); + s.execute("pivot.collapse", json!({"field": "Region", "items": ["East"]})).unwrap(); + for layout in ["tabular", "outline"] { + s.execute("pivot.layout", json!({"layout": layout})).unwrap(); + assert_eq!(text(&s, "C3"), "Values", "{layout}"); + let east = (4..20).find(|r| text(&s, &format!("A{r}")) == "East").unwrap(); + let first = if layout == "tabular" { east } else { east + 1 }; + assert_eq!(text(&s, &format!("B{first}")), "", "{layout}"); + assert_eq!(text(&s, &format!("C{first}")), "Sum of Sales", "{layout}"); + assert_eq!(val(&s, &format!("D{first}")), Value::Number(415.0), "{layout}"); + assert_eq!(text(&s, &format!("C{}", first + 1)), "Sum of Units", "{layout}"); + } + } + #[test] fn values_stay_last_in_columns() { let mut s = sales(); diff --git a/crates/engine/src/pivot.rs b/crates/engine/src/pivot.rs index 41b7f40..a0fb268 100644 --- a/crates/engine/src/pivot.rs +++ b/crates/engine/src/pivot.rs @@ -664,7 +664,10 @@ impl Ctx<'_> { labels: vec![(col, v, indent, fmt)], vi, }); - self.flatten_values(&[], depth + 1, prefix, out); + // Outline gives each level its own column, so the captions go in the Values + // column even when the levels between are collapsed away. + let level = if self.pt.layout == PivotLayout::Outline { self.vpos.unwrap_or(depth + 1) } else { depth + 1 }; + self.flatten_values(&[], level, prefix, out); } else if values_below { // Subtotals per value field, below the group (one line can't hold them all). out.push(Line { @@ -749,7 +752,7 @@ impl Ctx<'_> { let collapsed = depth + 1 < n && self.rows.get(depth).is_some_and(|f| is_collapsed(f, &label)); if depth + 1 >= n || collapsed || node.children.is_empty() { if values_below { - self.flatten_tabular_values(&[], depth + 1, prefix, &labels, out); + self.flatten_tabular_values(&[], self.vpos.unwrap_or(depth + 1), prefix, &labels, out); } else { out.push(Line { kind: LineKind::Item(false), leaf: true, path: prefix.clone(), values: true, labels, vi }); }