Source code for sme_sigpae_api.cardapio.base.api.viewsets

import datetime

from django.core.exceptions import ValidationError
from django.db.models import Case, IntegerField, Value, When
from rest_framework import mixins, status, viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet

from sme_sigpae_api.cardapio.base.api.serializers import (
    CardapioSerializer,
    CombosVinculoTipoAlimentoSimplesSerializer,
    HorarioDoComboDoTipoDeAlimentacaoPorUnidadeEscolarSerializer,
    MotivoDRENaoValidaSerializer,
    SubstituicaoDoComboVinculoTipoAlimentoSimplesSerializer,
    TipoAlimentacaoSerializer,
    TipoUnidadeEscolarAgrupadoSerializer,
    VinculoTipoAlimentoSimplesSerializer,
)
from sme_sigpae_api.cardapio.base.api.serializers_create import (
    CardapioCreateSerializer,
    ComboDoVinculoTipoAlimentoSimplesSerializerCreate,
    HorarioDoComboDoTipoDeAlimentacaoPorUnidadeEscolarSerializerCreate,
    SubstituicaoDoComboVinculoTipoAlimentoSimplesSerializerCreate,
    VinculoTipoAlimentoCreateSerializer,
)
from sme_sigpae_api.cardapio.base.models import (
    Cardapio,
    ComboDoVinculoTipoAlimentacaoPeriodoTipoUE,
    HorarioDoComboDoTipoDeAlimentacaoPorUnidadeEscolar,
    MotivoDRENaoValida,
    SubstituicaoDoComboDoVinculoTipoAlimentacaoPeriodoTipoUE,
    TipoAlimentacao,
    VinculoTipoAlimentacaoComPeriodoEscolarETipoUnidadeEscolar,
)
from sme_sigpae_api.cardapio.utils import ordem_periodos
from sme_sigpae_api.dados_comuns import constants
from sme_sigpae_api.escola.api.viewsets import PeriodoEscolarViewSet
from sme_sigpae_api.escola.constants import PERIODOS_ESPECIAIS_CEMEI
from sme_sigpae_api.escola.models import Escola, PeriodoEscolar
from sme_sigpae_api.inclusao_alimentacao.models import (
    InclusaoAlimentacaoNormal,
    QuantidadePorPeriodo,
)


[docs] class CardapioViewSet(viewsets.ModelViewSet): lookup_field = "uuid" serializer_class = CardapioSerializer queryset = Cardapio.objects.all().order_by("data")
[docs] def get_serializer_class(self): if self.action in ["create", "update", "partial_update"]: return CardapioCreateSerializer return CardapioSerializer
[docs] class TipoAlimentacaoViewSet(viewsets.ModelViewSet): lookup_field = "uuid" serializer_class = TipoAlimentacaoSerializer queryset = TipoAlimentacao.objects.all()
[docs] class HorarioDoComboDoTipoDeAlimentacaoPorUnidadeEscolarViewSet(viewsets.ModelViewSet): lookup_field = "uuid" serializer_class = HorarioDoComboDoTipoDeAlimentacaoPorUnidadeEscolarSerializer queryset = HorarioDoComboDoTipoDeAlimentacaoPorUnidadeEscolar.objects.all()
[docs] @action(detail=False, url_path="escola/(?P<escola_uuid>[^/.]+)") def filtro_por_escola(self, request, escola_uuid=None): combos = HorarioDoComboDoTipoDeAlimentacaoPorUnidadeEscolar.objects.filter( escola__uuid=escola_uuid ) page = self.paginate_queryset(combos) serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data)
[docs] def get_serializer_class(self): if self.action in ["create", "update", "partial_update"]: return HorarioDoComboDoTipoDeAlimentacaoPorUnidadeEscolarSerializerCreate return HorarioDoComboDoTipoDeAlimentacaoPorUnidadeEscolarSerializer
[docs] class VinculoTipoAlimentacaoViewSet( viewsets.ModelViewSet, mixins.RetrieveModelMixin, mixins.ListModelMixin, GenericViewSet, ): lookup_field = "uuid" serializer_class = VinculoTipoAlimentoSimplesSerializer queryset = ( VinculoTipoAlimentacaoComPeriodoEscolarETipoUnidadeEscolar.objects.filter( ativo=True ) )
[docs] @action( detail=False, url_path="tipo_unidade_escolar/(?P<tipo_unidade_escolar_uuid>[^/.]+)", ) def filtro_por_tipo_ue(self, request, tipo_unidade_escolar_uuid=None): vinculos = ( VinculoTipoAlimentacaoComPeriodoEscolarETipoUnidadeEscolar.objects.filter( tipo_unidade_escolar__uuid=tipo_unidade_escolar_uuid, ativo=True ).order_by("periodo_escolar__posicao") ) page = self.paginate_queryset(vinculos) serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data)
[docs] def get_vinculos_inclusoes_evento_especifico( self, mes, ano, tipo_solicitacao, escola ): gupos_uuids = ( InclusaoAlimentacaoNormal.objects.filter( data__month=int(mes), data__year=int(ano), motivo__nome="Evento Específico", grupo_inclusao__escola=escola, grupo_inclusao__status="CODAE_AUTORIZADO", ) .values_list("grupo_inclusao__uuid", flat=True) .distinct() ) periodos_escolares_uuids = escola.periodos_escolares().values_list( "uuid", flat=True ) quantidades_por_periodo = QuantidadePorPeriodo.objects.filter( grupo_inclusao_normal__uuid__in=gupos_uuids ).exclude(periodo_escolar__uuid__in=periodos_escolares_uuids) periodos_escolares_uuids = quantidades_por_periodo.values_list( "periodo_escolar__uuid" ).distinct() vinculos = ( VinculoTipoAlimentacaoComPeriodoEscolarETipoUnidadeEscolar.objects.filter( tipo_unidade_escolar__iniciais=escola.tipo_unidade.iniciais, periodo_escolar__nome__in=constants.PERIODOS_INCLUSAO_MOTIVO_ESPECIFICO, periodo_escolar__uuid__in=periodos_escolares_uuids, ) ) return vinculos
[docs] @action( detail=False, methods=["GET"], url_path=f"{constants.VINCULOS_INCLUSOES_EVENTO_ESPECIFICO_AUTORIZADAS}", ) def vinculos_inclusoes_evento_especifico_autorizadas(self, request): escola_uuid = request.query_params.get("escola_uuid") mes = request.query_params.get("mes") ano = request.query_params.get("ano") tipo_solicitacao = request.query_params.get("tipo_solicitacao") escola = Escola.objects.get(uuid=escola_uuid) vinculos = self.get_vinculos_inclusoes_evento_especifico( mes, ano, tipo_solicitacao, escola ) serializer = self.get_serializer(vinculos, many=True) return Response(serializer.data, status=status.HTTP_200_OK)
[docs] def trata_inclusao_continua_medicao_inicial( self, request, escola, ano, pega_atualmente ): mes = request.query_params.get("mes", None) periodos_escolares_inclusao_continua = None if mes: periodoEscolarViewset = PeriodoEscolarViewSet() response = periodoEscolarViewset.inclusao_continua_por_mes(request) if response.data and response.data.get("periodos", None): periodos_escolares_inclusao_continua = PeriodoEscolar.objects.filter( uuid__in=list(response.data["periodos"].values()) ) periodos_para_filtrar = escola.periodos_escolares(ano, pega_atualmente) if periodos_escolares_inclusao_continua: periodos_para_filtrar = ( periodos_para_filtrar | periodos_escolares_inclusao_continua ) return periodos_para_filtrar
[docs] @action(detail=False, url_path="escola/(?P<escola_uuid>[^/.]+)") def filtro_por_escola(self, request, escola_uuid=None): escola = Escola.objects.get(uuid=escola_uuid) mes = request.query_params.get("mes", datetime.date.today().month) ano = request.query_params.get("ano", datetime.date.today().year) data_referencia = datetime.date(int(ano), int(mes), 1) pega_atualmente = request.query_params.get("pega_atualmente", False) periodos_para_filtrar = self.trata_inclusao_continua_medicao_inicial( request, escola, ano, pega_atualmente ) ordem_personalizada = ordem_periodos(escola, data_referencia) if escola.eh_cemei_data(data_referencia): ordem_das_unidades = {"CEI DIRET": 1, "EMEI": 2} unidades = [ When(tipo_unidade_escolar__iniciais=key, then=Value(val)) for key, val in ordem_das_unidades.items() ] periodo_cases = [] for unidade, periodos in ordem_personalizada.items(): for periodo, ordem in periodos.items(): periodo_cases.append( When( tipo_unidade_escolar__iniciais=unidade, periodo_escolar__nome=periodo, then=Value(ordem), ) ) vinculos = ( VinculoTipoAlimentacaoComPeriodoEscolarETipoUnidadeEscolar.objects.filter( periodo_escolar__nome__in=PERIODOS_ESPECIAIS_CEMEI, tipo_unidade_escolar__iniciais__in=ordem_das_unidades.keys(), ) .annotate( unidade_order=Case( *unidades, default=Value(99), output_field=IntegerField() ), periodo_order=Case( *periodo_cases, default=Value(99), output_field=IntegerField() ), ) .order_by("unidade_order", "periodo_order") ) else: condicoes_ordenacao = [ When(periodo_escolar__nome=nome, then=Value(prioridade)) for nome, prioridade in ordem_personalizada.items() ] vinculos = ( VinculoTipoAlimentacaoComPeriodoEscolarETipoUnidadeEscolar.objects.filter( periodo_escolar__in=periodos_para_filtrar, ativo=True ) .annotate( ordem_personalizada=Case( *condicoes_ordenacao, default=Value(99), # Valor alto para períodos não listados output_field=IntegerField(), ) ) .order_by("ordem_personalizada") ) vinculos = vinculos.filter( tipo_unidade_escolar=escola.tipo_unidade_historico(data_referencia) ) page = self.paginate_queryset(vinculos) serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data)
[docs] @action( detail=False, url_path="atualizar_lista_de_vinculos", methods=["put"], ) def atualizar_lista_de_vinculos(self, request): try: if "vinculos" not in request.data: raise AssertionError("vinculos é um parâmetro obrigatório") vinculos_from_request = request.data.get("vinculos", []) for vinculo in vinculos_from_request: vinculo_class = ( VinculoTipoAlimentacaoComPeriodoEscolarETipoUnidadeEscolar ) instance = vinculo_class.objects.get(uuid=vinculo["uuid"]) instance.tipos_alimentacao.set( TipoAlimentacao.objects.filter( uuid__in=vinculo["tipos_alimentacao"] ) ) instance.save() vinculos_uuids = [vinculo["uuid"] for vinculo in vinculos_from_request] vinculos = vinculo_class.objects.filter(uuid__in=vinculos_uuids) page = self.paginate_queryset(vinculos) serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) except AssertionError as e: return Response({"detail": str(e)}, status=status.HTTP_400_BAD_REQUEST)
[docs] @action(detail=False, methods=["GET"], url_path="motivo_inclusao_especifico") def motivo_inclusao_especifico(self, request): try: tipo_unidade_escolar_iniciais = request.query_params.get( "tipo_unidade_escolar_iniciais", "" ) if tipo_unidade_escolar_iniciais: vinculos = VinculoTipoAlimentacaoComPeriodoEscolarETipoUnidadeEscolar.objects.filter( tipo_unidade_escolar__iniciais=tipo_unidade_escolar_iniciais, periodo_escolar__nome__in=constants.PERIODOS_INCLUSAO_MOTIVO_ESPECIFICO, ) serializer = self.get_serializer(vinculos, many=True) return Response(serializer.data, status=status.HTTP_200_OK) else: raise ValidationError( "tipo_unidade_escolar_iniciais é obrigatório via query_params" ) except ValidationError as e: return Response({"detail": e}, status=status.HTTP_400_BAD_REQUEST)
[docs] def get_serializer_class(self): if self.action in ["create", "update", "partial_update"]: return VinculoTipoAlimentoCreateSerializer return VinculoTipoAlimentoSimplesSerializer
[docs] class CombosDoVinculoTipoAlimentacaoPeriodoTipoUEViewSet( mixins.RetrieveModelMixin, mixins.ListModelMixin, mixins.CreateModelMixin, mixins.DestroyModelMixin, GenericViewSet, ): lookup_field = "uuid" serializer_class = CombosVinculoTipoAlimentoSimplesSerializer queryset = ComboDoVinculoTipoAlimentacaoPeriodoTipoUE.objects.all()
[docs] def get_serializer_class(self): if self.action == "create": return ComboDoVinculoTipoAlimentoSimplesSerializerCreate return CombosVinculoTipoAlimentoSimplesSerializer
[docs] def destroy(self, request, *args, **kwargs): instance = self.get_object() if not instance.pode_excluir(): return Response( data={ "detail": "Não pode excluir, o combo já tem movimentação no sistema" }, status=status.HTTP_403_FORBIDDEN, ) self.perform_destroy(instance) return Response(status=status.HTTP_204_NO_CONTENT)
[docs] class SubstituicaoDoCombosDoVinculoTipoAlimentacaoPeriodoTipoUEViewSet( mixins.RetrieveModelMixin, mixins.ListModelMixin, mixins.CreateModelMixin, mixins.DestroyModelMixin, GenericViewSet, ): lookup_field = "uuid" serializer_class = SubstituicaoDoComboVinculoTipoAlimentoSimplesSerializer queryset = SubstituicaoDoComboDoVinculoTipoAlimentacaoPeriodoTipoUE.objects.all()
[docs] def get_serializer_class(self): if self.action == "create": return SubstituicaoDoComboVinculoTipoAlimentoSimplesSerializerCreate return SubstituicaoDoComboVinculoTipoAlimentoSimplesSerializer
[docs] def destroy(self, request, *args, **kwargs): instance = self.get_object() if not instance.pode_excluir(): return Response( data={ "detail": "Não pode excluir, o combo já tem movimentação no sistema" }, status=status.HTTP_403_FORBIDDEN, ) self.perform_destroy(instance) return Response(status=status.HTTP_204_NO_CONTENT)
[docs] class MotivosDRENaoValidaViewSet(viewsets.ReadOnlyModelViewSet): lookup_field = "uuid" queryset = MotivoDRENaoValida.objects.all() serializer_class = MotivoDRENaoValidaSerializer
[docs] class VinculosPorTipoUnidadeEscolarViewSet(mixins.ListModelMixin, GenericViewSet):
[docs] def list(self, request): """ Lista todos os tipos de UE com seus períodos e tipos de alimentação """ vinculos = ( VinculoTipoAlimentacaoComPeriodoEscolarETipoUnidadeEscolar.objects.filter( ativo=True, tipo_unidade_escolar__ativo=True ) .select_related("tipo_unidade_escolar", "periodo_escolar") .prefetch_related("tipos_alimentacao") ) dados_agrupados = ( TipoUnidadeEscolarAgrupadoSerializer.agrupar_vinculos_por_tipo_ue(vinculos) ) serializer = TipoUnidadeEscolarAgrupadoSerializer(dados_agrupados, many=True) return Response({"results": serializer.data})