Skip to content

Tarjetas - Documentacion Tecnica Backend

Modulo: ventas Feature: Tarjetas (tipos de tarjeta para facturacion) Fecha: 2026-02-09

DOCUMENTACION RETROSPECTIVA - Generada a partir de codigo implementado el 2026-02-09


Documento de Negocio

Requisitos de Negocio - Tarjetas


Arquitectura Implementada

CapaArchivoResponsabilidad
RouteRoutes/Venta/TarjetaRoute.phpDefinicion de endpoints REST
Controllercontroller/modulo-venta/TarjetaController.phpManejo HTTP request/response
Serviceservice/Venta/TarjetaService.phpValidaciones de negocio, orquestacion
Modelmodels/modulo-venta/Tarjeta.phpAcceso a datos, mapeo a DTO
DTOResources/Venta/Tarjeta.phpObjeto de transferencia de datos
ValidatorValidators/Venta/TarjetaValidator.phpValidacion estructural de datos

Registro de ruta: Routes/Venta/VentaRoutes.php registra $group->group('/tarjetas', TarjetaRoute::class), bajo el grupo principal /mod-ventas.


Flujo de Peticion

Request → AuthMiddleware → ConnectionMiddleware → TarjetaRoute
  → TarjetaController → TarjetaService → (TarjetaValidator + Tarjeta Model) → Database
  → Response (JSON)

Nota: El TarjetaValidator no esta aplicado como middleware en la ruta. La validacion se invoca directamente desde el TarjetaService.validateRequestData().


Endpoints API

GET /api/mod-ventas/tarjetas

Descripcion: Obtener listado de todas las tarjetas activas (no eliminadas).

Parametros Body (opcionales):

CampoTipoDescripcion
filterstringFiltro ILIKE por nombre de tarjeta

Respuesta 200:

json
{
  "status": 200,
  "message": "Datos recibidos correctamente.",
  "data": [
    { "id": 1, "nombre": "Visa", "cuenta": 11050 },
    { "id": 2, "nombre": "Mastercard", "cuenta": 11051 }
  ]
}

Logica:

  • Filtra registros donde deleted_at IS NULL
  • Si se proporciona filter, aplica nombre ILIKE %{filter}%
  • Retorna array de TarjetaDTO

GET /api/mod-ventas/tarjetas/{id}

Descripcion: Obtener una tarjeta por su ID.

Parametros Path:

CampoTipoRequeridoDescripcion
idintegerSiID de la tarjeta

Respuesta 200:

json
{
  "status": 200,
  "message": "Datos recibidos correctamente.",
  "data": { "id": 1, "nombre": "Visa", "cuenta": 11050 }
}

Respuesta 400: Si no se proporciona ID.

Nota: La consulta getById no filtra por deleted_at. Esto significa que es posible obtener tarjetas eliminadas por ID.


POST /api/mod-ventas/tarjetas

Descripcion: Crear una nueva tarjeta.

Request Body:

CampoTipoRequeridoValidacionDescripcion
nombrestringSirequired|max:100Nombre de la tarjeta
cuentainteger|nullCondicionalnullable|integerNumero de cuenta contable

Logica de validacion en Service:

  1. Se ejecuta TarjetaValidator.validate(data) (validacion estructural).
  2. Se consulta la configuracion del sistema (PermisosEmpresa) para verificar si el modulo Tesoreria esta habilitado.
  3. Si Tesoreria esta habilitado:
    • El campo cuenta se vuelve obligatorio (error 400 si es null/falsy).
    • Se verifica que la cuenta exista en el plan de cuentas mediante Cuenta.getById() (error 400 si no existe).

Respuesta 200:

json
{
  "status": 200,
  "message": "Datos recibidos correctamente.",
  "data": { "id": 3, "nombre": "American Express", "cuenta": 11052 }
}

Nota sobre HTTP status: El controller retorna 200 en lugar del estandar 201 para creacion.


PUT /api/mod-ventas/tarjetas/{id}

Descripcion: Actualizar una tarjeta existente.

Parametros Path:

CampoTipoRequerido
idintegerSi

Request Body: Mismo esquema que POST.

Logica: Misma validacion que POST (validateRequestData), luego actualiza todos los campos.

Respuesta 200: Tarjeta actualizada como DTO.


DELETE /api/mod-ventas/tarjetas/{id}

Descripcion: Eliminacion logica de una tarjeta.

Parametros Path:

CampoTipoRequerido
idintegerSi

Logica: Ejecuta UPDATE tarjetas SET deleted_at = :fecha WHERE id = :id. No verifica si la tarjeta existe ni si tiene comprobantes asociados.

Respuesta 204: Sin contenido.


Capa de Servicio

TarjetaService

Dependencias:

DependenciaTipoProposito
ModelFactoryFactoryCreacion de modelos con conexion inyectada
Tarjeta (Model)ModelAcceso a datos de tarjetas (conexion oficial)
Config (Model)ModelLectura de configuracion del sistema (conexion oficial)
Cuenta (Model)ModelVerificacion de existencia de cuentas (conexion oficial)
TarjetaValidatorValidatorValidacion estructural de datos de entrada

Metodos publicos:

MetodoParametrosRetornoDescripcion
getAllarray $options = []TarjetaDTO[]Listar tarjetas con filtro opcional
getByIdint $id?TarjetaDTOObtener tarjeta por ID
insertarray $data?TarjetaDTOCrear tarjeta con validacion
updateint $id, array $data?TarjetaDTOActualizar tarjeta con validacion
deleteint $idboolEliminacion logica

Metodo privado validateRequestData(array $data):

  1. Ejecuta validacion estructural via TarjetaValidator.
  2. Obtiene configuracion PermisosEmpresa del sistema.
  3. Si modulo_tesoreria esta habilitado:
    • Verifica que $data['cuenta'] no sea falsy (error 400).
    • Verifica que la cuenta exista via Cuenta.getById() (error 400).

Observaciones:

  • No utiliza transacciones (beginTransaction/commit/rollback).
  • No implementa el trait Auditable ni Conectable.
  • No implementa AuditableInterface.
  • Usa ModelFactory en lugar del patron ConnectionManager directo.

Capa de Datos (Model)

Tarjeta Model

Tabla: tarjetasConexion: Instanciado via ModelFactory con conexion oficial (PDO).

Metodos:

MetodoSQLRetorno
getAll(array $options)SELECT id, nombre, cuenta FROM tarjetas WHERE deleted_at IS NULL [AND nombre ILIKE ...]TarjetaDTO[]
getById(int $id)SELECT nombre, cuenta FROM tarjetas WHERE id = :id?TarjetaDTO
insert(array $data)INSERT INTO tarjetas (nombre, cuenta) VALUES (...) RETURNING id?TarjetaDTO
update(int $id, array $data)UPDATE tarjetas SET nombre = ..., cuenta = ... WHERE id = :id?TarjetaDTO
delete(int $id)UPDATE tarjetas SET deleted_at = :fecha WHERE id = :idbool

Observaciones:

  • getById no filtra por deleted_at IS NULL, permitiendo obtener tarjetas eliminadas.
  • delete no verifica que deleted_at IS NULL antes de marcar como eliminado.
  • Usa prepared statements en todos los metodos (seguro contra SQL injection).

DTO (Data Transfer Object)

Tarjeta DTO

Clase: App\Resources\Venta\Tarjeta extends DTO

PropiedadTipoDefaultDescripcion
idint-ID de la tarjeta
nombrestring-Nombre de la tarjeta
cuenta?intnullNumero de cuenta contable

Hereda fromArray() y toArray() de la clase base DTO.


Esquema de Base de Datos

Tabla: tarjetas

Nivel de tenencia: EMPRESA (schema public)

Fuente: Migracion 20250610112734_new_table_tarjetas.php

CampoTipoConstraintsDescripcion
idSERIALPRIMARY KEYID autoincrementable
nombreVARCHAR(100)NOT NULLNombre de la tarjeta
cuentaDECIMAL(10)NULLNumero de cuenta contable
deleted_atTIMESTAMPNULLFecha de eliminacion logica

Comentario de tabla: "Listado correspondiente a los diferentes tipos de tarjetas."

Condicion de ejecucion: La migracion solo se ejecuta si el modulo de Ventas esta habilitado (isVentasEnabled()).

Observacion sobre tipo de cuenta: En la migracion se define como DECIMAL(10) pero en el DTO y validador se trata como integer. Esto no genera error en PostgreSQL pero podria causar inconsistencias en precision.


Relaciones con otras tablas

Las tarjetas se referencian desde comprobantes de venta mediante el campo id_tarjeta:

TablaCampoTipoConstraintMigracion
facturaid_tarjetaINTEGERNULL20250610120831_new_field_id_tarjeta_in_factura.php
creditoid_tarjetaINTEGERNULL20250610120834_new_field_id_tarjeta_in_credito.php
debitoid_tarjetaINTEGERNULL20250610120838_new_field_id_tarjeta_in_debito.php

Nota: No se definen FOREIGN KEY constraints formales en las migraciones. La relacion es logica, no fisicamente restringida por la base de datos.


Diagrama de Base de Datos

mermaid
erDiagram
    tarjetas {
        serial id PK
        varchar_100 nombre "NOT NULL"
        decimal_10 cuenta "NULL"
        timestamp deleted_at "NULL"
    }

    factura {
        integer id_tarjeta FK "NULL - referencia a tarjetas"
    }

    credito {
        integer id_tarjeta FK "NULL - referencia a tarjetas"
    }

    debito {
        integer id_tarjeta FK "NULL - referencia a tarjetas"
    }

    tarjetas ||--o{ factura : "referenciada por"
    tarjetas ||--o{ credito : "referenciada por"
    tarjetas ||--o{ debito : "referenciada por"

Validaciones Implementadas

Nivel 1: Validacion Estructural (TarjetaValidator)

CampoReglaMensaje
nombrerequired|max:100Campo obligatorio, maximo 100 caracteres
cuentanullable|integerPuede ser null, si tiene valor debe ser entero

Nota: El validator no esta aplicado como middleware de ruta. Se invoca directamente desde TarjetaService.validateRequestData().

Nivel 2: Validacion de Negocio (TarjetaService)

ReglaCondicionAccionError
Cuenta obligatoriaModulo Tesoreria habilitadoVerifica que cuenta no sea falsy400: "La cuenta es obligatoria."
Cuenta existenteModulo Tesoreria habilitado y cuenta proporcionadaVerifica existencia via Cuenta.getById()400: "La cuenta seleccionada no existe."

Nota sobre validación condicional por módulos: Este recurso implementa validación de negocio que depende de módulos habilitados (modulo_tesoreria). La falta de datos por módulos no se valida en backend sino que suelen tener campos por defecto como deshabilitación (Null, 0, N, false, etc.). En este caso, el campo cuenta es nullable y solo se valida su existencia cuando el módulo de tesorería está habilitado.


Integracion con Facturacion

La tarjeta se integra con el proceso de facturacion de la siguiente manera:

  1. CondicionVenta enum: TARJETA = 3 indica condicion de venta por tarjeta.
  2. CondicionVenta model: La tabla condvta tiene un campo booleano tarjeta (alias es_tarjeta) que indica si una condicion de venta es de tipo tarjeta.
  3. Comprobante DTO: ComprobanteRequest y Comprobante incluyen propiedad ?int $tarjeta.
  4. ComprobanteService: Al registrar un comprobante con condicionVenta === TARJETA:
    • Valida que se haya especificado una tarjeta.
    • Obtiene la cuenta contable de la tarjeta via Tarjeta.getById().
    • Genera un movimiento de caja adicional contra la cuenta de la tarjeta.
  5. Models de comprobantes: Factura, NotaCredito y NotaDebito almacenan id_tarjeta en sus respectivas tablas.

Tests Implementados

TarjetaModelMethodsTest (Unit)

TestDescripcion
testGetAllExistingRecordsVerifica que getAll retorna solo registros no eliminados
testGetAllWithFilters (DataProvider)Verifica filtrado ILIKE por nombre con multiples escenarios
testUpdateARecordVerifica actualizacion de nombre
testDeleteArecordVerifica soft delete (registro no aparece en getAll despues de delete)

TarjetaServiceMethodsTest (Unit)

TestDescripcion
testValidOperations (DataProvider)Verifica insert y update con Tesoreria deshabilitado
testExeptions (DataProvider)Verifica errores: cuenta faltante y cuenta inexistente con Tesoreria habilitado

Deuda Técnica Identificada

Durante el análisis retrospectivo del código se identificaron los siguientes aspectos pendientes de mejora:

Arquitectura Moderna con Service Layer

Este recurso utiliza correctamente la arquitectura de 5 capas (Routes + Validators + Controller + Service + Model). Es uno de los recursos que sigue el patrón moderno del sistema.

Aspectos positivos:

  • Usa Slim Routes con Validator middleware
  • Implementa Service Layer con validaciones de negocio
  • Implementa soft delete correctamente
  • Tiene tests unitarios implementados

Foreign Keys Lógicas

Las relaciones se validan en la capa de aplicación y Service Layer. No poseen FK físicas de momento, sólo FK lógicas como muchas de las FK del sistema.

Audit Logging Ausente

Aunque tiene Service Layer, no implementa audit logging automático. Pendiente de implementación en refactorización futura.

Nota: Este es uno de los recursos legacy mejor refactorizados. Sirve como ejemplo para la migración de otros recursos.

Falta de Índices en Tabla tarjetas

La migración de la tabla tarjetas no define índices explícitos (excepto PK automática sobre codigo). Casi ninguna tabla de recursos viejos poseen índices, esto es por migración pero podrían empezar a implementarse.

Campos candidatos para índices:

  • concepto (búsquedas por nombre con ILIKE en filter)
  • defecto (filtro por tarjeta por defecto)
  • activo (filtro por tarjetas activas)
  • tipo (FK lógica a condiciones de venta tipo tarjeta)

Agregado a TODO.md para evaluación e implementación gradual.


Preguntas Tecnicas Pendientes

Hay aspectos tecnicos que requieren validacion. Ver: Preguntas sobre Tarjetas


Referencias


NOTA IMPORTANTE: Esta documentacion fue generada automaticamente analizando el codigo implementado. Validar cambios futuros contra este baseline.