El módulo Reteica del sistema municipal de impuestos gestiona la retención de industria y comercio a través de cuatro pantallas principales relacionadas jerárquicamente: el catálogo de Terceros (personas naturales y jurídicas), el registro de Contribuyentes (terceros inscritos ante el municipio), el sub-módulo de Establecimientos (sedes comerciales de cada contribuyente) y el flujo de Presentar Declaración (declaración periódica de retención). Cada pantalla tiene su propio Page Object que extiende los componentes comunes con locators y métodos específicos de su formulario.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Giofelix/Proyecto-automatizacion-Empresa/llms.txt
Use this file to discover all available pages before exploring further.
Terceros
Catálogo de terceros con pestañas Básicos y Adicionales.
Contribuyentes
Registro de contribuyentes y navegación al menú de procesos.
Establecimientos
Sedes comerciales de un contribuyente con formulario de dos pestañas.
PresentarDeclaracion
Wizard de 4 pasos para declaraciones periódicas de Reteica.
Terceros
Archivo:pages/modulos/reteica/archivos/terceros.page.js
La página de Terceros organiza el formulario de datos del tercero en dos pestañas de Angular Material: Básicos (información fiscal y de contacto) y Adicionales (ubicación geográfica y datos complementarios). Los combos de régimen, naturaleza, país, departamento y ciudad utilizan componentes app-combo con botones de tipo play_arrow que no tienen nombre ARIA, por lo que se localizan mediante el texto de contenido del icono.
Constructor — locators principales
Pestaña Básicos
| Propiedad | Locator | Descripción |
|---|---|---|
tabBasicos | page.getByRole('tab', { name: 'Basicos' }) | Pestaña Básicos del formulario |
inputNit | page.getByRole('textbox', { name: 'Nit' }) | NIT del tercero (Tab dispara cálculo del dígito de verificación) |
inputRazonSocial | page.getByRole('textbox', { name: 'Primer nombre / Razón social' }) | Razón social o primer nombre |
inputDigitoVerificacion | page.getByRole('spinbutton', { name: 'Dígito de verificación' }) | Campo de solo lectura (auto-calculado) |
comboTipoRegimen | page.getByRole('combobox', { name: 'Tipo regimen' }) | Selector de tipo de régimen |
btnTipoRegimen | page.locator('mat-form-field').filter({ hasText: 'Tipo regimen' }).getByRole('button') | Botón play_arrow del combo Tipo regimen |
comboNaturaleza | page.getByRole('combobox', { name: 'Naturaleza' }) | Selector de naturaleza (campo requerido) |
btnNaturaleza | page.locator('mat-form-field').filter({ hasText: 'Naturaleza' }).getByRole('button') | Botón play_arrow del combo Naturaleza |
inputDireccion | page.getByRole('textbox', { name: 'Dirección' }) | Dirección del tercero |
inputTelefonos | page.getByRole('textbox', { name: 'Teléfonos' }) | Teléfonos de contacto |
comboTipoDocumento | page.getByRole('combobox', { name: 'Tipo de documento' }) | Tipo de documento de identidad |
btnTipoDocumento | page.locator('mat-form-field').filter({ hasText: 'Tipo de documento' }).getByRole('button') | Botón del combo Tipo de documento |
Pestaña Adicionales
| Propiedad | Locator | Descripción |
|---|---|---|
tabAdicionales | page.getByRole('tab', { name: 'Adicionales' }) | Pestaña Adicionales del formulario |
comboPais | page.getByRole('combobox', { name: 'Pais' }) | Combo de país |
btnPais | page.locator('#ID_PAIS').getByRole('button').filter({ hasText: 'play_arrow' }) | Botón del app-combo País (localizado por ID propio del componente) |
comboDepartamento | page.getByRole('combobox', { name: 'Departamento' }) | Combo de departamento |
btnDepartamento | page.locator('#ID_DEPARTAMENTO').getByRole('button').filter({ hasText: 'play_arrow' }) | Botón del app-combo Departamento |
comboCiudad | page.getByRole('combobox', { name: 'Ciudad' }) | Combo de ciudad (campo requerido) |
btnCiudad | page.locator('mat-form-field').filter({ hasText: 'Ciudad' }).getByRole('button') | Botón del combo Ciudad |
inputEmail | page.getByRole('textbox', { name: 'Direccion E-mail' }) | Dirección de correo electrónico |
Métodos
completarDatosBasicos(datos)
Hace clic en la pestaña Básicos y rellena los campos del formulario con los valores proporcionados.
Objeto con los campos de la pestaña Básicos.
completarDatosAdicionales(datos)
Hace clic en la pestaña Adicionales y rellena los combos de ubicación y el email.
Objeto con los campos de la pestaña Adicionales.
Ejemplo
El dígito de verificación (
inputDigitoVerificacion) es calculado automáticamente por el sistema en el backend al recibir el NIT. No debes escribirlo manualmente; el press('Tab') en completarDatosBasicos dispara el blur que inicia ese cálculo.Contribuyentes
Archivo:pages/modulos/reteica/archivos/contribuyentes/contribuyentes.page.js
La página de Contribuyentes gestiona el catálogo de contribuyentes del municipio. El flujo de creación implica un diálogo Nuevo Registro con un selector de terceros que se abre como mat-bottom-sheet. La vista de detalle expone un menú more_vert que da acceso a procesos secundarios como declaraciones, pagos parciales y estados de cuenta.
Constructor — locators principales
Diálogo Nuevo Registro
| Propiedad | Locator | Descripción |
|---|---|---|
dialogoNuevoRegistro | page.getByRole('dialog', { name: 'Nuevo Registro' }) | Contenedor del diálogo de creación |
selectorNombre | dialogoNuevoRegistro.getByRole('listbox', { name: 'Nombre' }) | Abre el selector de terceros (mat-bottom-sheet) |
inputMatricula | dialogoNuevoRegistro.getByRole('textbox', { name: 'Matrícula', exact: true }) | Número de matrícula del contribuyente |
inputFechaMatricula | dialogoNuevoRegistro.getByRole('textbox', { name: 'Fecha matrícula' }) | Fecha de matrícula del establecimiento |
Selector de Terceros (mat-bottom-sheet)
| Propiedad | Locator | Descripción |
|---|---|---|
dialogoSelectorTerceros | page.getByRole('dialog').filter({ has: page.locator('mat-tab-group') }) | Diálogo con pestañas DATOS / FILTROS |
tabDatosTerceros | page.getByRole('tab', { name: /datos/i }) | Pestaña de resultados de la búsqueda |
tabFiltrosTerceros | page.getByRole('tab', { name: /filtros/i }) | Pestaña de criterios de filtro |
inputFiltroNit | page.locator('mat-tab-group').getByRole('textbox', { name: /nit/i }) | Campo de filtro por NIT |
btnAplicarFiltro | page.getByRole('button', { name: 'Aplicar' }) | Ejecuta la búsqueda con los filtros activos |
gridTercerosCeldaNit(nit) | page.locator('mat-bottom-sheet-container mat-row').filter({ has: page.locator('mat-cell.cdk-column-NIT', { hasText: nit }) }).first() | Fila del tercero en el mat-bottom-sheet (NO en la tabla principal) |
Página de Detalle
| Propiedad | Locator | Descripción |
|---|---|---|
btnMenuProcesos | page.getByRole('button').filter({ hasText: 'more_vert' }) | Botón de menú de procesos adicionales |
menuProcesos | page.getByRole('menu') | Panel del menú desplegado |
inputNit | page.getByRole('textbox', { name: 'Nit del propietario' }) | NIT del tercero vinculado (solo lectura en detalle) |
inputNombre | page.getByRole('textbox', { name: 'Nombre' }) | Nombre del contribuyente |
inputEstado | page.getByRole('textbox', { name: 'Estado' }) | Estado del contribuyente (activo/inactivo) |
Métodos
irAProcesoDesdeMenu(nombreOpcion)
Abre el menú more_vert y hace clic en la opción indicada, esperando networkidle tras la navegación.
Nombre exacto del ítem de menú (valor de
name en getByRole('menuitem')). Opciones disponibles definidas en el constructor:
'Declaraciones', 'Actualizar otros impuestos',
'Emplazamiento por no declarar', 'Pagos parciales', 'Edicion de abonos',
'Terceros asociados', 'Documentos RIT', 'Activar', 'Bitacora estado',
'Facturas', 'Estado de cuenta', 'Generar RIT', 'Generar RIC',
'Histórico de declaraciones'.verificarContribuyenteEnTabla(nit)
NIT exacto del contribuyente a verificar en la tabla.
nit aparece en la tabla principal. Si la fila no está visible en la página actual, abre automáticamente el diálogo de filtro “Búsqueda por:”, filtra por NIT, cierra el diálogo y luego afirma la visibilidad de la celda con expect(...).toBeVisible().
seleccionarTerceroPorNit(nit)
NIT del tercero a seleccionar en el picker.
mat-bottom-sheet:
- Hace clic en la pestaña Filtros y escribe el NIT en
inputFiltroNit. - Hace clic en Aplicar y cambia a la pestaña Datos.
- Espera que la fila del tercero sea visible en
mat-bottom-sheet-containery la selecciona conforce: true(necesario por la intercepción de pointer events de Angular Material). - Espera que
mat-bottom-sheet-containerseadetacheddel DOM antes de retornar.
completarNuevoRegistro(datos)
Ejemplo
El
mat-bottom-sheet del selector de Terceros puede dejar un cdk-global-overlay-wrapper bloqueando los pointer events tras cerrarse. Los métodos seleccionarTerceroPorNit y aceptarNuevoRegistro usan force: true de forma deliberada para bypassear ese bloqueo transitorio.Establecimientos
Archivo:pages/modulos/reteica/archivos/contribuyentes/menu-procesos-contribuyentes/establecimientos.page.js
La página de Establecimientos gestiona las sedes comerciales asociadas a un contribuyente. El formulario de creación y edición se divide en dos pestañas de Angular Material — Básica (datos obligatorios de contacto y ubicación) y Adicional (datos complementarios opcionales). La navegación de vuelta a la lista se realiza a través del breadcrumb, ya que el formulario no expone un botón Cancelar explícito.
Constructor — locators principales
Tabla principal
| Propiedad | Locator | Descripción |
|---|---|---|
tablaGrid | page.getByRole('grid') | Grid principal de la lista de establecimientos |
columnaCodigo | page.getByRole('columnheader', { name: 'Código' }) | Encabezado de columna Código |
columnaNombre | page.getByRole('columnheader', { name: 'Nombre' }) | Encabezado de columna Nombre |
btnMenuLista | page.getByRole('button').filter({ hasText: 'more_vert' }) | Menú contextual de la lista (more_vert) |
menuItemRegistrarActividades | page.getByRole('menuitem', { name: 'Registrar actividades' }) | Ítem de menú para registrar actividades |
Formulario — pestaña Básica
| Propiedad | Locator | Descripción |
|---|---|---|
tabBasica | page.getByRole('tab', { name: 'Básica' }) | Pestaña Básica del formulario |
inputNombre | page.getByRole('textbox', { name: 'Nombre' }) | Nombre del establecimiento (obligatorio) |
inputTelefono | page.getByRole('spinbutton', { name: 'Teléfono' }) | Teléfono (obligatorio, tipo número) |
btnPais | page.locator('mat-form-field').filter({ hasText: 'País' }).getByRole('button') | Botón play_arrow del combo País (obligatorio) |
btnDepartamento | page.locator('mat-form-field').filter({ hasText: 'Departamento' }).getByRole('button') | Botón del combo Departamento (se habilita tras País) |
btnCiudad | page.locator('mat-form-field').filter({ hasText: 'Ciudad' }).getByRole('button') | Botón del combo Ciudad (se habilita tras Departamento) |
btnBarrio | page.locator('mat-form-field').filter({ hasText: 'Barrio' }).getByRole('button') | Botón del combo Barrio (obligatorio) |
inputDireccion | page.getByRole('textbox', { name: 'Dirección' }) | Dirección del establecimiento (obligatorio) |
inputCorreoElectronico | page.getByRole('textbox', { name: 'Correo electronico' }) | Correo electrónico (obligatorio) |
inputInicioActividad | page.getByRole('textbox', { name: 'Inicio actividad' }) | Fecha de inicio de actividad (obligatorio) |
btnBreadcrumbEstablecimientos | page.getByRole('button', { name: 'Establecimientos' }) | Botón de breadcrumb para volver a la lista |
Formulario — pestaña Adicional
| Propiedad | Locator | Descripción |
|---|---|---|
tabAdicional | page.getByRole('tab', { name: 'Adicional' }) | Pestaña Adicional del formulario |
inputCodigoCatastral | page.getByRole('textbox', { name: 'Código catastral' }) | Código catastral (opcional) |
inputPaginaWeb | page.getByRole('textbox', { name: 'Página web' }) | Página web (opcional) |
inputCodigoPostal | page.getByRole('textbox', { name: 'Código postal' }) | Código postal (opcional) |
inputCodigoAdicional | page.getByRole('tabpanel', { name: 'Adicional' }).getByPlaceholder('Código', { exact: true }) | Campo Código adicional (opcional) |
Métodos
completarTabBasica(datos)
Rellena todos los campos de la pestaña Básica. Los combos geográficos encadenados (País → Departamento → Ciudad → Barrio) se completan con seleccionarOpcionPlayArrow().
completarTabAdicional(datos)
Cambia a la pestaña Adicional y rellena los campos opcionales definidos en el objeto.
Objeto con claves opcionales:
codigoCatastral, paginaWeb, codigoPostal, codigoAdicional. Todos de tipo string.verificarEstablecimientoEnTabla(codigo)
Código exacto del establecimiento a verificar.
expect(...).toBeVisible({ timeout: 15000 }) que existe una gridcell con el código exacto en la tabla principal.
abrirEstablecimiento(nombre)
Nombre exacto del establecimiento tal como aparece en la tabla.
networkidle para la carga del formulario de detalle.
cancelar()
Navega de vuelta a la lista usando el botón del breadcrumb (btnBreadcrumbEstablecimientos) y espera a que la grilla o el mensaje “No existe información” sean visibles.
irARegistrarActividades()
Abre el menú more_vert de la lista y hace clic en Registrar actividades, esperando networkidle.
completarFiltros(filtros)
Rellena el diálogo de filtro “Búsqueda por:” con los criterios proporcionados y confirma con el botón Aceptar.
Objeto con claves opcionales:
codigo, nombre, telefono, direccion, estado, matricula, fechaMatricula, inicioActividad. Todos de tipo string.Ejemplo
El campo Código del establecimiento es autogenerado por el sistema y está deshabilitado en el formulario. No debe llenarse manualmente. El campo Consecutivo matrícula también es autogenerado.
PresentarDeclaracion
Archivo:pages/modulos/reteica/archivos/contribuyentes/menu-procesos-contribuyentes/presentar-declaracion.page.js
PresentarDeclaracion encapsula el wizard de cuatro pestañas para presentar una declaración periódica de Reteica. Cada pestaña corresponde a un paso del proceso: selección del período gravable, asignación de establecimientos, ingreso de valores de liquidación y firma electrónica mediante el diálogo de Terceros Asociados.
Wizard — estructura de pestañas
| # | Nombre de pestaña | Locator | Acción de avance |
|---|---|---|---|
| 1 | Año gravable | page.getByRole('tab', { name: 'Año gravable' }) | btnSiguienteAnio (mat-raised-button) |
| 2 | Establecimientos | page.getByRole('tab', { name: 'Establecimientos' }) | btnSiguienteEstablecimientos |
| 3 | Liquidación de conceptos | page.getByRole('tab', { name: 'Liquidación de conceptos' }) | btnSiguienteLiquidacion |
| 4 | Declaración | page.getByRole('tab', { name: 'Declaración' }) | — (finaliza con el diálogo de terceros) |
Constructor — locators principales
Sección 1 — Año gravable
| Propiedad | Locator |
|---|---|
btnAnio | page.locator('mat-form-field').filter({ hasText: 'Seleccione el año a declarar' }).getByRole('button') |
btnPeriodo | page.locator('mat-form-field').filter({ hasText: 'Período' }).getByRole('button') |
btnTipoDeclaracion | page.locator('mat-form-field').filter({ hasText: 'Tipo de declaración' }).getByRole('button') |
inputFechaPresentacion | page.getByRole('textbox', { name: 'Fecha de presentación' }) |
checkEntidadPublica | page.getByRole('checkbox', { name: 'Entidad publica u otros.' }) |
dialogoConfirmacion | page.getByRole('dialog', { name: 'Confirmación' }) |
Sección 3 — Liquidación de conceptos
Los campos de liquidación se dividen en dos grupos dentro del mismo tabpanel:- Solo lectura (
input[readonly][placeholder="..."]): valores calculados por el sistema. Locators con prefijoinputSist*. - Editables (
input:not([readonly])[placeholder="..."]): valores ingresados por el usuario. Locators con prefijoinputLiq*.
COMPRAS, SERVICIOS, INDUSTRIA, FINANCIERA, AUTORETENCION VENTAS, AUTORETENCION SERVICIOS, AUTORETENCION OTROS CONCEPTOS, TOTAL RETENCIONES, INTERES DE MORA, EXTEMPORANEIDAD, TOTAL SALDO A CARGO, VALOR A PAGAR, MAS OTRAS SANCIONES, SANCIÓN POR CORRECCIÓN, TOTAL SANCION, TOTAL A PAGAR.
Sección 4 — Terceros Asociados (diálogo)
| Propiedad | Locator |
|---|---|
dialogoTercerosAsociados | page.getByRole('dialog').filter({ has: page.getByRole('heading', { name: 'Terceros asociados' }) }) |
btnDeclTipoDeclarante | dialogoTercerosAsociados.locator('mat-form-field').filter({ hasText: 'Tipo declarante' }).getByRole('button') |
btnDeclTipoDocumento | dialogoTercerosAsociados.locator('mat-form-field').filter({ hasText: 'Tipo de documento' }).getByRole('button').nth(0) |
inputDeclNumeroDocumento | dialogoTercerosAsociados.getByRole('textbox', { name: 'Número de documento' }).nth(0) |
inputDeclNombres | dialogoTercerosAsociados.getByRole('textbox', { name: 'Nombres' }).nth(0) |
btnGuardarDialogo | dialogoTercerosAsociados.getByRole('button', { name: 'Guardar' }) |
Dentro del diálogo de Terceros Asociados existen dos instancias de los campos Tipo de documento, Número de documento y Nombres:
nth(0) corresponde al declarante y nth(1) al contador o revisor fiscal.Métodos
completarSeccion1(datos)
Selecciona año, período y tipo de declaración, y opcionalmente rellena la fecha de presentación.
completarSeccion3(datos)
Rellena los campos editables de la sección de Liquidación de conceptos. Todos los campos son opcionales; sólo se invoca fill() para los que estén definidos en el objeto.
Objeto con claves:
compras, servicios, industria, financiera, autoRetencionVentas, autoRetencionServicios, autoRetencionOtros, interesMora, extemporaneidad, masOtrasSanciones, sancionCorreccion. Todos de tipo string (valor monetario como texto).actualizarLiquidacion()
Hace clic en el botón Actualizar de la sección 3 y espera networkidle (30 s). Esto recalcula los totales (TOTAL RETENCIONES, TOTAL SALDO A CARGO, TOTAL A PAGAR, etc.) en el panel de Liquidación del sistema.
avanzarDesdeEstablecimientos()
Hace clic en btnSiguienteEstablecimientos y espera networkidle. Avanza del paso 2 al paso 3.
avanzarDesdeLiquidacion()
Hace clic en btnSiguienteLiquidacion y espera networkidle. Avanza del paso 3 al paso 4 y abre automáticamente el diálogo de Terceros Asociados.
completarDatosDeclarante(datos)
Rellena la sub-sección Datos declarante del diálogo Terceros Asociados.
guardarTercerosAsociados()
Hace clic en el botón Guardar del diálogo de Terceros Asociados y espera networkidle.
verificarTabActiva(nombreTab)
Nombre de la pestaña que debe estar activa (valor del atributo
aria-selected="true").expect(tab).toHaveAttribute('aria-selected', 'true') para asegurar que el wizard se encuentra en el paso correcto.
verificarDialogoTercerosVisible()
Afirma con expect(dialogoTercerosAsociados).toBeVisible({ timeout: 15000 }) que el diálogo de Terceros Asociados está visible. Se usa como precondición antes de completarDatosDeclarante().