@@ -71,6 +71,76 @@ pub struct NumberTypeOption {
7171}
7272impl_type_option ! ( NumberTypeOption , FieldType :: Number ) ;
7373
74+ impl NumberTypeOption {
75+ pub fn new ( ) -> Self {
76+ Self :: default ( )
77+ }
78+
79+ fn cell_content_from_number_str ( & self , s : & str ) -> FlowyResult < String > {
80+ return match self . format {
81+ NumberFormat :: Number => {
82+ if let Ok ( v) = s. parse :: < f64 > ( ) {
83+ return Ok ( v. to_string ( ) ) ;
84+ }
85+
86+ if let Ok ( v) = s. parse :: < i64 > ( ) {
87+ return Ok ( v. to_string ( ) ) ;
88+ }
89+
90+ Ok ( "" . to_string ( ) )
91+ }
92+ NumberFormat :: Percent => {
93+ let content = s. parse :: < f64 > ( ) . map_or ( String :: new ( ) , |v| v. to_string ( ) ) ;
94+ Ok ( content)
95+ }
96+ _ => self . money_from_number_str ( s) ,
97+ } ;
98+ }
99+
100+ pub fn set_format ( & mut self , format : NumberFormat ) {
101+ self . format = format;
102+ self . symbol = format. symbol ( ) ;
103+ }
104+
105+ fn money_from_number_str ( & self , s : & str ) -> FlowyResult < String > {
106+ let mut number = self . strip_currency_symbol ( s) ;
107+
108+ if s. is_empty ( ) {
109+ return Ok ( "" . to_string ( ) ) ;
110+ }
111+
112+ match Decimal :: from_str ( & number) {
113+ Ok ( mut decimal) => {
114+ decimal. set_sign_positive ( self . sign_positive ) ;
115+ let money = rusty_money:: Money :: from_decimal ( decimal, self . format . currency ( ) ) . to_string ( ) ;
116+ Ok ( money)
117+ }
118+ Err ( _) => match rusty_money:: Money :: from_str ( & number, self . format . currency ( ) ) {
119+ Ok ( money) => Ok ( money. to_string ( ) ) ,
120+ Err ( _) => {
121+ number. retain ( |c| !STRIP_SYMBOL . contains ( & c. to_string ( ) ) ) ;
122+ if number. chars ( ) . all ( char:: is_numeric) {
123+ self . money_from_number_str ( & number)
124+ } else {
125+ Err ( FlowyError :: invalid_data ( ) . context ( "Should only contain numbers" ) )
126+ }
127+ }
128+ } ,
129+ }
130+ }
131+
132+ fn strip_currency_symbol < T : ToString > ( & self , s : T ) -> String {
133+ let mut s = s. to_string ( ) ;
134+ for symbol in CURRENCY_SYMBOL . iter ( ) {
135+ if s. starts_with ( symbol) {
136+ s = s. strip_prefix ( symbol) . unwrap_or ( "" ) . to_string ( ) ;
137+ break ;
138+ }
139+ }
140+ s
141+ }
142+ }
143+
74144impl CellDataOperation < String > for NumberTypeOption {
75145 fn decode_cell_data < T > (
76146 & self ,
@@ -103,7 +173,7 @@ impl CellDataOperation<String> for NumberTypeOption {
103173 Ok ( DecodedCellData :: new ( content) )
104174 }
105175 _ => {
106- let content = self . number_from_str ( & cell_data) ;
176+ let content = self . money_from_number_str ( & cell_data) . unwrap_or ( "" . to_string ( ) ) ;
107177 Ok ( DecodedCellData :: new ( content) )
108178 }
109179 }
@@ -114,15 +184,8 @@ impl CellDataOperation<String> for NumberTypeOption {
114184 C : Into < CellContentChangeset > ,
115185 {
116186 let changeset = changeset. into ( ) ;
117- let mut data = changeset. trim ( ) . to_string ( ) ;
118-
119- if self . format != NumberFormat :: Number {
120- data = self . strip_symbol ( data) ;
121- if !data. chars ( ) . all ( char:: is_numeric) {
122- return Err ( FlowyError :: invalid_data ( ) . context ( "Should only contain numbers" ) ) ;
123- }
124- }
125-
187+ let data = changeset. trim ( ) . to_string ( ) ;
188+ let _ = self . cell_content_from_number_str ( & data) ?;
126189 Ok ( data)
127190 }
128191}
@@ -141,54 +204,6 @@ impl std::default::Default for NumberTypeOption {
141204 }
142205}
143206
144- impl NumberTypeOption {
145- pub fn set_format ( & mut self , format : NumberFormat ) {
146- self . format = format;
147- self . symbol = format. symbol ( ) ;
148- }
149-
150- fn number_from_str ( & self , s : & str ) -> String {
151- match Decimal :: from_str ( s) {
152- Ok ( mut decimal) => {
153- match decimal. set_scale ( self . scale ) {
154- Ok ( _) => { }
155- Err ( e) => {
156- tracing:: error!( "Set decimal scale failed: {:?}" , e) ;
157- }
158- }
159-
160- decimal. set_sign_positive ( self . sign_positive ) ;
161- let money = rusty_money:: Money :: from_decimal ( decimal, self . format . currency ( ) ) ;
162- money. to_string ( )
163- }
164- Err ( _) => {
165- let s = self . strip_symbol ( s) ;
166- if !s. is_empty ( ) && s. chars ( ) . all ( char:: is_numeric) {
167- self . number_from_str ( & s)
168- } else {
169- "" . to_owned ( )
170- }
171- }
172- }
173- }
174-
175- fn strip_symbol < T : ToString > ( & self , s : T ) -> String {
176- let mut s = s. to_string ( ) ;
177-
178- for symbol in CURRENCY_SYMBOL . iter ( ) {
179- if s. starts_with ( symbol) {
180- s = s. strip_prefix ( symbol) . unwrap_or ( "" ) . to_string ( ) ;
181- break ;
182- }
183- }
184-
185- if !s. chars ( ) . all ( char:: is_numeric) {
186- s. retain ( |c| !STRIP_SYMBOL . contains ( & c. to_string ( ) ) ) ;
187- }
188- s
189- }
190- }
191-
192207#[ cfg( test) ]
193208mod tests {
194209 use crate :: services:: field:: FieldBuilder ;
@@ -206,14 +221,21 @@ mod tests {
206221 assert_equal ( & type_option, "abc" , "" , & field_type, & field_meta) ;
207222 }
208223
224+ #[ test]
225+ fn number_type_option_strip_symbol_test ( ) {
226+ let mut type_option = NumberTypeOption :: new ( ) ;
227+ type_option. format = NumberFormat :: USD ;
228+ assert_eq ! ( type_option. strip_currency_symbol( "$18,443" ) , "18,443" . to_owned( ) ) ;
229+
230+ type_option. format = NumberFormat :: Yuan ;
231+ assert_eq ! ( type_option. strip_currency_symbol( "$0.2" ) , "0.2" . to_owned( ) ) ;
232+ }
233+
209234 #[ test]
210235 fn number_type_option_format_number_test ( ) {
211236 let mut type_option = NumberTypeOption :: default ( ) ;
212237 let field_type = FieldType :: Number ;
213238 let field_meta = FieldBuilder :: from_field_type ( & field_type) . build ( ) ;
214- assert_eq ! ( type_option. strip_symbol( "¥18,443" ) , "18443" . to_owned( ) ) ;
215- assert_eq ! ( type_option. strip_symbol( "$18,443" ) , "18443" . to_owned( ) ) ;
216- assert_eq ! ( type_option. strip_symbol( "€18.443" ) , "18443" . to_owned( ) ) ;
217239
218240 for format in NumberFormat :: iter ( ) {
219241 type_option. format = format;
@@ -248,10 +270,12 @@ mod tests {
248270 type_option. format = format;
249271 match format {
250272 NumberFormat :: Number => {
251- // assert_equal(&type_option, "18443", "18443", &field_type, &field_meta);
273+ assert_equal ( & type_option, "18443" , "18443" , & field_type, & field_meta) ;
274+ assert_equal ( & type_option, "0.2" , "0.2" , & field_type, & field_meta) ;
252275 }
253276 NumberFormat :: USD => {
254277 assert_equal ( & type_option, "$18,44" , "$1,844" , & field_type, & field_meta) ;
278+ assert_equal ( & type_option, "$0.2" , "$0.2" , & field_type, & field_meta) ;
255279 assert_equal ( & type_option, "" , "" , & field_type, & field_meta) ;
256280 assert_equal ( & type_option, "abc" , "" , & field_type, & field_meta) ;
257281 }
@@ -264,43 +288,15 @@ mod tests {
264288 assert_equal ( & type_option, "CN¥1844" , "CN¥1,844" , & field_type, & field_meta) ;
265289 }
266290 NumberFormat :: EUR => {
267- assert_equal ( & type_option, "€18.44" , "€1.844" , & field_type, & field_meta) ;
291+ assert_equal ( & type_option, "€18.44" , "€18,44" , & field_type, & field_meta) ;
292+ assert_equal ( & type_option, "€0.5" , "€0,5" , & field_type, & field_meta) ;
268293 assert_equal ( & type_option, "€1844" , "€1.844" , & field_type, & field_meta) ;
269294 }
270295 _ => { }
271296 }
272297 }
273298 }
274299
275- #[ test]
276- fn number_type_option_scale_test ( ) {
277- let mut type_option = NumberTypeOption {
278- scale : 1 ,
279- ..Default :: default ( )
280- } ;
281- let field_type = FieldType :: Number ;
282- let field_meta = FieldBuilder :: from_field_type ( & field_type) . build ( ) ;
283-
284- for format in NumberFormat :: iter ( ) {
285- type_option. format = format;
286- match format {
287- NumberFormat :: Number => {
288- assert_equal ( & type_option, "18443" , "18443" , & field_type, & field_meta) ;
289- }
290- NumberFormat :: USD => {
291- assert_equal ( & type_option, "18443" , "$1,844.3" , & field_type, & field_meta) ;
292- }
293- NumberFormat :: Yen => {
294- assert_equal ( & type_option, "18443" , "¥1,844.3" , & field_type, & field_meta) ;
295- }
296- NumberFormat :: EUR => {
297- assert_equal ( & type_option, "18443" , "€1.844,3" , & field_type, & field_meta) ;
298- }
299- _ => { }
300- }
301- }
302- }
303-
304300 #[ test]
305301 fn number_description_sign_test ( ) {
306302 let mut type_option = NumberTypeOption {
0 commit comments