137 lines
4.1 KiB
Python
137 lines
4.1 KiB
Python
"""Importa a aba VOOS do Quadro de Voo 2025 para a base de validacao."""
|
|
|
|
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 validacao.")
|
|
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 validacao 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()
|