Files
tradon/modules/purchase_trade/numbers_to_words.py
2026-02-27 07:04:54 +01:00

152 lines
3.6 KiB
Python

from decimal import Decimal, ROUND_HALF_UP
from datetime import date
UNITS = (
"ZERO ONE TWO THREE FOUR FIVE SIX SEVEN EIGHT NINE TEN ELEVEN TWELVE "
"THIRTEEN FOURTEEN FIFTEEN SIXTEEN SEVENTEEN EIGHTEEN NINETEEN"
).split()
TENS = "ZERO TEN TWENTY THIRTY FORTY FIFTY SIXTY SEVENTY EIGHTY NINETY".split()
def format_date_en(d):
if not d:
return ''
day = d.day
# Gestion des suffixes ordinaux
if 10 <= day % 100 <= 20:
suffix = 'TH'
else:
suffix = {1: 'ST', 2: 'ND', 3: 'RD'}.get(day % 10, 'TH')
return f"{day}{suffix} {d.strftime('%B').upper()} {d.year}"
def _under_thousand(n):
words = []
hundreds = n // 100
remainder = n % 100
if hundreds:
words.append(UNITS[hundreds])
words.append("HUNDRED")
if remainder:
words.append("AND")
if remainder:
if remainder < 20:
words.append(UNITS[remainder])
else:
words.append(TENS[remainder // 10])
if remainder % 10:
words.append(UNITS[remainder % 10])
return " ".join(words)
def integer_to_words(n):
if n == 0:
return "ZERO"
parts = []
millions = n // 1_000_000
thousands = (n // 1_000) % 1_000
remainder = n % 1_000
if millions:
parts.append(_under_thousand(millions))
parts.append("MILLION")
if thousands:
parts.append(_under_thousand(thousands))
parts.append("THOUSAND")
if remainder:
parts.append(_under_thousand(remainder))
return " ".join(parts)
# ==============================
# 💰 MONETARY
# ==============================
def amount_to_currency_words(amount,
major_singular="DOLLAR",
major_plural="DOLLARS",
minor_singular="CENT",
minor_plural="CENTS"):
"""
Example:
1.20 → ONE DOLLAR AND TWENTY CENTS
2.00 → TWO DOLLARS
"""
amount = Decimal(str(amount)).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
integer_part = int(amount)
decimal_part = int((amount - integer_part) * 100)
words = []
# Major unit
major_words = integer_to_words(integer_part)
words.append(major_words)
if integer_part == 1:
words.append(major_singular)
else:
words.append(major_plural)
# Minor unit
if decimal_part:
words.append("AND")
minor_words = integer_to_words(decimal_part)
words.append(minor_words)
if decimal_part == 1:
words.append(minor_singular)
else:
words.append(minor_plural)
return " ".join(words)
# ==============================
# ⚖️ QUANTITY WITH UNIT
# ==============================
def quantity_to_words(quantity,
unit_singular="METRIC TON",
unit_plural="METRIC TONS"):
"""
Example:
1 → ONE METRIC TON
23 → TWENTY THREE METRIC TONS
1.5 → ONE POINT FIVE METRIC TONS
"""
quantity = Decimal(str(quantity)).normalize()
if quantity == quantity.to_integral():
integer_part = int(quantity)
words = integer_to_words(integer_part)
if integer_part == 1:
unit = unit_singular
else:
unit = unit_plural
return f"{words} {unit}"
else:
# lecture décimale simple pour quantités
integer_part = int(quantity)
decimal_str = str(quantity).split(".")[1]
words = integer_to_words(integer_part)
decimal_words = " ".join(UNITS[int(d)] for d in decimal_str)
return f"{words} POINT {decimal_words} {unit_plural}"