Skip to content

Carteras - Documentacion Tecnica Frontend

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

Modulo: Ventas (vista principal) + CtaCte (componentes React reutilizables) Feature: Carteras (Agrupacion de clientes) Fecha: 2026-02-09


Arquitectura Implementada

Patron: Hibrido - Vista legacy (PHP + vanilla JS) + Componentes React reutilizables

La funcionalidad de Carteras tiene dos capas frontend:

  1. Vista de ABM (legacy): PHP template + vanilla JS con DataTables y Bootstrap modals
  2. Componentes de seleccion (React/TypeScript): CarteraSelect y ControlledCarteraSelect para uso en otros formularios

Componentes Implementados

1. Vista Legacy: ABM de Carteras

Pagina principal

Ubicacion: public/view/mod-ventas/cartera.phpScript: public/js/view/mod-ventas/cartera.jsFormulario HTML: public/php/components/mod-venta/forms/cartera.htmlProxy API: public/php/backend/carteras.php

Proposito: Listado, alta y modificacion de carteras de clientes

Dependencias externas:

  • jQuery
  • DataTables (con plugins: responsive, buttons, export PDF/Excel)
  • Bootstrap 4 (modales, layout)
  • AdminLTE (sidebar, skin)

cartera.js (Vista principal)

Ubicacion: public/js/view/mod-ventas/cartera.jsTipo: Modulo ES6

Funcionalidad implementada:

  1. Inicializacion de DataTable: Tabla #tablaCarteras con columnas:

    • Codigo (campo id)
    • Nombre (campo nombre)
    • Acciones (boton editar con icono lapiz)
    • Botones de exportacion: Excel, PDF
  2. Carga de datos: Fetch via ApiRequest.get('carteras', { tipo: 'cliente' })

  3. Alta: Boton #btn_alta -> abre modal via createFormCartera({ onSubmitCallback })

  4. Modificacion: Click en boton #idBtnmodificarCartera -> abre modal via createFormCartera({ updateData, onSubmitCallback }) con datos de la fila

Imports:

  • createFormCartera desde ../../components/forms/ventas/cartera.js
  • ApiRequest desde ../../middleware/API.js
  • reemplazarFila desde ../../util/datatable-methods.js

cartera.js (Formulario)

Ubicacion: public/js/components/forms/ventas/cartera.jsTipo: Modulo ES6, exporta funcion createFormCartera

Parametros de entrada:

{
  appendTo?: HTMLElement,    // Contenedor opcional (inline form)
  updateData?: { id, nombre }, // Datos para edicion
  onSubmitCallback: (data) => void  // Callback post-submit
}

Comportamiento:

  1. Carga el HTML del formulario desde cartera.html via fetch
  2. Crea un modal Bootstrap dinamicamente
  3. Si updateData tiene datos, carga los valores en el formulario (modo edicion)
  4. En submit:
    • Si cartera.id existe: ApiRequest.put('carteras', cartera) (modificacion)
    • Si cartera.id es null: ApiRequest.post('carteras', cartera) (alta)
  5. Muestra toast de confirmacion
  6. Ejecuta onSubmitCallback con los datos resultantes
  7. Cierra el modal

Estructura de datos interna:

javascript
let cartera = {
  id: null,
  nombre: null
}

Validaciones frontend:

  • isValidForm(form): Validacion HTML5 nativa (required)
  • validateType en blur del input: Validacion de tipo de dato
  • maxlength="20" en el input HTML

cartera.html (Template del formulario)

Ubicacion: public/php/components/mod-venta/forms/cartera.html

Estructura:

  • Modal Bootstrap (fade)
  • Titulo: "Formulario de carteras"
  • Un solo campo: Denominacion (input text, maxlength=20, required)
  • Botones: Cancelar (cierra modal) y Aceptar (submit)

2. Componentes React: Selectores de Cartera

CarteraSelect

Ubicacion: public/ts/ctacte/components/CarteraSelect.tsxTipo: Componente React funcional (mountable component)

Proposito: Selector dropdown de carteras para uso en formularios legacy (vanilla JS) y otros contextos React.

Props:

typescript
interface CarteraSelectProps {
  type: 'cliente' | 'proveedor';
  label?: string;           // Default: 'Cartera'
  name?: string;            // Default: 'cartera'
  value?: string;
  onChange?: (cartera: CarteraRecord | null) => void;
  onDataLoaded?: (records: CarteraRecord[]) => void;
  records?: CarteraRecord[];   // Records pre-cargados (evita fetch)
  loading?: boolean;
  error?: FieldError;
  className?: string;
  getApi?: (api: InputFormApi) => void;  // API externa (mountable)
}

Comportamiento:

  1. Obtiene carteras via useCarteraData(type) (o usa records proporcionados)
  2. Auto-selecciona el primer registro si no hay valor previo y no esta en RangeSelector
  3. Expone API via getApi para control externo (focus, blur, setValue, disable, enable)
  4. Renderiza FormField + DataSelect con las opciones de carteras

Componentes internos utilizados:

  • DataSelect (de core/components)
  • FormField (de core/components/form)

ControlledCarteraSelect

Ubicacion: public/ts/ctacte/components/ControlledCarteraSelect.tsxTipo: Componente React funcional para React Hook Form

Proposito: Version del selector de carteras integrada con React Hook Form para formularios modernos (MUI).

Props:

typescript
interface ControlledCarteraSelectProps<T extends FieldValues> {
  name: FieldPath<T>;
  control: Control<T>;
  label: string;
  type: 'cliente' | 'proveedor';
  error?: FieldError;
  disabled?: boolean;
  required?: boolean;
  placeholder?: string;     // Default: 'Seleccione...'
  onValueChange?: (cartera: CarteraRecord | null) => void;
}

Comportamiento:

  1. Usa Controller de React Hook Form para controlar el valor
  2. Obtiene carteras via useCarteraData(type, disabled)
  3. Renderiza un TextField de MUI en modo select con MenuItems
  4. Muestra spinner de carga cuando los datos estan cargando
  5. Emite onValueChange con el objeto cartera completo al cambiar

Componentes de MUI utilizados:

  • TextField (modo select)
  • MenuItem
  • CircularProgress
  • Box

Hook Personalizado

useCarteraData

Ubicacion: public/ts/ctacte/hooks/useCarteraData.ts

Parametros:

typescript
function useCarteraData(type: 'cliente' | 'proveedor', skip: boolean = false)

Retorno:

typescript
{ records: CarteraRecord[], loading: boolean, error: string | null }

Implementacion:

  • Usa useDataSelect del core (patron generico de carga de datos para selects)
  • URL base: 'carteras'
  • Query params: { tipo: type }
  • El parametro skip permite evitar la carga de datos (cuando ya se proporcionaron records externos o el componente esta deshabilitado)

Tipos TypeScript

CarteraRecord

Ubicacion: public/ts/ctacte/types/carteras.ts

typescript
export const carteraIdField = "id";
export const carteraNameField = "nombre";

export interface CarteraRecord extends RecordType {
  id: number;
  nombre: string;
}

Integracion con Backend

Endpoints Consumidos

EndpointMetodoUsoConsumidor
carteras?tipo=clienteGETListar carteras de clientescartera.js, CarteraSelect, ControlledCarteraSelect
carteras?tipo=proveedorGETListar carteras de proveedoresCarteraSelect (en contextos de compras)
carterasPOSTCrear carteracartera.js (formulario)
carterasPUTModificar carteracartera.js (formulario)

Proxy API

Ubicacion: public/php/backend/carteras.php

El proxy frontend actua como intermediario entre el frontend (ApiRequest/axios) y el backend. Realiza:

  1. Validacion de sesion ($_SESSION['SD_USER'])
  2. Validacion de datos de entrada (reglas tipo, id, nombre, etc.)
  3. Reenvio de la solicitud al backend via clase Request interna
  4. Formateo de respuesta

Routing y Navegacion

Vista legacy

  • URL: ?loc=mvcc
  • Breadcrumb: Home > Ventas > Carteras
  • Sidebar: Ventas > Bases > Carteras (condicionado a empres.cartera y permiso VENTAS_BASES_CARTERAS)
  • Sidebar highlight: idNavMainSideBarBases (abierto) + idMainSideBarCartera (activo)

Componentes React

No tienen routing propio. Se montan dinámicamente donde se necesiten:

  • CarteraSelect: Montable via mountComponent() en formularios legacy
  • ControlledCarteraSelect: Integrado en formularios React con React Hook Form

Contextos de Uso de CarteraSelect

1. Formulario de Clientes (legacy)

Archivo: public/js/components/forms/general/cliente.jsPatron: Mountable component

javascript
import CarteraSelect from '../../../../dist/ctacte/components/CarteraSelect.js';
import { mountComponent } from '../../../../dist/main.js';

const props = {
    onChange: (record) => { Cliente.cartera = record; },
    type: 'cliente',
    className: 'form-group col-md-6',
};
const api = await mountComponent(container, CarteraSelect, props);

2. Formulario de Clientes (React - ListaClientesForm)

Archivo: public/ts/ventas/components/ListaClientesForm.tsxPatron: ControlledCarteraSelect dentro de React Hook Form

3. Informes de Saldos (CtaCte)

Archivo: public/ts/ctacte/ (varios contextos) Patron: CarteraSelect como filtro de rango

4. Formulario de Proveedores

Archivo: public/js/view/mod-compras/registro-proveedor.jsPatron: CarteraSelect montado con type='proveedor'

5. Modulo Tesoreria

Archivos: Cheques, boleta de deposito Patron: Referencia a cartera como filtro


Diagrama de Componentes

mermaid
flowchart TD
    subgraph "Vista ABM (Legacy)"
        A[cartera.php] --> B[cartera.js<br/>Vista DataTable]
        B --> C[createFormCartera<br/>Modal Bootstrap]
        C --> D[cartera.html<br/>Template]
        B --> E[ApiRequest<br/>API.js]
        C --> E
        E --> F[Proxy PHP<br/>carteras.php]
    end

    subgraph "Componentes React (ts/ctacte/)"
        G[CarteraSelect.tsx] --> H[useCarteraData.ts]
        I[ControlledCarteraSelect.tsx] --> H
        H --> J[useDataSelect<br/>core hook]
        J --> K[axios<br/>api.ts]
        K --> F
    end

    subgraph "Consumidores"
        L[cliente.js] -->|mountComponent| G
        M[ListaClientesForm.tsx] --> I
        N[registro-proveedor.js] -->|mountComponent| G
        O[Informes CtaCte] --> G
    end

    F --> P[Backend<br/>carteras.php]

Observaciones Tecnicas

Organizacion de codigo cross-module

Los componentes React de Carteras estan en ts/ctacte/ aunque la vista principal de ABM esta en view/mod-ventas/. Esto se debe a que los componentes selectores se usan predominantemente en contextos de cuenta corriente. Sin embargo, esto crea una dependencia cross-module donde ventas depende de ctacte para sus componentes.

Patron de montaje dual

CarteraSelect implementa el patron MountableComponentProps que permite su uso tanto en contextos React como en vanilla JS via mountComponent(). Expone un InputFormApi con metodos focus, blur, setValue, disable, enable.

Sin migracion a React de la vista principal

La vista de ABM de carteras (listado + formulario) sigue siendo completamente legacy (PHP + vanilla JS + DataTables + Bootstrap modales). Solo los componentes de seleccion han sido migrados a React.


Preguntas Tecnicas Pendientes

Aclaraciones Requeridas: Hay aspectos tecnicos que requieren validacion. Ver: Preguntas sobre Carteras


Referencias


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