Files
Escalante-Pastor/src/planejador_missao/rules.py
2026-06-26 18:15:55 -03:00

109 lines
4.6 KiB
Python

"""Regras operacionais de disponibilidade, qualificação e progressão."""
from __future__ import annotations
from datetime import date
import pandas as pd
from .utils import normalizar_texto
def piloto_disponivel(tripulante: str, data_missao: date, indisponibilidades: pd.DataFrame) -> bool:
trip = normalizar_texto(tripulante)
conflitos = indisponibilidades[
(indisponibilidades["tripulante"] == trip)
& (indisponibilidades["inicio"] <= data_missao)
& (indisponibilidades["fim"] >= data_missao)
]
return conflitos.empty
def classe_principal(qualificacao: str) -> str:
qual = normalizar_texto(qualificacao)
for classe in ["IN", "PO", "PB", "AL"]:
if classe in qual.split("/"):
return classe
if classe in qual.split():
return classe
return "OUTRO"
def qualificacao_base_aeronave(tripulante: str, aeronave: str, cadastro: pd.DataFrame) -> str:
linha = cadastro[cadastro["tripulante"] == normalizar_texto(tripulante)]
if linha.empty:
return "OUTRO"
qt = [x for x in normalizar_texto(linha.iloc[0]["qt"]).split("/") if x]
quals = [x for x in normalizar_texto(linha.iloc[0]["qualificacao"]).split("/") if x]
if len(qt) == len(quals) and aeronave in qt:
return classe_principal(quals[qt.index(aeronave)])
return classe_principal(linha.iloc[0]["qualificacao"])
def subprograma_concluido(progresso: pd.DataFrame, tripulante: str, aeronave: str, subprograma: str, catalogo: pd.DataFrame) -> bool:
necessarias = set(catalogo[(catalogo["aeronave"] == aeronave) & (catalogo["subprograma"] == subprograma)]["oi"])
if not necessarias:
return False
concluidas = set(
progresso[
(progresso["tripulante"] == normalizar_texto(tripulante))
& (progresso["aeronave"] == aeronave)
& (progresso["subprograma"] == subprograma)
& (progresso["concluida"] == True)
]["oi"]
)
return necessarias.issubset(concluidas)
def qualificacao_operacional(tripulante: str, aeronave: str, cadastro: pd.DataFrame, progresso: pd.DataFrame, catalogo: pd.DataFrame) -> str:
rank = {"OUTRO": 0, "AL": 1, "PB": 2, "PO": 3, "IN": 4}[qualificacao_base_aeronave(tripulante, aeronave, cadastro)]
if subprograma_concluido(progresso, tripulante, aeronave, "SPFO-1", catalogo):
rank = max(rank, 2)
if subprograma_concluido(progresso, tripulante, aeronave, "SPFO-2", catalogo):
rank = max(rank, 3)
if aeronave == "C98" and subprograma_concluido(progresso, tripulante, aeronave, "SPQE-3", catalogo):
rank = max(rank, 4)
if aeronave == "C97" and subprograma_concluido(progresso, tripulante, aeronave, "SPQE-4", catalogo):
rank = max(rank, 4)
return {0: "OUTRO", 1: "AL", 2: "PB", 3: "PO", 4: "IN"}[rank]
def concluiu_ois(progresso: pd.DataFrame, tripulante: str, aeronave: str, ois: list[str]) -> bool:
concluidas = set(
progresso[
(progresso["tripulante"] == normalizar_texto(tripulante))
& (progresso["aeronave"] == aeronave)
& (progresso["concluida"] == True)
]["oi"]
)
return set(ois).issubset(concluidas)
def eh_instrutor_adaptado(tripulante: str, aeronave: str, cadastro: pd.DataFrame, progresso: pd.DataFrame, catalogo: pd.DataFrame) -> bool:
trip = normalizar_texto(tripulante)
instrutores_base = {
"C95": {"MES", "BRI"},
"C97": {"AEU", "MAT"},
"C98": {"BRI", "FIA", "MDO", "SLS", "CFF"},
}
if trip in instrutores_base.get(aeronave, set()):
return True
if aeronave == "C97" and trip in {"SEI", "LPS"}:
return concluiu_ois(progresso, trip, aeronave, ["01TL01D41", "04TL01N42"])
if aeronave == "C98" and trip in {"MCH", "DOG"}:
return concluiu_ois(progresso, trip, aeronave, ["01TL01D31", "04TL01N32"])
return qualificacao_operacional(trip, aeronave, cadastro, progresso, catalogo) == "IN"
def combinar_progresso_com_historico(progresso: pd.DataFrame, historico: pd.DataFrame, catalogo: pd.DataFrame) -> pd.DataFrame:
if historico.empty:
return progresso
voadas = historico[(historico["oi"] != "") & (historico["horas_voadas"] > 0)]
if voadas.empty:
return progresso
hist = voadas.merge(catalogo[["aeronave", "subprograma", "oi"]].drop_duplicates(), on=["aeronave", "oi"], how="left")
hist = hist.dropna(subset=["subprograma"])
hist = hist[["tripulante", "aeronave", "subprograma", "oi", "horas_voadas"]].rename(columns={"horas_voadas": "horas_realizadas"})
hist["concluida"] = True
return pd.concat([progresso, hist], ignore_index=True).drop_duplicates(["tripulante", "aeronave", "subprograma", "oi"])