mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-29 21:26:48 -06:00
Merge PR #1930: Accounting format: the documented currency symbol is honoured
This commit is contained in:
@@ -133,9 +133,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
has_doc,
|
||||
number_format
|
||||
),
|
||||
cmd!("home.accounting", "Accounting Number Format", ["Home", "Number"], None, "{range?, symbol?: \"$\"}", has_doc, |s, p| set_fmt(
|
||||
s, p, ACCOUNTING
|
||||
)),
|
||||
cmd!("home.accounting", "Accounting Number Format", ["Home", "Number"], None, "{range?, symbol?: \"$\"}", has_doc, accounting),
|
||||
cmd!("home.percent", "Percent Style", ["Home", "Number"], Some("Ctrl+Shift+%"), "{range?}", has_doc, |s, p| set_fmt(s, p, "0%")),
|
||||
cmd!("home.comma", "Comma Style", ["Home", "Number"], None, "{range?}", has_doc, |s, p| set_fmt(s, p, COMMA)),
|
||||
cmd!("home.increaseDecimal", "Increase Decimal", ["Home", "Number"], None, "{range?}", has_doc, |s, p| decimals(s, p, 1)),
|
||||
@@ -202,6 +200,23 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
const ACCOUNTING: &str = "_(\"$\"* #,##0.00_);_(\"$\"* \\(#,##0.00\\);_(\"$\"* \"-\"??_);_(@_)";
|
||||
const COMMA: &str = "_(* #,##0.00_);_(* \\(#,##0.00\\);_(* \"-\"??_);_(@_)";
|
||||
|
||||
/// Accounting Number Format with the currency symbol to use (Excel's own button takes the system
|
||||
/// currency; `symbol` is how the control channel picks another one, e.g. `"L"` for lempiras).
|
||||
fn accounting(s: &mut Session, p: &Json) -> Result<Json> {
|
||||
let symbol = str_param(p, "symbol").unwrap_or("$");
|
||||
// The symbol goes into a quoted literal: a quote or a backslash would end it, and a control
|
||||
// character would reach the format's text as-is.
|
||||
if symbol.contains(['"', '\\']) || symbol.chars().any(char::is_control) {
|
||||
return Err(bad("home.accounting", "the symbol can't contain a quote, a backslash or a control character"));
|
||||
}
|
||||
set_fmt(s, p, &accounting_format(symbol))
|
||||
}
|
||||
|
||||
fn accounting_format(symbol: &str) -> String {
|
||||
let symbol = format!("\"{symbol}\"");
|
||||
format!("_({symbol}* #,##0.00_);_({symbol}* \\(#,##0.00\\);_({symbol}* \"-\"??_);_(@_)")
|
||||
}
|
||||
|
||||
fn with(p: &Json, key: &str, v: Json) -> Json {
|
||||
let mut m = p.as_object().cloned().unwrap_or_default();
|
||||
m.insert(key.into(), v);
|
||||
@@ -1137,6 +1152,11 @@ mod tests {
|
||||
assert_eq!(v(&mut s, "D1"), json!(4.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_default_symbol_reproduces_the_accounting_format() {
|
||||
assert_eq!(accounting_format("$"), ACCOUNTING);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decimal_steps() {
|
||||
let v = gridcraft_core::Value::Number(1.5);
|
||||
|
||||
@@ -1339,6 +1339,28 @@ fn slicer_filters_table() {
|
||||
assert!(s.execute("slicer.toggle", json!({"value": "Nowhere"})).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn accounting_format_takes_the_symbol_it_is_given() {
|
||||
// The command documents `symbol`; it used to be dropped, so only `$` was ever reachable
|
||||
// from the control channel (asking for lempiras, #1893, changed nothing).
|
||||
let text = |s: &Session, a: &str| {
|
||||
let d = s.doc().unwrap();
|
||||
crate::display::cell_text(&d.wb, d.wb.active().unwrap(), CellRef::parse(a).unwrap())
|
||||
};
|
||||
let mut s = s();
|
||||
s.execute("cell.set", json!({"cell": "A1", "input": "1234.5"})).unwrap();
|
||||
s.execute("home.accounting", json!({"range": "A1", "symbol": "L"})).unwrap();
|
||||
assert_eq!(text(&s, "A1"), " L 1,234.50 ");
|
||||
// Without a symbol it stays the default `$` format, character for character.
|
||||
s.execute("home.accounting", json!({"range": "A1"})).unwrap();
|
||||
assert_eq!(text(&s, "A1"), " $ 1,234.50 ");
|
||||
// A quote or a backslash would end the format's quoted text, and a control character would
|
||||
// reach it as-is, so those symbols are refused.
|
||||
for bad in ["\"", "\\", "\n", "L\t"] {
|
||||
assert!(s.execute("home.accounting", json!({"range": "A1", "symbol": bad})).is_err(), "{bad:?}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn table_header_formatted_as_accounting_keeps_its_text_as_the_column_name() {
|
||||
// Found by the command-sequence fuzzer: the accounting format pads text (` 172.4 `), and that
|
||||
|
||||
Reference in New Issue
Block a user