Metadata-Version: 2.5
Name: spellmoney
Version: 2.0.0
Summary: Convierte montos a letras en español, inglés, portugués y francés para cheques, facturas, recibos y contratos, con las 156 divisas del estándar ISO 4217 y sus subunidades.
Project-URL: Homepage, https://github.com/brandriver-bit/spellmoney
Project-URL: Repository, https://github.com/brandriver-bit/spellmoney
Project-URL: Issues, https://github.com/brandriver-bit/spellmoney/issues
Project-URL: Puerto a JavaScript, https://github.com/brandriver-bit/spellmoney-js
Author: Brandon Rivera Alvarado
License-Expression: MIT
License-File: LICENSE
Keywords: amount-to-words,cheques,english,facturacion,french,invoicing,iso4217,latam,monto-en-letras,numero-a-letras,portuguese,spanish
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: Natural Language :: English
Classifier: Natural Language :: French
Classifier: Natural Language :: Portuguese (Brazilian)
Classifier: Natural Language :: Spanish
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial :: Accounting
Classifier: Topic :: Software Development :: Localization
Classifier: Typing :: Typed
Requires-Python: >=3.9
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == 'dev'
Description-Content-Type: text/markdown

# spellmoney

**Convierte montos numéricos a letras, con el formato exacto que exigen los documentos legales y financieros** — cheques, facturas, recibos y contratos: `CIENTO VEINTICINCO DÓLARES CON 50/100`.

[![PyPI](https://img.shields.io/pypi/v/spellmoney?logo=pypi&logoColor=white&color=3775A9&label=pypi)](https://pypi.org/project/spellmoney/)
![Python](https://img.shields.io/badge/Python-%3E%3D3.9-3776AB?logo=python&logoColor=white)
![Tests](https://github.com/brandriver-bit/spellmoney/actions/workflows/tests.yml/badge.svg)
![License](https://img.shields.io/badge/license-MIT-green)
![Dependencies](https://img.shields.io/badge/dependencias-cero-brightgreen)
![Idiomas](https://img.shields.io/badge/idiomas-es%20%7C%20en%20%7C%20pt%20%7C%20fr-blue)

**[▶ Probalo en el navegador](https://brandriver-bit.github.io/spellmoney-js/)** · *[Read this in English](#english)*

Existe también el [puerto a TypeScript/JavaScript](https://github.com/brandriver-bit/spellmoney-js) — misma lógica, mismos datos de moneda, mismo resultado exacto.

## Instalación

```bash
pip install spellmoney
```

## Uso

```python
from spellmoney import a_letras

a_letras(125.50)
# 'CIENTO VEINTICINCO DÓLARES CON 50/100'

a_letras("125.50")
# 'CIENTO VEINTICINCO DÓLARES CON 50/100'  (lectura decimal exacta)

a_letras(1, moneda="GTQ")
# 'UN QUETZAL CON 00/100'

a_letras(21000000, moneda="EUR")
# 'VEINTIÚN MILLONES DE EUROS CON 00/100'

a_letras(2, moneda="GBP", mayusculas=False)
# 'dos libras esterlinas con 00/100'

a_letras(10.50, centavos="palabras")
# 'DIEZ DÓLARES CON CINCUENTA CENTAVOS'
```

### Otros idiomas

```python
a_letras(125.50, idioma="en")
# 'ONE HUNDRED TWENTY-FIVE DOLLARS AND 50/100'

a_letras(125.50, idioma="pt", moneda="BRL")
# 'CENTO E VINTE E CINCO REAIS E 50/100'

a_letras(125.50, idioma="fr", moneda="EUR")
# 'CENT VINGT-CINQ EUROS ET 50/100'
```

### Desde la terminal

```bash
spellmoney 125.50
spellmoney 125.50 --moneda GTQ
spellmoney 1000000 --moneda EUR --idioma fr
spellmoney --monedas quetzal
```

### Solo el número, sin moneda

```python
from spellmoney import (
    numero_a_letras,
    numero_a_letras_en,
    numero_a_letras_pt,
    numero_a_letras_fr,
)

numero_a_letras(1000000)        # 'un millón'
numero_a_letras(1000000000)     # 'mil millones'   (¡no "un billón"!)
numero_a_letras(1000000000000)  # 'un billón'
numero_a_letras(200, "f")       # 'doscientas'    (concordancia de género)

numero_a_letras_en(1000000000)  # 'one billion'    (escala corta del inglés)

numero_a_letras_pt(21, "f")     # 'vinte e uma'    (concordancia de género)

numero_a_letras_fr(71)          # 'soixante et onze'  (base vigesimal del francés)
```

## Divisas y subunidades

El catálogo sigue el estándar **ISO 4217**, incluido el número de decimales de cada divisa. Eso cambia la salida:

```python
a_letras(125.50, moneda="JPY")
# 'CIENTO VEINTISÉIS YENES JAPONESES'      el yen no tiene subunidad

a_letras("125.500", moneda="KWD")
# 'CIENTO VEINTICINCO DINARES KUWAITÍES CON 500/1000'   el dinar se divide en 1000

a_letras(1.25, moneda="GBP", centavos="palabras")
# 'UNA LIBRA ESTERLINA CON VEINTICINCO PENIQUES'        no "centavos"

a_letras(1.25, moneda="EUR", centavos="palabras")
# 'UN EURO CON VEINTICINCO CÉNTIMOS'
```

El género de la divisa arrastra al número, como exige la gramática — y no solo
en el último dígito: las centenas concuerdan aunque se interponga "mil".

```python
a_letras(200, moneda="GBP")
# 'DOSCIENTAS LIBRAS ESTERLINAS CON 00/100'

a_letras(200000, moneda="GBP")
# 'DOSCIENTAS MIL LIBRAS ESTERLINAS CON 00/100'

a_letras(200, moneda="USD")
# 'DOSCIENTOS DÓLARES CON 00/100'

a_letras(200000000, moneda="GBP")
# 'DOSCIENTOS MILLONES DE LIBRAS ESTERLINAS CON 00/100'   "millones" es masculino
```

Los cuatro idiomas cubren **las 156 divisas del catálogo**, cada una con su nombre, su género gramatical y, cuando la tiene, el nombre de su subunidad:

| Idioma | Divisas | Ejemplo |
|---|---|---|
| `es` (español) | 156 | `UNA CORONA CHECA CON 00/100` |
| `en` (inglés) | 156 | `ONE CZECH KORUNA AND 00/100` |
| `pt` (portugués) | 156 | `UMA COROA TCHECA E 00/100` |
| `fr` (francés) | 156 | `UNE COURONNE TCHÈQUE ET 00/100` |

**Divisas retiradas.** Las que el estándar retiró se conservan, marcadas con la fecha en `MONEDAS[codigo]["retirada"]` — el florín antillano (ANG, 2025-03), el dólar zimbabuense (ZWL, 2024-09) y el lev búlgaro (BGN, 2026-01). Una factura de 2023 se tiene que poder escribir igual.

## Montos negativos

Por defecto se rechazan, porque en un cheque casi siempre son un error. Para notas de crédito y devoluciones:

```python
a_letras(-125.50, negativos="prefijo")
# 'MENOS CIENTO VEINTICINCO DÓLARES CON 50/100'
```

## Plantilla de salida

Cada país tiene su fórmula legal. La plantilla permite calcarla:

```python
a_letras(125.50, plantilla="SON: {monto} {moneda} {conector} {centavos}")
# 'SON: CIENTO VEINTICINCO DÓLARES CON 50/100'

a_letras(125.50, plantilla="{monto} {moneda} ({codigo})")
# 'CIENTO VEINTICINCO DÓLARES (USD)'
```

Marcadores disponibles: `{signo}`, `{monto}`, `{moneda}`, `{conector}`, `{centavos}` y `{codigo}`. Los espacios sobrantes se colapsan.

Ojo con `mayusculas`: pasa **todo** el resultado a mayúsculas o a minúsculas, la plantilla incluida. No conserva el texto tal como se escribió.

## API

| Función | Descripción |
|---|---|
| `a_letras(monto, ...)` | Convierte un monto con nombre de moneda. |
| `numero_a_letras(n, genero="m")` | Solo el número, en español. |
| `numero_a_letras_en(n)` | Solo el número, en inglés. |
| `numero_a_letras_pt(n, genero="m")` | Solo el número, en portugués. |
| `numero_a_letras_fr(n)` | Solo el número, en francés. |
| `MONEDAS` | Catálogo de divisas ISO 4217, con decimales y subunidades. |
| `IDIOMAS` | `("es", "en", "pt", "fr")`. |
| `SpellMoneyError` | Error lanzado ante un monto, moneda o idioma inválidos. |

Parámetros de `a_letras`:

| Parámetro | Valores | Por defecto |
|---|---|---|
| `monto` | `int`, `float`, `Decimal` o cadena decimal | — |
| `moneda` | código ISO 4217 | `"USD"` |
| `idioma` | `"es"`, `"en"`, `"pt"`, `"fr"` | `"es"` |
| `centavos` | `"fraccion"`, `"palabras"` | `"fraccion"` |
| `mayusculas` | `bool` | `True` |
| `negativos` | `"error"`, `"prefijo"` | `"error"` |
| `plantilla` | `str` | según la divisa |

## Redondeo y precisión

Un monto se puede pasar como `float`, como `Decimal` o como cadena decimal, y la diferencia importa:

- **Cadena o `Decimal`** — `a_letras("125.50")`, `a_letras(Decimal("125.50"))`: los dígitos se leen tal como fueron escritos, sin pasar por punto flotante. El redondeo del primer decimal sobrante es half-up exacto, así que `"2.675"` da `68/100`. Es la vía recomendada cuando el monto viene de una base de datos, un formulario o un archivo.
- **`float`** — `a_letras(125.50)`: los montos de **dos decimales** se convierten de forma exacta. Verificado sobre el millón de montos de `0.00` a `9999.99`: ninguna diferencia frente a aritmética decimal exacta. Con **tres o más decimales**, el empate exacto se resuelve según el valor binario que el `float` almacena realmente, que puede quedar apenas por debajo del decimal escrito: `2.675` da `67/100`. Es una propiedad del tipo `float`, no de esta librería.

## Rango soportado

Enteros de `0` a `999,999,999,999,999`. Un monto fuera de ese rango lanza `SpellMoneyError`, igual que una moneda no reconocida o un idioma no soportado.

## Desarrollo

```bash
git clone https://github.com/brandriver-bit/spellmoney.git
cd spellmoney
pip install -e ".[dev]"
pytest
```

## Licencia

MIT — ver [`LICENSE`](LICENSE).

---

<a name="english"></a>

# spellmoney (English)

**Turns numeric amounts into words, in the exact format legal and financial documents require** — cheques, invoices, receipts and contracts: `ONE HUNDRED TWENTY-FIVE DOLLARS AND 50/100`.

**[▶ Try it in your browser](https://brandriver-bit.github.io/spellmoney-js/)** · *[Leer esto en español](#spellmoney)*

Four languages — Spanish, English, Brazilian Portuguese and French — and the ISO 4217 currency catalog, including each currency's minor units. Zero dependencies. There is also a [TypeScript/JavaScript port](https://github.com/brandriver-bit/spellmoney-js) with identical output.

## Install

```bash
pip install spellmoney
```

## Usage

```python
from spellmoney import a_letras

a_letras(125.50, idioma="en")
# 'ONE HUNDRED TWENTY-FIVE DOLLARS AND 50/100'

a_letras("125.50", idioma="en", moneda="GBP", centavos="palabras")
# 'ONE HUNDRED TWENTY-FIVE POUNDS STERLING AND FIFTY PENCE'

a_letras(125.50, idioma="en", moneda="JPY")
# 'ONE HUNDRED TWENTY-SIX JAPANESE YEN'      the yen has no minor unit

a_letras("125.500", idioma="en", moneda="KWD")
# 'ONE HUNDRED TWENTY-FIVE KUWAITI DINARS AND 500/1000'
```

There's also a CLI:

```bash
spellmoney 125.50 --idioma en --moneda GBP
```

The API is in Spanish because that's the audience it was written for. `a_letras(amount, ...)` is the entry point; `moneda` is the ISO 4217 code, `idioma` the language, `centavos` whether the minor unit is written as a fraction (`50/100`) or in words, `mayusculas` the casing, `negativos` how to treat negative amounts, and `plantilla` an output template for matching a specific legal wording.

Pass the amount as a **string** or a `Decimal` to have its digits read exactly, without floating point: `"2.675"` rounds half-up to `68/100`, while the `float` `2.675` gives `67/100` because the nearest double sits just below it.

All four languages cover every currency in the catalog, each with its name, grammatical gender and, where it has one, the name of its minor unit. Withdrawn currencies are kept and flagged with the date they left the standard, so older documents can still be spelled.


MIT licensed.
