Skip to content

Categoria IVA - Documentación Técnica Backend

⚠️ DOCUMENTACIÓN RETROSPECTIVA - Generada a partir de código implementado el 2026-02-11

Módulo: Ventas Tipo: Resource (solo lectura) Fecha: 2026-02-11


Referencia a Requisitos de Negocio

Esta documentación técnica implementa los requisitos definidos en:


Arquitectura Implementada

Capas del Sistema

El módulo de Categoria IVA implementa una arquitectura simplificada de 2 capas (sin Service Layer) dado que es un recurso de solo lectura sin lógica de negocio:

API Layer (Route + Controller)

Model Layer (Data Access)

Database Layer (PostgreSQL)

Justificación: Al tratarse de un recurso de solo lectura sin validaciones de negocio ni transacciones, no se requiere Service Layer. El Controller invoca directamente al Model.

Archivos Implementados

CapaArchivoResponsabilidad
Routebackend/categoria-iva.phpEndpoint legacy, routing manual
Controllercontroller/modulo-venta/CategoriaIvaController.phpHTTP handling, respuestas JSON
Modelmodels/modulo-venta/CategoriaIva.phpData access, queries
DTOResources/Venta/CategoriaIva.phpTransferencia de datos
Migrationmigrations/tenancy/20240823200722_new_table_aliva.phpSchema de base de datos
Seedmigrations/seeds/tenancy/Aliva.phpDatos de referencia ARCA

API Endpoints

GET /backend/categoria-iva.php

Descripción: Endpoint legacy para consulta de categorías de IVA.

Autenticación: JWT requerido (middleware global)

Headers:

  • Authorization: Bearer {jwt_token}
  • X-Schema: {schema} (opcional, para multi-tenancy)

Operación: Listar todas las categorías

Request:

http
GET /backend/categoria-iva.php HTTP/1.1
Content-Type: application/json

{}

Response 200 OK:

json
{
  "status": 200,
  "message": "Datos recibidos correctamente.",
  "data": [
    {
      "codigo": 5,
      "nombre": "IVA 21 %",
      "porcentaje": 21.00
    },
    {
      "codigo": 3,
      "nombre": "Exento",
      "porcentaje": 0.00
    },
    {
      "codigo": 4,
      "nombre": "IVA 10.50 %",
      "porcentaje": 10.50
    }
  ]
}

Operación: Obtener categoría por código

Request:

http
GET /backend/categoria-iva.php HTTP/1.1
Content-Type: application/json

{
  "codigo": 5
}

Response 200 OK:

json
{
  "status": 200,
  "message": "Datos recibidos correctamente.",
  "data": {
    "codigo": 5,
    "nombre": "IVA 21 %",
    "porcentaje": 21.00
  }
}

Response 404 Not Found:

json
{
  "error": "Not Found"
}

Operación: Obtener categoría por porcentaje

Request:

http
GET /backend/categoria-iva.php HTTP/1.1
Content-Type: application/json

{
  "porcentaje": 21.00
}

Response 200 OK:

json
{
  "status": 200,
  "message": "Datos recibidos correctamente.",
  "data": {
    "codigo": 5,
    "nombre": "IVA 21 %",
    "porcentaje": 21.00
  }
}

Response 404 Not Found:

json
{
  "error": "Not Found"
}

Códigos de Estado HTTP

CódigoUso
200Consulta exitosa (getAll, getOne)
401No autenticado (sin JWT o JWT inválido)
404Categoría no encontrada (código/porcentaje inexistente)
500Error interno del servidor

Capa de Controller

CategoriaIvaController

Archivo: controller/modulo-venta/CategoriaIvaController.php

Namespace: App\controller\Venta

Extiende: App\controller\Controller

Dependencias

  • App\models\Venta\CategoriaIva (Model)
  • PDO (Database connection)

Métodos Implementados

__construct(PDO $conn)

Inicializa el controller con la conexión de base de datos y crea instancia del model.

Parámetros:

  • $conn: Conexión PDO configurada con el schema correcto

getAll(): array

Retorna todas las categorías de IVA.

Retorna: CategoriaIvaDTO[]

Propósito: Listar el catálogo completo de alícuotas de IVA.

Lógica:

  1. Invoca $this->model->getAll()
  2. Retorna array de DTOs

getOne(array $option): ?CategoriaIvaDTO

Retorna una categoría de IVA por código o porcentaje.

Parámetros:

  • $option['codigo']: int (opcional) - Código ARCA
  • $option['porcentaje']: float (opcional) - Porcentaje de alícuota

Retorna: CategoriaIvaDTO|null

Lógica:

  1. Si existe $option['porcentaje'], busca por porcentaje
  2. Si existe $option['codigo'], busca por código
  3. Si no existe ninguno, lanza NotFound exception
  4. Retorna DTO o null si no encuentra

Nota: Prioriza porcentaje sobre código si ambos están presentes.


Capa de Model

CategoriaIva

Archivo: models/modulo-venta/CategoriaIva.php

Namespace: App\models\Venta

Extiende: App\models\Model

Tabla: aliva

Métodos Implementados

getAll(): array

Obtiene todas las categorías de IVA.

SQL:

sql
SELECT codigo, nombre, porcentaje
FROM aliva

Retorna: CategoriaIvaDTO[] (array vacío si no hay registros)

Mapeo: Usa CategoriaIvaDTO::fromArray() para mapear cada fila

Nota: No filtra por deleted_at porque la tabla no tiene soft deletes (dato de referencia fiscal).


getByCodigo(int $codigo): ?CategoriaIvaDTO

Obtiene categoría por código ARCA.

Parámetros:

  • $codigo: Código oficial de ARCA (ej: 5 para IVA 21%)

SQL:

sql
SELECT codigo, nombre, porcentaje
FROM aliva
WHERE codigo = :codigo

Retorna: CategoriaIvaDTO|null

Uso: Búsqueda por identificador oficial de ARCA en procesos de facturación.


getByPorcentaje(float $porcentaje): ?CategoriaIvaDTO

Obtiene categoría por porcentaje de alícuota.

Parámetros:

  • $porcentaje: Porcentaje de IVA (ej: 21.00)

SQL:

sql
SELECT codigo, nombre, porcentaje
FROM aliva
WHERE porcentaje = :porcentaje

Retorna: CategoriaIvaDTO|null

Uso: Importación de productos cuando se conoce el porcentaje pero no el código ARCA.


Capa de DTO (Resources)

CategoriaIva DTO

Archivo: Resources/Venta/CategoriaIva.php

Namespace: App\Resources\Venta

Extiende: App\Resources\DTO

Propiedades

PropiedadTipoValidaciónDescripción
codigointrequired|integerCódigo oficial ARCA
porcentajefloatrequired|numericPorcentaje de alícuota
nombrestringrequired|max:100Nombre descriptivo

Constructor

Valida los datos contra las reglas definidas y asigna propiedades.

Validaciones automáticas:

  • Campos requeridos no pueden ser null
  • codigo debe ser entero
  • porcentaje debe ser numérico
  • nombre máximo 100 caracteres

Esquema de Base de Datos

Tabla: aliva

Nivel Multi-Tenancy: EMPRESA (schema public)

Justificación: Las categorías de IVA son definidas por ARCA (organismo fiscal) y son las mismas para todas las sucursales y cajas de una empresa. No varían por ubicación.

Habilitación: Solo se crea si módulo Ventas o Compras está habilitado.

Schema SQL

sql
CREATE TABLE aliva (
    codigo     INTEGER        NOT NULL PRIMARY KEY,
    nombre     VARCHAR(100)   NOT NULL,
    porcentaje DECIMAL(5, 2)  NOT NULL
);

Columnas

CampoTipoConstraintsDescripción
codigoINTEGERPRIMARY KEY NOT NULLCódigo oficial ARCA (3, 4, 5, 6, 8, 9)
nombreVARCHAR(100)NOT NULLNombre descriptivo ("IVA 21 %", "Exento", etc.)
porcentajeDECIMAL(5,2)NOT NULLPorcentaje (0.00, 2.50, 5.00, 10.50, 21.00, 27.00)

Índices

  • PRIMARY KEY: codigo

No se requieren índices adicionales dado el bajo volumen de datos (6 registros conocidos).

Foreign Keys

Ninguna. Esta tabla no tiene relaciones FK de entrada.

Tablas que referencian a aliva:

  • producto - Productos tienen categoría de IVA
  • items_factura - Items de factura pueden tener código de IVA

Constraints

Ninguno adicional. La validación de integridad se realiza a nivel de aplicación.

Datos de Referencia (Seed)

Los registros se cargan automáticamente vía seed Aliva.php:

Código ARCANombrePorcentaje
3Exento0.00
4IVA 10.50 %10.50
5IVA 21 %21.00
6IVA 27 %27.00
8IVA 5 %5.00
9IVA 2.5 %2.50

Origen de datos: Resolución General 5616/2024 ARCA (Administración Federal de Ingresos Públicos de Argentina).


Multi-Tenancy

Nivel de Aislamiento

EMPRESA (public schema): Datos compartidos por todas las sucursales y cajas.

Razón: Las alícuotas de IVA son definidas por normativa fiscal nacional y no varían por ubicación geográfica.

Configuración en Migration

php
protected function getDefaultLevels(): array
{
    return [self::LEVEL_EMPRESA];
}

Header X-Schema

El endpoint respeta el header X-Schema para multi-tenancy, pero siempre consulta los datos del schema public (empresa) independientemente del schema del usuario.

Implicación: No importa si el usuario está en suc0001 o suc0002, todos ven las mismas categorías de IVA.


Validaciones

Nivel 1: Validación Estructural

NO IMPLEMENTADA - El endpoint legacy no tiene Validator middleware.

⚠️ Observación técnica: El endpoint acepta cualquier estructura de JSON sin validación previa. La validación ocurre en el DTO.

Nivel 2: Validación de DTO

Implementada en CategoriaIva DTO mediante método validate() heredado.

Reglas:

  • codigo: required|integer
  • porcentaje: required|numeric
  • nombre: required|max:100

Comportamiento: Si un campo no cumple las reglas, el DTO lanza excepción durante construcción.

Nivel 3: Validación de Negocio

NO APLICA - Recurso de solo lectura sin validaciones de negocio.


Puntos de Integración

Consumidores Internos

Módulo de Productos

Uso: Asignación de categoría IVA a productos.

Método usado: getByCodigo(int $codigo)

Contexto: Al crear/editar un producto, se valida que el código de IVA exista.


Módulo de Facturación Electrónica

Uso: Construcción de requests ARCA para facturación.

Trait: Membresia\Domain\Facturacion\Builder\Traits\ArcaAlicuotasTrait

Método usado: findCategoriaByPorcentaje(array $categorias, float $porcentaje)

Contexto: Durante la facturación masiva, se buscan categorías de IVA para armar alícuotas en el request ARCA.

Nota: El trait recibe un array pre-cargado de categorías en lugar de consultar la base de datos en cada iteración (optimización).


Importación de Productos

Uso: Asignación automática de categoría IVA durante importación masiva.

Método usado: getByPorcentaje(float $porcentaje)

Contexto: Al importar productos desde archivo Excel/CSV, se busca la categoría por porcentaje.


Servicios Externos

ARCA (AFIP) - Webservice WSFE

Integración: Los códigos de la tabla aliva corresponden a la codificación oficial de ARCA para facturación electrónica.

Uso: Al emitir un comprobante electrónico, se envían las alícuotas de IVA con sus códigos oficiales.

Ejemplo de request ARCA:

php
'IvaAliq' => [
    [
        'Id' => 5,           // Código de aliva
        'BaseImp' => 1000.00,
        'Importe' => 210.00
    ]
]

Normativa: RG 5616/2024 ARCA - Códigos de alícuota de IVA.


Estrategia de Testing

Unit Tests

NO IMPLEMENTADOS - No se encontraron tests unitarios para este módulo.

Tests recomendados (si se implementaran):

php
// CategoriaIvaModelTest.php
class CategoriaIvaModelTest extends TestCase
{
    public function testGetAllReturnsArray(): void;
    public function testGetByCodigoReturnsDTO(): void;
    public function testGetByCodigoReturnsNullWhenNotFound(): void;
    public function testGetByPorcentajeReturnsDTO(): void;
    public function testGetByPorcentajeReturnsNullWhenNotFound(): void;
}

Integration Tests

NO IMPLEMENTADOS - No se encontraron tests de integración.

Tests recomendados (si se implementaran):

php
// CategoriaIvaIntegrationTest.php
class CategoriaIvaIntegrationTest extends BaseIntegrationTestCase
{
    public function testEndpointReturnsAllCategories(): void;
    public function testEndpointReturnsOneByCode(): void;
    public function testEndpointReturnsOneByPercentage(): void;
    public function testEndpointReturns404WhenNotFound(): void;
}

Mocking Strategy

Para tests que usan CategoriaIva como dependencia (ej: tests de facturación):

Mock de Model:

php
$mockCategoriaIvaModel = $this->createMock(CategoriaIva::class);
$mockCategoriaIvaModel->method('getByCodigo')
    ->willReturn(new CategoriaIvaDTO(5, 21.00, 'IVA 21 %'));

Mock de DTO:

php
$categoriaIva = new CategoriaIvaDTO(
    codigo: 5,
    porcentaje: 21.00,
    nombre: 'IVA 21 %'
);

Rendimiento

Volumen de Datos

  • Registros actuales: 6 (datos de referencia fiscal)
  • Crecimiento esperado: Muy bajo (solo cuando cambia normativa ARCA)
  • Paginación: NO requerida

Optimizaciones Implementadas

Consultas

  • Queries simples sin JOINs
  • PRIMARY KEY en codigo (acceso O(1))
  • No se requieren índices adicionales

Caching

NO IMPLEMENTADO - No se encontró cache de categorías.

Recomendación: Dado que los datos son estables y de bajo volumen, se podría implementar cache en memoria:

php
// Cache sugerido (no implementado)
private static ?array $categoriesCache = null;

public function getAll(): array
{
    if (self::$categoriesCache === null) {
        self::$categoriesCache = // query DB
    }
    return self::$categoriesCache;
}

Justificación: Las categorías de IVA cambian raramente (solo con cambios legislativos) y se consultan frecuentemente en procesos de facturación.


Seguridad

Autenticación

  • JWT requerido: Implementado en JwtHandler.php (include en route legacy)
  • Validación: Token debe ser válido con firma RSA
  • Payload: Contiene db, schema, id, permisos

Autorización

NO IMPLEMENTADA - No hay validación de permisos específica.

Comportamiento actual: Cualquier usuario autenticado puede consultar categorías de IVA.

Justificación: Los datos son públicos (normativa fiscal) y no contienen información sensible.

Sanitización

Prevención de SQL Injection:

  • ✅ Uso de prepared statements en todos los métodos del Model
  • ✅ PDO con placeholders (:codigo, :porcentaje)

Ejemplo:

php
$stmt->execute([':codigo' => $codigo]);

Auditoría

NO IMPLEMENTADA - No se registran operaciones de auditoría.

Justificación: Recurso de solo lectura. Los cambios a los datos se realizan exclusivamente vía migraciones controladas por desarrollo.


Preguntas Técnicas Pendientes

⚠️ Aclaraciones Requeridas: Hay aspectos técnicos que requieren validación.

Ver: Preguntas sobre Categoria IVA

Preguntas técnicas principales:

  1. Migración a Slim Routes: ¿Se planea migrar el endpoint legacy a Slim Framework con Validator middleware?
  2. Cache: ¿Se debería implementar cache dado el bajo volumen y alta estabilidad de datos?
  3. Tests: ¿Se requiere cobertura de tests para este módulo?
  4. Validator: ¿Se necesita validación estructural con middleware antes del DTO?

Referencias


Notas Adicionales

Legacy vs Modern Architecture

Este módulo utiliza arquitectura legacy (route manual en backend/categoria-iva.php) en lugar del patrón moderno Slim Framework.

Patrón moderno esperado (no implementado):

php
// Routes/Venta/CategoriaIvaRoutes.php (NO EXISTE)
$group->get('/categoria-iva', [CategoriaIvaController::class, 'getAll']);
$group->get('/categoria-iva/{codigo}', [CategoriaIvaController::class, 'getById']);

Implicación: El endpoint actual no se beneficia de middleware de validación, CORS mejorado, ni inyección de dependencias de Slim.

Normativa Fiscal

Los códigos de alícuota deben mantenerse sincronizados con la normativa de ARCA:

  • Fuente oficial: Resolución General 5616/2024 ARCA
  • Cambios: Solo mediante migraciones aprobadas por desarrollo
  • Verificación: Antes de migración, validar contra webservice ARCA homologación

⚠️ NOTA IMPORTANTE: Esta documentación fue generada automáticamente analizando el código implementado. Validar cambios futuros contra este baseline. Las categorías de IVA son datos fiscales regulados que solo se modifican mediante migraciones controladas cuando cambia la normativa de ARCA.