Appearance
ABM de Clientes - Documentacion Tecnica Frontend
Modulo: ventas Feature: ABM de Clientes Fecha: 2026-02-09
DOCUMENTACION RETROSPECTIVA - Generada a partir de codigo implementado el 2026-02-09.
Referencia de Negocio
Estado de Migracion
El frontend del ABM de Clientes se encuentra en un estado de migracion parcial:
| Funcionalidad | Estado | Tecnologia |
|---|---|---|
| Formulario CRUD (crear/editar) | Legacy | Vanilla JS (no migrado a React) |
| Tabla de listado (DataTables SSR) | Legacy | Vanilla JS + DataTables jQuery |
| Hook de datos de clientes | Migrado | React + TypeScript + Axios |
| Informe Lista de Clientes | Migrado | React + TypeScript + Zod + RHF |
| Informe Comprobante por Conceptos | Migrado | React + TypeScript + Zod + RHF |
Formulario CRUD (Vanilla JS Legacy)
El formulario principal de alta y modificacion de clientes esta implementado en vanilla JS, no en React. Es un componente modularizado y reutilizable.
Archivos del Formulario CRUD
| Archivo | Proposito |
|---|---|
view/mod-ventas/form-cliente.php | Template PHP con layout AdminLTE (card, breadcrumb, sidebar) |
js/view/mod-ventas/form-cliente.js | Inicializador: carga el componente createFormCliente, determina modo (alta/edicion) |
js/components/forms/general/cliente.js | Componente reutilizable createFormCliente - logica del formulario completo |
Flujo del Formulario
- El template PHP (
form-cliente.php) carga el layout AdminLTE con un contenedor vacio#form_container - El script
form-cliente.jsse ejecuta como modulo ES6 - Extrae el parametro
idde la URL para determinar si es alta o modificacion - Invoca
createFormCliente(updateData, callback)del componente reutilizable - El componente carga su HTML desde
php/components/mod-venta/forms/clientevia fetch - Monta el formulario en el contenedor y configura event listeners
Componente createFormCliente
Ubicacion: js/components/forms/general/cliente.jsProposito: Componente reutilizable de formulario de clientes Patron: Funcion factory que crea y retorna un elemento DOM con todo el formulario
Parametros:
updateData(object): Si incluyeid, opera en modo edicion; vacio para altaoptions(object):{ inModal: false, isShowing: false }para uso en modalesonSubmitCallback(function): Callback post-submit (por defecto redirige a listado)
Estructura de datos interna (objeto Cliente):
id,nombre,domicilio1,domicilio2,emaillocalidad(objeto),condicion_iva(objeto),iibb(objeto),vendedor(objeto),cartera(objeto)identificacion,comision,nro_iibbtiene_ctacte(boolean),margen_credito,margen_fact_imprel_lista('S'/'N'),lista
Metodos del objeto Cliente:
setCondicionIva(condicion)- Configura condicion IVA y ajusta requerimiento de CUITsetIngresosBrutos(iibb)- Configura IIBB y habilita/deshabilita campo numero IIBBpermiteCtaCte(flag)- Muestra/oculta panel de cuenta corriente (jQuery collapse)relacionaLista(flag)- Habilita/deshabilita campo de lista de precios propiagetData()- Retorna solo propiedades de datos (excluye metodos)
Campos del formulario:
- Nombre (input text, required)
- Email (input email, configurado con
setInputEmail) - Domicilio 1 y 2 (input text)
- Localidad (autocomplete jQuery UI)
- Telefono 1 y 2 (input, configurado con
setInputTelefono) - Condicion IVA (select)
- Identificacion DNI/CUIT (input, configurado con
setInputIdentificacion) - Ingresos Brutos tipo (select)
- Numero IIBB (input, habilitado condicionalmente)
- Vendedor (autocomplete)
- Comision (input numerico con badge)
- Cartera (componente React
CarteraSelectmontado viamountComponent) - Checkbox cuenta corriente (toggle panel CtaCte)
- Margen credito, Saldo cliente, Margen facturas impagas (campos CtaCte)
- Checkbox lista de precios propia + Numero de lista
- Fecha alta y Fecha ultimo movimiento (solo lectura en edicion)
Integracion hibrida vanilla JS + React: El campo de Cartera usa un componente React (CarteraSelect) montado dentro del formulario vanilla JS usando la funcion mountComponent de dist/main.js. Esto demuestra el patron de migracion progresiva donde componentes React se insertan en contextos legacy.
Dependencias legacy:
ApiRequest(js/middleware/API.js) - Comunicacion con backendgetPermisosModulos(js/auth/permisos.js) - Permisos del usuarioempresaSingleton(js/util/empresaSingleton.js) - Datos de empresa- jQuery UI Autocomplete - Campos de localidad y vendedor
- jQuery Bootstrap Collapse - Panel de cuenta corriente
- SweetAlert2 - Popups de carga y error
- DataTables jQuery - Tabla de listado (en la vista de listado, no en este formulario)
Componentes Implementados (React/TypeScript)
ListaClientesApp
Ubicacion: ts/ventas/informes/ListaClientesApp.tsxProposito: Aplicacion React standalone para el informe de lista de clientes Tipo: Aplicacion montable (no mountable component)
Estructura:
- Componente funcional simple que renderiza
ListaClientesFormdentro de un container fluid - Se auto-inicializa buscando el elemento
#lista-clientes-appen el DOM al cargar la pagina - Usa la funcion
mountAppdemain.tsxpara montar la aplicacion React
Montaje en PHP/HTML:
html
<div id="lista-clientes-app"></div>
<script type="module" src="dist/ventas/informes/lista-clientes.js"></script>ListaClientesForm
Ubicacion: ts/ventas/components/ListaClientesForm.tsxProposito: Formulario de parametros para generar el informe de lista de clientes Lineas: 245
Dependencias:
react-hook-form+@hookform/resolvers/zodpara manejo de formularioCarteraSelectdets/ctacte/components/para seleccion de carterasuseCarteraDatadets/ctacte/hooks/para datos de carterasFormField,RangeSelectordets/core/components/form/generarInformedejs/middleware/informes.js(legacy)ApiRequestdejs/middleware/API.js(legacy)getPermisosModulosdejs/auth/permisos.js(legacy)
Estado Local (useState):
| Variable | Tipo | Proposito |
|---|---|---|
ctacteEnabled | boolean | Controla visibilidad del filtro de cuenta corriente |
carteraEnabled | boolean | Controla visibilidad del filtro de cartera |
Configuracion del Formulario (React Hook Form):
| Campo | Tipo | Default | Descripcion |
|---|---|---|---|
codReporte | number | 6 | Codigo fijo del reporte |
carteraDesde | number | null | null | ID de cartera desde |
carteraHasta | number | null | null | ID de cartera hasta |
ordenamiento | number (1-3) | 1 | 1=Codigo, 2=Alfabeto, 3=Vendedor |
filtroCtaCte | number (1-3) | 3 | 1=Tienen CtaCte, 2=No tienen, 3=Todos |
ordenarPorLocalidades | boolean | false | Ordenar resultado por localidad |
Logica de inicializacion:
- Al montar, obtiene permisos del usuario via
getPermisosModulos()(legacy) - Obtiene datos de empresa via
ApiRequest.get('empres')(legacy) - Habilita filtro de cuenta corriente si
permisos.modulo_ctacte === 1 - Habilita filtro de cartera si
empres.cartera === true
UI Condicional:
- El selector de rango de carteras (
RangeSelector+CarteraSelect) solo se muestra sicarteraEnabled - Los radio buttons de filtro de cuenta corriente solo se muestran si
ctacteEnabled - El boton de submit muestra "Generando..." con spinner durante el envio
Submit: Invoca generarInforme(data) del sistema legacy de informes.
Cancelar: Invoca la funcion global back('mv') del sistema legacy para navegar al menu de ventas.
Hook de Datos
useClienteData
Ubicacion: ts/ventas/hooks/useClienteData.tsProposito: Obtener lista de clientes del backend Lineas: 54
Firma:
typescript
function useClienteData(
scope: string = "min",
skip: boolean = false,
): {
records: ClienteRecord[];
loading: boolean;
error: string | null;
};Tipo exportado:
typescript
interface ClienteRecord {
id: number;
nombre: string;
identificacion?: string | null;
}Comportamiento:
- Usa
useState+useEffectpara fetch de datos (patron legacy, no TanStack Query) - Llama a
api.get('ordcon', { params: { scope } })directamente al endpoint legacy - El parametro
skippermite omitir la carga (util para carga condicional) - Retorna array vacio si la respuesta no es array
- Maneja errores con fallback a mensaje generico
Endpoint consumido: GET backend/ordcon?scope={scope}
Nota: Este hook usa Axios (api.ts) directamente en lugar de TanStack Query. Es un patron de migracion intermedio.
Schemas de Validacion (Zod)
listaClientesSchema
Ubicacion: ts/ventas/schemas/informes.ts
Definicion:
typescript
z.object({
codReporte: z.number(),
carteraDesde: z.number().nullable(),
carteraHasta: z.number().nullable(),
ordenamiento: z.number().min(1).max(3),
filtroCtaCte: z.number().min(1).max(3),
ordenarPorLocalidades: z.boolean(),
});Refinamiento custom:
carteraDesdeno puede ser mayor quecarteraHasta(validacion cruzada)- Mensaje: "La cartera desde no puede ser mayor a la cartera hasta"
- Path del error:
carteraDesde
Tipo generado: ListaClientesFormData = z.infer<typeof listaClientesSchema>
Integracion con Backend
Endpoints Consumidos
| Componente | Metodo | Endpoint | Proposito |
|---|---|---|---|
useClienteData | GET | backend/ordcon | Obtener lista de clientes |
ListaClientesForm | GET | /session/empres (legacy API) | Datos de configuracion de empresa |
ListaClientesForm | - | getPermisosModulos() (legacy) | Permisos del usuario |
ListaClientesForm | - | generarInforme() (legacy) | Generar reporte PDF |
Integracion con Sistema Legacy
El componente ListaClientesForm depende fuertemente del sistema legacy:
generarInforme(js/middleware/informes.js): Servicio legacy para generacion de informes PDFApiRequest(js/middleware/API.js): Cliente HTTP legacy (FormData + fetch)getPermisosModulos(js/auth/permisos.js): Sistema legacy de permisosback('mv'): Funcion global del sistema legacy de navegacion
Estas dependencias legacy se importan con // @ts-ignore ya que no tienen tipos TypeScript.
Integracion con Otros Modulos
Modulo CtaCte (Cuentas Corrientes)
| Componente/Hook | Origen | Proposito |
|---|---|---|
CarteraSelect | ts/ctacte/components/CarteraSelect.js | Selector de carteras |
useCarteraData | ts/ctacte/hooks/useCarteraData.js | Datos de carteras |
CarteraRecord | ts/ctacte/types/carteras.js | Tipo de dato de cartera |
Modulo Core (Compartido)
| Componente | Origen | Proposito |
|---|---|---|
FormField | ts/core/components/form/ | Wrapper de campos con error |
RangeSelector | ts/core/components/form/ | Selector de rango (desde-hasta) |
Routing
No se utiliza React Router. La navegacion se maneja de forma legacy:
- Montaje: La app se monta como una aplicacion React standalone en un contenedor HTML
- Navegacion: La funcion global
back('mv')del sistema legacy maneja la navegacion "atras" - Entrada: El punto de entrada se referencia desde una plantilla PHP con
<script type="module">
Estructura de Archivos
Archivos Legacy (Vanilla JS)
view/mod-ventas/
└── form-cliente.php # Template PHP del formulario CRUD
js/
├── view/mod-ventas/
│ └── form-cliente.js # Inicializador del formulario
└── components/forms/general/
└── cliente.js # Componente reutilizable createFormClienteArchivos React/TypeScript
ts/ventas/
├── components/
│ └── ListaClientesForm.tsx # Formulario de informe de clientes
├── hooks/
│ └── useClienteData.ts # Hook para obtener datos de clientes
├── informes/
│ ├── ListaClientesApp.tsx # App standalone de informe
│ └── ComprobantePorConceptosForm.tsx # Otro informe que usa clientes
├── schemas/
│ └── informes.ts # Schemas Zod para informes
└── config/
└── queryKeys.ts # Keys de TanStack Query (no usado en clientes aun)Patrones Identificados
Patron de Migracion Progresiva
El ABM de Clientes muestra el patron de migracion progresiva del sistema:
- El CRUD principal permanece en vanilla JS
- Los nuevos componentes (informes) se implementan en React
- Se usan imports
@ts-ignorepara integrar con funciones legacy - El hook
useClienteDatausa Axios directamente (migracion intermedia), no TanStack Query
Patron de App Standalone
ListaClientesApp se auto-monta al detectar el contenedor #lista-clientes-app en DOMContentLoaded. Esto permite insertar la aplicacion React en cualquier pagina PHP sin necesidad de React Router.
Patron de Habilitacion por Permisos
La visibilidad de secciones del formulario se controla dinamente segun:
- Permisos del modulo (
modulo_ctacte) - Configuracion de empresa (
empres.cartera)
Consideraciones de Accesibilidad
- Los inputs usan
labelasociados viahtmlFor - Los radio buttons usan la estructura
custom-controlde AdminLTE/Bootstrap - Los botones deshabilitados usan el atributo
disableddurante submit - El spinner de carga proporciona feedback visual durante la generacion
Recomendaciones de Migracion [OBSERVACIONES RETROSPECTIVAS]
Basado en el analisis del codigo implementado, se identifican las siguientes oportunidades:
- CRUD principal: El formulario de alta/edicion de clientes (
createFormCliente) es el candidato principal para migracion a React. Actualmente opera en vanilla JS con jQuery UI autocomplete, jQuery collapse y SweetAlert2 - useClienteData: Migrar de
useState + useEffecta TanStack Query para aprovechar cache, revalidacion y deduplicacion - Dependencias legacy: Reemplazar
generarInforme,ApiRequestygetPermisosModuloscon equivalentes TypeScript - Tipos: Crear tipos completos de
Cliente(scope max) ents/ventas/types/para uso en todo el modulo - CarteraSelect ya esta en React: El campo de cartera dentro del formulario legacy ya fue migrado a React via
mountComponent, lo que demuestra viabilidad de migracion progresiva
Referencias
Actualizaciones Post-Generacion
Fecha: 2026-02-09
Informacion Validada:
- [x] Eliminacion de clientes: No implementada (integridad referencial)
- [x] Tabla compartida: ordcon usada por clientes (ventas) y miembros (membresias)
- [x] Formulario CRUD: Vanilla JS legacy (form-cliente.php + form-cliente.js + cliente.js)
- [x] Campo defecto: Valor inicial en formularios (ej: facturacion electronica)
- [x] Validacion: Legacy (proxy frontend, backend, model/DTO), no middleware
- [x] Concurrencia: Sin problemas actuales, mejora pendiente
- [x] Permisos: Client-side only, no backend
- [x] Ruta cross-module: Compartida Ventas + CtaCte
- [x] Schema: Actualizado con migracion 20240823200741
NOTA IMPORTANTE: Esta documentacion fue generada automaticamente analizando el codigo implementado y actualizada con validaciones del equipo de desarrollo el 2026-02-09. Las secciones marcadas como [OBSERVACIONES RETROSPECTIVAS] son inferencias del analisis, no requisitos confirmados.