diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs index f91fc8bb48..4a64fc3eca 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs @@ -150,8 +150,7 @@ impl CellDataOperation for DateTypeOption { (true, Some(time)) => { let time = Some(time.trim().to_uppercase()); let utc = self.utc_date_time_from_timestamp(date_timestamp); - let timestamp = self.timestamp_from_utc_with_time(&utc, &time)?; - timestamp + self.timestamp_from_utc_with_time(&utc, &time)? } _ => date_timestamp, }, @@ -548,7 +547,7 @@ mod tests { assert_changeset_result( &type_option, DateCellContentChangeset { - date: Some(date_timestamp.clone()), + date: Some(date_timestamp), time: Some("1:00".to_owned()), }, &type_option.field_type(), @@ -568,7 +567,7 @@ mod tests { assert_changeset_result( &type_option, DateCellContentChangeset { - date: Some(date_timestamp.clone()), + date: Some(date_timestamp), time: Some("1:00 am".to_owned()), }, &type_option.field_type(), @@ -622,7 +621,7 @@ mod tests { if type_option.include_time { format!("{}{}", decoded_data.date, decoded_data.time) } else { - format!("{}", decoded_data.date) + decoded_data.date } } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs index bb3130c597..82970ab25a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs @@ -71,6 +71,76 @@ pub struct NumberTypeOption { } impl_type_option!(NumberTypeOption, FieldType::Number); +impl NumberTypeOption { + pub fn new() -> Self { + Self::default() + } + + fn cell_content_from_number_str(&self, s: &str) -> FlowyResult { + return match self.format { + NumberFormat::Number => { + if let Ok(v) = s.parse::() { + return Ok(v.to_string()); + } + + if let Ok(v) = s.parse::() { + return Ok(v.to_string()); + } + + Ok("".to_string()) + } + NumberFormat::Percent => { + let content = s.parse::().map_or(String::new(), |v| v.to_string()); + Ok(content) + } + _ => self.money_from_number_str(s), + }; + } + + pub fn set_format(&mut self, format: NumberFormat) { + self.format = format; + self.symbol = format.symbol(); + } + + fn money_from_number_str(&self, s: &str) -> FlowyResult { + let mut number = self.strip_currency_symbol(s); + + if s.is_empty() { + return Ok("".to_string()); + } + + match Decimal::from_str(&number) { + Ok(mut decimal) => { + decimal.set_sign_positive(self.sign_positive); + let money = rusty_money::Money::from_decimal(decimal, self.format.currency()).to_string(); + Ok(money) + } + Err(_) => match rusty_money::Money::from_str(&number, self.format.currency()) { + Ok(money) => Ok(money.to_string()), + Err(_) => { + number.retain(|c| !STRIP_SYMBOL.contains(&c.to_string())); + if number.chars().all(char::is_numeric) { + self.money_from_number_str(&number) + } else { + Err(FlowyError::invalid_data().context("Should only contain numbers")) + } + } + }, + } + } + + fn strip_currency_symbol(&self, s: T) -> String { + let mut s = s.to_string(); + for symbol in CURRENCY_SYMBOL.iter() { + if s.starts_with(symbol) { + s = s.strip_prefix(symbol).unwrap_or("").to_string(); + break; + } + } + s + } +} + impl CellDataOperation for NumberTypeOption { fn decode_cell_data( &self, @@ -103,7 +173,7 @@ impl CellDataOperation for NumberTypeOption { Ok(DecodedCellData::new(content)) } _ => { - let content = self.number_from_str(&cell_data); + let content = self.money_from_number_str(&cell_data).unwrap_or("".to_string()); Ok(DecodedCellData::new(content)) } } @@ -114,15 +184,8 @@ impl CellDataOperation for NumberTypeOption { C: Into, { let changeset = changeset.into(); - let mut data = changeset.trim().to_string(); - - if self.format != NumberFormat::Number { - data = self.strip_symbol(data); - if !data.chars().all(char::is_numeric) { - return Err(FlowyError::invalid_data().context("Should only contain numbers")); - } - } - + let data = changeset.trim().to_string(); + let _ = self.cell_content_from_number_str(&data)?; Ok(data) } } @@ -141,54 +204,6 @@ impl std::default::Default for NumberTypeOption { } } -impl NumberTypeOption { - pub fn set_format(&mut self, format: NumberFormat) { - self.format = format; - self.symbol = format.symbol(); - } - - fn number_from_str(&self, s: &str) -> String { - match Decimal::from_str(s) { - Ok(mut decimal) => { - match decimal.set_scale(self.scale) { - Ok(_) => {} - Err(e) => { - tracing::error!("Set decimal scale failed: {:?}", e); - } - } - - decimal.set_sign_positive(self.sign_positive); - let money = rusty_money::Money::from_decimal(decimal, self.format.currency()); - money.to_string() - } - Err(_) => { - let s = self.strip_symbol(s); - if !s.is_empty() && s.chars().all(char::is_numeric) { - self.number_from_str(&s) - } else { - "".to_owned() - } - } - } - } - - fn strip_symbol(&self, s: T) -> String { - let mut s = s.to_string(); - - for symbol in CURRENCY_SYMBOL.iter() { - if s.starts_with(symbol) { - s = s.strip_prefix(symbol).unwrap_or("").to_string(); - break; - } - } - - if !s.chars().all(char::is_numeric) { - s.retain(|c| !STRIP_SYMBOL.contains(&c.to_string())); - } - s - } -} - #[cfg(test)] mod tests { use crate::services::field::FieldBuilder; @@ -206,14 +221,21 @@ mod tests { assert_equal(&type_option, "abc", "", &field_type, &field_meta); } + #[test] + fn number_type_option_strip_symbol_test() { + let mut type_option = NumberTypeOption::new(); + type_option.format = NumberFormat::USD; + assert_eq!(type_option.strip_currency_symbol("$18,443"), "18,443".to_owned()); + + type_option.format = NumberFormat::Yuan; + assert_eq!(type_option.strip_currency_symbol("$0.2"), "0.2".to_owned()); + } + #[test] fn number_type_option_format_number_test() { let mut type_option = NumberTypeOption::default(); let field_type = FieldType::Number; let field_meta = FieldBuilder::from_field_type(&field_type).build(); - assert_eq!(type_option.strip_symbol("¥18,443"), "18443".to_owned()); - assert_eq!(type_option.strip_symbol("$18,443"), "18443".to_owned()); - assert_eq!(type_option.strip_symbol("€18.443"), "18443".to_owned()); for format in NumberFormat::iter() { type_option.format = format; @@ -248,10 +270,12 @@ mod tests { type_option.format = format; match format { NumberFormat::Number => { - // assert_equal(&type_option, "18443", "18443", &field_type, &field_meta); + assert_equal(&type_option, "18443", "18443", &field_type, &field_meta); + assert_equal(&type_option, "0.2", "0.2", &field_type, &field_meta); } NumberFormat::USD => { assert_equal(&type_option, "$18,44", "$1,844", &field_type, &field_meta); + assert_equal(&type_option, "$0.2", "$0.2", &field_type, &field_meta); assert_equal(&type_option, "", "", &field_type, &field_meta); assert_equal(&type_option, "abc", "", &field_type, &field_meta); } @@ -264,7 +288,8 @@ mod tests { assert_equal(&type_option, "CN¥1844", "CN¥1,844", &field_type, &field_meta); } NumberFormat::EUR => { - assert_equal(&type_option, "€18.44", "€1.844", &field_type, &field_meta); + assert_equal(&type_option, "€18.44", "€18,44", &field_type, &field_meta); + assert_equal(&type_option, "€0.5", "€0,5", &field_type, &field_meta); assert_equal(&type_option, "€1844", "€1.844", &field_type, &field_meta); } _ => {} @@ -272,35 +297,6 @@ mod tests { } } - #[test] - fn number_type_option_scale_test() { - let mut type_option = NumberTypeOption { - scale: 1, - ..Default::default() - }; - let field_type = FieldType::Number; - let field_meta = FieldBuilder::from_field_type(&field_type).build(); - - for format in NumberFormat::iter() { - type_option.format = format; - match format { - NumberFormat::Number => { - assert_equal(&type_option, "18443", "18443", &field_type, &field_meta); - } - NumberFormat::USD => { - assert_equal(&type_option, "18443", "$1,844.3", &field_type, &field_meta); - } - NumberFormat::Yen => { - assert_equal(&type_option, "18443", "¥1,844.3", &field_type, &field_meta); - } - NumberFormat::EUR => { - assert_equal(&type_option, "18443", "€1.844,3", &field_type, &field_meta); - } - _ => {} - } - } - } - #[test] fn number_description_sign_test() { let mut type_option = NumberTypeOption {