mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: disable set decimal scale
This commit is contained in:
parent
8b40244c73
commit
72e26ab229
@ -150,8 +150,7 @@ impl CellDataOperation<String> for DateTypeOption {
|
|||||||
(true, Some(time)) => {
|
(true, Some(time)) => {
|
||||||
let time = Some(time.trim().to_uppercase());
|
let time = Some(time.trim().to_uppercase());
|
||||||
let utc = self.utc_date_time_from_timestamp(date_timestamp);
|
let utc = self.utc_date_time_from_timestamp(date_timestamp);
|
||||||
let timestamp = self.timestamp_from_utc_with_time(&utc, &time)?;
|
self.timestamp_from_utc_with_time(&utc, &time)?
|
||||||
timestamp
|
|
||||||
}
|
}
|
||||||
_ => date_timestamp,
|
_ => date_timestamp,
|
||||||
},
|
},
|
||||||
@ -548,7 +547,7 @@ mod tests {
|
|||||||
assert_changeset_result(
|
assert_changeset_result(
|
||||||
&type_option,
|
&type_option,
|
||||||
DateCellContentChangeset {
|
DateCellContentChangeset {
|
||||||
date: Some(date_timestamp.clone()),
|
date: Some(date_timestamp),
|
||||||
time: Some("1:00".to_owned()),
|
time: Some("1:00".to_owned()),
|
||||||
},
|
},
|
||||||
&type_option.field_type(),
|
&type_option.field_type(),
|
||||||
@ -568,7 +567,7 @@ mod tests {
|
|||||||
assert_changeset_result(
|
assert_changeset_result(
|
||||||
&type_option,
|
&type_option,
|
||||||
DateCellContentChangeset {
|
DateCellContentChangeset {
|
||||||
date: Some(date_timestamp.clone()),
|
date: Some(date_timestamp),
|
||||||
time: Some("1:00 am".to_owned()),
|
time: Some("1:00 am".to_owned()),
|
||||||
},
|
},
|
||||||
&type_option.field_type(),
|
&type_option.field_type(),
|
||||||
@ -622,7 +621,7 @@ mod tests {
|
|||||||
if type_option.include_time {
|
if type_option.include_time {
|
||||||
format!("{}{}", decoded_data.date, decoded_data.time)
|
format!("{}{}", decoded_data.date, decoded_data.time)
|
||||||
} else {
|
} else {
|
||||||
format!("{}", decoded_data.date)
|
decoded_data.date
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,6 +71,76 @@ pub struct NumberTypeOption {
|
|||||||
}
|
}
|
||||||
impl_type_option!(NumberTypeOption, FieldType::Number);
|
impl_type_option!(NumberTypeOption, FieldType::Number);
|
||||||
|
|
||||||
|
impl NumberTypeOption {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cell_content_from_number_str(&self, s: &str) -> FlowyResult<String> {
|
||||||
|
return match self.format {
|
||||||
|
NumberFormat::Number => {
|
||||||
|
if let Ok(v) = s.parse::<f64>() {
|
||||||
|
return Ok(v.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(v) = s.parse::<i64>() {
|
||||||
|
return Ok(v.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok("".to_string())
|
||||||
|
}
|
||||||
|
NumberFormat::Percent => {
|
||||||
|
let content = s.parse::<f64>().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<String> {
|
||||||
|
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<T: ToString>(&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<String> for NumberTypeOption {
|
impl CellDataOperation<String> for NumberTypeOption {
|
||||||
fn decode_cell_data<T>(
|
fn decode_cell_data<T>(
|
||||||
&self,
|
&self,
|
||||||
@ -103,7 +173,7 @@ impl CellDataOperation<String> for NumberTypeOption {
|
|||||||
Ok(DecodedCellData::new(content))
|
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))
|
Ok(DecodedCellData::new(content))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,15 +184,8 @@ impl CellDataOperation<String> for NumberTypeOption {
|
|||||||
C: Into<CellContentChangeset>,
|
C: Into<CellContentChangeset>,
|
||||||
{
|
{
|
||||||
let changeset = changeset.into();
|
let changeset = changeset.into();
|
||||||
let mut data = changeset.trim().to_string();
|
let data = changeset.trim().to_string();
|
||||||
|
let _ = self.cell_content_from_number_str(&data)?;
|
||||||
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"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(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<T: ToString>(&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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::services::field::FieldBuilder;
|
use crate::services::field::FieldBuilder;
|
||||||
@ -206,14 +221,21 @@ mod tests {
|
|||||||
assert_equal(&type_option, "abc", "", &field_type, &field_meta);
|
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]
|
#[test]
|
||||||
fn number_type_option_format_number_test() {
|
fn number_type_option_format_number_test() {
|
||||||
let mut type_option = NumberTypeOption::default();
|
let mut type_option = NumberTypeOption::default();
|
||||||
let field_type = FieldType::Number;
|
let field_type = FieldType::Number;
|
||||||
let field_meta = FieldBuilder::from_field_type(&field_type).build();
|
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() {
|
for format in NumberFormat::iter() {
|
||||||
type_option.format = format;
|
type_option.format = format;
|
||||||
@ -248,10 +270,12 @@ mod tests {
|
|||||||
type_option.format = format;
|
type_option.format = format;
|
||||||
match format {
|
match format {
|
||||||
NumberFormat::Number => {
|
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 => {
|
NumberFormat::USD => {
|
||||||
assert_equal(&type_option, "$18,44", "$1,844", &field_type, &field_meta);
|
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, "", "", &field_type, &field_meta);
|
||||||
assert_equal(&type_option, "abc", "", &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);
|
assert_equal(&type_option, "CN¥1844", "CN¥1,844", &field_type, &field_meta);
|
||||||
}
|
}
|
||||||
NumberFormat::EUR => {
|
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);
|
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]
|
#[test]
|
||||||
fn number_description_sign_test() {
|
fn number_description_sign_test() {
|
||||||
let mut type_option = NumberTypeOption {
|
let mut type_option = NumberTypeOption {
|
||||||
|
Loading…
Reference in New Issue
Block a user