Saltar al contenido principal

Amortización

Aprende a gestionar la amortización de manera efectiva en Beancount, permitiéndote distribuir los gastos a lo largo del tiempo para una mayor claridad y gestión financiera.

Registra los costos prepagados como activos y luego libera la parte mensual al gasto con transacciones ordinarias de Beancount. El script a continuación genera libros contables completos y reproducibles para seguros, software, un anticipo a cuenta y depreciación de equipos. Requiere Python 3 y no necesita bibliotecas de terceros.

Por ejemplo, una póliza de seguro de automóvil de seis meses cuesta $600 por adelantado. Seis liberaciones mensuales de $100 separan el pago en efectivo del reconocimiento del gasto y te ayudan a presupuestar de manera efectiva.

¿Qué es la Amortización?

La amortización distribuye el costo de un activo intangible o de un artículo prepagado a lo largo de los períodos que beneficia. Estos ejemplos utilizan una convención mensual simple para informes de gestión. No determinan una deducción fiscal ni un método de depreciación legal.

La Solución Beancount: fava.plugins.amortize_over

Compatibilidad verificada el 2026-09-07: fava.plugins.amortize_over no está presente en el directorio de plugins de Fava estándar 1.30.16. Agregar su directiva plugin a esa instalación estándar produce un error de importación. Los ejemplos portátiles aquí fueron probados con Beancount 3.2.3, beanquery 0.2.0 y Fava 1.30.16.

El código fuente personalizado de Beancount.io sí contiene una implementación de amortize_over. Espera un pago separado y una transacción de calendario con exactamente dos asientos y metadatos amortize_months. Sus fechas mensuales siguen el día original del calendario y omite copias futuras en el momento de la carga. Su regla de redondeo distribuye los céntimos entre los períodos restantes. Esta evidencia del código fuente no establece qué versión ejecuta actualmente un despliegue alojado. Los calendarios explícitos a continuación tienen sus propias fechas declaradas y regla de redondeo para el período final.

Paso 1: Habilitar el Plugin

No hay ningún plugin que habilitar para este flujo de trabajo. Guarda el bloque de Python del paso 3 como amortize.py. Instala uv para ejecutar los comandos de validación y consulta con las versiones utilizadas aquí. Fava solo es necesario si deseas los informes web.

El script escribe transacciones ordinarias en la salida estándar. Redirige esa salida a un nuevo archivo de ejemplo, inspecciónalo y valídalo antes de incorporar las entradas a tus libros. Volver a ejecutar con > reemplaza ese archivo de ejemplo generado; agregar con >> duplicaría las transacciones.

Paso 2: Estructurar tus Cuentas

Cada archivo generado es un libro contable de ejemplo independiente. El ejemplo del seguro abre estas cuentas y proporciona un saldo bancario inicial ilustrativo de $600 antes de pagar la prima:

CuentaPropósito
Assets:Bank:CheckingEfectivo utilizado para el pago
Assets:Prepaid:InsurancePrima pendiente de reconocimiento del gasto
Expenses:Insurance:AutoGasto mensual del seguro
Equity:Opening-BalancesContrapartida del efectivo inicial del ejemplo

Al adaptar las transacciones generadas a un libro contable existente, utiliza tus aperturas de cuenta y saldo bancario reales. No agregues el efectivo inicial del ejemplo a una cuenta ya financiada, ni registres una compra nuevamente si ya está en tus libros.

Paso 3: Registrar la Transacción Amortizada

Guarda este programa completo como amortize.py. Cada escenario especifica la fecha de pago, el número de liberaciones mensuales, el activo de compra, la cuenta de gastos y la cuenta acreditada por las liberaciones. La primera liberación es en la fecha de pago; las liberaciones posteriores caen el mismo día de los meses siguientes, ajustadas al final del mes si es necesario.

import argparse
import calendar
from datetime import date
from decimal import Decimal, ROUND_HALF_EVEN
 
# amount, months, payment date, purchase asset, expense, release credit account
SCENARIOS = {
    "insurance": (
        "600.00", 6, "2024-06-01", "Assets:Prepaid:Insurance",
        "Expenses:Insurance:Auto", "Assets:Prepaid:Insurance",
    ),
    "software": (
        "1200.00", 12, "2024-01-15", "Assets:Prepaid:Software",
        "Expenses:Software:Adobe", "Assets:Prepaid:Software",
    ),
    "retainer": (
        "4500.00", 3, "2024-01-05", "Assets:Prepaid:Professional",
        "Expenses:Professional:Legal", "Assets:Prepaid:Professional",
    ),
    "equipment": (
        "3000.00", 36, "2024-01-20", "Assets:Equipment:Computers:Cost",
        "Expenses:Depreciation:Computers", "Assets:Equipment:Computers:AccumDep",
    ),
}
 
parser = argparse.ArgumentParser()
parser.add_argument("scenario", choices=SCENARIOS)
args = parser.parse_args()
amount, months, paid, asset, expense, credit = SCENARIOS[args.scenario]
total = Decimal(amount)
start = date.fromisoformat(paid)
monthly = (total / months).quantize(Decimal("0.01"), rounding=ROUND_HALF_EVEN)
bank = "Assets:Bank:Checking"
equity = "Equity:Opening-Balances"
 
 
def transaction(day, narration, debit, credit_account, value):
    print(f'\n{day} * "{narration}"')
    print(f"  {debit}  {value:.2f} USD")
    print(f"  {credit_account}  {-value:.2f} USD")
 
 
print('option "operating_currency" "USD"')
for account in sorted({bank, equity, asset, expense, credit}):
    print(f"2024-01-01 open {account} USD")
transaction("2024-01-01", "Example opening cash", bank, equity, total)
transaction(paid, f"Pay {args.scenario}", asset, bank, total)
 
for index in range(months):
    year, month_index = divmod(start.year * 12 + start.month - 1 + index, 12)
    month = month_index + 1
    day = min(start.day, calendar.monthrange(year, month)[1])
    release_date = date(year, month, day)
    # Put the entire rounding remainder into the final release exactly once.
    release = monthly if index < months - 1 else total - monthly * (months - 1)
    transaction(release_date, f"{args.scenario} release {index + 1}/{months}",
                expense, credit, release)

Ejecuta este bloque de comandos desde el directorio que contiene amortize.py:

python3 amortize.py insurance > insurance.beancount
uvx --from beancount-io==0.1.0 bea --file insurance.beancount check

El pago acredita la cuenta corriente por 600.00 USD y debita el seguro prepagado por la misma cantidad. Cada liberación debita el gasto y acredita el seguro prepagado por 100.00 USD. Hay seis liberaciones, el 1 de junio, el 1 de julio, el 1 de agosto, el 1 de septiembre, el 1 de octubre y el 1 de noviembre de 2024. El saldo prepagado es 500.00 USD después de la liberación de junio, 400.00 USD después de la de julio y cero después de la de noviembre.

Ejemplos Prácticos

Licencia de Software Anual

Usa el mismo script guardado para generar un ejemplo de software independiente adicional:

python3 amortize.py software > software.beancount
uvx --from beancount-io==0.1.0 bea --file software.beancount check

El pago de la licencia de $1,200 se realiza el 15 de enero de 2024. Doce liberaciones de 100.00 USD se ejecutan desde el 15 de enero hasta el 15 de diciembre de 2024. Este ejemplo reconoce un mes completo al inicio de cada mes; no prorratea enero. Después de la última liberación, Assets:Prepaid:Software es cero y Expenses:Software:Adobe suma 1200.00 USD.

Anticipo a Cuenta de Servicios Profesionales

Este ejemplo independiente trata el pago de $4,500 del 5 de enero como una tarifa prepagada consumida por igual en enero, febrero y marzo:

python3 amortize.py retainer > retainer.beancount
uvx --from beancount-io==0.1.0 bea --file retainer.beancount check

Tres liberaciones de 1500.00 USD, fechadas el 5 de enero, el 5 de febrero y el 5 de marzo de 2024, dejan Assets:Prepaid:Professional en cero y Expenses:Professional:Legal en 4500.00 USD. Para un anticipo a cuenta devengado a medida que se prestan los servicios, reemplaza esta suposición con el calendario de servicios real.

Depreciación de Equipos (Activos Fijos)

La depreciación de activos fijos utiliza una cuenta de contrapartida de activo para preservar el costo de compra. Este ejemplo asume una vida útil de tres años, valor residual cero y reconocimiento mensual completo a partir del 20 de enero de 2024:

python3 amortize.py equipment > equipment.beancount
uvx --from beancount-io==0.1.0 bea --file equipment.beancount check

La compra debita Assets:Equipment:Computers:Cost por 3000.00 USD una sola vez. Las 36 liberaciones debitan Expenses:Depreciation:Computers y acreditan Assets:Equipment:Computers:AccumDep. Las liberaciones 1–35 son de 83.33 USD; la liberación 36 del 20 de diciembre de 2026 es de 83.45 USD. Así, 35 × 83.33 + 83.45 = 3000.00. Usar 83.33 USD para las 36 dejaría 0.12 USD sin depreciar.

Al finalizar, el costo permanece en 3000.00 USD, la depreciación acumulada es -3000.00 USD y su valor contable neto es cero. La cuenta de contrapartida de activo en sí no vuelve a cero mientras el equipo aún esté registrado.

Informes y Verificación

1. Monitorear los Saldos Prepagados con Aserciones

Beancount verifica un saldo al inicio de su fecha, antes de las transacciones de ese día. Agrega este bloque de aserciones contextuales al insurance.beancount generado y luego vuelve a ejecutar su comando bea check:

2024-06-02 balance Assets:Prepaid:Insurance 500.00 USD
2024-07-02 balance Assets:Prepaid:Insurance 400.00 USD
2024-07-02 balance Expenses:Insurance:Auto 200.00 USD
2024-11-02 balance Assets:Prepaid:Insurance 0.00 USD
2024-11-02 balance Expenses:Insurance:Auto 600.00 USD

El 2 de julio sigue a dos liberaciones, el 1 de junio y el 1 de julio. Una aserción de 500.00 USD el 2 de julio es incorrecta. Estas aserciones necesitan el libro contable de seguro generado; no son transacciones independientes.

2. Verificación Avanzada con bea query

Con el archivo de seguro generado, este comando ejecutable devuelve los saldos acumulados hasta el 1 de julio, utilizando un corte excluyente del 2 de julio:

uvx --from beancount-io==0.1.0 bea --file insurance.beancount query "SELECT account, sum(position) WHERE date < 2024-07-02 AND account ~ '^(Assets:Prepaid:Insurance|Expenses:Insurance:Auto)$' GROUP BY account ORDER BY account"

Espera Assets:Prepaid:Insurance en 400.00 USD y Expenses:Insurance:Auto en 200.00 USD. Agrupar por fecha en su lugar mostraría el movimiento de cada día en lugar de un saldo acumulado.

Para ver cualquier archivo generado en la versión local probada de Fava, usa:

uv run --no-project --with beancount==3.2.3 --with beanquery==0.2.0 --with fava==1.30.16 fava insurance.beancount

Abre la URL local que Fava imprime. Consulta la referencia de opciones de Fava para la configuración. Selecciona el período de informe explícitamente: el generador emite el calendario completo, incluidas fechas futuras, por lo que un total sin restricciones incluye liberaciones futuras. Para archivos de planificación separados, consulta el flujo de trabajo de escenarios de pronóstico.

Limitaciones y Consejos Finales

  • Las fechas son explícitas: Cambiar una fecha de compra no difiere silenciosamente la primera liberación. En este script, la primera liberación es igual a la fecha de pago; adapta el inicio por separado si el servicio comienza más tarde.
  • El redondeo ocurre una vez: El script redondea el monto mensual regular a céntimos y luego coloca el remanente en la liberación final. Conserva el calendario completo generado para preservar ese ajuste.
  • Las entradas ordinarias persisten: Estas liberaciones se guardan en el archivo generado. Revísalas y regístralas una sola vez. No habilites también la amortización automática para el mismo costo, o el gasto se reconocería dos veces.
  • Elige el calendario contable: Estos son ejemplos de gestión, no reglas fiscales específicas de una jurisdicción. Para beneficios irregulares o prorrateo diario, calcula y registra los montos y fechas reales en su lugar.

Fuente: https://beancount.io/es/docs/Tips/amortize