fix(reports): localize and group exported income values

This commit is contained in:
2026-04-27 21:14:02 +03:30
parent 208e81139b
commit 7bd60fd641
2 changed files with 52 additions and 12 deletions

View File

@@ -2,6 +2,7 @@ from __future__ import annotations
from dataclasses import dataclass
from datetime import date
from decimal import Decimal, InvalidOperation
from pathlib import Path
from typing import Iterable
@@ -89,6 +90,16 @@ PERIOD_LABELS = {
},
}
CURRENCY_LABELS = {
"USD": {"en": "USD", "fa": "دلار آمریکا"},
"EUR": {"en": "EUR", "fa": "یورو"},
"GBP": {"en": "GBP", "fa": "پوند"},
"IRR": {"en": "IRR", "fa": "ریال"},
"IRT": {"en": "IRT", "fa": "تومان"},
"AED": {"en": "AED", "fa": "درهم"},
"TRY": {"en": "TRY", "fa": "لیر"},
}
@dataclass(frozen=True)
class ExportLocale:
@@ -122,14 +133,40 @@ class ExportLocale:
def format_duration(self, value: str, *, ascii_digits: bool = False) -> str:
return self.format_number(value, ascii_digits=ascii_digits)
def format_amount(self, value: object, *, ascii_digits: bool = False) -> str:
raw = str(value).strip()
if not raw:
return raw
try:
decimal_value = Decimal(raw)
except InvalidOperation:
return self.format_number(raw, ascii_digits=ascii_digits)
sign = "-" if decimal_value < 0 else ""
unsigned = abs(decimal_value)
normalized = format(unsigned, "f")
integer_part, _, fractional_part = normalized.partition(".")
grouped_integer = f"{int(integer_part):,}"
formatted = f"{sign}{grouped_integer}"
if fractional_part:
trimmed_fraction = fractional_part.rstrip("0")
if trimmed_fraction:
formatted = f"{formatted}.{trimmed_fraction}"
return self.format_number(formatted, ascii_digits=ascii_digits)
def format_money_label(self, income_totals: list[dict], *, ascii_digits: bool = False) -> str:
if not income_totals:
return "-"
parts = []
for item in income_totals:
parts.append(f"{self.format_number(item['amount'], ascii_digits=ascii_digits)} {item['currency']}")
currency = self.currency_label(item["currency"])
parts.append(f"{self.format_amount(item['amount'], ascii_digits=ascii_digits)} {currency}")
return " | ".join(parts)
def currency_label(self, code: str | None) -> str:
raw = str(code or "").upper()
return CURRENCY_LABELS.get(raw, {}).get(self.language, raw)
def shape(self, text: object) -> str:
raw = str(text)
if not any(start <= ord(char) <= end for char in raw for start, end in ARABIC_RANGES):