Backend · documento oficial
Contrato vigente de la API. Refleja el modelo de Las tablas del negocio y los roles de Roles y permisos.
El motor (Django + Django REST Framework) expone una API REST en JSON, versionada bajo /api/v1/. La intranet y la tienda pública son clientes ligeros: solo piden y presentan datos; todas las reglas —descontar stock, calcular el costo en soles, encolar la emisión a SUNAT— viven aquí.
/api/v1/.JSON (salvo subida de fotos, multipart). Fechas ISO 8601, montos como número.JWT (rest_framework_simplejwt) en Authorization: Bearer …, 8 h de vida. El catálogo y las fotos son de lectura pública sin token.?page=, 25 por página), con ?buscar= (búsqueda) y filtros propios de cada recurso (?categoria=, ?estado=…).200/201 bien, 400 datos inválidos, 401/403 sin permiso, 404 no existe, 409 conflicto de negocio (sin stock, orden ya recibida…).| Endpoint | Qué hace y reglas |
|---|---|
POST /auth/login { email, password } → { access, refresh } | Valida credenciales y devuelve un JWT con el rol dentro. Además abre una sesión Django compartida (cookie Domain=.importacionleon.com) para que Documentation reconozca la sesión sin manejar el JWT. |
POST /auth/registro { nombre, email, password, rol } → 201, sin token Público, sin autenticación | Autoregistro del equipo. Crea la cuenta ya bloqueada (activo=false, aprobado=false); no admite pedir el rol admin. Queda visible en /equipo hasta que un admin la apruebe. |
POST /auth/refresh | Renueva el token antes de que caduque (7 días de vida el refresh, rota en cada uso). |
POST /auth/logout | Invalida (blacklist) el refresh token y cierra también la sesión Django compartida. |
GET /auth/verificar | Solo mira la cookie de sesión (no el JWT); la usa nginx (auth_request) para proteger Documentation. 401 si no hay sesión o la cuenta ya no está activo. |
GET /auth/yo | El usuario en sesión: email, nombre, rol, activo y tema. |
GET/PATCH /auth/preferencias | Lee o cambia la preferencia de tema claro/oscuro del usuario en sesión. La fuente de verdad es esta; el navegador solo cachea el último valor. |
| Endpoint | Qué hace y reglas |
|---|---|
GET /equipo ?activo=&aprobado=&rol= | Lista el equipo interno, incluidas las solicitudes de autoregistro (aprobado=false). |
POST /equipo | Alta directa. Aprovisiona la credencial y devuelve password_temporal una única vez; no hay envío de correo con la contraseña. |
PATCH /equipo/{id} | Edita nombre, rol o activo; sincroniza la credencial (staff/superusuario según el rol). |
POST /equipo/{id}/aprobar | Aprueba una solicitud de autoregistro y avisa por correo (best-effort: si no hay SMTP, la aprobación se aplica igual). |
POST /equipo/{id}/rechazar | Borra una solicitud de autoregistro aún no aprobada, junto con su credencial. |
| Endpoint | Qué hace y reglas |
|---|---|
GET /productos ?buscar=&categoria=&proveedor_principal=&activo= | Lista productos con sus variantes. ?buscar= usa pg_trgm sobre nombre/marca. |
POST/PATCH/DELETE /productos/{id} | Crear/editar/borrar. Borrar da 409 si el producto tiene variantes con historial (ventas, compras o movimientos). |
GET /variantes/{id} | El SKU real, con stock e imagenes calculados (cruza con leon_fotos por variante_id). |
GET /variantes/{id}/stock | El stock calculado (nunca escrito): stock (físico), reservado y disponible (físico − reservado), más el físico por almacén. |
GET /categorias ?buscar= | Árbol de categorías (con padre_id). Borrar da 409 si tiene productos. |
| Endpoint | Qué hace y reglas |
|---|---|
GET /almacenes | Las zonas físicas, con espacio_disponible calculado. Borrar da 409 si tiene movimientos. |
GET /movimientos ?variante=&almacen=&tipo= | El historial de entradas/salidas. |
POST /movimientos | Registra un ajuste o merma a mano — sin PATCH ni DELETE en este recurso. Las compras y ventas generan su movimiento automáticamente vía recibir/confirmar, no por aquí. |
| Endpoint | Qué hace y reglas |
|---|---|
GET /proveedores | Fábricas y mayoristas, con sus productos anidados. Borrar da 409 si tiene órdenes o muestras. |
POST /ordenes-compra ?proveedor=&estado= | Crea un pedido a un proveedor con sus líneas. Guarda tipo_cambio para el costo real en soles. |
PATCH /ordenes-compra/{id} | Avanza el estado (pedido → producción → tránsito → recibido) o edita datos generales. |
POST /ordenes-compra/{id}/recibir { almacen } | Genera las entradas de stock de todas las líneas, en una transacción. 409 si ya estaba recibida (idempotencia). |
GET /embarques ?orden_compra= | Incoterm, contenedor, fechas, y sus costos/documentos anidados (flete, aduana, seguro). |
GET /muestras | Control de calidad previo a importar. Sin interfaz propia en la intranet hoy — solo API. |
| Endpoint | Qué hace y reglas |
|---|---|
GET /clientes ?buscar= | Personas y empresas. El doc_tipo (DNI/RUC) decide boleta o factura. |
POST /pedidos { …, es_reserva, almacen, fecha_expiracion, tipo_comprobante } | Crea una venta con sus líneas. Un pedido normal no verifica stock al crear. Un pedido a futuro (es_reserva) genera una reserva por línea en el almacen indicado — 409 si pide más que el disponible. tipo_comprobante se deriva del documento del cliente; Factura exige RUC (400 si no). |
PATCH /pedidos/{id} | Edita líneas solo en pendiente (ajusta las reservas en la misma transacción). Cambios de estado permitidos: pendiente→enviado/anulado, pagado→enviado/anulado, enviado→entregado/anulado. Prohibido salir de entregado/anulado/expirado, poner pagado (usa confirmar) o expirado a mano (solo la tarea). |
POST /pedidos/{id}/confirmar { almacen } — no hace falta en reservas | Pasa el pedido a pagado generando la venta real. En un pedido normal descuenta del almacén indicado (todo o nada; 409 con el detalle si no alcanza). En un pedido a futuro consume la reserva en su propio almacén. Transacción atómica. |
GET /pedidos/{id} | Detalle con líneas; el total no es una columna, se calcula sumándolas. |
POST /envios ?pedido=&estado= | Registra el despacho. courier/tracking son texto libre — sin API de courier real conectada. |
| Endpoint | Qué hace y reglas |
|---|---|
POST /comprobantes ?pedido=&estado_sunat=&tipo= | Registra el comprobante y encola emitir_comprobante_sunat (Celery); responde 202. La tarea simula el envío y marca aceptado — no hay integración SUNAT real. |
GET /comprobantes/{id} | Estado SUNAT (siempre aceptado tras el simulacro). El XML/CDR vive en /documentos-sunat. |
POST /notas-credito | Devolución o anulación que referencia al comprobante original. Sin interfaz propia en la intranet hoy — solo API. |
POST /pagos ?pedido=&estado=&metodo= | Registra el cobro (Yape, Plin, tarjeta, transferencia, efectivo). Sin interfaz propia para crear pagos en la intranet — solo API. |
POST /pagos/{id}/confirmar | Marca el pago confirmado y, si la suma cubre el total, pasa el pedido a pagado. Esta acción sí está en la intranet (Facturación). |
| Endpoint | Qué hace y reglas |
|---|---|
GET /imagenes ?variante_id=&sku= | Lista imágenes de una variante. Público, sin token. |
POST /imagenes multipart: variante_id, sku, archivo, alt?, orden? | Sube la foto (guarda el render "original") y encola procesar_imagen (conversión real a WebP con Pillow) sin bloquear la respuesta (201). |
GET /imagenes-render/{id}/archivo | Sirve el binario (modo autónomo, el usado hoy) o redirige a una URL de CDN si está configurada. Siempre público (AllowAny), para que un <img src> funcione sin JWT. |
ReadOnlyModelViewSet: el documento lo genera la tarea Celery, no se crea por API.| Endpoint | Qué hace y reglas |
|---|---|
GET /documentos-sunat ?comprobante_id=&estado_sunat=&tipo=&receptor_doc= | Lista los documentos generados (siempre simulados hoy). |
GET /documentos-sunat/{id} | Detalle con sus eventos anidados (generado → enviado → aceptado). |
annotate/aggregate), nunca trayendo datos crudos. Mismo selector de periodo (?desde=&hasta=) en todos salvo stock-bajo.| Endpoint | Qué hace y reglas |
|---|---|
GET /reportes/ventas ?desde=&hasta= | Ventas por día/semana/mes (granularidad automática), variación vs. periodo anterior de igual duración, ticket medio, top productos. |
GET /reportes/stock-bajo | Variantes bajo mínimo, con nivel de urgencia (agotado/crítico/bajo). Foto de "ahora", sin periodo. |
GET /reportes/inventario ?desde=&hasta= | Valor de inventario (foto de hoy), entradas vs. salidas del periodo, SKU con stock parado. |
GET /reportes/compras ?desde=&hasta= | Compras por proveedor en el periodo, pendientes de recibir (snapshot). |
GET /reportes/rentabilidad ?desde=&hasta= | Margen bruto global y por producto, con el costo actual de la variante (no hay coste histórico por venta). |
SoloAdminOSistemas) — el único recurso sin lectura abierta a cualquier autenticado.| Endpoint | Qué hace y reglas |
|---|---|
GET /actividad ?usuario=&accion=&modelo_afectado=&buscar=&desde=&hasta= | Registro de auditoría, solo lectura, paginado de 50 en 50. Ver Registro de actividad. |
GET /salud | Health check: responde si el motor y la base están vivos. Sin autenticación. |
Tres reglas atraviesan toda la API: el stock se calcula (nunca se fija por endpoint — ver Cómo se deriva el stock), confirmar pedido y recibir orden son transacciones que no dejan estados a medias, y lo lento (SUNAT, fotos) es asíncrono vía Celery — aunque hoy SUNAT es un simulacro, no una integración real. Además, una tarea de Celery beat (apps.principal.tasks.expirar_reservas_vencidas, cada hora en punto) libera las reservas de los pedidos a futuro vencidos y los marca expirado; es idempotente y atómica por pedido (ver Tareas automáticas). El detalle de cada tabla está en Las tablas del negocio; el panorama de componentes, en El motor.