EN|ES
← proyectos/
catoca-ventas.nest.tsEn desarrollo

CATOCA · Sistema de ventas

Ventas, inventario por lotes, comisiones y prefacturación DIAN para una exportadora de café

empresa:
CATOCA (cliente)
periodo:
Sep 2026 — en curso
  • NestJS 12
  • Fastify
  • Drizzle ORM
  • PostgreSQL 18
  • React 19
  • Vite 8
  • TanStack Router / Query
  • Tailwind CSS 4
  • Zod (contratos compartidos)
  • Vitest
  • Testcontainers
  • Playwright
  • Docker + Nginx

// problema

Las ventas de los vendedores, el inventario y las comisiones se llevaban por separado y a mano. La tienda en línea no descontaba inventario, y la contadora tenía que reconstruir cada factura para cargarla en Siigo.

// mi rol

Arquitectura y desarrollo completo por fases: modelo de datos, API NestJS con Drizzle sobre PostgreSQL 18, panel web en React, integración con la tienda en línea y con Wompi, y la estrategia de pruebas.

// arquitectura

Panel webReact 19 · TanStack
catoca.cafeAPI Key + HMAC
Wompiwebhook firmado
NginxTLS · rate limit · SPA
APINestJS · Fastify · Drizzle
PostgreSQL 18kardex · auditoría
Prefacturascampos DIAN
Exporte Siigo.xlsx contable

La tienda en línea crea pedidos con API Key + HMAC y Wompi confirma el pago con un webhook firmado; ambos se convierten en ventas del canal web.

// decisiones técnicas

Dinero exacto y tarifas guardadas en cada venta

Montos en numeric(18,2), siempre en COP. El IVA se calcula acumulando la base por tarifa y redondeando una sola vez sobre el total (ROUND_HALF_UP). Cada venta guarda la tarifa de IVA y el porcentaje de comisión con que se calculó, y esas tarifas solo las cambia el admin, con historial.

Inventario por lotes con kardex y salida FIFO

Cada entrada exige fecha de lote y de tostión. Las ventas consumen los lotes más antiguos primero, cada movimiento queda en el kardex y el sistema no deja vender sin stock.

Ventas inmutables y auditadas

El vendedor siempre es el usuario autenticado y no puede editar una venta guardada. Solo el admin edita, con motivo obligatorio y revisión antes/después. Una anulación devuelve el inventario y anula la comisión (con ajuste negativo si ya se pagó); una devolución devuelve el inventario pero no toca la comisión.

Pruebas como especificación

Cobertura del 100 % obligatoria, pruebas de API contra PostgreSQL real con Testcontainers y E2E con Playwright. Una prueba ya commiteada nunca se modifica para que el código pase: un hook bloquea su edición y un script lo verifica contra main.

// impacto

Cobertura de pruebas
100%

umbral obligatorio en Vitest

Módulos del backend
14
Canales de venta
3

vendedor · tienda web · admin

Contabilidad
Siigo

exporte .xlsx por rango de fechas

// capturas

Dashboard del administrador: ventas por mes y por canal
Dashboard del administrador: ventas por mes y por canal
Dashboard del vendedor: ventas y comisión del mes
Dashboard del vendedor: ventas y comisión del mes
Registrar una venta con IVA calculado
Registrar una venta con IVA calculado
Ventas registradas con estado de pago
Ventas registradas con estado de pago
Comisiones: aprobación y liquidación por vendedor
Comisiones: aprobación y liquidación por vendedor
Inventario por lotes con fecha de tostión
Inventario por lotes con fecha de tostión

Repositorio privado. Capturas tomadas de una instalación local con datos de demostración, no de la operación real.