Plataforma técnica · Sevastopol
Legal Representatives View Island
Islands Sevastopol Administración
Propósito
Section titled “Propósito”LegalRepresentativesViewIsland opera el padrón de representantes legales y socios del tenant: CRUD básico + dos acciones contables que afectan el plan de cuentas — activar/desactivar la cuenta corriente socio (sub-cuenta bajo 2204000) y revisar los movimientos del socio contra esa cuenta.
Ubicación
Section titled “Ubicación”Directorysevastopol/src/components/islands/admin/
- LegalRepresentativesViewIsland.tsx — componente único, internamente
LegalRepresentativesView
- LegalRepresentativesViewIsland.tsx — componente único, internamente
Directorysevastopol/src/config/
- headers.ts —
HEADERS_LEGAL_REPS
- headers.ts —
Estado
Section titled “Estado”const { tenantId } = useActiveTenant((id) => void fetchData(id));const [representatives, setRepresentatives] = createSignal<LegalRep[]>([]);const [selectedRep, setSelectedRep] = createSignal<LegalRep | null>(null);const [movimientos, setMovimientos] = createSignal<MovimientoSocio[]>([]);Filtros y modal:
| Signal | Tipo | Uso |
|---|---|---|
qName / qRUT | string | Filtros locales sub-string. |
qActive | string | "", "true" (vigentes), "false" (no vigentes). |
showModal / editingId / formData | edición | Modal de alta/edición. |
selectedRep / movimientos / loadingMov | panel | Panel lateral de movimientos del socio. |
Filtros y orden
Section titled “Filtros y orden”const filteredReps = createMemo(() => { let list = [...representatives()]; if (qName()) { const q = qName().toLowerCase(); list = list.filter(r => r.nombres.toLowerCase().includes(q) || r.apellidos.toLowerCase().includes(q), ); } if (qRUT()) list = list.filter(r => r.rut.includes(qRUT())); if (qActive() === "true") list = list.filter(r => r.vigente); if (qActive() === "false") list = list.filter(r => !r.vigente); return list.sort((a, b) => a.apellidos.localeCompare(b.apellidos));});Orden estable por apellido — facilita lectura tipo guía telefónica.
Métricas en pills
Section titled “Métricas en pills”| Métrica | Cálculo |
|---|---|
| Total | representatives.length |
| Vigentes | representatives.filter(r => r.vigente).length |
| Pendientes | representatives.filter(r => !r.vigente && !r.fecha_hasta).length (sin fecha de baja explícita) |
| Con cuenta | representatives.filter(r => r.tiene_cuenta_socio).length |
CRUD principal
Section titled “CRUD principal”| Campo | Obligatorio | Notas |
|---|---|---|
rut | Sí | Formato ^\d{7,8}-[\dkK]$ (validado en backend). |
nombres | Sí | — |
apellidos | Sí | — |
fecha_desde | Sí | Inicio de vigencia. |
fecha_hasta | No | Si está, marca baja. |
vigente | — | Default true. |
cargo | No | Texto libre (gerente general, director, etc.). |
email | No | Validado en backend si está. |
telefono | No | — |
direccion | No | — |
observaciones | No | — |
Validación de cliente: los 4 primeros campos no vacíos. El resto va tal cual al backend.
if (!payload.rut || !payload.nombres || !payload.apellidos || !payload.fecha_desde) { toast.push("RUT, Nombres, Apellidos y Fecha Desde son obligatorios", "error"); return;}Cuenta corriente socio
Section titled “Cuenta corriente socio”Cada representante puede tener una cuenta corriente socio asociada: una sub-cuenta dinámica bajo 2204000 (cuentas por pagar socios) más un banco virtual que rastrea aportes/retiros del socio.
async function handleToggleCuenta(rep: LegalRep) { const action = rep.tiene_cuenta_socio ? "desactivar" : "activar"; if (rep.tiene_cuenta_socio && !confirm("¿Desactivar la cuenta corriente socio? El banco quedará inactivo.")) { return; } const r = await authenticatedFetch( `${API_BASE}/${rep.id}/${action}-cuenta?tenant_id=${tenantId()}`, { method: "POST" }, );}| Estado | Acción visible | Endpoint |
|---|---|---|
Sin cuenta (tiene_cuenta_socio === false) | Activar cuenta | POST /:id/activar-cuenta |
Con cuenta (tiene_cuenta_socio === true) | Desactivar cuenta | POST /:id/desactivar-cuenta (con confirm) |
Solo la desactivación pide confirm — la activación es no destructiva.
Panel de movimientos del socio
Section titled “Panel de movimientos del socio”Al clickear una fila, se carga el listado de MovimientoSocio del representante seleccionado:
| Columna | Origen |
|---|---|
| Fecha | fmtDate(movimiento.fecha) |
| Tipo | APORTE / RETIRO / AJUSTE |
| Monto | fmtCLP(monto) |
| Descripción | Glosa o referencia al asiento. |
loadingMov bloquea el panel mientras se hace el fetch. El panel se cierra al deseleccionar la fila.
Endpoints consumidos
Section titled “Endpoints consumidos”| Método | Ruta | Operación |
|---|---|---|
GET | /api/admin/representatives?tenant_id=... | Lista del padrón. |
POST | /api/admin/representatives?tenant_id=... | Alta. |
PUT | /api/admin/representatives/:id?tenant_id=... | Edición. |
DELETE | /api/admin/representatives/:id?tenant_id=... | Eliminación. |
POST | /api/admin/representatives/:id/activar-cuenta?tenant_id=... | Crea sub-cuenta socio + banco virtual. |
POST | /api/admin/representatives/:id/desactivar-cuenta?tenant_id=... | Marca cuenta socio inactiva. |
GET | /api/admin/representatives/:id/movimientos?tenant_id=... | Movimientos del socio. |
Reglas de UI
Section titled “Reglas de UI”| Regla | Motivo |
|---|---|
| Validar 4 campos clave antes de enviar | Acelera el feedback; el backend igual valida. |
| Confirm en desactivar cuenta, no en activar | Activar no destruye nada; desactivar oculta el banco virtual. |
| Confirm en eliminar representante | El backend impide eliminar si tiene movimientos asociados; la confirmación evita el viaje. |
Conteo Con cuenta en pill | Da visibilidad rápida del compromiso contable abierto. |
| Carga de movimientos a demanda (al seleccionar) | El fetch puede ser pesado por representante; lazy load mejora la carga inicial. |
| Orden por apellido en la tabla | Padrón con muchos socios se lee como guía. |
| Hereda RUT/nombres como identidad mostrada | El header de fila muestra “Nombres Apellidos” sobre “RUT” para escaneo rápido. |
Sin filtrar por tiene_cuenta_socio | El filtro vigente cubre el caso normal; agregar otra dimensión saturaría la UI. |