|
|
|
|
|
import streamlit as st
|
|
|
import pandas as pd
|
|
|
from io import BytesIO
|
|
|
from datetime import date
|
|
|
from banco import SessionLocal
|
|
|
from models import Equipamento
|
|
|
|
|
|
|
|
|
def limpar_estado_consulta():
|
|
|
"""
|
|
|
Remove do session_state qualquer dado
|
|
|
relacionado ao módulo Consulta
|
|
|
"""
|
|
|
for key in list(st.session_state.keys()):
|
|
|
if key.startswith("consulta_"):
|
|
|
del st.session_state[key]
|
|
|
|
|
|
|
|
|
def _coerce_date(x):
|
|
|
"""Garante que valores sejam datas (date) ou NaT para comparação."""
|
|
|
if pd.isna(x):
|
|
|
return pd.NaT
|
|
|
if isinstance(x, (pd.Timestamp, )):
|
|
|
return x.date()
|
|
|
if isinstance(x, date):
|
|
|
return x
|
|
|
try:
|
|
|
return pd.to_datetime(x).date()
|
|
|
except Exception:
|
|
|
return pd.NaT
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if not st.session_state.get("_consulta_inicializado"):
|
|
|
limpar_estado_consulta()
|
|
|
st.session_state["_consulta_inicializado"] = True
|
|
|
|
|
|
st.title("🔍 Consulta de Registros")
|
|
|
|
|
|
db = SessionLocal()
|
|
|
|
|
|
try:
|
|
|
registros = db.query(Equipamento).all()
|
|
|
|
|
|
if not registros:
|
|
|
st.info("Nenhum registro encontrado.")
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
df = pd.DataFrame([
|
|
|
{
|
|
|
"ID": r.id,
|
|
|
|
|
|
|
|
|
"FPSO1": r.fpso1,
|
|
|
"FPSO": r.fpso,
|
|
|
"Data Coleta": r.data_coleta,
|
|
|
|
|
|
|
|
|
"Especialista": r.especialista,
|
|
|
"Conferente": r.conferente,
|
|
|
"OSM": r.osm,
|
|
|
|
|
|
|
|
|
"Modal": r.modal,
|
|
|
"Quantidade Equip.": r.quant_equip,
|
|
|
"MROB": r.mrob,
|
|
|
|
|
|
|
|
|
"Linhas OSM": r.linhas_osm,
|
|
|
"Linhas MROB": r.linhas_mrob,
|
|
|
"Linhas Erros": r.linhas_erros,
|
|
|
|
|
|
|
|
|
"Erro Storekeeper": r.erro_storekeeper,
|
|
|
"Erro Operação": r.erro_operacao,
|
|
|
"Erro Especialista": r.erro_especialista,
|
|
|
"Erro Outros": r.erro_outros,
|
|
|
|
|
|
|
|
|
"Inclusão / Exclusão": r.inclusao_exclusao,
|
|
|
"PO": r.po,
|
|
|
"Part Number": r.part_number,
|
|
|
"Material": r.material,
|
|
|
|
|
|
"Solicitante": r.solicitante,
|
|
|
"Motivo": getattr(r, "motivo", None),
|
|
|
"Requisitante": r.requisitante,
|
|
|
"Nota Fiscal": r.nota_fiscal,
|
|
|
"Impacto": r.impacto,
|
|
|
"Dimensão": r.dimensao,
|
|
|
|
|
|
"Observações": r.observacoes,
|
|
|
"Dia Inclusão": r.dia_inclusao,
|
|
|
|
|
|
|
|
|
"Data/Hora Input": r.data_hora_input,
|
|
|
}
|
|
|
for r in registros
|
|
|
])
|
|
|
|
|
|
|
|
|
if "Data Coleta" in df.columns:
|
|
|
df["Data Coleta"] = df["Data Coleta"].apply(_coerce_date)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
st.subheader("🔎 Filtros")
|
|
|
|
|
|
col1, col2, col3 = st.columns(3)
|
|
|
|
|
|
with col1:
|
|
|
filtro_fpso = st.multiselect(
|
|
|
"FPSO",
|
|
|
sorted(df["FPSO"].dropna().unique()),
|
|
|
key="consulta_fpso"
|
|
|
)
|
|
|
|
|
|
filtro_dia = st.multiselect(
|
|
|
"Dia de Inclusão (D1 / D2 / D3)",
|
|
|
sorted(df["Dia Inclusão"].dropna().unique()),
|
|
|
key="consulta_dia"
|
|
|
)
|
|
|
|
|
|
with col2:
|
|
|
filtro_modal = st.multiselect(
|
|
|
"Modal",
|
|
|
sorted(df["Modal"].dropna().unique()),
|
|
|
key="consulta_modal"
|
|
|
)
|
|
|
|
|
|
filtro_especialista = st.multiselect(
|
|
|
"Especialista",
|
|
|
sorted(df["Especialista"].dropna().unique()),
|
|
|
key="consulta_especialista"
|
|
|
)
|
|
|
|
|
|
|
|
|
filtro_osm = st.multiselect(
|
|
|
"OSM",
|
|
|
sorted(df["OSM"].dropna().unique()),
|
|
|
key="consulta_osm"
|
|
|
)
|
|
|
|
|
|
with col3:
|
|
|
periodo = st.date_input(
|
|
|
"Período de Coleta",
|
|
|
value=None,
|
|
|
key="consulta_periodo"
|
|
|
)
|
|
|
|
|
|
|
|
|
st.markdown("**Nota Fiscal**")
|
|
|
nota_input_text = st.text_input(
|
|
|
"Digite um ou mais números (separados por vírgula)",
|
|
|
value="",
|
|
|
key="consulta_nf_text"
|
|
|
)
|
|
|
|
|
|
filtro_nf_multi = st.multiselect(
|
|
|
"Ou selecione",
|
|
|
sorted([str(x) for x in df["Nota Fiscal"].dropna().unique()]),
|
|
|
key="consulta_nf_multi"
|
|
|
)
|
|
|
mostrar_apenas_duplicadas = st.checkbox(
|
|
|
"Mostrar apenas notas duplicadas",
|
|
|
value=False,
|
|
|
key="consulta_mostrar_dup_nf"
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if filtro_fpso:
|
|
|
df = df[df["FPSO"].isin(filtro_fpso)]
|
|
|
|
|
|
if filtro_modal:
|
|
|
df = df[df["Modal"].isin(filtro_modal)]
|
|
|
|
|
|
if filtro_especialista:
|
|
|
df = df[df["Especialista"].isin(filtro_especialista)]
|
|
|
|
|
|
if filtro_dia:
|
|
|
df = df[df["Dia Inclusão"].isin(filtro_dia)]
|
|
|
|
|
|
if filtro_osm:
|
|
|
df = df[df["OSM"].isin(filtro_osm)]
|
|
|
|
|
|
|
|
|
if isinstance(periodo, (list, tuple)) and len(periodo) == 2 and all(periodo):
|
|
|
data_inicio, data_fim = periodo
|
|
|
df = df[
|
|
|
(df["Data Coleta"] >= data_inicio) &
|
|
|
(df["Data Coleta"] <= data_fim)
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
notas_texto = []
|
|
|
if nota_input_text.strip():
|
|
|
notas_texto = [x.strip() for x in nota_input_text.split(",") if x.strip()]
|
|
|
|
|
|
|
|
|
notas_escolhidas = set([str(x) for x in filtro_nf_multi] + [str(x) for x in notas_texto])
|
|
|
|
|
|
if notas_escolhidas:
|
|
|
|
|
|
df = df[df["Nota Fiscal"].astype(str).isin(notas_escolhidas)]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nf_series = df["Nota Fiscal"].astype(str).fillna("")
|
|
|
contagem_nf = nf_series.value_counts(dropna=False)
|
|
|
|
|
|
notas_duplicadas = contagem_nf[(contagem_nf > 1) & (contagem_nf.index != "")]
|
|
|
|
|
|
|
|
|
df["Duplicidade Nota"] = df["Nota Fiscal"].astype(str).isin(notas_duplicadas.index)
|
|
|
|
|
|
|
|
|
if len(notas_duplicadas) > 0:
|
|
|
st.warning(
|
|
|
f"⚠️ Foram encontradas **{int(notas_duplicadas.sum())}** ocorrências em **{len(notas_duplicadas)}** "
|
|
|
f"números de Nota Fiscal duplicados no resultado."
|
|
|
)
|
|
|
with st.expander("Ver lista de notas duplicadas"):
|
|
|
dup_df = pd.DataFrame({
|
|
|
"Nota Fiscal": notas_duplicadas.index,
|
|
|
"Ocorrências": notas_duplicadas.values
|
|
|
}).sort_values(by="Ocorrências", ascending=False)
|
|
|
st.dataframe(dup_df, use_container_width=True)
|
|
|
|
|
|
|
|
|
if mostrar_apenas_duplicadas:
|
|
|
df = df[df["Duplicidade Nota"] == True]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
st.subheader("📊 Resultados")
|
|
|
st.caption("A coluna **Duplicidade Nota** indica se há mais de um registro com o mesmo número de Nota Fiscal no resultado atual.")
|
|
|
st.dataframe(df, use_container_width=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
buffer = BytesIO()
|
|
|
with pd.ExcelWriter(buffer, engine="openpyxl") as writer:
|
|
|
df.to_excel(writer, index=False, sheet_name="Consulta")
|
|
|
|
|
|
buffer.seek(0)
|
|
|
|
|
|
st.download_button(
|
|
|
label="⬇️ Exportar para Excel",
|
|
|
data=buffer,
|
|
|
file_name="consulta_equipamentos.xlsx",
|
|
|
mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
|
)
|
|
|
|
|
|
finally:
|
|
|
db.close()
|
|
|
|
|
|
|
|
|
|
|
|
|