Conversión de divisas y cálculo de impuestos con precisión decimal exacta
Project description
MoneyMap
Conversión de divisas y cálculo de impuestos con precisión decimal exacta.
MoneyMap resuelve el problema de los errores de redondeo al trabajar con dinero en Python. Usa el tipo Decimal de la librería estándar para garantizar que nunca pierdas un centavo en tus cálculos.
from moneymap import convertir, impuesto
pago = convertir(1000, origen="MXN", destino="USD")
print(f"Total: {pago} USD") # Total: 58.65 USD
iva = impuesto(1000, pais="Mexico")
print(f"IVA: {iva}") # IVA: 160.00
Instalación
pip install moneymap # solo funciones básicas
pip install moneymap[pandas] # con soporte para pandas
pip install moneymap[polars] # con soporte para polars
pip install moneymap[pandas,polars] # ambos
Requiere Python 3.10+.
Referencia de API
convertir(monto, origen, destino)
Convierte un monto de una divisa a otra.
| Parámetro | Tipo | Descripción |
|---|---|---|
monto |
int | float | str | Decimal |
El valor a convertir |
origen |
str |
Código ISO de la divisa de origen |
destino |
str |
Código ISO de la divisa de destino |
Retorna: Decimal — el monto convertido, redondeado a 2 decimales.
from moneymap import convertir
convertir(100, "USD", "MXN") # Decimal('1705.00')
convertir(500, "EUR", "GBP") # Decimal('429.35')
convertir(1, "USD", "JPY") # Decimal('149.50')
impuesto(monto, pais)
Calcula el monto del impuesto aplicable (IVA, VAT, GST, etc.) según el país.
Nota: Devuelve sólo el impuesto, no el total. Para obtener el total, usa total_con_impuesto().
from moneymap import impuesto
impuesto(1000, "Mexico") # Decimal('160.00') → IVA 16%
impuesto(1000, "España") # Decimal('210.00') → IVA 21%
impuesto(1000, "USA") # Decimal('0.00') → Sin IVA federal
registrar_tasa(divisa, referencia, tasa)
Registra o actualiza la tasa de cambio de una divisa.
from moneymap import registrar_tasa, convertir
registrar_tasa("MXN", "USD", 17.05) # 1 USD = 17.05 MXN
registrar_tasa("VEF", "USD", 35.50) # divisa nueva
Funciones adicionales (módulo moneymap.taxes)
from moneymap.taxes import total_con_impuesto, tasa_fiscal
total_con_impuesto(1000, "Mexico") # Decimal('1160.00')
tasa_fiscal("Mexico") # Decimal('16')
tasa_fiscal("Suecia") # Decimal('25')
divisas_disponibles() / paises_disponibles()
from moneymap import divisas_disponibles, paises_disponibles
divisas_disponibles()
# ['ARS', 'AUD', 'BRL', 'CAD', 'CHF', 'CLP', 'CNY', 'COP', 'EUR', ...]
paises_disponibles()
# ['Alemania', 'Argentina', 'Australia', 'Austria', 'Belgica', ...]
Integración con pandas
Activa el accessor importando el módulo una vez. Todas las operaciones son no destructivas y encadenables.
import pandas as pd
import moneymap.dataframepd # activa df.moneymap
df = pd.DataFrame({
"producto": ["Laptop", "Monitor", "Teclado"],
"precio": [25000, 8500, 1200],
})
Métodos disponibles
# Agrega columna "precio_USD"
df = df.moneymap.convertir(col="precio", origen="MXN", destino="USD")
# Agrega columna "precio_impuesto"
df = df.moneymap.impuesto(col="precio", pais="Mexico")
# Agrega columna "precio_total"
df = df.moneymap.total_con_impuesto(col="precio", pais="Mexico")
# Agrega precio_impuesto + precio_total + precio_tasa_pct en una sola llamada
df = df.moneymap.resumen_fiscal(col="precio", pais="España")
Encadenado
resultado = (
df
.moneymap.convertir(col="precio", origen="MXN", destino="USD")
.moneymap.impuesto(col="precio_USD", pais="USA")
.moneymap.total_con_impuesto(col="precio_USD", pais="USA")
)
El parámetro opcional resultado permite nombrar la columna de salida:
df.moneymap.convertir(col="precio", origen="MXN", destino="USD", resultado="precio_dolar")
Integración con Polars
Polars no tiene sistema de accessors, por lo que la integración usa funciones que reciben el DataFrame como primer argumento. Soporta DataFrame, LazyFrame y expresiones (pl.Expr).
import polars as pl
import moneymap.dataframepl as mm
DataFrame y LazyFrame
El mismo API funciona para ambos tipos — si pasas un LazyFrame, recibes un LazyFrame:
df_pl = pl.DataFrame({
"producto": ["Laptop", "Monitor", "Teclado"],
"precio": [25000, 8500, 1200],
})
# DataFrame normal
df_pl = mm.convertir(df_pl, col="precio", origen="MXN", destino="USD")
df_pl = mm.impuesto(df_pl, col="precio", pais="Mexico")
df_pl = mm.total_con_impuesto(df_pl, col="precio", pais="Mexico")
df_pl = mm.resumen_fiscal(df_pl, col="precio", pais="España")
# LazyFrame — evaluación diferida, todo se ejecuta en .collect()
resultado = (
df_pl.lazy()
.pipe(mm.convertir, col="precio", origen="MXN", destino="USD")
.pipe(mm.impuesto, col="precio_USD", pais="USA")
.pipe(mm.total_con_impuesto, col="precio_USD", pais="USA")
.collect()
)
Expresiones
Las funciones expr_* devuelven una pl.Expr para usar dentro de .with_columns() o .select(), permitiendo calcular múltiples columnas en una sola pasada:
df_pl = df_pl.with_columns(
mm.expr_convertir("precio", "MXN", "USD").alias("precio_USD"),
mm.expr_convertir("precio", "MXN", "EUR").alias("precio_EUR"),
mm.expr_impuesto("precio", "Mexico").alias("iva"),
mm.expr_total_con_impuesto("precio", "Mexico").alias("precio_total"),
)
| Función | Retorna | Uso |
|---|---|---|
mm.convertir(df, col, origen, destino) |
DataFrame / LazyFrame |
Agrega columna {col}_{DESTINO} |
mm.impuesto(df, col, pais) |
DataFrame / LazyFrame |
Agrega columna {col}_impuesto |
mm.total_con_impuesto(df, col, pais) |
DataFrame / LazyFrame |
Agrega columna {col}_total |
mm.resumen_fiscal(df, col, pais) |
DataFrame / LazyFrame |
Agrega impuesto + total + tasa_pct |
mm.expr_convertir(col, origen, destino) |
pl.Expr |
Para usar en .with_columns() |
mm.expr_impuesto(col, pais) |
pl.Expr |
Para usar en .with_columns() |
mm.expr_total_con_impuesto(col, pais) |
pl.Expr |
Para usar en .with_columns() |
Ayuda integrada
from moneymap import ayuda
ayuda() # índice de todas las funciones
ayuda("convertir") # detalle con argumentos, retorno y ejemplo
ayuda("impuesto")
ayuda("registrar_tasa")
ayuda("total_con_impuesto")
ayuda("tasa_fiscal")
ayuda("divisas_disponibles")
ayuda("paises_disponibles")
Divisas incluidas
| Código | Divisa | Código | Divisa |
|---|---|---|---|
| USD | Dólar estadounidense | MXN | Peso mexicano |
| EUR | Euro | CAD | Dólar canadiense |
| GBP | Libra esterlina | JPY | Yen japonés |
| BRL | Real brasileño | ARS | Peso argentino |
| COP | Peso colombiano | CLP | Peso chileno |
| PEN | Sol peruano | CHF | Franco suizo |
| CNY | Yuan chino | INR | Rupia india |
| AUD | Dólar australiano | ... | y más |
Nota: Las tasas de cambio incluidas son valores de referencia aproximados. Para producción se recomienda actualizar con
registrar_tasa()usando una API en tiempo real.
Países e impuestos incluidos
Más de 35 países de América Latina, Europa y Asia, incluyendo:
- México (IVA 16%), Argentina (IVA 21%), Colombia (IVA 19%)
- España (IVA 21%), Alemania (19%), Francia (20%), Reino Unido (20%)
- Japón (10%), China (13%), India (18%), Australia (10%)
- Y muchos más — consulta
paises_disponibles()para la lista completa.
¿Por qué Decimal y no float?
# ❌ Con float: error de punto flotante
0.1 + 0.2 == 0.3 # False
0.1 + 0.2 # 0.30000000000000004
# ✅ Con MoneyMap: precisión exacta
from decimal import Decimal
Decimal("0.1") + Decimal("0.2") == Decimal("0.3") # True
Docker
Ejecutar MoneyMap sin instalar nada localmente:
# Build
docker build -t moneymap .
# Ejecutar el demo completo
docker run --rm moneymap
# Ejecutar los tests
docker run --rm moneymap pytest
# Shell interactivo
docker run --rm -it moneymap bash
Desarrollo
git clone https://github.com/AndreGoros/moneymap
cd moneymap
pip install -e ".[dev]"
pytest
pytest --cov=moneymap --cov-report=term-missing
ruff check moneymap/
Flujo de publicación (GitHub Actions)
El repositorio incluye un workflow en que:
- **En cada push o PR a ** — corre los tests en Python 3.10, 3.11 y 3.12.
- **Al crear un tag ** — construye la distribución y la publica automáticamente en PyPI.
Licencia
MIT — libre para uso personal y comercial.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file moneymap-0.1.12.tar.gz.
File metadata
- Download URL: moneymap-0.1.12.tar.gz
- Upload date:
- Size: 20.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4764750141b414b6a8e19e4693e0d59e60abcec1c0551d71e6d0a2b1806ea7cb
|
|
| MD5 |
1981413b4f926acc641a08b69682b2b1
|
|
| BLAKE2b-256 |
dc0f3ccf3db9cc159804d6a034e7da48d2a174a35423dc7194452dd2668391f2
|
Provenance
The following attestation bundles were made for moneymap-0.1.12.tar.gz:
Publisher:
pypi-publish.yml on AndreGoros/moneymap
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
moneymap-0.1.12.tar.gz -
Subject digest:
4764750141b414b6a8e19e4693e0d59e60abcec1c0551d71e6d0a2b1806ea7cb - Sigstore transparency entry: 1298697966
- Sigstore integration time:
-
Permalink:
AndreGoros/moneymap@6cb9dd70d52dd51f923435c092a60bc245f9bc4b -
Branch / Tag:
refs/tags/v0.1.12 - Owner: https://github.com/AndreGoros
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@6cb9dd70d52dd51f923435c092a60bc245f9bc4b -
Trigger Event:
push
-
Statement type:
File details
Details for the file moneymap-0.1.12-py3-none-any.whl.
File metadata
- Download URL: moneymap-0.1.12-py3-none-any.whl
- Upload date:
- Size: 21.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
deabe2dc3041a37dcb79a278acb59a1202f5c86c72056495530286e673118cea
|
|
| MD5 |
fc641e2b6722f952370e9b828499557b
|
|
| BLAKE2b-256 |
8b080fcf7ab169b5a0f38b6a151507171880dac3b885f4ae5d5225b74c274d0d
|
Provenance
The following attestation bundles were made for moneymap-0.1.12-py3-none-any.whl:
Publisher:
pypi-publish.yml on AndreGoros/moneymap
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
moneymap-0.1.12-py3-none-any.whl -
Subject digest:
deabe2dc3041a37dcb79a278acb59a1202f5c86c72056495530286e673118cea - Sigstore transparency entry: 1298698073
- Sigstore integration time:
-
Permalink:
AndreGoros/moneymap@6cb9dd70d52dd51f923435c092a60bc245f9bc4b -
Branch / Tag:
refs/tags/v0.1.12 - Owner: https://github.com/AndreGoros
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@6cb9dd70d52dd51f923435c092a60bc245f9bc4b -
Trigger Event:
push
-
Statement type: