Skip to content

Plataforma técnica · Sevastopol

Ppm Actualizacion Anual Island

Ingresos Islands Sevastopol

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.

  • Directorysevastopol/src/components/islands/contabilidad/
    • PpmActualizacionAnualIsland.tsx — componente único, internamente PpmActualizacionAnualPanel
    • ContabilidadWorkspace.tsx — tokens visuales (solo workspaceFieldClass aquí)
  • Directorysevastopol/src/pages/api/reportes/
    • […path].ts — proxy genérico vía createProxy(“/api/reportes”)
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()));
HookAportaReactividad
useActiveTenantUUID 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:

SignalTipoUso
aniostringAño consultado (editable manualmente vía <input type="number" min=2000 max=2100>).
dataPpmResumen | nullRespuesta del backend; null en error o sin tenant.
loadingbooleanBloqueo durante el GET.
saving"contabilizar" | "reversar" | nullDistingue la acción en curso para etiquetar el botón.
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: [],
});

Cuatro tarjetas en el header:

MétricaValorSubtexto
PPM declaradoclp(total_declarado){meses_declarados} mes(es) con declaración
PPM actualizadoclp(total_actualizado)”Actualizado a diciembre”
Ajuste CMclp(total_ajuste)”Impacta 1108001 vs 4201002”
Estadoestado_general (badge){meses_contabilizados}/{meses_con_ajuste} mes(es) contabilizados

8 columnas, ordenada por sortMes = -row.mes (más reciente arriba):

ColumnaRender
MesMONTH_LABELS[row.mes - 1]
Declaraciónrow.declaracion_estado o "-"
PPM declaradoclp(ppm_declarado)
FactorfmtFactor(factor_aplicable)1.034521x
PPM actualizadoclp(ppm_actualizado)
Ajusteclp(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.

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)}`,
);

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.

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.

estado_generalSignificado
PENDIENTEHay PPM declarado pero ningún mes contabilizado.
PARCIALAlgunos meses con ajuste están contabilizados; otros no.
CONTABILIZADOTodos los meses con ajuste están contabilizados.

Por fila (row.estado):

EstadoSignificado
PENDIENTEF29 declarado, sin ajuste por contabilizar.
BORRADORAjuste calculado, falta confirmar.
CONTABILIZADOAsiento generado contra 1108001/4201002.
REVERSADOAsiento eliminado del balance; mes conserva el registro.
MétodoRutaOperación
GET/api/reportes/ppm-actualizacion-anual?tenant_id&anioResumen 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.
ReglaMotivo
Año editable manualmenteEl operador puede revisar años pasados sin cambiar el período del workspace.
Sincronizar anio con period().yearEl cambio de año global debe traer el resumen correspondiente.
Acciones bloqueadas por saving !== nullEvita 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 CONTABILIZADODistingue contabilizar nuevo vs reemplazar ya contabilizado; el backend usa el mismo endpoint.
Reversa solo si hay filas CONTABILIZADOSin 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 respuestaEl operador confirma cuántos meses y qué ajuste se aplicó/revirtió sin recargar.
Resumen vacío sintetizado en clienteSin data del backend (sin tenant, año futuro), el componente sigue renderizando una tabla vacía en vez de error.