106 lines
3.7 KiB
Python
106 lines
3.7 KiB
Python
"""Aplicación de reglas seleccionadas sobre un DataFrame."""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Any, Optional
|
|
|
|
import pandas as pd
|
|
|
|
from .cop_mod import _apply_cop_mod_split, merge_moderadora_config
|
|
from .documents import _apply_doc_id_split_columns
|
|
from .notas import _apply_nota_extract_columns
|
|
from .rules import get_rule_fn, get_rule_name
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def apply_rules(
|
|
df: pd.DataFrame,
|
|
rules_per_column: dict[str, list[str]],
|
|
*,
|
|
cop_mod_fecha_column: Optional[dict[str, str]] = None,
|
|
cop_mod_config: Optional[dict[str, Any]] = None,
|
|
) -> tuple[pd.DataFrame, list[str]]:
|
|
"""Aplica las reglas seleccionadas a cada columna.
|
|
|
|
`rules_per_column` es un dict de `columna -> lista de IDs de reglas en el
|
|
orden a aplicar`. La regla `cop_mod_split` se difiere a una segunda pasada
|
|
tras el resto, para que la columna de fecha pueda normalizarse antes.
|
|
|
|
`cop_mod_fecha_column`: mapa columna de importe -> nombre de columna Fecha Servicio.
|
|
`cop_mod_config`: opcional; puede incluir ``moderadora_by_year`` (dict año → lista).
|
|
"""
|
|
result = df.copy()
|
|
log: list[str] = []
|
|
|
|
moderadora_years = merge_moderadora_config(cop_mod_config)
|
|
|
|
def _run_rules_for_column(col: str, rule_ids: list[str]) -> None:
|
|
if not rule_ids:
|
|
return
|
|
if col not in result.columns:
|
|
log.append(f"[WARN] Columna no encontrada: {col}")
|
|
return
|
|
split_has_homologation = (
|
|
"doc_id_split_tipo_numero" in rule_ids and "doc_type_homologate" in rule_ids
|
|
)
|
|
for rule_id in rule_ids:
|
|
if rule_id == "doc_id_split_tipo_numero":
|
|
try:
|
|
_apply_doc_id_split_columns(
|
|
result, col, log, homologate_type=split_has_homologation
|
|
)
|
|
except Exception as exc: # noqa: BLE001
|
|
logger.exception("Error aplicando regla %s a %s", rule_id, col)
|
|
log.append(f"[ERROR] '{col}' regla '{rule_id}': {exc}")
|
|
continue
|
|
if rule_id == "nota_paciente_autorizacion":
|
|
try:
|
|
_apply_nota_extract_columns(result, col, log)
|
|
except Exception as exc: # noqa: BLE001
|
|
logger.exception("Error aplicando regla %s a %s", rule_id, col)
|
|
log.append(f"[ERROR] '{col}' regla '{rule_id}': {exc}")
|
|
continue
|
|
if rule_id == "doc_type_homologate" and split_has_homologation:
|
|
continue
|
|
fn = get_rule_fn(rule_id)
|
|
if fn is None:
|
|
log.append(f"[WARN] Regla desconocida '{rule_id}' en columna '{col}'")
|
|
continue
|
|
try:
|
|
result[col] = fn(result[col])
|
|
log.append(f"[OK] '{col}' <- {get_rule_name(rule_id)}")
|
|
except Exception as exc: # noqa: BLE001
|
|
logger.exception("Error aplicando regla %s a %s", rule_id, col)
|
|
log.append(f"[ERROR] '{col}' regla '{rule_id}': {exc}")
|
|
|
|
# Fase 1: todas las reglas excepto cop_mod_split
|
|
for col, rule_ids in rules_per_column.items():
|
|
filtered = [r for r in rule_ids if r != "cop_mod_split"]
|
|
_run_rules_for_column(col, filtered)
|
|
|
|
# Fase 2: Separa COP/MOD sobre el DataFrame ya transformado
|
|
fecha_map = cop_mod_fecha_column or {}
|
|
for col, rule_ids in rules_per_column.items():
|
|
if "cop_mod_split" not in rule_ids:
|
|
continue
|
|
fecha_col = fecha_map.get(col)
|
|
if not fecha_col:
|
|
log.append(
|
|
f"[WARN] COP/MOD en '{col}': indique la columna «Fecha Servicio» en la tarjeta; se omite."
|
|
)
|
|
continue
|
|
try:
|
|
_apply_cop_mod_split(
|
|
result,
|
|
col,
|
|
fecha_col,
|
|
log,
|
|
moderadora_by_year=moderadora_years,
|
|
)
|
|
except Exception as exc: # noqa: BLE001
|
|
logger.exception("Error aplicando COP/MOD a %s", col)
|
|
log.append(f"[ERROR] '{col}' regla 'cop_mod_split': {exc}")
|
|
|
|
return result, log
|