Facturación + Contabilidad Pyme
Un mensaje desordenado → factura, registro de gastos y el próximo borrador de recordatorio. Sin cuenta, sin suscripción, sin compromiso — tu dinero, en archivos que te pertenecen.
Las pequeñas empresas no fracasan por el trabajo. Fracasan por la espera: alrededor del 55% de las facturas B2B en América del Norte se pagan tarde (Atradius, a través de Crestmont Capital, actualizado 2026), las pequeñas empresas estadounidenses esperaron en promedio 29,3 días para cobrar en el segundo trimestre de 2026, ~9 días después de la fecha de vencimiento (Xero Small Business Insights, a través de Foundrly, agosto 2026), y el 82% de los fracasos de pequeñas empresas se atribuyen a problemas de flujo de caja (Cámara de Comercio de EE. UU., a través de Crestmont, 2026). La probabilidad de cobrar cae rápidamente con el tiempo: más del 95% en los primeros 30 días si se hace un seguimiento proactivo, hasta un 20-30% más allá de 120 días (Crestmont, 2026). La factura es la parte fácil. El seguimiento es el producto — y en todas partes el seguimiento está sujeto a pago: los recordatorios automáticos son solo para Pro en Wave ($19/mes) e Invoice Ninja ($14/mes) (páginas de precios de los proveedores, noviembre 2026), Wave no puede enviar facturas fuera de EE. UU./Canadá (soporte de Wave, 8 de septiembre de 2026), y el plan gratuito de Zoho Invoice limita a 500 facturas/año y elimina datos inactivos después de 180 días (zoho.com/invoice/pricing, consultado el 2026-11-11). Esta habilidad redacta el seguimiento de forma gratuita.
Versión 0.2.0. Reconstruida a partir de la revisión adversarial de la v0.1.0 (20 brechas, todas corregidas o registradas en
MEASUREMENTS.md§11) y las correcciones de investigación profunda (research-notes-v2.md§1). Lo que cambió está enCHANGELOG.md. Los números a continuación son ejecuciones reales con los datos de muestra incluidos, no estimaciones.
No es asesoramiento legal, fiscal ni financiero. Esta habilidad te ayuda a crear facturas y realizar un seguimiento del dinero. Las tasas impositivas, los umbrales de registro y los requisitos de facturación difieren según el país y cambian con el tiempo. Establece tu propia tasa impositiva y confirma las reglas para tu negocio con la autoridad fiscal local (en Bangladesh: la Junta Nacional de Ingresos, nbr.gov.bd) o un contador calificado. Este descargo de responsabilidad también se imprime en el pie de página de cada factura y recibo generado — en bengalí en los documentos en bengalí. Para las reglas de mantenimiento de registros subyacentes (qué conservar, TIN/BIN en facturas, formularios Mushak, retención), consulta el compañero de referencia: la habilidad
bd-bookkeepingde OpenAccountants (openaccountants/openaccountants, 484★, actualizado 2026-11-11) — una guía de referencia en inglés, explícitamente "solo referencia general… no revisada para los hechos de ninguna persona en particular". No genera facturas. Esta habilidad sí lo hace.
Ejecutarlo
python3 scripts/bookkeeper.py <comando>
Python ≥ 3.9, solo biblioteca estándar. Sin paso de instalación, sin dependencias, sin llamada de red, sin clave API, sin cuenta. Los datos viven en archivos JSON simples que puedes abrir, copiar y llevar a cualquier lugar.
Reglas del dinero: léelas antes de confiar en cualquier número
Estas son las reglas que hacen que los totales sean fiables, y las que la revisión de la v0.1.0 detectó que esta habilidad incumplía:
- El dinero se redondea hacia arriba a la mitad (
ROUND_HALF_UP), como redondea el dueño de una tienda con una calculadora — nunca redondeo bancario. ৳2.345 es ৳2.35. - Las cantidades son exactas, nunca redondeadas como dinero. Una cantidad de 1.005 es 1.005; solo el total de la línea se redondea. Las cantidades se imprimen sin ceros finales (3, nunca 3,00).
- El impuesto es por línea, sobre el importe de la línea con descuento — el impuesto de cada línea se redondea hacia arriba a la mitad en esa línea, luego se suma (como lo hacen Wave / Xero / FreshBooks). 3 líneas de ৳0,35 con un impuesto del 15% = ৳0,15, no ৳0,16.
- El estado de pago proviene del saldo, nunca de la cadena de estado. Una factura marcada como "pagada" que aún adeuda ৳4.000 reporta ৳4.000 adeudados, y el informe dice que el estado es incorrecto. El estado es una pista; el estado de vencimiento se deriva de la fecha de vencimiento y el saldo.
- El dinero nunca se suma entre divisas. Un libro contable con múltiples divisas reporta totales por divisa (৳5.000 + $100) y rechaza un total combinado y un neto combinado — la habilidad no tiene tipo de cambio y lo indica.
- Un problema en el libro contable es ruidoso y provoca la salida con código 2.
overdueycashflowsalen con código 2 cuando se omite una fila (datos no válidos), un número está duplicado, una factura "pagada" aún tiene saldo, un pago sobrepaga, o un pago no tienepaid_date. El informe aún se imprime; el código de salida indica que se debe corregir el libro contable antes de confiar en él. - El dinero negativo imprime el signo menos primero: −৳4.100 — una convención, en todas partes.
El flujo de trabajo: una entrada → factura → recibo → recordatorio → flujo de caja
1. Factura, cotización o recibo a partir de una entrada JSON
python3 scripts/bookkeeper.py invoice --input samples/invoice-input.json --out out/invoice.html --config config/bd.json
python3 scripts/bookkeeper.py invoice --input samples/invoice-input-bn.json --out out/invoice-bn.html --config config/bd.json --lang bn
python3 scripts/bookkeeper.py invoice --input my-quote.json --out out/quote.html --format md
python3 scripts/bookkeeper.py receipt --input samples/invoice-input.json --out out/receipt.html --paid-date 2026-11-05 --amount-paid 4500
- La entrada es un pequeño archivo JSON: datos del negocio + cliente + líneas de artículo
(descripción, cantidad, precio unitario) + número de factura + fecha de emisión +
fecha de vencimiento. Consulta
samples/invoice-input.jsonpara la forma exacta. - Cotización → factura → recibo es un solo ciclo de vida, un solo modelo de datos.
type: "quote"necesitavalid_untilen lugar de una fecha de vencimiento; una factura necesita una fecha de vencimiento de calendario real, no solo "Neto 30"; un recibo se genera a partir de una factura pagada con--paid-datey--amount-paidy muestra el বাকি (saldo pendiente) restante si el pago fue parcial. Se rechaza un recibo con un importe de 0 — un recibo confirma dinero recibido. Una cotización nunca muestra filas de pagado/saldo (no se debe nada en una propuesta), en HTML o Markdown, y su número está etiquetado como "Número de cotización", no "Número de factura". - La factura lleva los campos que toda factura necesita (notas de investigación §3.1): la palabra "Factura", un número secuencial único, fecha de emisión, fecha de vencimiento, datos del vendedor, datos del comprador, descripciones específicas, líneas de artículo, impuesto como línea separada, instrucciones de pago + total adeudado. Se hace referencia a un número de cotización en la factura cuando existe; el número de orden de compra (PO) del cliente y el número de registro fiscal del vendedor (tax_id — en Bangladesh, el BIN de 13 dígitos) se imprimen en la factura cuando se proporcionan.
- La numeración es secuencial (
INV-2026-001,INV-2026-002, …). Nunca omitir ni reutilizar un número: un salto o duplicado parece ingresos faltantes o un gasto inventado en el momento de declarar impuestos. Los comandos del libro contable advierten en voz alta y salen con código 2 si hay un número duplicado. Elnumbering_prefixde la configuración se verifica con el número de factura (una advertencia, no un error);default_termscompleta la línea de Términos cuando la entrada no tiene ninguno. - La salida es HTML limpio e imprimible (ábrelo en un navegador, imprime a PDF)
o Markdown (
--format md). Sin recursos externos en el HTML, por lo que se imprime exactamente como se ve — las muestras enviadas se procesaron en Chromium sin cabeza y se imprimieron a PDF una vez (consultaMEASUREMENTS.md§11.6, capturas de pantalla endocs/). - El dinero se calcula con
Decimal, nunca con flotante. El descuento es un porcentaje del subtotal, aplicado por línea; el impuesto es por línea sobre el importe descontado (consulta "Reglas del dinero"). - La validación es estricta y el código de salida es 2 en caso de entrada incorrecta: falta la fecha de vencimiento, cantidad o precio negativos, tasa impositiva fuera del 0-100%, fechas incorrectas, JSON mal formado, archivo faltante, fecha de vencimiento anterior a la fecha de emisión, pago con fecha anterior a la fecha de emisión. Se permite una factura con cero artículos (total ৳0) pero imprime una advertencia — es un borrador, no un error que ocultar. Pagar de más un documento imprime una advertencia en ambos comandos de documento (un recibo nunca debe mostrar "Saldo pendiente: ৳-825").
2. Impuesto: una configuración que escribes, nunca una tasa fija
# En la entrada de la factura (este es el ÚNICO lugar donde vive una tasa):
"tax": {"name": "IVA", "rate_percent": 15}
- Ninguna herramienta tiene una tasa fija, y esta habilidad tampoco. Toda herramienta de facturación (Zoho, FreshBooks, Wave, Xero — notas de investigación §5.1) permite al usuario definir un impuesto con nombre + porcentaje, lo aplica por línea y lo muestra como una línea separada. Esta habilidad copia eso exactamente: el impuesto es un impuesto con nombre + tasa % en la entrada, por defecto 0% / sin impuesto.
- Los ajustes preestablecidos por país en
config/proporcionan la etiqueta del impuesto, la moneda, los métodos de pago, los términos predeterminados y el prefijo de numeración — nunca una tasa.config/bd.json(Bangladesh: ৳, "IVA", bKash / Nagad / Rocket / transferencia bancaria / efectivo) yconfig/us.json(EE. UU.: $, "Impuesto sobre las ventas", Neto 30).tax_rate_percenten ambas configuraciones esnulla propósito. Untax_iden la configuración (tu BIN) completa la factura cuando la entrada no tiene ninguno. - La factura de muestra utiliza un IVA del 15% porque la entrada de muestra lo indica — la tasa estándar de IVA de Bangladesh es del 15% según la Ley de IVA e Impuesto Suplementario de 2012 (ArthiKalap, actualizado el 25 de julio de 2026; TRW, FY 2026-27; TaxDo, 2026; SDTT Academy, principios de 2026) — pero la habilidad no lo sabe y nunca se debe citar como si lo supiera. Las declaraciones de IVA son mensuales nuevamente (vencen dentro de los 15 días): la Ley de Finanzas 2026 las hizo trimestrales a partir del 1 de julio de 2026, pero una ordenanza de enmienda publicada en la gaceta el 14 de octubre de 2026 restableció las declaraciones mensuales (TRW "Doing Business in Bangladesh 2026", ley vigente al 24 de octubre de 2026; entrepreneurs.bd, 2026). Cualquier línea "trimestral" en notas anteriores ahora es incorrecta.
- Los umbrales de registro NO están codificados en esta habilidad. Tres guías independientes de octubre a noviembre de 2026 ahora convergen en las mismas cifras: registro obligatorio por encima de Tk 50 lakh de facturación anual; alistamiento para Tk 30–50 lakh al 4% de impuesto sobre la facturación; algunas actividades se registran independientemente de la facturación (TRW "VAT in Bangladesh 2026", posición del 18 de octubre de 2026; TRW "VAT Registration"; entrepreneurs.bd, 2026; Aniday, verificado en septiembre de 2026). Pero la verificación directa contra la NBR no se logró: la página de inicio de la NBR (cargada el 2026-11-11) no contiene texto sobre umbrales, y vat.gov.bd no se pudo alcanzar ese día. Por lo tanto, estas cifras se informan aquí como fuentes secundarias convergentes, no un hecho verificado por la NBR — la habilidad nunca establece un umbral como propio y dirige a los usuarios a nbr.gov.bd. El BIN tiene 13 dígitos (listado de servicios de la página de inicio de la NBR, 2026-11-11 — una etiqueta, no una gaceta; confirma el número de dígitos en la guía de registro de IVA de la NBR cuando verifiques los umbrales).
- Los precios con impuestos incluidos son compatibles:
"tax": {"name": "IVA", "rate_percent": 15, "inclusive": true}extrae el impuesto del precio bruto (IVA = bruto × 15 ÷ 115). Medido enMEASUREMENTS.md§5: ৳1.150 brutos → ৳150 de IVA, el total se mantiene en ৳1.150.
3. Registro de gastos: lenguaje sencillo, archivos sencillos
python3 scripts/bookkeeper.py expense add --ledger gastos.json --date 2026-11-11 --category Materiales --amount 1200 --note "alambre de cobre, 20 m"
python3 scripts/bookkeeper.py expense list --ledger gastos.json --month 2026-11
python3 scripts/bookkeeper.py expense export --ledger gastos.json --out gastos.csv
- Un gasto = fecha, categoría, importe, nota. El libro contable es una lista
JSON;
exportescribe un CSV que se abre en cualquier hoja de cálculo. - Las categorías están en lenguaje sencillo, no en un plan de cuentas: Materiales,
Transporte, Herramientas, Móvil/internet, Comidas, Alquiler, Mano de obra, Empaque,
Otros. Una categoría desconocida es un error, nunca se acepta en silencio.
Se rechazan los importes negativos.
--monthdebe ser unYYYY-MMreal (2026-1se rechaza: una coincidencia de prefijo sin formato fusionaría octubre y noviembre en silencio). - Una fila del libro contable que no sea un objeto se omite en voz alta con una advertencia
y código de salida 2 — nunca un traceback, nunca en silencio.
expense addse niega a reescribir un libro contable que contenga una fila rota (arréglala primero).
4. Seguimiento de vencidos + borradores de recordatorio: el núcleo de la habilidad
python3 scripts/bookkeeper.py overdue --invoices samples/invoices.json --as-of 2026-11-11
python3 scripts/bookkeeper.py overdue --invoices samples/invoices.json --as-of 2026-11-11 --lang bn --json
- Escanea el libro contable de facturas, enumera cada factura abierta por tramo de antigüedad (actual / 1–30 / 31–60 / 61–90 / 90+ días vencidos) y redacta el próximo recordatorio en la etapa correcta para cada una.
- La secuencia de 6 etapas (el consenso de 5 contactos de Raoura, verificado en julio de 2026; InvoiceCub, 31 de octubre de 2026; InvoiceFly, ~noviembre de 2026; HeroThemes, ~agosto de 2026; FreelanceDesk, ~junio de 2026 — antes del vencimiento, fecha de vencimiento, 7, 14, 30 días — más el aviso amistoso temprano para 1–6 días vencido de la versión de 7 contactos; el contacto adicional de 21 días de la versión de 7 contactos no es una etapa separada, su terreno está cubierto por el borrador de 14 días cuyo próximo contacto es el día 30): 3 días antes del vencimiento, en la fecha de vencimiento, 7 días vencido, 14 días vencido, 30 días aviso final, más el aviso de 1 a 6 días. Escalada gradual, nunca acusación primero: asume buenas intenciones al principio (olvidó / enterrado / en una cola de aprobación); menciona un recargo por mora solo cuando el acuerdo lo prevé y la factura tiene ~2 semanas de vencida. Cada borrador reafirma el número de factura, el importe, la fecha de vencimiento original — y los reales días de vencimiento (a una factura de 8 días se le dice "8 días vencida", nunca el número de etapa).
- Solo borradores — la habilidad nunca envía nada. Tú envías
el recordatorio. El informe también imprime la próxima fecha de contacto, para que la
escalada no dependa de recordarla. Una próxima fecha de contacto que ya pasó
se imprime como "enviar ahora (vencía el …)", nunca como una fecha pasada sin más. El
aviso final da un plazo de al menos 7 días a partir de hoy (
max(vencimiento + 37 días, as-of + 7 días)) — una exigencia cuyo plazo ya pasó es peor que ninguna exigencia. - Medido en las muestras (al 2026-11-11): 6 facturas abiertas, ৳48.650
adeudados (বাকি), 4 vencidas por un total de ৳28.250 — una en cada
etapa, desde el aviso hasta el aviso final. Consulta
MEASUREMENTS.md§3. - Las facturas borrador se excluyen de "adeudados a ti" — una factura no enviada no es dinero aún adeudado. Las facturas pagadas (saldo 0) también se excluyen. (Las empresas que hacen seguimiento del 100% de las facturas vencidas tienen un 76% más de probabilidades de cobrar en una semana — Informe AR 2026 de Chaser, a través de Raoura, de segunda mano.)
5. Vista simple de flujo de caja: los números que el dueño realmente revisa
python3 scripts/bookkeeper.py cashflow --invoices samples/invoices.json --expenses samples/expenses.json --as-of 2026-11-11
python3 scripts/bookkeeper.py cashflow --i