Changeset - de10197af7f5
[Not reviewed]
0 3 0
Brett Smith - 4 years ago 2020-09-04 19:29:10
brettcsmith@brettcsmith.org
reports: Improve formatting of non-currency commodities.

Introduce the get_commodity_format() function, which returns Babel's
usual format string for currencies, but returns a version of it
"merged" with the locale's currency unit pattern for other
commodities.

BaseODS then calls this function where needed to format amounts.
3 files changed with 49 insertions and 14 deletions:
0 comments (0 inline, 0 general)
conservancy_beancount/reports/core.py
Show inline comments
...
 
@@ -739,3 +739,3 @@ class BaseODS(BaseSpreadsheet[RT, ST], metaclass=abc.ABCMeta):
 
            code: str,
 
            fmt_index: int,
 
            amount: DecimalCompat=0,
 
            properties: Optional[odf.style.TextProperties]=None,
...
 
@@ -748,7 +748,3 @@ class BaseODS(BaseSpreadsheet[RT, ST], metaclass=abc.ABCMeta):
 
        pattern = locale.currency_formats[fmt_key]
 
        fmts = pattern.pattern.split(';')
 
        try:
 
            fmt = fmts[fmt_index]
 
        except IndexError:
 
            fmt = fmts[0]
 
        fmt = get_commodity_format(locale, code, amount, fmt_key)
 
        style = self.replace_child(
...
 
@@ -825,3 +821,3 @@ class BaseODS(BaseSpreadsheet[RT, ST], metaclass=abc.ABCMeta):
 
            curr_style = self._build_currency_style(
 
                root, locale, code, 1, negative_properties,
 
                root, locale, code, -1, negative_properties,
 
            )
...
 
@@ -1135,5 +1131,5 @@ class BaseODS(BaseSpreadsheet[RT, ST], metaclass=abc.ABCMeta):
 
        else:
 
            lines = [babel.numbers.format_currency(
 
                number, currency, locale=self.locale, format_type=self.currency_fmt_key,
 
            ) for number, currency in balance.values()]
 
            lines = [babel.numbers.format_currency(number, currency, get_commodity_format(
 
                self.locale, currency, None, self.currency_fmt_key,
 
            )) for number, currency in balance.values()]
 
            attrs['stylename'] = self.merge_styles(
...
 
@@ -1289,2 +1285,43 @@ def account_balances(
 

	
 
def get_commodity_format(locale: babel.core.Locale,
 
                         code: str,
 
                         amount: Optional[DecimalCompat]=None,
 
                         format_type: str='accounting',
 
) -> str:
 
    """Return a format string for a commodity
 

	
 
    Typical use looks like::
 

	
 
      number, code = post.units
 
      fmt = get_commodity_format(locale, code)
 
      units_s = babel.numbers.format_currency(number, code, fmt)
 

	
 
    When the commodity code refers to a real currency, you get the same format
 
    string provided by Babel.
 

	
 
    For other commodities like stock, you get a format code built from the
 
    locale's currency unit pattern.
 

	
 
    If ``amount`` is defined, the format string will be specifically for that
 
    number, whether positive or negative. Otherwise, the format string may
 
    define both positive and negative formats.
 
    """
 
    fmt: str = locale.currency_formats[format_type].pattern
 
    if amount is not None:
 
        fmt, _, neg_fmt = fmt.partition(';')
 
        if amount < 0 and neg_fmt:
 
            fmt = neg_fmt
 
    symbol = babel.numbers.get_currency_symbol(code, locale)
 
    if symbol != code:
 
        return fmt
 
    else:
 
        long_fmt: str = babel.numbers.get_currency_unit_pattern(code, locale=locale)
 
        return re.sub(
 
            r'[#0,.\s¤]+',
 
            lambda match: long_fmt.format(
 
                match.group(0).replace('¤', '').strip(), '¤¤',
 
            ),
 
            fmt,
 
        )
 

	
 
def normalize_amount_func(account_name: str) -> Callable[[T], T]:
setup.py
Show inline comments
...
 
@@ -7,3 +7,3 @@ setup(
 
    description="Plugin, library, and reports for reading Conservancy's books",
 
    version='1.9.5',
 
    version='1.9.6',
 
    author='Software Freedom Conservancy',
tests/test_reports_spreadsheet.py
Show inline comments
...
 
@@ -551,5 +551,3 @@ def test_ods_writer_balance_cell_multi_currency(ods_writer):
 
    cell = ods_writer.balance_cell(balance)
 
    assert cell.text == '\0'.join(babel.numbers.format_currency(
 
        number, currency, locale=EN_US, format_type='accounting',
 
    ) for number, currency in amounts)
 
    assert cell.text == '2,500.00 RUB\0R$3,500.00'
 

	
0 comments (0 inline, 0 general)