Skip to content

Auditoria de Lotes de Facturacion — Membresias

Modulo: Membresias Tipo: Technical Reference Estado: Implementado Fecha: 2026-03-17


Proposito

El modulo de auditoria de lotes registra y expone el historial de ejecuciones de facturacion por lotes del modulo de Membresias. Cada vez que un lote finaliza con estado completed, se persiste un registro completo con el detalle por socio (comprobantes generados, excluidos y errores), permitiendo la consulta y reimpresion de resultados en cualquier momento posterior.

Ademas del historial de lectura, el modulo permite eliminar lotes ejecutados en modo simulacion (prueba), manteniendo la inmutabilidad de los lotes de facturacion real.


Endpoints

GET /mod-membresia/auditoria/lotes

Retorna el listado paginado de lotes de facturacion registrados para la sucursal activa.

Query params opcionales:

ParametroTipoDescripcion
periodostringFiltro por periodo en formato YYYY-MM (ej: 2026-03)
modostringFiltro por modo: prueba o oficial. Si se omite, retorna todos
paginaintNumero de pagina (default: 1)
por_paginaintRegistros por pagina (default: configurable en el servicio)

Response 200:

json
{
  "data": [
    {
      "id": 42,
      "tipo_operacion": "facturacion",
      "periodo": "2026-03",
      "ejecutado_en": "2026-03-15T10:30:00",
      "finalizado_en": "2026-03-15T10:35:12",
      "socio_id_desde": 1,
      "socio_id_hasta": 500,
      "usuario_id": 7,
      "total_procesados": 498,
      "exitosos": 490,
      "fallidos": 8,
      "modo_simulacion": false,
      "has_detalle": true
    }
  ],
  "total": 12,
  "pagina": 1,
  "por_pagina": 20
}

Campos destacados:

CampoDescripcion
modo_simulaciontrue si el lote fue ejecutado en modo prueba; false para modo oficial
has_detalletrue si el campo detalles tiene datos (lotes completed con detalle); false para lotes anteriores a la migracion o con error

Aislamiento: El listado filtra automaticamente por el schema activo (header X-Schema) y por usuario_id del JWT.


GET /mod-membresia/auditoria/lotes/{id}/detalle

Retorna el detalle completo de un lote, incluyendo el resultado por cada socio procesado.

Response 200:

json
{
  "id": 42,
  "tipo_operacion": "facturacion",
  "periodo": "2026-03",
  "ejecutado_en": "2026-03-15T10:30:00",
  "finalizado_en": "2026-03-15T10:35:12",
  "socio_id_desde": 1,
  "socio_id_hasta": 500,
  "usuario_id": 7,
  "total_procesados": 498,
  "exitosos": 490,
  "fallidos": 8,
  "modo_simulacion": false,
  "detalles": [
    {
      "socio_id": 123,
      "nombre": "Juan Perez",
      "estado": "exitoso",
      "tipo_comprobante": "B",
      "numero_comprobante": "0001-00001234",
      "cae": "71234567890123",
      "fecha_comprobante": "2026-03-15",
      "total": 15000.00,
      "items": [
        {
          "descripcion": "Cuota mensual - Categoria Adulto",
          "cantidad": 1,
          "precio_unitario": 12000.00,
          "total": 12000.00
        }
      ]
    },
    {
      "socio_id": 456,
      "nombre": "Maria Lopez",
      "estado": "excluido",
      "motivo": "Ya facturado en este periodo"
    },
    {
      "socio_id": 789,
      "nombre": "Carlos Garcia",
      "estado": "error",
      "observaciones_arca": "10001 - El CUIT del receptor no es valido"
    }
  ]
}

Response 404: Cuando el lote no existe, pertenece a otro schema, o detalles IS NULL (lote sin detalle disponible).

json
{ "error": "Detalle no disponible" }

DELETE /mod-membresia/auditoria/lotes/{id}

Elimina un lote del historial. Solo permitido para lotes de simulacion.

Response 204: Lote de simulacion eliminado correctamente. Body vacio.

Response 403: El lote existe pero es de facturacion real (simulacion = false). Los lotes reales son inmutables.

json
{ "error": "No se puede eliminar un lote de facturacion real" }

Response 404: El lote no existe o pertenece a otro schema/usuario.

json
{ "error": "Lote no encontrado" }

Estructura del campo detalles (JSONB)

El campo detalles de la tabla membresia_facturacion_lote_auditoria almacena un array JSON con el resultado individual de cada socio procesado en el lote.

Esquema del array

Cada elemento del array representa un socio procesado y puede tener uno de tres estados:

Estado exitoso:

json
{
  "socio_id": 123,
  "nombre": "Razon Social o Nombre del Socio",
  "estado": "exitoso",
  "tipo_comprobante": "A|B|C",
  "numero_comprobante": "PPPP-NNNNNNNN",
  "cae": "NNNNNNNNNNNNN",
  "fecha_comprobante": "YYYY-MM-DD",
  "total": 0.00,
  "items": [
    {
      "descripcion": "Descripcion del concepto",
      "cantidad": 1,
      "precio_unitario": 0.00,
      "total": 0.00
    }
  ]
}

Estado excluido:

json
{
  "socio_id": 456,
  "nombre": "Razon Social o Nombre del Socio",
  "estado": "excluido",
  "motivo": "Descripcion del motivo de exclusion"
}

Estado error:

json
{
  "socio_id": 789,
  "nombre": "Razon Social o Nombre del Socio",
  "estado": "error",
  "observaciones_arca": "Codigo y mensaje de error retornado por ARCA"
}

Notas sobre items[]

Los items solo estan presentes en socios con estado exitoso. Representan los conceptos incluidos en la factura (cuota mensual, disciplinas, productos). Se registran al momento de la finalizacion del lote junto con los precios efectivos facturados.


Reglas de Negocio

Solo lotes completed tienen detalles

El campo detalles se persiste unicamente cuando el lote finaliza con estado completed. Los lotes con estado error no tienen detalle (campo NULL). Los lotes con estado gap_c (lotes que no generaron ningun comprobante por ausencia de deuda) no se registran en la tabla de auditoria.

Simulaciones registradas y eliminables

Los lotes de modo prueba (simulacion = true) se registran en el historial de la misma forma que los lotes oficiales. La diferencia es que los lotes de prueba pueden eliminarse mediante DELETE /auditoria/lotes/{id}. Los lotes de facturacion real (simulacion = false) son inmutables y no pueden eliminarse.

Lotes anteriores a la migracion

Los lotes ejecutados antes de la implementacion de esta funcionalidad tienen detalles = NULL. El campo has_detalle (calculado como detalles IS NOT NULL) permite al frontend comunicar al usuario que el detalle no esta disponible para esos lotes.

Aislamiento por schema

Todos los endpoints filtran por el schema activo derivado del header X-Schema. Un usuario no puede ver ni eliminar lotes de otra sucursal, incluso si conoce el id del lote.

Aislamiento por usuario

El listado y el detalle filtran adicionalmente por usuario_id del JWT. Cada operador ve exclusivamente los lotes que el mismo ejecuto.


Tabla de Base de Datos

Tabla: membresia_facturacion_lote_auditoria

ColumnaTipoDescripcion
idserialIdentificador unico del registro
tipo_operacionvarchar'facturacion' o 'refacturacion'
periodovarcharPeriodo facturado en formato YYYY-MM
ejecutado_entimestampFecha y hora de inicio del lote
finalizado_entimestampFecha y hora de finalizacion del lote
socio_id_desdeintID de socio inicial del rango procesado
socio_id_hastaintID de socio final del rango procesado
usuario_idintID del usuario que ejecuto el lote
total_procesadosintCantidad total de socios procesados
exitososintCantidad de comprobantes generados correctamente
fallidosintCantidad de comprobantes con error
simulacionbooleantrue si fue ejecutado en modo prueba
detallesjsonbArray de resultados por socio (NULL si no disponible)

Indice recomendado: (usuario_id, ejecutado_en DESC) para el listado paginado con filtros.


Componentes Involucrados

CapaArchivoResponsabilidad
RoutesMembresiaRoutes.phpRegistra GET /auditoria/lotes, GET /auditoria/lotes/{id}/detalle, DELETE /auditoria/lotes/{id}
ControllerAuditoriaLotesController.phpManeja requests HTTP, aplica filtros, retorna responses con codigos correctos
ServiceAuditoriaLotesService.phpOrquesta modelo con filtros, paginacion y guard de simulacion
ModelMembresiaFacturacionLoteAuditoria.phpEjecuta queries PostgreSQL; getLotes(), getDetalle(), deleteLote()
DTOAuditLogFinalizacionDTO.phpTransporta datos de finalizacion incluyendo detalles[] con items[]
Audit ServiceBatchInvoicingAuditService.phpLlama registrarFinalizacion() al completar un lote; omite registro para gap_c

Relacionado