import datetime
from collections import Counter
from dateutil.relativedelta import relativedelta
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Q
from src.dados_comuns.utils import quantidade_meses
from src.dieta_especial.constants import ETAPA_INFANTIL
from src.dieta_especial.logs_models.models import (
LogQuantidadeDietasAutorizadas,
LogQuantidadeDietasAutorizadasCEI,
LogQuantidadeDietasAutorizadasRecreioNasFerias,
LogQuantidadeDietasAutorizadasRecreioNasFeriasCEI,
)
from src.dieta_especial.solicitacao_dieta_especial.models import (
ClassificacaoDieta,
)
from src.escola.models import FaixaEtaria, PeriodoEscolar
from src.medicao_inicial.models import SolicitacaoMedicaoInicial
[docs]
def cria_logs_totais_cei_por_faixa_etaria(logs_escola, ontem, escola):
logs = [log for log in logs_escola if log.periodo_escolar.nome == "INTEGRAL"]
if not logs:
return logs_escola
for classificacao in ClassificacaoDieta.objects.all():
quantidade_total = sum(
[log.quantidade for log in logs if log.classificacao == classificacao]
)
log_total = LogQuantidadeDietasAutorizadasCEI(
data=ontem,
escola=escola,
quantidade=quantidade_total,
classificacao=classificacao,
periodo_escolar=logs[0].periodo_escolar,
faixa_etaria=None,
)
logs_escola.append(log_total)
return logs_escola
[docs]
def get_quantidade_nao_matriculados_entre_4_e_6_anos(dietas, data_referencia):
return dietas.filter(
tipo_solicitacao="ALUNO_NAO_MATRICULADO",
aluno__data_nascimento__lte=data_referencia - relativedelta(years=4),
aluno__data_nascimento__gte=data_referencia - relativedelta(years=6),
).count()
[docs]
def get_quantidade_nao_matriculados_maior_6_anos(dietas, data_referencia):
return dietas.filter(
tipo_solicitacao="ALUNO_NAO_MATRICULADO",
aluno__data_nascimento__lte=data_referencia - relativedelta(years=6),
).count()
[docs]
def get_quantidade_dietas_emebs(each, dietas, data_referencia):
dietas_sem_alunos_nao_matriculados = dietas.exclude(
tipo_solicitacao="ALUNO_NAO_MATRICULADO"
)
if each == "INFANTIL":
quantidade = dietas_sem_alunos_nao_matriculados.filter(
aluno__etapa=ETAPA_INFANTIL
).count()
quantidade += get_quantidade_nao_matriculados_entre_4_e_6_anos(
dietas, data_referencia
)
elif each == "FUNDAMENTAL":
quantidade = dietas_sem_alunos_nao_matriculados.exclude(
aluno__etapa=ETAPA_INFANTIL
).count()
quantidade += get_quantidade_nao_matriculados_maior_6_anos(
dietas, data_referencia
)
else:
quantidade = dietas_sem_alunos_nao_matriculados.count()
quantidade += get_quantidade_nao_matriculados_maior_6_anos(
dietas, data_referencia
)
quantidade += get_quantidade_nao_matriculados_entre_4_e_6_anos(
dietas, data_referencia
)
return quantidade
[docs]
def logs_a_criar_sem_periodo_escolar(
logs_a_criar, escola, dietas_filtradas, ontem, classificacao
):
if escola.eh_emebs:
for each in ["INFANTIL", "FUNDAMENTAL", "N/A"]:
quantidade = get_quantidade_dietas_emebs(each, dietas_filtradas, ontem)
log = LogQuantidadeDietasAutorizadas(
quantidade=quantidade,
escola=escola,
data=ontem,
classificacao=classificacao,
infantil_ou_fundamental=each,
)
logs_a_criar.append(log)
else:
log = LogQuantidadeDietasAutorizadas(
quantidade=dietas_filtradas.count(),
escola=escola,
data=ontem,
classificacao=classificacao,
)
logs_a_criar.append(log)
return logs_a_criar
[docs]
def logs_periodo_integral_cei_ou_emei_escola_cemei(
logs_a_criar,
dietas_autorizadas,
classificacao,
escola,
periodo_escolar_nome,
dict_periodos,
ontem,
):
dietas = dietas_autorizadas.filter(
classificacao=classificacao, escola_destino=escola
).filter(
Q(aluno__periodo_escolar__nome=periodo_escolar_nome)
| Q(tipo_solicitacao="ALUNO_NAO_MATRICULADO")
)
quantidade_cei = 0
quantidade_emei = 0
for dieta in dietas:
if not dieta.aluno.serie:
quantidade_cei += 1
quantidade_emei += 1
elif dieta.aluno.ciclo == dieta.aluno.CICLO_ALUNO_CEI:
quantidade_cei += 1
else:
quantidade_emei += 1
log_cei = LogQuantidadeDietasAutorizadas(
quantidade=quantidade_cei,
escola=escola,
data=ontem,
periodo_escolar=dict_periodos[periodo_escolar_nome],
classificacao=classificacao,
cei_ou_emei="CEI",
)
log_emei = LogQuantidadeDietasAutorizadas(
quantidade=quantidade_emei,
escola=escola,
data=ontem,
periodo_escolar=dict_periodos[periodo_escolar_nome],
classificacao=classificacao,
cei_ou_emei="EMEI",
)
return logs_a_criar + [log_cei] + [log_emei]
[docs]
def gera_logs_dietas_escolas_comuns(escola, dietas_autorizadas, ontem):
logs_a_criar = []
dict_periodos = PeriodoEscolar.dict_periodos()
for classificacao in ClassificacaoDieta.objects.all():
dietas_filtradas = dietas_autorizadas.filter(
classificacao=classificacao, escola_destino=escola
)
logs_a_criar = logs_a_criar_sem_periodo_escolar(
logs_a_criar, escola, dietas_filtradas, ontem, classificacao
)
for periodo_escolar_nome in escola.periodos_escolares_com_alunos:
dietas_filtradas_periodo = dietas_autorizadas.filter(
classificacao=classificacao, escola_destino=escola
).filter(
Q(aluno__periodo_escolar__nome=periodo_escolar_nome)
| Q(tipo_solicitacao="ALUNO_NAO_MATRICULADO")
)
if escola.eh_cemei and periodo_escolar_nome == "INTEGRAL":
logs_a_criar = logs_periodo_integral_cei_ou_emei_escola_cemei(
logs_a_criar,
dietas_autorizadas,
classificacao,
escola,
periodo_escolar_nome,
dict_periodos,
ontem,
)
if escola.eh_emebs:
for each in ["INFANTIL", "FUNDAMENTAL"]:
quantidade = get_quantidade_dietas_emebs(
each, dietas_filtradas_periodo, ontem
)
log = LogQuantidadeDietasAutorizadas(
quantidade=quantidade,
escola=escola,
data=ontem,
periodo_escolar=dict_periodos[periodo_escolar_nome],
classificacao=classificacao,
infantil_ou_fundamental=each,
)
logs_a_criar.append(log)
else:
log = LogQuantidadeDietasAutorizadas(
quantidade=dietas_filtradas_periodo.count(),
escola=escola,
data=ontem,
periodo_escolar=dict_periodos[periodo_escolar_nome],
classificacao=classificacao,
)
logs_a_criar.append(log)
return logs_a_criar
[docs]
def append_periodo_parcial(periodos, solicitacao_medicao):
if solicitacao_medicao.ue_possui_alunos_periodo_parcial:
periodos.append("PARCIAL")
return periodos
[docs]
def append_faixas_dietas(dietas, escola, data_referencia):
faixas = []
for dieta_periodo in dietas:
faixa = _faixa_etaria_para_aluno(dieta_periodo.aluno, data_referencia)
if not faixa:
continue
if (
escola.eh_cemei
and dieta_periodo.aluno.ciclo != dieta_periodo.aluno.CICLO_ALUNO_CEI
):
continue
faixas.append(faixa)
return faixas
[docs]
def criar_logs_integral_parcial(
eh_integral,
dietas,
solicitacao_medicao,
escola,
ontem,
classificacao,
periodo,
faixas,
):
logs = []
dict_periodos = PeriodoEscolar.dict_periodos()
faixas_alunos_parciais = []
for dieta in dietas:
if dieta.aluno.nome in solicitacao_medicao.alunos_periodo_parcial.values_list(
"aluno__nome", flat=True
):
faixa = _faixa_etaria_para_aluno(dieta.aluno, ontem)
if not faixa:
continue
faixas_alunos_parciais.append(faixa)
faixas = faixas if eh_integral else faixas_alunos_parciais
for faixa, quantidade in Counter(faixas).items():
if eh_integral and faixa in Counter(faixas_alunos_parciais).keys():
quantidade = quantidade - Counter(faixas_alunos_parciais).get(faixa)
log = LogQuantidadeDietasAutorizadasCEI(
quantidade=quantidade,
escola=escola,
data=ontem,
classificacao=classificacao,
periodo_escolar=dict_periodos[periodo],
faixa_etaria=faixa,
)
logs.append(log)
return logs
[docs]
def faixas_por_periodo_e_faixa_etaria(escola, periodo, ontem):
try:
return escola.matriculados_por_periodo_e_faixa_etaria(data=ontem)[periodo]
except KeyError:
return escola.matriculados_por_periodo_e_faixa_etaria(data=ontem)["INTEGRAL"]
[docs]
def condicoes(log, escola, ontem, classificacao, periodo, faixa):
resultado = (
log.escola == escola
and log.data == ontem
and log.classificacao == classificacao
and log.periodo_escolar.nome == periodo
and str(log.faixa_etaria.uuid) == faixa
)
return resultado
[docs]
def existe_log(logs_a_criar, escola, ontem, classificacao, periodo, faixa):
resultado = list(
filter(
lambda log: condicoes(log, escola, ontem, classificacao, periodo, faixa),
logs_a_criar,
)
)
return resultado
[docs]
def append_logs_a_criar_de_quantidade_zero(logs_a_criar, periodos, escola, ontem):
dict_periodos = PeriodoEscolar.dict_periodos()
for periodo in periodos:
faixas = faixas_por_periodo_e_faixa_etaria(escola, periodo, ontem)
for faixa, _ in faixas.items():
if faixa in [
str(f)
for f in FaixaEtaria.objects.filter(ativo=True).values_list(
"uuid", flat=True
)
]:
for classificacao in ClassificacaoDieta.objects.all():
if not existe_log(
logs_a_criar, escola, ontem, classificacao, periodo, faixa
):
log = LogQuantidadeDietasAutorizadasCEI(
quantidade=0,
escola=escola,
data=ontem,
classificacao=classificacao,
periodo_escolar=dict_periodos[periodo],
faixa_etaria=FaixaEtaria.objects.get(uuid=faixa),
)
logs_a_criar.append(log)
return logs_a_criar
[docs]
def adicionar_logs_a_criar_integral_parcial(
periodos,
periodo,
dietas,
solicitacao_medicao,
escola,
ontem,
classificacao,
faixas,
logs_a_criar,
dict_periodos,
):
if periodo == "INTEGRAL" and "PARCIAL" in periodos:
logs_a_criar.extend(
criar_logs_integral_parcial(
True,
dietas,
solicitacao_medicao,
escola,
ontem,
classificacao,
periodo,
faixas,
)
)
elif periodo == "PARCIAL":
logs_a_criar.extend(
criar_logs_integral_parcial(
False,
dietas,
solicitacao_medicao,
escola,
ontem,
classificacao,
periodo,
None,
)
)
else:
for faixa, quantidade in Counter(faixas).items():
logs_a_criar.append(
LogQuantidadeDietasAutorizadasCEI(
quantidade=quantidade,
escola=escola,
data=ontem,
classificacao=classificacao,
periodo_escolar=dict_periodos[periodo],
faixa_etaria=faixa,
)
)
return logs_a_criar
[docs]
def logs_a_criar_existe_solicitacao_medicao(escola, dietas_autorizadas, ontem):
solicitacao_medicao = SolicitacaoMedicaoInicial.objects.filter(
escola__codigo_eol=escola.codigo_eol,
mes=f"{datetime.date.today().month:02d}",
ano=datetime.date.today().year,
recreio_nas_ferias=None,
).first()
if not solicitacao_medicao:
raise ObjectDoesNotExist("Solicitação de Medição Inicial não encontrada.")
logs_a_criar = []
periodos = escola.periodos_escolares_com_alunos
periodos = append_periodo_parcial(periodos, solicitacao_medicao)
periodos = list(set(periodos))
dict_periodos = PeriodoEscolar.dict_periodos()
for periodo in periodos:
for classificacao in ClassificacaoDieta.objects.all():
dietas = dietas_autorizadas.filter(
classificacao=classificacao, escola_destino=escola
)
dietas_filtradas_periodo = dietas.filter(
aluno__periodo_escolar__nome=periodo
)
dietas_nao_matriculados = dietas.filter(
tipo_solicitacao="ALUNO_NAO_MATRICULADO"
)
faixas = []
faixas += append_faixas_dietas(dietas_filtradas_periodo, escola, ontem)
faixas += append_faixas_dietas(dietas_nao_matriculados, escola, ontem)
adicionar_logs_a_criar_integral_parcial(
periodos,
periodo,
dietas,
solicitacao_medicao,
escola,
ontem,
classificacao,
faixas,
logs_a_criar,
dict_periodos,
)
logs_a_criar = append_logs_a_criar_de_quantidade_zero(
logs_a_criar, periodos, escola, ontem
)
return logs_a_criar
[docs]
def logs_a_criar_nao_existe_solicitacao_medicao(escola, dietas_autorizadas, ontem):
logs_a_criar = []
periodos = escola.periodos_escolares_com_alunos
dict_periodos = PeriodoEscolar.dict_periodos()
for periodo in periodos:
for classificacao in ClassificacaoDieta.objects.all():
dietas = dietas_autorizadas.filter(
classificacao=classificacao, escola_destino=escola
)
dietas_filtradas_periodo = dietas.filter(
aluno__periodo_escolar__nome=periodo
)
dietas_nao_matriculados = dietas.filter(
tipo_solicitacao="ALUNO_NAO_MATRICULADO"
)
faixas = []
faixas += append_faixas_dietas(dietas_filtradas_periodo, escola, ontem)
faixas += append_faixas_dietas(dietas_nao_matriculados, escola, ontem)
for faixa, quantidade in Counter(faixas).items():
log = LogQuantidadeDietasAutorizadasCEI(
quantidade=quantidade,
escola=escola,
data=ontem,
classificacao=classificacao,
periodo_escolar=dict_periodos[periodo],
faixa_etaria=faixa,
)
logs_a_criar.append(log)
logs_a_criar = append_logs_a_criar_de_quantidade_zero(
logs_a_criar, periodos, escola, ontem
)
return logs_a_criar
[docs]
def gera_logs_dietas_escolas_cei(escola, dietas_autorizadas, ontem):
try:
return logs_a_criar_existe_solicitacao_medicao(
escola, dietas_autorizadas, ontem
)
except ObjectDoesNotExist:
return logs_a_criar_nao_existe_solicitacao_medicao(
escola, dietas_autorizadas, ontem
)
[docs]
def gera_logs_dietas_recreio_ferias_escolas_comuns(escola, dietas_recreio, data_log):
logs_a_criar = []
for classificacao in ClassificacaoDieta.objects.all():
dietas_filtradas = dietas_recreio.filter(
classificacao=classificacao,
escola_destino=escola,
)
quantidade = dietas_filtradas.count()
log = LogQuantidadeDietasAutorizadasRecreioNasFerias(
quantidade=quantidade,
escola=escola,
data=data_log,
classificacao=classificacao,
)
logs_a_criar.append(log)
return logs_a_criar
[docs]
def gera_logs_dietas_recreio_ferias_parte_sem_faixa_cemei(
escola, dietas_recreio, data_log
):
"""
- alunos >= 4 anos OU ciclo != CICLO_ALUNO_CEI
- alunos não matriculados com idade >= 4 anos.
"""
logs_a_criar = []
for classificacao in ClassificacaoDieta.objects.all():
dietas_filtradas = dietas_recreio.filter(
classificacao=classificacao,
escola_destino=escola,
)
cont = _contar_dietas_sem_faixa(dietas_filtradas, data_log)
log = LogQuantidadeDietasAutorizadasRecreioNasFerias(
quantidade=cont,
escola=escola,
data=data_log,
classificacao=classificacao,
)
logs_a_criar.append(log)
return logs_a_criar
def _contar_dietas_sem_faixa(dietas_filtradas, data_referencia):
"""Conta dietas que atendem aos critérios sem faixa etária."""
cont = 0
for dieta in dietas_filtradas:
aluno = getattr(dieta, "aluno", None)
if not aluno:
continue
if _deve_contar_aluno_sem_faixa(dieta, aluno, data_referencia):
cont += 1
return cont
def _deve_contar_aluno_sem_faixa(dieta, aluno, data_referencia):
"""Verifica se aluno deve ser contado (>= 4 anos ou ciclo != CEI)."""
if dieta.tipo_solicitacao == "ALUNO_NAO_MATRICULADO":
return _aluno_nao_matriculado_tem_4_anos_ou_mais(aluno, data_referencia)
return aluno.ciclo != aluno.CICLO_ALUNO_CEI
def _aluno_nao_matriculado_tem_4_anos_ou_mais(aluno, data_referencia):
"""Verifica se aluno não matriculado tem 4 anos ou mais."""
if not aluno.data_nascimento:
return False
idade_meses = quantidade_meses(data_referencia, aluno.data_nascimento)
return idade_meses >= 48 # 4 anos * 12 meses
def _faixa_etaria_para_aluno(aluno, data_referencia):
if not aluno.data_nascimento:
return None
meses = quantidade_meses(data_referencia, aluno.data_nascimento)
ultima_faixa = FaixaEtaria.objects.filter(ativo=True).order_by("fim").last()
if not ultima_faixa:
return None
if meses >= ultima_faixa.fim:
return ultima_faixa
return FaixaEtaria.objects.filter(
ativo=True, inicio__lte=meses, fim__gt=meses
).first()
[docs]
def gera_logs_dietas_recreio_ferias_escolas_cei(escola, dietas_recreio, data_log):
"""
- alunos NÃO MATRICULADOS com idade <= 3a11m entram
- alunos MATRICULADOS ciclo 1 entram
"""
logs_a_criar = []
for classificacao in ClassificacaoDieta.objects.all():
dietas_filtradas = dietas_recreio.filter(
classificacao=classificacao,
escola_destino=escola,
)
contador_faixas = _contar_dietas_por_faixa(escola, dietas_filtradas, data_log)
logs_a_criar.extend(
_criar_logs_com_quantidade(escola, data_log, classificacao, contador_faixas)
)
logs_a_criar.extend(
_criar_logs_faixas_sem_alunos(escola, data_log, classificacao, logs_a_criar)
)
return logs_a_criar
def _contar_dietas_por_faixa(escola, dietas_filtradas, data_referencia):
contador_faixas = Counter()
for dieta in dietas_filtradas:
aluno = getattr(dieta, "aluno", None)
if not aluno:
continue
faixa = _obter_faixa_etaria_dieta(escola, dieta, aluno, data_referencia)
if faixa:
contador_faixas[faixa] += 1
return contador_faixas
def _obter_faixa_etaria_dieta(escola, dieta, aluno, data_referencia):
"""Obtém faixa etária do aluno se ele atender aos critérios."""
if escola.eh_cemei:
return _obter_faixa_cemei(dieta, aluno, data_referencia)
return _faixa_etaria_para_aluno(aluno, data_referencia)
def _obter_faixa_cemei(dieta, aluno, data_referencia):
"""Obtém faixa etária para alunos de CEMEI."""
if dieta.tipo_solicitacao == "ALUNO_NAO_MATRICULADO":
return _obter_faixa_nao_matriculado_cemei(aluno, data_referencia)
if aluno.ciclo == aluno.CICLO_ALUNO_CEI:
return _faixa_etaria_para_aluno(aluno, data_referencia)
return None
def _obter_faixa_nao_matriculado_cemei(aluno, data_referencia):
"""Obtém faixa para aluno não matriculado em CEMEI (até 3a11m)."""
if not aluno.data_nascimento:
return None
meses = quantidade_meses(data_referencia, aluno.data_nascimento)
if meses <= 47: # até 3a11m
return _faixa_etaria_para_aluno(aluno, data_referencia)
return None
def _criar_logs_com_quantidade(escola, data_log, classificacao, contador_faixas):
logs = []
for faixa, qtd in contador_faixas.items():
log = LogQuantidadeDietasAutorizadasRecreioNasFeriasCEI(
quantidade=qtd,
escola=escola,
data=data_log,
classificacao=classificacao,
faixa_etaria=faixa,
)
logs.append(log)
return logs
def _criar_logs_faixas_sem_alunos(escola, data_log, classificacao, logs_existentes):
faixas_atuais = set(FaixaEtaria.objects.filter(ativo=True))
faixas_com_log = {
log.faixa_etaria
for log in logs_existentes
if log.escola == escola and log.classificacao == classificacao
}
faixas_sem_log = faixas_atuais - faixas_com_log
logs = []
for faixa in faixas_sem_log:
log_zero = LogQuantidadeDietasAutorizadasRecreioNasFeriasCEI(
quantidade=0,
escola=escola,
data=data_log,
classificacao=classificacao,
faixa_etaria=faixa,
)
logs.append(log_zero)
return logs
[docs]
def filtrar_logs_comuns_ja_existentes(logs):
chaves_existentes = set(
LogQuantidadeDietasAutorizadas.objects.filter(
data__in={log.data for log in logs}
).values_list(
"escola_id",
"data",
"classificacao_id",
"periodo_escolar_id",
"cei_ou_emei",
"infantil_ou_fundamental",
)
)
logs_filtrados = []
for log in logs:
chave = (
log.escola_id,
log.data,
log.classificacao_id,
log.periodo_escolar_id,
log.cei_ou_emei,
log.infantil_ou_fundamental,
)
if chave not in chaves_existentes:
logs_filtrados.append(log)
chaves_existentes.add(chave)
return logs_filtrados
[docs]
def filtrar_logs_cei_ja_existentes(logs):
chaves_existentes = set(
LogQuantidadeDietasAutorizadasCEI.objects.filter(
data__in={log.data for log in logs}
).values_list(
"escola_id",
"data",
"classificacao_id",
"periodo_escolar_id",
"faixa_etaria_id",
)
)
logs_filtrados = []
for log in logs:
chave = (
log.escola_id,
log.data,
log.classificacao_id,
log.periodo_escolar_id,
log.faixa_etaria_id,
)
if chave not in chaves_existentes:
logs_filtrados.append(log)
chaves_existentes.add(chave)
return logs_filtrados
[docs]
def filtrar_logs_recreio_ferias_ja_existentes(logs):
chaves_existentes = set(
LogQuantidadeDietasAutorizadasRecreioNasFerias.objects.filter(
data__in={log.data for log in logs}
).values_list(
"escola_id",
"data",
"classificacao_id",
)
)
logs_filtrados = []
for log in logs:
chave = (
log.escola_id,
log.data,
log.classificacao_id,
)
if chave not in chaves_existentes:
logs_filtrados.append(log)
chaves_existentes.add(chave)
return logs_filtrados
[docs]
def filtrar_logs_recreio_ferias_cei_ja_existentes(logs):
chaves_existentes = set(
LogQuantidadeDietasAutorizadasRecreioNasFeriasCEI.objects.filter(
data__in={log.data for log in logs}
).values_list(
"escola_id",
"data",
"classificacao_id",
"faixa_etaria_id",
)
)
logs_filtrados = []
for log in logs:
chave = (
log.escola_id,
log.data,
log.classificacao_id,
log.faixa_etaria_id,
)
if chave not in chaves_existentes:
logs_filtrados.append(log)
chaves_existentes.add(chave)
return logs_filtrados