Plataforma técnica · Sevastopol
Ppm Actualizacion Anual Island
Ingresos Islands Sevastopol
Propósito
Section titled “Propósito”PpmActualizacionAnualIsland muestra el resumen del PPM declarado vs PPM actualizado del año con su factor de corrección monetaria por mes, y permite contabilizar el ajuste (cargo 1108001 PPM por recuperar / abono 4201002 ingreso por ajuste CM) y reversar filas ya contabilizadas. La acción se llama desde el paso ppm de CicloContableIsland o directamente desde Ingresos View Island.
Ubicación
Section titled “Ubicación”Directorysevastopol/src/components/islands/contabilidad/
- PpmActualizacionAnualIsland.tsx — componente único, internamente
PpmActualizacionAnualPanel - ContabilidadWorkspace.tsx — tokens visuales (solo
workspaceFieldClassaquí)
- PpmActualizacionAnualIsland.tsx — componente único, internamente
Directorysevastopol/src/pages/api/reportes/
- […path].ts — proxy genérico vía createProxy(“/api/reportes”)
Hooks y estado global
Section titled “Hooks y estado global”const { tenantId } = useActiveTenant(() => void loadData());const { period } = useActivePeriod(() => { if (period().year) setAnio(String(period().year));});const [anio, setAnio] = createSignal(String(period().year ?? new Date().getFullYear()));| Hook | Aporta | Reactividad |
|---|---|---|
useActiveTenant | UUID del tenant. | Recarga el resumen al cambiar tenant. |
useActivePeriod | { year, month }. | Solo lee year; month se ignora porque la DJ es anual. Sincroniza anio y re-fetcha. |
Dos createEffect mantienen anio sincronizado con el período activo y disparan recarga ante cualquier cambio:
createEffect(() => { const activeYear = period().year; if (activeYear && String(activeYear) !== anio()) setAnio(String(activeYear));});
createEffect(() => { if (tenantId() && anio()) void loadData();});Signals locales:
| Signal | Tipo | Uso |
|---|---|---|
anio | string | Año consultado (editable manualmente vía <input type="number" min=2000 max=2100>). |
data | PpmResumen | null | Respuesta del backend; null en error o sin tenant. |
loading | boolean | Bloqueo durante el GET. |
saving | "contabilizar" | "reversar" | null | Distingue la acción en curso para etiquetar el botón. |
Estructura del resumen
Section titled “Estructura del resumen”interface PpmResumen { anio: number; total_declarado: number; total_actualizado: number; total_ajuste: number; meses_declarados: number; meses_con_ajuste: number; meses_contabilizados: number; estado_general: "PENDIENTE" | "PARCIAL" | "CONTABILIZADO"; filas: PpmRow[];}
interface PpmRow { id: number | null; anio: number; mes: number; periodo: string; declaracion_f29_id: string | null; declaracion_estado: string | null; ppm_declarado: number; factor_aplicable: number; ppm_actualizado: number; ajuste_correccion: number; cuenta_activo_codigo: string; cuenta_ingreso_codigo: string; fuente_url: string | null; estado: "BORRADOR" | "CONTABILIZADO" | "REVERSADO" | "PENDIENTE"; fecha_contabilizacion: string | null; fecha_reversa: string | null;}El backend devuelve esta estructura por año/tenant. Cuando no existe data, se sintetiza un resumen vacío en el frontend:
const resumen = createMemo<PpmResumen>(() => data() ?? { anio: Number(anio()), total_declarado: 0, total_actualizado: 0, total_ajuste: 0, meses_declarados: 0, meses_con_ajuste: 0, meses_contabilizados: 0, estado_general: "PENDIENTE", filas: [],});Métricas en StatCard
Section titled “Métricas en StatCard”Cuatro tarjetas en el header:
| Métrica | Valor | Subtexto |
|---|---|---|
| PPM declarado | clp(total_declarado) | {meses_declarados} mes(es) con declaración |
| PPM actualizado | clp(total_actualizado) | ”Actualizado a diciembre” |
| Ajuste CM | clp(total_ajuste) | ”Impacta 1108001 vs 4201002” |
| Estado | estado_general (badge) | {meses_contabilizados}/{meses_con_ajuste} mes(es) contabilizados |
Tabla mensual
Section titled “Tabla mensual”8 columnas, ordenada por sortMes = -row.mes (más reciente arriba):
| Columna | Render |
|---|---|
| Mes | MONTH_LABELS[row.mes - 1] |
| Declaración | row.declaracion_estado o "-" |
| PPM declarado | clp(ppm_declarado) |
| Factor | fmtFactor(factor_aplicable) — 1.034521x |
| PPM actualizado | clp(ppm_actualizado) |
| Ajuste | clp(ajuste_correccion) en verde |
| Estado | <span class={badgeClassForStatus(estado)}> |
| Contab. / Rev. | fmtFecha(fecha_contabilizacion) y, si existe, Rev. {fmtFecha(fecha_reversa)} |
DataTable recibe sumKeys={["ppm_declarado", "ppm_actualizado", "ajuste_correccion"]} para totalizar las columnas numéricas automáticamente.
Contabilización
Section titled “Contabilización”El botón Contabilizar se habilita cuando hay tenant + monto declarado:
const canContabilizar = createMemo(() => Boolean(tenantId()) && resumen().total_declarado > 0);El click pide confirmación explícita con el detalle contable:
const ok = confirm( `¿Contabilizar actualización de PPM ${anio()}? Esto cargará 1108001 y abonará 4201002 en balance/reportes.`,);Tras confirmar, hace POST /api/reportes/ppm-actualizacion-anual/contabilizar?tenant_id=... con { anio }. La respuesta trae { contabilizados, ajuste_total } que se muestran en el toast:
toast.success( `PPM anual contabilizado: ${body?.contabilizados ?? 0} mes(es) · ajuste ${clp(body?.ajuste_total ?? 0)}`,);Recontabilizar
Section titled “Recontabilizar”Si estado_general === "CONTABILIZADO", el botón cambia de etiqueta a Recontabilizar:
{saving() === "contabilizar" ? "Contabilizando..." : resumen().estado_general === "CONTABILIZADO" ? "Recontabilizar" : "Contabilizar"}El endpoint es el mismo — el backend detecta el estado y reemplaza filas previas. Útil cuando se corrige un factor anterior y hay que re-emitir los asientos.
Reversa
Section titled “Reversa”El botón Reversar se habilita solo si hay al menos una fila CONTABILIZADO:
const canReversar = createMemo(() => resumen().filas.some((row) => row.estado === "CONTABILIZADO"));Confirmación explícita con el efecto contable:
const ok = confirm( `¿Reversar actualización de PPM ${anio()}? Se eliminará el impacto en 1108001 y 4201002 del balance.`,);POST /api/reportes/ppm-actualizacion-anual/reversar?tenant_id=... con { anio }. La respuesta { reversados, ajuste_total } aparece en el toast. La reversa no elimina las filas — las marca como REVERSADO y conserva la trazabilidad con fecha_reversa.
Estados visibles
Section titled “Estados visibles”estado_general | Significado |
|---|---|
PENDIENTE | Hay PPM declarado pero ningún mes contabilizado. |
PARCIAL | Algunos meses con ajuste están contabilizados; otros no. |
CONTABILIZADO | Todos los meses con ajuste están contabilizados. |
Por fila (row.estado):
| Estado | Significado |
|---|---|
PENDIENTE | F29 declarado, sin ajuste por contabilizar. |
BORRADOR | Ajuste calculado, falta confirmar. |
CONTABILIZADO | Asiento generado contra 1108001/4201002. |
REVERSADO | Asiento eliminado del balance; mes conserva el registro. |
Endpoints consumidos
Section titled “Endpoints consumidos”| Método | Ruta | Operación |
|---|---|---|
GET | /api/reportes/ppm-actualizacion-anual?tenant_id&anio | Resumen anual con filas mensuales. |
POST | /api/reportes/ppm-actualizacion-anual/contabilizar?tenant_id body { anio } | Genera asientos para los meses con ajuste. |
POST | /api/reportes/ppm-actualizacion-anual/reversar?tenant_id body { anio } | Marca filas CONTABILIZADO como REVERSADO. |
Reglas de UI
Section titled “Reglas de UI”| Regla | Motivo |
|---|---|
| Año editable manualmente | El operador puede revisar años pasados sin cambiar el período del workspace. |
Sincronizar anio con period().year | El cambio de año global debe traer el resumen correspondiente. |
Acciones bloqueadas por saving !== null | Evita doble click que dispararía dos contabilizaciones. |
Confirmación con cuentas explícitas en el confirm() | El operador lee qué cuentas afecta antes de aceptar. |
| Etiqueta Recontabilizar cuando el estado es CONTABILIZADO | Distingue contabilizar nuevo vs reemplazar ya contabilizado; el backend usa el mismo endpoint. |
| Reversa solo si hay filas CONTABILIZADO | Sin nada que reversar, el botón no aplica. |
| Reversa preserva filas (no las elimina) | La trazabilidad del ajuste original y la fecha de reversa son auditables. |
| Toast con detalle numérico de la respuesta | El operador confirma cuántos meses y qué ajuste se aplicó/revirtió sin recargar. |
| Resumen vacío sintetizado en cliente | Sin data del backend (sin tenant, año futuro), el componente sigue renderizando una tabla vacía en vez de error. |