Files
Escalante-Pastor/scripts/_arquivados/importar_quadro_voo_2025.py
2026-06-26 18:15:55 -03:00

137 lines
4.1 KiB
Python

"""Importa a aba VOOS do Quadro de Voo 2025 para a base de validação."""
from __future__ import annotations
import argparse
import re
import sys
from datetime import time, timedelta
from pathlib import Path
import pandas as pd
BASE_DIR = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(BASE_DIR))
from src.planejador_missao.utils import normalizar_texto
COLUNAS_VALIDACAO = ["slot_id", "data", "aeronave", "tipo_escala", "tripulante", "funcao", "oi", "horas_voadas", "sbv"]
def _horas(valor: object) -> float:
if pd.isna(valor):
return 0.0
if isinstance(valor, timedelta):
return round(valor.total_seconds() / 3600, 2)
if isinstance(valor, time):
return round(valor.hour + valor.minute / 60 + valor.second / 3600, 2)
if isinstance(valor, str):
texto = valor.strip()
if not texto or texto == "-":
return 0.0
partes = texto.split(":")
if len(partes) >= 2:
return round(float(partes[0]) + float(partes[1]) / 60, 2)
return float(texto.replace(",", "."))
if isinstance(valor, (int, float)):
return round(float(valor) * 24, 2) if 0 < float(valor) < 1 else float(valor)
return 0.0
def _aeronave(valor: object) -> str:
texto = normalizar_texto(valor)
match = re.search(r"(\d{4})", texto)
if not match:
return ""
numero = match.group(1)
if numero.startswith("20"):
return "C97"
if numero.startswith("23"):
return "C95"
if numero.startswith("27"):
return "C98"
return ""
def _tripulantes(valor: object) -> list[str]:
partes = re.split(r"\s*/\s*", str(valor))
trips = []
for parte in partes:
texto = normalizar_texto(parte)
texto = re.sub(r"\([^)]*\)", " ", texto)
texto = re.sub(r"[^A-Z0-9]+", " ", texto).strip()
if texto and texto != "NAN":
trips.append(texto)
return trips[:2]
def importar(origem: Path, destino: Path) -> pd.DataFrame:
raw = pd.read_excel(origem, sheet_name="VOOS", header=None)
linhas = []
slot_id = 0
for _, row in raw.iterrows():
data = pd.to_datetime(row[2], errors="coerce")
if pd.isna(data) or data.year != 2025:
continue
if normalizar_texto(row[41]) != "REALIZADO":
continue
aeronave = _aeronave(row[37])
if not aeronave:
continue
slot_id += 1
tipo_escala = normalizar_texto(row[1])
horas_voadas = _horas(row[30])
oi = normalizar_texto(row[35])
if not oi or oi == "-":
oi = normalizar_texto(row[32])
for idx, tripulante in enumerate(_tripulantes(row[8]), start=1):
linhas.append(
{
"slot_id": slot_id,
"data": data.date().isoformat(),
"aeronave": aeronave,
"tipo_escala": tipo_escala,
"tripulante": tripulante,
"funcao": "PILOTO" if idx == 1 else "COPILOTO",
"oi": oi,
"horas_voadas": horas_voadas,
"sbv": 0,
}
)
df = pd.DataFrame(linhas, columns=COLUNAS_VALIDACAO)
destino.parent.mkdir(parents=True, exist_ok=True)
df.to_csv(destino, index=False)
return df
def main() -> None:
parser = argparse.ArgumentParser(description="Importa voos realizados de 2025 para a validação.")
parser.add_argument(
"--origem",
type=Path,
default=BASE_DIR / "dados" / "Quadro de Voo 2025 (2).xlsx",
help="Planilha com aba VOOS.",
)
parser.add_argument(
"--destino",
type=Path,
default=BASE_DIR / "dados" / "validacao" / "voos_2025.csv",
help="CSV de validação gerado.",
)
args = parser.parse_args()
df = importar(args.origem, args.destino)
print(f"Arquivo gerado: {args.destino}")
print(f"Registros exportados: {len(df)}")
print(f"Voos/slots exportados: {df['slot_id'].nunique() if not df.empty else 0}")
print(f"Tripulantes exportados: {df['tripulante'].nunique() if not df.empty else 0}")
if __name__ == "__main__":
main()