Descripción General
El endpoint de Compras permite gestionar las compras realizadas a proveedores, incluyendo el registro de productos adquiridos, control automático de inventario, gestión de documentos (facturas, boletas), y seguimiento de pagos al contado o a crédito.
Cada compra registrada actualiza automáticamente el stock de los productos y genera movimientos de inventario para trazabilidad completa.
Permisos Requeridos
Las operaciones en este endpoint requieren los siguientes permisos:
compras.view - Ver listado y detalle de compras
compras.create - Crear nuevas compras
compras.edit - Actualizar compras existentes
compras.delete - Eliminar y anular compras
Los usuarios con rol de Administrador (rol_id=1) tienen acceso automático a todas las operaciones.
Listar Compras
Obtiene el listado completo de compras de la empresa del usuario autenticado, ordenadas por ID descendente (más recientes primero).
Token de autenticación Bearer
Accept
string
default: "application/json"
Tipo de contenido aceptado
Permisos
Requiere permiso: compras.view
Respuesta Exitosa
Indica si la operación fue exitosa
Array de compras Show Estructura de cada compra
Número de documento formateado (serie-número con 8 dígitos) Ejemplo: F001-00000042
Serie del documento (máx. 4 caracteres)
Número correlativo del documento
Fecha de emisión del documento (formato: Y-m-d)
Fecha de vencimiento para compras a crédito (formato: Y-m-d)
Información del proveedor Show Campos del proveedor
Razón social o nombre comercial
Tipo de pago: “Contado” o “Crédito”
ID del tipo de pago (1=Contado, 2=Crédito)
Código de moneda: “PEN” (Soles) o “USD” (Dólares)
Monto total de la compra (formato decimal con 2 decimales)
Estado de la compra: “1” (Activo) o “0” (Anulado)
Nombre legible del estado: “Activo” o “Anulado”
Nombre del usuario que registró la compra
Fecha y hora de creación (formato: Y-m-d H:i:s)
Ejemplo de Solicitud
curl --request GET \
--url https://tu-dominio.com/api/compras \
--header 'Authorization: Bearer tu_token_aqui' \
--header 'Accept: application/json'
Ejemplo de Respuesta
{
"success" : true ,
"data" : [
{
"id_compra" : 42 ,
"documento" : "F001-00000042" ,
"serie" : "F001" ,
"numero" : "42" ,
"fecha_emision" : "2026-03-04" ,
"fecha_vencimiento" : "2026-04-04" ,
"proveedor" : {
"proveedor_id" : 15 ,
"ruc" : "20123456789" ,
"razon_social" : "DISTRIBUIDORA COMERCIAL SAC"
},
"tipo_pago" : "Crédito" ,
"id_tipo_pago" : 2 ,
"moneda" : "PEN" ,
"total" : "5420.00" ,
"estado" : "1" ,
"estado_nombre" : "Activo" ,
"usuario" : "Juan Pérez" ,
"created_at" : "2026-03-04 14:30:22"
}
]
}
Crear Compra
Registra una nueva compra a proveedor. Automáticamente actualiza el inventario de productos, genera movimientos de stock, y crea cuotas de pago si es a crédito.
Token de autenticación Bearer
Content-Type
string
default: "application/json"
Tipo de contenido de la solicitud
Permisos
Requiere permiso: compras.create
Parámetros del Body
ID del proveedor (debe existir en la tabla proveedores)
ID del tipo de documento según tabla documentos_sunat Ejemplos comunes:
1 = Factura
3 = Boleta de Venta
Serie del documento (1-4 caracteres alfanuméricos en mayúsculas) Ejemplos: F001, B001, NC01
Número correlativo del documento (solo dígitos, máximo 8)
Fecha de emisión del documento (formato: Y-m-d)
Fecha de vencimiento para compras a crédito (formato: Y-m-d)
Código de moneda:
PEN = Soles Peruanos
USD = Dólares Americanos
Array de productos comprados (mínimo 1 producto) Show Estructura de cada producto
ID del producto (debe existir en tabla productos)
Cantidad comprada (mínimo 0.01)
Costo unitario del producto (mínimo 0)
Array de IDs de empresas asociadas a la compra (para compras compartidas)
Array de cuotas de pago (requerido si id_tipo_pago = 2) Show Estructura de cada cuota
Fecha de vencimiento de la cuota (formato: Y-m-d)
Dirección asociada a la compra
Observaciones o notas adicionales
Validaciones Importantes
La combinación de proveedor + tipo_doc + serie + número debe ser única
La serie debe ser alfanumérica en mayúsculas (1-4 caracteres)
El número debe contener solo dígitos (máximo 8)
Debe incluir al menos 1 producto
Si es pago a crédito (id_tipo_pago=2), debe incluir cuotas
Respuesta Exitosa
Siempre true en caso de éxito
Datos de la compra creada Número de documento formateado (serie-número)
Ejemplo de Solicitud
curl --request POST \
--url https://tu-dominio.com/api/compras \
--header 'Authorization: Bearer tu_token_aqui' \
--header 'Content-Type: application/json' \
--data '{
"id_proveedor": 15,
"tipo_doc": 1,
"serie": "F001",
"numero": "00000123",
"fecha_emision": "2026-03-04",
"fecha_vencimiento": "2026-04-04",
"id_tipo_pago": 2,
"moneda": "PEN",
"direccion": "Av. Los Industriales 456",
"observaciones": "Compra de mercadería para almacén central",
"productos": [
{
"id_producto": 10,
"cantidad": 50,
"costo": 25.50
},
{
"id_producto": 12,
"cantidad": 100,
"costo": 12.80
}
],
"cuotas": [
{
"monto": 1000.00,
"fecha": "2026-03-19"
},
{
"monto": 1555.00,
"fecha": "2026-04-04"
}
],
"empresas_ids": [1, 3]
}'
Ejemplo de Respuesta
{
"success" : true ,
"message" : "Compra registrada exitosamente" ,
"data" : {
"id_compra" : 43 ,
"documento" : "F001-00000123"
}
}
Errores Comunes
{
"success" : false ,
"message" : "Ya existe una compra registrada con este documento del proveedor"
}
{
"success" : false ,
"message" : "Serie inválida. Use 1-4 caracteres alfanuméricos"
}
{
"success" : false ,
"message" : "Número inválido. Use solo dígitos (máximo 8)"
}
Obtener Detalle de Compra
Obtiene el detalle completo de una compra específica, incluyendo productos, proveedor, cuotas de pago y empresas asociadas.
Token de autenticación Bearer
Permisos
Requiere permiso: compras.view
Parámetros de Ruta
ID de la compra a consultar
Respuesta Exitosa
Indica si la operación fue exitosa
Objeto con el detalle completo de la compra Fecha de emisión (formato: Y-m-d)
Fecha de vencimiento (formato: Y-m-d)
ID del tipo de pago (1=Contado, 2=Crédito)
Código de moneda (PEN o USD)
Monto del IGV (normalmente 0 en compras)
Observaciones de la compra
Estado: “1” (Activo) o “0” (Anulado)
Datos del proveedor Show Campos del proveedor
Array de productos comprados Show Estructura de cada detalle
Subtotal del producto (cantidad × costo)
Array de cuotas de pago (solo para compras a crédito) Show Estructura de cada cuota
Fecha de vencimiento (formato: Y-m-d)
Estado de la cuota: “1” (Pendiente) o “0” (Pagada)
Array de empresas asociadas Show Estructura de cada empresa
Ejemplo de Solicitud
curl --request GET \
--url https://tu-dominio.com/api/compras/43 \
--header 'Authorization: Bearer tu_token_aqui' \
--header 'Accept: application/json'
Ejemplo de Respuesta
{
"success" : true ,
"data" : {
"id_compra" : 43 ,
"serie" : "F001" ,
"numero" : "00000123" ,
"fecha_emision" : "2026-03-04" ,
"fecha_vencimiento" : "2026-04-04" ,
"id_tipo_pago" : 2 ,
"moneda" : "PEN" ,
"subtotal" : 2555.00 ,
"igv" : 0.00 ,
"total" : 2555.00 ,
"direccion" : "Av. Los Industriales 456" ,
"observaciones" : "Compra de mercadería para almacén central" ,
"estado" : "1" ,
"proveedor" : {
"proveedor_id" : 15 ,
"ruc" : "20123456789" ,
"razon_social" : "DISTRIBUIDORA COMERCIAL SAC" ,
"direccion" : "Jr. Las Flores 123, Lima"
},
"detalles" : [
{
"id_producto" : 10 ,
"codigo" : "PROD-001" ,
"nombre" : "Producto A" ,
"cantidad" : 50 ,
"costo" : 25.50 ,
"subtotal" : 1275.00
},
{
"id_producto" : 12 ,
"codigo" : "PROD-003" ,
"nombre" : "Producto C" ,
"cantidad" : 100 ,
"costo" : 12.80 ,
"subtotal" : 1280.00
}
],
"cuotas" : [
{
"monto" : 1000.00 ,
"fecha" : "2026-03-19" ,
"estado" : "1"
},
{
"monto" : 1555.00 ,
"fecha" : "2026-04-04" ,
"estado" : "1"
}
],
"empresas" : [
{
"id_empresa" : 1 ,
"comercial" : "Empresa Principal SAC" ,
"ruc" : "20612706702"
},
{
"id_empresa" : 3 ,
"comercial" : "Sucursal Norte EIRL" ,
"ruc" : "20987654321"
}
]
}
}
Error - Compra No Encontrada
{
"success" : false ,
"message" : "Error al obtener compra: No query results for model..."
}
Actualizar Compra
Este endpoint está definido en las rutas pero no está implementado en el controlador. Actualmente, la actualización de compras no está disponible para mantener la integridad del inventario y trazabilidad de movimientos de stock.
Permisos
Requiere permiso: compras.edit
Si necesitas modificar una compra, se recomienda anularla y crear una nueva con los datos correctos para mantener el historial de auditoría.
Eliminar Compra
Este endpoint está definido en las rutas pero no está implementado en el controlador. Para eliminar lógicamente una compra, utiliza el endpoint de anulación.
Permisos
Requiere permiso: compras.delete
Anular Compra
Anula una compra existente. Esta operación revierte automáticamente el stock de todos los productos incluidos en la compra y genera movimientos de stock de salida para mantener la trazabilidad.
La anulación es irreversible. Los productos volverán a su stock anterior y se generarán movimientos de inventario de tipo “anulacion_compra”.
Token de autenticación Bearer
Permisos
Requiere permiso: compras.delete
Parámetros de Ruta
Proceso de Anulación
Al anular una compra, el sistema ejecuta las siguientes operaciones en una transacción:
Valida que la compra no esté ya anulada
Cambia el estado de la compra a “0” (Anulado)
Para cada producto en la compra:
Reduce el stock actual por la cantidad comprada
Genera un movimiento de stock de tipo “salida” con motivo “Anulación de compra”
Mantiene las cuotas y relaciones para historial
Respuesta Exitosa
Siempre true en caso de éxito
Mensaje de confirmación: “Compra anulada exitosamente”
Ejemplo de Solicitud
curl --request POST \
--url https://tu-dominio.com/api/compras/43/anular \
--header 'Authorization: Bearer tu_token_aqui' \
--header 'Accept: application/json'
Ejemplo de Respuesta
{
"success" : true ,
"message" : "Compra anulada exitosamente"
}
Errores Comunes
{
"success" : false ,
"message" : "La compra ya está anulada"
}
{
"success" : false ,
"message" : "Error al anular compra: No query results for model..."
}
Códigos de Estado HTTP
Código Descripción 200 Operación exitosa 400 Error de validación o lógica de negocio 401 No autenticado (token inválido o faltante) 403 No autorizado (falta permiso requerido) 404 Compra no encontrada 500 Error interno del servidor
Notas Importantes
Control de Inventario Automático Todas las operaciones de compra afectan automáticamente el inventario:
Al crear: Incrementa stock y costo de productos
Al anular: Revierte el stock al estado anterior
Todos los movimientos quedan registrados en movimientos_stock
Ámbito Multi-Empresa Todas las consultas están automáticamente filtradas por la empresa del usuario autenticado (id_empresa). No es posible acceder a compras de otras empresas.
Unicidad de Documentos La combinación de proveedor + tipo_doc + serie + número debe ser única dentro de cada empresa. Esto evita registrar duplicados del mismo documento.
Compras a Crédito Las compras con id_tipo_pago = 2 requieren:
Fecha de vencimiento
Array de cuotas con montos y fechas
Las cuotas se crean con estado “1” (Pendiente)
Modelos Relacionados
Compra
{
"id_compra" : integer ,
"id_tido" : integer , // ID tipo de documento
"serie" : string , // Máx. 4 caracteres
"numero" : string , // Máx. 8 dígitos
"id_proveedor" : integer ,
"proveedor_id" : integer , // Redundante para relación
"fecha_emision" : date ,
"fecha_vencimiento" : date | null ,
"id_tipo_pago" : integer , // 1=Contado, 2=Crédito
"moneda" : string , // PEN o USD
"subtotal" : decimal ( 10 , 2 ),
"igv" : decimal ( 10 , 2 ),
"total" : decimal ( 10 , 2 ),
"direccion" : string ,
"observaciones" : text ,
"id_empresa" : integer ,
"id_usuario" : integer ,
"sucursal" : integer ,
"estado" : string , // 1=Activo, 0=Anulado
"created_at" : timestamp ,
"updated_at" : timestamp
}
ProductoCompra (Detalle)
{
"id_compra" : integer ,
"id_producto" : integer ,
"cantidad" : decimal ( 10 , 2 ),
"precio" : decimal ( 10 , 2 ), // Precio unitario
"costo" : decimal ( 10 , 2 ), // Costo unitario
"subtotal" : decimal ( 10 , 2 ) // cantidad × costo
}
DiaCompra (Cuota)
{
"id_compra" : integer ,
"monto" : decimal ( 10 , 2 ),
"fecha" : date ,
"estado" : string // 1=Pendiente, 0=Pagada
}
MovimientoStock
{
"id_producto" : integer ,
"tipo_movimiento" : string , // "entrada" o "salida"
"cantidad" : decimal ( 10 , 2 ),
"stock_anterior" : decimal ( 10 , 2 ),
"stock_nuevo" : decimal ( 10 , 2 ),
"tipo_documento" : string , // "compra" o "anulacion_compra"
"id_documento" : integer , // id_compra
"documento_referencia" : string , // "F001-00000123"
"motivo" : string ,
"id_almacen" : integer ,
"id_empresa" : integer ,
"id_usuario" : integer ,
"fecha_movimiento" : timestamp
}
Ejemplos de Integración
JavaScript/React
// Listar compras
const fetchCompras = async () => {
const response = await fetch ( 'https://tu-dominio.com/api/compras' , {
method: 'GET' ,
headers: {
'Authorization' : `Bearer ${ localStorage . getItem ( 'auth_token' ) } ` ,
'Accept' : 'application/json'
}
});
const data = await response . json ();
return data . data ;
};
// Crear compra
const crearCompra = async ( compraData ) => {
const response = await fetch ( 'https://tu-dominio.com/api/compras' , {
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ localStorage . getItem ( 'auth_token' ) } ` ,
'Content-Type' : 'application/json' ,
'Accept' : 'application/json'
},
body: JSON . stringify ( compraData )
});
const result = await response . json ();
if ( ! result . success ) {
throw new Error ( result . message );
}
return result . data ;
};
// Anular compra
const anularCompra = async ( idCompra ) => {
const response = await fetch (
`https://tu-dominio.com/api/compras/ ${ idCompra } /anular` ,
{
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ localStorage . getItem ( 'auth_token' ) } ` ,
'Accept' : 'application/json'
}
}
);
const result = await response . json ();
if ( ! result . success ) {
throw new Error ( result . message );
}
return result ;
};
PHP
<? php
$baseUrl = 'https://tu-dominio.com/api' ;
$token = 'tu_token_aqui' ;
// Crear compra
$compraData = [
'id_proveedor' => 15 ,
'tipo_doc' => 1 ,
'serie' => 'F001' ,
'numero' => '00000124' ,
'fecha_emision' => '2026-03-04' ,
'id_tipo_pago' => 1 ,
'moneda' => 'PEN' ,
'productos' => [
[
'id_producto' => 10 ,
'cantidad' => 50 ,
'costo' => 25.50
]
]
];
$ch = curl_init ( "{ $baseUrl }/compras" );
curl_setopt ( $ch , CURLOPT_RETURNTRANSFER , true );
curl_setopt ( $ch , CURLOPT_POST , true );
curl_setopt ( $ch , CURLOPT_POSTFIELDS , json_encode ( $compraData ));
curl_setopt ( $ch , CURLOPT_HTTPHEADER , [
"Authorization: Bearer { $token }" ,
'Content-Type: application/json' ,
'Accept: application/json'
]);
$response = curl_exec ( $ch );
$result = json_decode ( $response , true );
if ( $result [ 'success' ]) {
echo "Compra creada: { $result ['data']['documento']} \n " ;
} else {
echo "Error: { $result ['message']} \n " ;
}
curl_close ( $ch );
Python
import requests
import json
BASE_URL = 'https://tu-dominio.com/api'
TOKEN = 'tu_token_aqui'
headers = {
'Authorization' : f 'Bearer { TOKEN } ' ,
'Accept' : 'application/json' ,
'Content-Type' : 'application/json'
}
# Listar compras
def listar_compras ():
response = requests.get( f ' { BASE_URL } /compras' , headers = headers)
response.raise_for_status()
return response.json()[ 'data' ]
# Crear compra
def crear_compra ( compra_data ):
response = requests.post(
f ' { BASE_URL } /compras' ,
headers = headers,
json = compra_data
)
response.raise_for_status()
return response.json()
# Ver detalle
def ver_compra ( id_compra ):
response = requests.get(
f ' { BASE_URL } /compras/ { id_compra } ' ,
headers = headers
)
response.raise_for_status()
return response.json()[ 'data' ]
# Anular
def anular_compra ( id_compra ):
response = requests.post(
f ' { BASE_URL } /compras/ { id_compra } /anular' ,
headers = headers
)
response.raise_for_status()
return response.json()
# Ejemplo de uso
if __name__ == '__main__' :
# Crear nueva compra
nueva_compra = {
'id_proveedor' : 15 ,
'tipo_doc' : 1 ,
'serie' : 'F001' ,
'numero' : '00000125' ,
'fecha_emision' : '2026-03-04' ,
'id_tipo_pago' : 1 ,
'moneda' : 'PEN' ,
'productos' : [
{
'id_producto' : 10 ,
'cantidad' : 50 ,
'costo' : 25.50
}
]
}
resultado = crear_compra(nueva_compra)
print ( f "Compra creada: { resultado[ 'data' ][ 'documento' ] } " )
Preguntas Frecuentes
¿Puedo modificar una compra después de crearla?
No, actualmente no está implementada la funcionalidad de actualización de compras. Esto es por diseño para mantener la integridad del inventario y la trazabilidad de movimientos de stock. Si necesitas corregir una compra, debes anularla y crear una nueva.
¿Qué pasa con el stock al anular una compra?
Al anular una compra, el sistema automáticamente:
Reduce el stock de cada producto por la cantidad comprada
Genera movimientos de stock de tipo “salida” con motivo “Anulación de compra”
El stock nunca será menor a 0 (se usa max(0, stock - cantidad))
¿Cómo funcionan las compras a crédito?
Para compras a crédito (id_tipo_pago = 2):
Debes proporcionar fecha_vencimiento
Debes incluir un array de cuotas con montos y fechas
Las cuotas se crean con estado “1” (Pendiente)
La suma de cuotas debería coincidir con el total (no se valida automáticamente)
¿Puedo asociar una compra a múltiples empresas?
Sí, puedes incluir el campo empresas_ids con un array de IDs de empresas. Esto es útil para compras compartidas o distribución de costos entre sucursales.
¿El IGV se calcula automáticamente?
No, en las compras el IGV normalmente es 0 ya que se registra el costo neto. El total se calcula como subtotal + igv. Si necesitas registrar IGV, debes incluirlo en el costo unitario de los productos.
¿Cómo evito documentos duplicados?
El sistema valida automáticamente que no exista otra compra con la misma combinación de:
Proveedor
Tipo de documento
Serie
Número
Si intentas crear un duplicado, recibirás un error 400.