|
1 | 1 | from decimal import ROUND_DOWN, Decimal, InvalidOperation |
2 | | -from typing import Union |
3 | 2 |
|
4 | 3 | from num2words import num2words |
5 | 4 |
|
6 | 5 |
|
7 | | -def format_currency(value): # type: (float) -> str | None |
| 6 | +def format_currency(value: float | int | str | Decimal) -> str | None: |
8 | 7 | """ |
9 | | - Formats a given float as Brazilian currency (R$). |
10 | | -
|
11 | | - This function takes a float value and returns a formatted string representing |
12 | | - the value as Brazilian currency, using the correct thousand and decimal separators. |
| 8 | + Format a numeric value as Brazilian currency (R$). |
13 | 9 |
|
14 | 10 | Args: |
15 | | - value (float or Decimal): The numeric value to be formatted. |
| 11 | + value: The numeric value to format. Accepts float, int, str, or Decimal. |
16 | 12 |
|
17 | 13 | Returns: |
18 | | - str or None: A string formatted as Brazilian currency, or None if the input is invalid. |
| 14 | + Formatted currency string (e.g., "R$ 1.234,56") or None if invalid. |
19 | 15 |
|
20 | 16 | Example: |
21 | 17 | >>> format_currency(1234.56) |
22 | | - "R$ 1.234,56" |
| 18 | + 'R$ 1.234,56' |
23 | 19 | >>> format_currency(0) |
24 | | - "R$ 0,00" |
| 20 | + 'R$ 0,00' |
25 | 21 | >>> format_currency(-9876.54) |
26 | | - "R$ -9.876,54" |
27 | | - >>> format_currency(None) |
28 | | - None |
29 | | - >>> format_currency("not a number") |
| 22 | + 'R$ -9.876,54' |
| 23 | + >>> format_currency("invalid") |
30 | 24 | None |
31 | 25 | """ |
32 | | - |
33 | 26 | try: |
34 | 27 | decimal_value = Decimal(value) |
35 | 28 | formatted_value = ( |
36 | 29 | f"R$ {decimal_value:,.2f}".replace(",", "_") |
37 | 30 | .replace(".", ",") |
38 | 31 | .replace("_", ".") |
39 | 32 | ) |
40 | | - |
41 | 33 | return formatted_value |
42 | | - except InvalidOperation: |
| 34 | + except (InvalidOperation, TypeError, ValueError): |
43 | 35 | return None |
44 | 36 |
|
45 | 37 |
|
46 | | -def convert_real_to_text(amount: Decimal) -> Union[str, None]: |
| 38 | +def convert_real_to_text(amount: Decimal | float | int | str) -> str | None: |
47 | 39 | """ |
48 | | - Converts a given monetary value in Brazilian Reais to its textual representation. |
49 | | -
|
50 | | - This function takes a decimal number representing a monetary value in Reais |
51 | | - and converts it to a string with the amount written out in Brazilian Portuguese. It |
52 | | - handles both the integer part (Reais) and the fractional part (centavos), respecting |
53 | | - the correct grammar for singular and plural cases, as well as special cases like zero |
54 | | - and negative values. |
| 40 | + Convert a monetary value in Brazilian Reais to textual representation. |
55 | 41 |
|
56 | 42 | Args: |
57 | | - amount (decimal): The monetary value to be converted into text. |
58 | | - - The integer part represents Reais. |
59 | | - - The decimal part represents centavos. |
60 | | - - 2 decimal places |
| 43 | + amount: Monetary value to convert. Accepts Decimal, float, int, or str. |
61 | 44 |
|
62 | 45 | Returns: |
63 | | - str: A string with the monetary value written out in Brazilian Portuguese. |
64 | | - - Returns "Zero reais" for a value of 0.00. |
65 | | - - Returns None if the amount is invalid or absolutely greater than 1 quadrillion. |
66 | | - - Handles negative values, adding "Menos" at the beginning of the string. |
| 46 | + Textual representation in Brazilian Portuguese, or None if invalid. |
67 | 47 |
|
68 | | - Limitations: |
69 | | - - This function may lose precision by ±1 cent for cases where the absolute value |
70 | | - is beyond trillions due to floating-point rounding errors. |
| 48 | + Note: |
| 49 | + - Values are rounded down to 2 decimal places |
| 50 | + - Maximum supported value is 1 quadrillion reais |
| 51 | + - Negative values are prefixed with "Menos" |
71 | 52 |
|
72 | 53 | Example: |
73 | 54 | >>> convert_real_to_text(1523.45) |
74 | | - "Mil, quinhentos e vinte e três reais e quarenta e cinco centavos" |
| 55 | + 'Mil, quinhentos e vinte e três reais e quarenta e cinco centavos' |
75 | 56 | >>> convert_real_to_text(1.00) |
76 | | - "Um real" |
| 57 | + 'Um real' |
77 | 58 | >>> convert_real_to_text(0.50) |
78 | | - "Cinquenta centavos" |
| 59 | + 'Cinquenta centavos' |
79 | 60 | >>> convert_real_to_text(0.00) |
80 | | - "Zero reais" |
81 | | - >>> convert_real_to_text(-50.25) |
82 | | - "Menos cinquenta reais e vinte e cinco centavos" |
| 61 | + 'Zero reais' |
83 | 62 | """ |
84 | | - |
85 | 63 | try: |
86 | 64 | amount = Decimal(str(amount)).quantize( |
87 | 65 | Decimal("0.01"), rounding=ROUND_DOWN |
88 | 66 | ) |
89 | | - except InvalidOperation: |
| 67 | + except (InvalidOperation, TypeError, ValueError): |
90 | 68 | return None |
91 | 69 |
|
92 | 70 | if amount.is_nan() or amount.is_infinite(): |
|
0 commit comments