from datetime import datetime
from django_filters import rest_framework as filters
from rest_framework import mixins, viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_400_BAD_REQUEST
from src.dados_comuns.helpers_autenticidade import (
verificar_autenticidade_usuario,
)
from src.dados_comuns.permissions import (
PermissaoParaAnalisarFichaTecnica,
PermissaoParaDashboardFichaTecnica,
PermissaoParaRelatorioFichasTecnicas,
PermissaoParaVisualizarCronograma,
PermissaoParaVisualizarFichaTecnica,
UsuarioEhFornecedor,
)
from src.pre_recebimento.ficha_tecnica.api.filters import FichaTecnicaFilter
from src.pre_recebimento.ficha_tecnica.api.serializers.serializer_create import (
AnaliseFichaTecnicaCreateSerializer,
AnaliseFichaTecnicaRascunhoSerializer,
CorrecaoFichaTecnicaSerializer,
FichaTecnicaAtualizacaoSerializer,
FichaTecnicaCreateSerializer,
FichaTecnicaFLVCreateSerializer,
FichaTecnicaRascunhoSerializer,
)
from src.pre_recebimento.ficha_tecnica.api.serializers.serializers import (
FichaTecnicaComAnaliseDetalharSerializer,
FichaTecnicaCronogramaSerializer,
FichaTecnicaDetalharSerializer,
FichaTecnicaListagemSerializer,
FichaTecnicaSimplesSerializer,
PainelFichaTecnicaSerializer,
RelatorioFichaTecnicaSerializer,
)
from src.pre_recebimento.ficha_tecnica.api.services import (
ServiceDashboardFichaTecnica,
)
from src.pre_recebimento.tasks import (
exporta_relatorio_fichas_tecnicas_xlsx,
)
from ....dados_comuns.api.paginations import DefaultPagination
from ....relatorios.relatorios import get_pdf_ficha_tecnica
from ..models import FichaTecnicaDoProduto
[docs]
class FichaTecnicaRascunhoViewSet(
mixins.CreateModelMixin, mixins.UpdateModelMixin, viewsets.GenericViewSet
):
lookup_field = "uuid"
serializer_class = FichaTecnicaRascunhoSerializer
queryset = FichaTecnicaDoProduto.objects.all().order_by("-criado_em")
permission_classes = (UsuarioEhFornecedor,)
[docs]
class FichaTecnicaModelViewSet(
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
mixins.CreateModelMixin,
mixins.UpdateModelMixin,
viewsets.GenericViewSet,
):
lookup_field = "uuid"
serializer_class = FichaTecnicaRascunhoSerializer
queryset = FichaTecnicaDoProduto.objects.all().order_by("-criado_em")
permission_classes = (PermissaoParaVisualizarFichaTecnica,)
pagination_class = DefaultPagination
filter_backends = (filters.DjangoFilterBackend,)
filterset_class = FichaTecnicaFilter
[docs]
def get_queryset(self):
user = self.request.user
if user.eh_fornecedor:
return FichaTecnicaDoProduto.objects.filter(
empresa=user.vinculo_atual.instituicao
).order_by("-criado_em")
return FichaTecnicaDoProduto.objects.all().order_by("-criado_em")
[docs]
def get_serializer_class(self):
serializer_classes_map = {
"list": FichaTecnicaListagemSerializer,
"retrieve": FichaTecnicaDetalharSerializer,
"create": self._get_create_update_serializer(),
"update": self._get_create_update_serializer(),
"listagem_relatorio": RelatorioFichaTecnicaSerializer,
}
return serializer_classes_map.get(self.action, FichaTecnicaRascunhoSerializer)
def _get_create_update_serializer(self):
if self.action == "update":
ficha = self.get_object()
if ficha.categoria == "FLV":
return FichaTecnicaFLVCreateSerializer
elif self.action == "create":
categoria = self.request.data.get("categoria")
if categoria == "FLV":
return FichaTecnicaFLVCreateSerializer
return FichaTecnicaCreateSerializer
[docs]
def create(self, request, *args, **kwargs):
if auth_response := verificar_autenticidade_usuario(request):
return auth_response
return super().create(request, *args, **kwargs)
[docs]
def update(self, request, *args, **kwargs):
if auth_response := verificar_autenticidade_usuario(request):
return auth_response
return super().update(request, *args, **kwargs)
[docs]
@action(
detail=False,
methods=["GET"],
url_path="dashboard",
permission_classes=(PermissaoParaDashboardFichaTecnica,),
)
def dashboard(self, request):
qs = FichaTecnicaDoProduto.objects.order_by("-alterado_em")
dashboard_service = ServiceDashboardFichaTecnica(
qs,
FichaTecnicaFilter,
PainelFichaTecnicaSerializer,
request,
)
return Response({"results": dashboard_service.get_dados_dashboard()})
[docs]
@action(
detail=False,
methods=["GET"],
url_path="lista-simples",
permission_classes=(PermissaoParaVisualizarFichaTecnica,),
)
def lista_simples(self, request, **kwargs):
usuario = self.request.user
qs = (
self.get_queryset().filter(empresa=usuario.vinculo_atual.instituicao)
if usuario.eh_empresa
else self.get_queryset()
)
qs = qs.exclude(status=FichaTecnicaDoProduto.workflow_class.RASCUNHO)
return Response({"results": FichaTecnicaSimplesSerializer(qs, many=True).data})
[docs]
@action(
detail=False,
methods=["GET"],
url_path="lista-simples-aprovadas",
permission_classes=(PermissaoParaVisualizarFichaTecnica,),
)
def lista_simples_aprovadas(self, request, **kwargs):
usuario = self.request.user
qs = (
self.get_queryset().filter(empresa=usuario.vinculo_atual.instituicao)
if usuario.eh_empresa
else self.get_queryset()
)
qs = qs.filter(status=FichaTecnicaDoProduto.workflow_class.APROVADA)
return Response({"results": FichaTecnicaSimplesSerializer(qs, many=True).data})
[docs]
@action(
detail=False,
methods=["GET"],
url_path="lista-simples-sem-cronograma",
permission_classes=(PermissaoParaVisualizarFichaTecnica,),
)
def lista_simples_sem_cronograma(self, request, **kwargs):
qs = (
self.get_queryset()
.exclude(status=FichaTecnicaDoProduto.workflow_class.RASCUNHO)
.exclude(cronograma__isnull=False)
)
return Response({"results": FichaTecnicaSimplesSerializer(qs, many=True).data})
[docs]
@action(
detail=False,
methods=["GET"],
url_path="lista-simples-sem-layout-embalagem",
permission_classes=(PermissaoParaVisualizarFichaTecnica,),
)
def lista_simples_sem_layout_embalagem(self, request, **kwargs):
usuario = self.request.user
qs = (
self.get_queryset().filter(empresa=usuario.vinculo_atual.instituicao)
if usuario.eh_empresa
else self.get_queryset()
)
qs = qs.exclude(status=FichaTecnicaDoProduto.workflow_class.RASCUNHO).exclude(
layout_embalagem__isnull=False
)
return Response({"results": FichaTecnicaSimplesSerializer(qs, many=True).data})
[docs]
@action(
detail=False,
methods=["GET"],
url_path="lista-simples-sem-questoes-conferencia",
permission_classes=(PermissaoParaVisualizarFichaTecnica,),
)
def lista_simples_sem_questoes_conferencia(self, request, **kwargs):
usuario = self.request.user
qs = (
self.get_queryset().filter(empresa=usuario.vinculo_atual.instituicao)
if usuario.eh_empresa
else self.get_queryset()
)
qs = qs.exclude(status=FichaTecnicaDoProduto.workflow_class.RASCUNHO).exclude(
questoes_conferencia__isnull=False
)
return Response({"results": FichaTecnicaSimplesSerializer(qs, many=True).data})
[docs]
@action(
detail=True,
methods=["GET"],
url_path="dados-cronograma",
permission_classes=(PermissaoParaVisualizarCronograma,),
)
def dados_cronograma(self, request, **kwargs):
return Response(FichaTecnicaCronogramaSerializer(self.get_object()).data)
[docs]
@action(
detail=True,
methods=["GET"],
url_path="detalhar-com-analise",
permission_classes=(PermissaoParaVisualizarFichaTecnica,),
)
def detalhar_com_analise(self, request, **kwargs):
return Response(
FichaTecnicaComAnaliseDetalharSerializer(
self.get_object(),
context=self.get_serializer_context(),
).data
)
[docs]
@action(
detail=True,
methods=["POST", "PUT"],
url_path="rascunho-analise-gpcodae",
permission_classes=(PermissaoParaAnalisarFichaTecnica,),
)
def rascunho_analise_gpcodae(self, request, *args, **kwargs):
ficha_tecnica = self.get_object()
analise = ficha_tecnica.analises.last()
criado_por = self.request.user
serializer = AnaliseFichaTecnicaRascunhoSerializer(
instance=analise,
data=request.data,
context={
"ficha_tecnica": ficha_tecnica,
"criado_por": criado_por,
},
)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(
serializer.data,
status=HTTP_201_CREATED if analise is None else HTTP_200_OK,
)
[docs]
@action(
detail=True,
methods=["POST", "PUT"],
url_path="analise-gpcodae",
permission_classes=(PermissaoParaAnalisarFichaTecnica,),
)
def analise_gpcodae(self, request, *args, **kwargs):
ficha_tecnica = self.get_object()
analise = ficha_tecnica.analises.last()
criado_por = self.request.user
serializer = AnaliseFichaTecnicaCreateSerializer(
instance=analise,
data=request.data,
context={
"ficha_tecnica": ficha_tecnica,
"criado_por": criado_por,
},
)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(status=HTTP_201_CREATED if analise is None else HTTP_200_OK)
[docs]
@action(
detail=True,
methods=["PATCH"],
url_path="correcao-fornecedor",
permission_classes=(UsuarioEhFornecedor,),
)
def correcao_fornecedor(self, request, *args, **kwargs):
if auth_response := verificar_autenticidade_usuario(request):
return auth_response
return self._processa_correcao(request, *args, **kwargs)
def _processa_correcao(self, request, *args, **kwargs):
serializer = CorrecaoFichaTecnicaSerializer(
instance=self.get_object(),
data=request.data,
context={"request": request},
)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(HTTP_200_OK)
[docs]
@action(
detail=True,
methods=["PATCH"],
url_path="atualizacao-fornecedor",
permission_classes=(UsuarioEhFornecedor,),
)
def atualizacao_fornecedor(self, request, *args, **kwargs):
if auth_response := verificar_autenticidade_usuario(request):
return auth_response
return self._processa_atualizacao(request, *args, **kwargs)
def _processa_atualizacao(self, request, *args, **kwargs):
serializer = FichaTecnicaAtualizacaoSerializer(
instance=self.get_object(),
data=request.data,
context={"request": request},
)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(HTTP_200_OK)
def _calcular_totalizadores(self, qs):
workflow = FichaTecnicaDoProduto.workflow_class
return {
"Total de Fichas Aprovadas": qs.filter(
status=workflow.APROVADA
).count(),
"Total de Fichas Enviadas para Correção": qs.filter(
status=workflow.ENVIADA_PARA_CORRECAO
).count(),
"Total de Fichas Pendentes de Aprovação": qs.filter(
status=workflow.ENVIADA_PARA_ANALISE
).count(),
}
[docs]
@action(detail=True, methods=["GET"], url_path="gerar-pdf-ficha")
def gerar_pdf_ficha(self, request, uuid=None):
ficha = self.get_object()
try:
return get_pdf_ficha_tecnica(request, ficha)
except Exception:
return Response(
dict(
detail="Ocorreu um erro durante a geração do pdf de Ficha Técnica"
),
status=HTTP_400_BAD_REQUEST,
)
[docs]
@action(
detail=False,
methods=["GET"],
url_path="listagem-relatorio",
permission_classes=(PermissaoParaRelatorioFichasTecnicas,),
)
def listagem_relatorio(self, request):
queryset = self._queryset_relatorio()
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
response = self.get_paginated_response(serializer.data)
response.data["totalizadores"] = self._calcular_totalizadores(queryset)
return response
serializer = self.get_serializer(queryset, many=True)
return Response(
{
"results": serializer.data,
"totalizadores": self._calcular_totalizadores(queryset),
}
)
[docs]
@action(
detail=False,
methods=["GET"],
url_path="exportar-excel",
permission_classes=(PermissaoParaRelatorioFichasTecnicas,),
)
def exportar_excel(self, request):
queryset = self._queryset_relatorio()
nome_arquivo = datetime.now().strftime(
"Relatorio_Fichas_Tecnicas_%Y-%m-%d_%H%M%S.xlsx"
)
exporta_relatorio_fichas_tecnicas_xlsx.delay(
user=request.user.get_username(),
nome_arquivo=nome_arquivo,
fichas_ids=list(queryset.values_list("id", flat=True)),
)
return Response(
{"detail": "Solicitação de geração de arquivo recebida com sucesso."},
status=HTTP_200_OK,
)
def _queryset_relatorio(self):
"""Queryset do relatório: mesmos filtros da tela, excluindo fichas da categoria FLV."""
return self.filter_queryset(
self.get_queryset().exclude(categoria=FichaTecnicaDoProduto.CATEGORIA_FLV)
)