From 932b902cb5f4629c463006267a3e51c49bf4466b Mon Sep 17 00:00:00 2001 From: neonew Date: Sat, 16 Dec 2023 13:34:35 +0100 Subject: [PATCH] Format negative currency values in red See also: https://github.com/thscharler/spreadsheet-ods/issues/34 --- Cargo.lock | 256 +++++++++++++++++++++++++++++---------------- Cargo.toml | 4 +- src/writers/ods.rs | 27 ++++- 3 files changed, 193 insertions(+), 94 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2050d68..7ef8428 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,17 +30,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "ahash" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", -] - [[package]] name = "aho-corasick" version = "1.0.2" @@ -137,6 +126,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + [[package]] name = "base64ct" version = "1.6.0" @@ -155,6 +150,18 @@ version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -166,47 +173,26 @@ dependencies = [ [[package]] name = "borsh" -version = "0.10.3" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" +checksum = "9897ef0f1bd2362169de6d7e436ea2237dc1085d7d1e4db75f4be34d86f309d1" dependencies = [ "borsh-derive", - "hashbrown 0.13.2", + "cfg_aliases", ] [[package]] name = "borsh-derive" -version = "0.10.3" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" +checksum = "478b41ff04256c5c8330f3dfdaaae2a5cc976a8e75088bafa4625b0d0208de8c" dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", + "once_cell", "proc-macro-crate", - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "borsh-derive-internal" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "borsh-schema-derive-internal" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" -dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.23", + "syn_derive", ] [[package]] @@ -291,6 +277,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "chrono" version = "0.4.26" @@ -360,9 +352,9 @@ checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" [[package]] name = "color-rs" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d6cda18d80350d6a6d15d1f2dd6f5c88b3d61882e08801e8d68f506434b808" +checksum = "3415c18b81f66b23614db9fcccbf19d2af434e04d9a6c7ac10e49930f39d89f8" dependencies = [ "angle", "half", @@ -547,6 +539,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "generic-array" version = "0.14.7" @@ -580,16 +578,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.6", -] - -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash 0.8.3", + "ahash", ] [[package]] @@ -758,6 +747,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kparse" +version = "3.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "503149c856ef5f8728156b55609019cf2714a29ebdb2a82dc1a831d2c743f28a" +dependencies = [ + "bytecount", + "memchr", + "nom", + "nom_locate", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -819,15 +820,6 @@ dependencies = [ "adler", ] -[[package]] -name = "mktemp" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bdc1f74dd7bb717d39f784f844e490d935b3aa7e383008006dbbf29c1f7820a" -dependencies = [ - "uuid", -] - [[package]] name = "new_debug_unreachable" version = "1.0.4" @@ -976,11 +968,35 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "0.1.5" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a" dependencies = [ - "toml", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", ] [[package]] @@ -1014,9 +1030,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.26.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" dependencies = [ "memchr", ] @@ -1030,6 +1046,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.8.5" @@ -1097,23 +1119,26 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.7.40" +version = "0.7.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c30f1d45d9aa61cbc8cd1eb87705470892289bb2d01943e7803b873a57404dc3" +checksum = "0200c8230b013893c0b2d6213d6ec64ed2b9be2e0e016682b7224ff82cff5c58" dependencies = [ + "bitvec", "bytecheck", "hashbrown 0.12.3", "ptr_meta", "rend", "rkyv_derive", "seahash", + "tinyvec", + "uuid", ] [[package]] name = "rkyv_derive" -version = "0.7.40" +version = "0.7.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff26ed6c7c4dfc2aa9480b86a60e3c7233543a270a680e10758a507c5a4ce476" +checksum = "b2e06b915b5c230a17d7a736d1e2e63ee753c256a8614ef3f5147b13a4f5541d" dependencies = [ "proc-macro2", "quote", @@ -1131,14 +1156,12 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.30.0" +version = "1.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0446843641c69436765a35a5a77088e28c2e6a12da93e84aa3ab1cd4aa5a042" +checksum = "06676aec5ccb8fc1da723cc8c0f9a46549f21ebb8753d3915c6c41db1e7f1dc4" dependencies = [ "arrayvec", "borsh", - "bytecheck", - "byteorder", "bytes", "num-traits", "rand", @@ -1149,9 +1172,9 @@ dependencies = [ [[package]] name = "rust_decimal_macros" -version = "1.30.0" +version = "1.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca5c398d85f83b9a44de754a2048625a8c5eafcf070da7b8f116b685e2f6608" +checksum = "2e43721f4ef7060ebc2c3ede757733209564ca8207f47674181bcd425dd76945" dependencies = [ "quote", "rust_decimal", @@ -1271,15 +1294,16 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "spreadsheet-ods" -version = "0.15.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dedd2b14d76d7f9116905fd53adb0465d468070127f9bb8596a4cf7d24c2992" +checksum = "c01a02ad8d000202b7e4fb379bf08edfce9755a634362ffd1e1dc1b6deeade4b" dependencies = [ + "base64", "chrono", "color-rs", "icu_locid", + "kparse", "lazy_static", - "mktemp", "nom", "nom_locate", "quick-xml", @@ -1339,6 +1363,24 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.23", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "termcolor" version = "1.2.0" @@ -1385,12 +1427,35 @@ dependencies = [ ] [[package]] -name = "toml" -version = "0.5.11" +name = "tinyvec" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ - "serde", + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap 2.0.0", + "toml_datetime", + "winnow", ] [[package]] @@ -1427,12 +1492,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.2.2" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" -dependencies = [ - "getrandom", -] +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" [[package]] name = "version_check" @@ -1612,12 +1674,30 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "winnow" +version = "0.5.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c830786f7720c2fd27a1a0e27a709dbd3c4d009b56d098fc742d4f4eab91fe2" +dependencies = [ + "memchr", +] + [[package]] name = "writeable" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60e49e42bdb1d5dc76f4cd78102f8f0714d32edfa3efb82286eb0f0b1fc0da0f" +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "xmlparser" version = "0.13.5" diff --git a/Cargo.toml b/Cargo.toml index 22bc1e7..01a9fc8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] chrono = { version = "0.4.26", features = ["serde"] } clap = { version = "4.3.5", features = ["derive"] } -color-rs = "0.7.1" +color-rs = "0.8.0" csv = "1.2.2" env_logger = "0.10.0" iban_validate = { version = "4.0.1", features = ["serde"] } @@ -18,7 +18,7 @@ rust_decimal = "1.30.0" rusty-money = "0.4.1" serde = { version = "1.0.164", features = ["derive"] } serde_json = "1.0.99" -spreadsheet-ods = "0.15.0" +spreadsheet-ods = "0.20.0" tree_magic_mini = "3.0.3" zip = "0.6.6" diff --git a/src/writers/ods.rs b/src/writers/ods.rs index b18c1aa..c788bd2 100644 --- a/src/writers/ods.rs +++ b/src/writers/ods.rs @@ -1,12 +1,14 @@ use std::error::Error; use std::io::Write; +use color::Rgb; use icu_locid::{locale, Locale}; use indexmap::indexmap; use Length::Mm; use rusty_money::iso; -use spreadsheet_ods::{CellStyle, CellStyleRef, Length, Sheet, ValueFormatText, WorkBook}; -use spreadsheet_ods::format::{create_date_dmy_format, create_loc_currency_suffix}; +use spreadsheet_ods::{CellStyle, CellStyleRef, Length, Sheet, ValueFormatCurrency, ValueFormatText, WorkBook}; +use spreadsheet_ods::condition::ValueCondition; +use spreadsheet_ods::format::{create_date_dmy_format, create_loc_currency_suffix, ValueFormatTrait, ValueStyleMap}; use crate::transaction::Transaction; use crate::writers::Writer; @@ -32,10 +34,27 @@ impl Ods { } fn create_currency_style(workbook: &mut WorkBook, locale: Locale) -> CellStyleRef { - let currency_format = create_loc_currency_suffix("currency_format", locale.clone(), locale, iso::EUR.symbol); + let currency_format = create_loc_currency_suffix("currency_format", locale.clone(), locale.clone(), iso::EUR.symbol); let currency_format = workbook.add_currency_format(currency_format); - let currency_style = CellStyle::new("eur_currency_style", ¤cy_format); + let mut currency_format_negative = ValueFormatCurrency::new_localized("currency_format_negative", locale.clone()); + currency_format_negative.part_text("-").build(); + currency_format_negative.part_number() + .min_integer_digits(1) + .decimal_places(2) + .min_decimal_places(2) + .grouping() + .build(); + currency_format_negative.part_text(" ").build(); + currency_format_negative.part_currency() + .locale(locale) + .symbol(iso::EUR.symbol) + .build(); + currency_format_negative.set_color(Rgb::new(255, 0, 0)); + currency_format_negative.push_stylemap(ValueStyleMap::new(ValueCondition::value_ge(0), currency_format)); + let currency_format_negative = workbook.add_currency_format(currency_format_negative); + + let currency_style = CellStyle::new("eur_currency_style", ¤cy_format_negative); workbook.add_cellstyle(currency_style) } }