diff --git a/sapl/base/forms.py b/sapl/base/forms.py index bde2f51ca..949b232f8 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -1073,6 +1073,7 @@ class ConfiguracoesAppForm(ModelForm): 'assinatura_ata', 'estatisticas_acesso_normas', 'escolher_numero_materia_proposicao', + 'revisao_setor_legislativo', 'tramitacao_origem_fixa', 'tramitacao_materia', 'ordenacao_pesquisa_materia', diff --git a/sapl/base/migrations/0064_appconfig_revisao_setor_legislativo.py b/sapl/base/migrations/0064_appconfig_revisao_setor_legislativo.py new file mode 100644 index 000000000..43c68f5e0 --- /dev/null +++ b/sapl/base/migrations/0064_appconfig_revisao_setor_legislativo.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.28 on 2026-02-23 14:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0063_merge_20260210_1053'), + ] + + operations = [ + migrations.AddField( + model_name='appconfig', + name='revisao_setor_legislativo', + field=models.BooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=False, verbose_name='Habilitar etapa de revisão pelo Setor Legislativo?'), + ), + ] diff --git a/sapl/base/models.py b/sapl/base/models.py index 93b118bf1..9edc27862 100644 --- a/sapl/base/models.py +++ b/sapl/base/models.py @@ -185,6 +185,10 @@ class AppConfig(models.Model): verbose_name=_( 'Indicar número da matéria a ser gerada na proposição?'), choices=YES_NO_CHOICES, default=False) + revisao_setor_legislativo = models.BooleanField( + verbose_name=_( + 'Habilitar etapa de revisão pelo Setor Legislativo?'), + choices=YES_NO_CHOICES, default=False) # MÓDULO MATÉRIA LEGISLATIVA # Linha 1 ------------------ diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index c932f36b2..28d186297 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -2334,6 +2334,71 @@ class DevolverProposicaoForm(forms.ModelForm): return self.instance +class RevisaoSetorForm(forms.ModelForm): + + observacao_setor = forms.CharField( + required=False, + label=_('Observações da revisão'), + widget=widgets.Textarea(attrs={'rows': 5})) + + logger = logging.getLogger(__name__) + + class Meta: + model = Proposicao + fields = [ + 'observacao_setor', + 'user', + 'ip' + ] + widgets = { + 'user': forms.HiddenInput(), + 'ip': forms.HiddenInput(), + } + + def __init__(self, *args, **kwargs): + super(RevisaoSetorForm, self).__init__(*args, **kwargs) + fields = [] + + fields.append( + Fieldset( + _('Revisão do Setor Legislativo'), + to_column(('observacao_setor', 12)), + to_column( + (form_actions(label=_('Devolver ao Autor'), + name='devolver_setor', + css_class='btn-success float-right'), 12) + ) + ) + ) + + self.helper = SaplFormHelper() + self.helper.layout = Layout(*fields) + + @transaction.atomic + def save(self, commit=False): + cd = self.cleaned_data + + self.instance.data_retorno_setor = timezone.now() + self.instance.usuario_retorno_setor = self.initial['user'] + self.instance.save() + + observacao = cd.get('observacao_setor', '') + HistoricoProposicao.objects.create( + proposicao=self.instance, + status='V', + user=self.initial['user'], + ip=self.initial['ip'], + observacao=observacao) + + self.instance.results = { + 'messages': { + 'success': [_('Proposição revisada e devolvida ao autor com sucesso.'), ] + }, + 'url': reverse('sapl.materia:proposicao-pendente-setor') + } + return self.instance + + class ConfirmarProposicaoForm(ProposicaoForm): tipo_readonly = forms.CharField( diff --git a/sapl/materia/migrations/0092_auto_20260223_1102.py b/sapl/materia/migrations/0092_auto_20260223_1102.py new file mode 100644 index 000000000..8a7888b52 --- /dev/null +++ b/sapl/materia/migrations/0092_auto_20260223_1102.py @@ -0,0 +1,50 @@ +# Generated by Django 2.2.28 on 2026-02-23 14:02 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('materia', '0091_add_codigo_autenticacao'), + ] + + operations = [ + migrations.AlterModelOptions( + name='proposicao', + options={'ordering': ['-data_recebimento'], 'permissions': (('detail_proposicao_enviada', 'Pode acessar detalhes de uma proposição enviada.'), ('detail_proposicao_devolvida', 'Pode acessar detalhes de uma proposição devolvida.'), ('detail_proposicao_incorporada', 'Pode acessar detalhes de uma proposição incorporada.'), ('detail_proposicao_em_revisao_setor', 'Pode acessar detalhes de uma proposição em revisão pelo setor.')), 'verbose_name': 'Proposição', 'verbose_name_plural': 'Proposições'}, + ), + migrations.AddField( + model_name='proposicao', + name='data_envio_setor', + field=models.DateTimeField(blank=True, null=True, verbose_name='Data de Envio ao Setor Legislativo'), + ), + migrations.AddField( + model_name='proposicao', + name='data_retorno_setor', + field=models.DateTimeField(blank=True, null=True, verbose_name='Data de Retorno do Setor Legislativo'), + ), + migrations.AddField( + model_name='proposicao', + name='observacao_setor', + field=models.TextField(blank=True, default='', verbose_name='Observação do Setor Legislativo'), + ), + migrations.AddField( + model_name='proposicao', + name='usuario_envio_setor', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='proposicoes_enviadas_setor', to=settings.AUTH_USER_MODEL, verbose_name='Usuário Responsável pelo Envio ao Setor'), + ), + migrations.AddField( + model_name='proposicao', + name='usuario_retorno_setor', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='proposicoes_retornadas_setor', to=settings.AUTH_USER_MODEL, verbose_name='Usuário Responsável pelo Retorno do Setor'), + ), + migrations.AlterField( + model_name='historicoproposicao', + name='status', + field=models.CharField(choices=[('E', 'Enviada'), ('R', 'Recebida'), ('T', 'Retornada'), ('D', 'Devolvida'), ('S', 'Enviada ao Setor Legislativo'), ('V', 'Revisada pelo Setor Legislativo')], db_index=True, max_length=1, verbose_name='Status de Proposição'), + ), + ] diff --git a/sapl/materia/models.py b/sapl/materia/models.py index 561d67e79..27e467927 100644 --- a/sapl/materia/models.py +++ b/sapl/materia/models.py @@ -855,6 +855,42 @@ class Proposicao(models.Model): verbose_name=_('Data de Devolução') ) + data_envio_setor = models.DateTimeField( + blank=True, + null=True, + verbose_name=_('Data de Envio ao Setor Legislativo') + ) + + data_retorno_setor = models.DateTimeField( + blank=True, + null=True, + verbose_name=_('Data de Retorno do Setor Legislativo') + ) + + usuario_envio_setor = models.ForeignKey( + get_settings_auth_user_model(), + verbose_name=_('Usuário Responsável pelo Envio ao Setor'), + on_delete=models.PROTECT, + related_name='proposicoes_enviadas_setor', + blank=True, + null=True + ) + + usuario_retorno_setor = models.ForeignKey( + get_settings_auth_user_model(), + verbose_name=_('Usuário Responsável pelo Retorno do Setor'), + on_delete=models.PROTECT, + related_name='proposicoes_retornadas_setor', + blank=True, + null=True + ) + + observacao_setor = models.TextField( + blank=True, + default='', + verbose_name=_('Observação do Setor Legislativo') + ) + usuario_envio = models.ForeignKey( get_settings_auth_user_model(), verbose_name=_('Usuário Responsável pelo Envio'), @@ -1057,6 +1093,8 @@ class Proposicao(models.Model): _('Pode acessar detalhes de uma proposição devolvida.')), ('detail_proposicao_incorporada', _('Pode acessar detalhes de uma proposição incorporada.')), + ('detail_proposicao_em_revisao_setor', + _('Pode acessar detalhes de uma proposição em revisão pelo setor.')), ) def __str__(self): @@ -1123,7 +1161,9 @@ class HistoricoProposicao(models.Model): STATUS_PROPOSICAO = Choices(('E', 'ENVIADA', _('Enviada')), ('R', 'RECEBIDA', _('Recebida')), ('T', 'RETORNADA', _('Retornada')), - ('D', 'DEVOLVIDA', _('Devolvida'))) + ('D', 'DEVOLVIDA', _('Devolvida')), + ('S', 'ENVIADA_SETOR', _('Enviada ao Setor Legislativo')), + ('V', 'REVISADA_SETOR', _('Revisada pelo Setor Legislativo'))) proposicao = models.ForeignKey(Proposicao, verbose_name=_('Proposição'), diff --git a/sapl/materia/onlyoffice_views.py b/sapl/materia/onlyoffice_views.py index 28fadbd68..c02d995dd 100644 --- a/sapl/materia/onlyoffice_views.py +++ b/sapl/materia/onlyoffice_views.py @@ -40,9 +40,21 @@ def onlyoffice_config(request, pk): proposicao = get_object_or_404(Proposicao, pk=pk) # Verifica se o usuário tem permissão para editar + is_autor_operador = proposicao.autor.operadores.filter(id=request.user.id).exists() + + # Setor Legislativo pode editar quando a proposição está com o setor + from sapl.rules import SGVP_GROUP_SETOR_LEGISLATIVO + is_setor = request.user.groups.filter(name=SGVP_GROUP_SETOR_LEGISLATIVO).exists() + setor_can_edit = ( + is_setor and + proposicao.data_envio_setor is not None and + proposicao.data_retorno_setor is None and + proposicao.data_envio is None + ) + can_edit = ( not proposicao.data_envio and - proposicao.autor.operadores.filter(id=request.user.id).exists() + (is_autor_operador or setor_can_edit) ) # URLs para o OnlyOffice acessar (dentro da rede Docker) @@ -358,7 +370,18 @@ def onlyoffice_editor(request, pk): proposicao = get_object_or_404(Proposicao, pk=pk) # Verifica se o usuário tem permissão - if not proposicao.autor.operadores.filter(id=request.user.id).exists(): + is_autor_operador = proposicao.autor.operadores.filter(id=request.user.id).exists() + + from sapl.rules import SGVP_GROUP_SETOR_LEGISLATIVO + is_setor = request.user.groups.filter(name=SGVP_GROUP_SETOR_LEGISLATIVO).exists() + setor_can_edit = ( + is_setor and + proposicao.data_envio_setor is not None and + proposicao.data_retorno_setor is None and + proposicao.data_envio is None + ) + + if not is_autor_operador and not setor_can_edit: from django.contrib import messages from django.shortcuts import redirect messages.error(request, 'Você não tem permissão para editar esta proposição.') diff --git a/sapl/materia/urls.py b/sapl/materia/urls.py index bbdf7f9fa..f6896278e 100644 --- a/sapl/materia/urls.py +++ b/sapl/materia/urls.py @@ -17,6 +17,7 @@ from sapl.materia.views import (AcompanhamentoConfirmarView, NumeracaoCrud, OrgaoCrud, OrigemCrud, PrimeiraTramitacaoEmLoteView, ProposicaoCrud, ProposicaoDevolvida, ProposicaoPendente, + ProposicaoPendenteSetor, ProposicaoRecebida, ProposicaoTaView, ReceberProposicao, ReciboProposicaoView, RegimeTramitacaoCrud, RelatoriaCrud, @@ -26,7 +27,7 @@ from sapl.materia.views import (AcompanhamentoConfirmarView, TramitacaoEmLoteView, UnidadeTramitacaoCrud, proposicao_texto, recuperar_materia, ExcluirTramitacaoEmLoteView, - RetornarProposicao, + RetornarProposicao, RevisarProposicaoSetor, MateriaPesquisaSimplesView, DespachoInicialMultiCreateView, get_zip_docacessorios, get_pdf_docacessorios, get_zip_completo, get_pdf_completo, @@ -231,6 +232,10 @@ urlpatterns_proposicao = [ name='proposicao-recebida'), url(r'^proposicao/devolvida/', ProposicaoDevolvida.as_view(), name='proposicao-devolvida'), + url(r'^proposicao/pendente-setor/', ProposicaoPendenteSetor.as_view(), + name='proposicao-pendente-setor'), + url(r'^proposicao/(?P\d+)/revisao-setor/', RevisarProposicaoSetor.as_view(), + name='revisao-proposicao-setor'), # OnlyOffice endpoints para confirmação de proposição (DEVE vir antes de proposicao-confirmar) url(r'^proposicao/confirmar/P(?P[0-9A-Fa-f]+)/(?P\d+)/onlyoffice/editor$', onlyoffice_confirmar_editor, diff --git a/sapl/materia/views.py b/sapl/materia/views.py index df6ac80f0..de3dfccaa 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -49,6 +49,7 @@ from sapl.materia.forms import (AnexadaForm, AutoriaForm, AutoriaMultiCreateForm ConfirmarProposicaoForm, DevolverProposicaoForm, DespachoInicialCreateForm, LegislacaoCitadaForm, MateriaPesquisaSimplesForm, OrgaoForm, ProposicaoForm, + RevisaoSetorForm, TipoProposicaoForm, TramitacaoForm, TramitacaoUpdateForm, ConfigEtiquetaMateriaLegislativaForms) from sapl.norma.models import LegislacaoCitada from sapl.parlamentares.models import ( @@ -613,6 +614,73 @@ class ProposicaoRecebida(PermissionRequiredMixin, ListView): return context +class ProposicaoPendenteSetor(PermissionRequiredMixin, ListView): + template_name = 'materia/prop_pendentes_setor_list.html' + model = Proposicao + ordering = ['data_envio_setor', 'autor', 'tipo', 'descricao'] + paginate_by = 10 + permission_required = ('materia.detail_proposicao_em_revisao_setor', ) + + def get_queryset(self): + return Proposicao.objects.filter( + data_envio_setor__isnull=False, + data_retorno_setor__isnull=True, + data_envio__isnull=True) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + paginator = context['paginator'] + page_obj = context['page_obj'] + context['AppConfig'] = sapl.base.models.AppConfig.objects.all().last() + context['page_range'] = make_pagination( + page_obj.number, paginator.num_pages) + context['NO_ENTRIES_MSG'] = 'Nenhuma proposição pendente de revisão pelo setor.' + qr = self.request.GET.copy() + context['filter_url'] = ('&o=' + qr['o']) if 'o' in qr.keys() else '' + return context + + +class RevisarProposicaoSetor(PermissionRequiredMixin, UpdateView): + template_name = "materia/revisar_proposicao_setor.html" + model = Proposicao + form_class = RevisaoSetorForm + permission_required = ('materia.detail_proposicao_em_revisao_setor', ) + logger = logging.getLogger(__name__) + + def get_initial(self): + initial = super().get_initial() + initial['ip'] = get_client_ip(self.request) + initial['user'] = self.request.user + return initial + + def get_success_url(self): + msgs = self.object.results['messages'] + for key, value in msgs.items(): + for item in value: + getattr(messages, key)(self.request, item) + return self.object.results['url'] + + def dispatch(self, request, *args, **kwargs): + username = request.user.username + try: + p = Proposicao.objects.get(id=kwargs['pk']) + except Exception: + raise Http404() + + if not p.data_envio_setor or p.data_envio: + messages.error(request, + _('Esta proposição não está pendente de revisão pelo setor.')) + return redirect(reverse('sapl.materia:proposicao-pendente-setor')) + + return super().dispatch(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['subnav_template_name'] = '' + context['proposicao'] = self.object + return context + + class ReceberProposicao(PermissionRequiredForAppCrudMixin, FormView): app_label = sapl.protocoloadm.apps.AppConfig.label template_name = "materia/receber_proposicao.html" @@ -884,7 +952,8 @@ class ProposicaoCrud(Crud): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['subnav_template_name'] = '' - context['AppConfig'] = sapl.base.models.AppConfig.objects.all().last() + app_config = sapl.base.models.AppConfig.objects.all().last() + context['AppConfig'] = app_config context['title'] = '%s (%s)' % ( self.object, self.object.autor) @@ -893,6 +962,17 @@ class ProposicaoCrud(Crud): context['proposicao'] = Proposicao.objects.get( pk=self.kwargs['pk'] ) + context['revisao_setor_legislativo'] = ( + app_config.revisao_setor_legislativo if app_config else False + ) + + # Check if current user is member of the Setor Legislativo group + from sapl.rules import SGVP_GROUP_SETOR_LEGISLATIVO + context['is_setor_legislativo'] = ( + self.request.user.groups.filter( + name=SGVP_GROUP_SETOR_LEGISLATIVO + ).exists() + ) return context def get(self, request, *args, **kwargs): @@ -935,6 +1015,8 @@ class ProposicaoCrud(Crud): str(p.pk)) p.data_devolucao = None + p.data_envio_setor = None + p.data_retorno_setor = None p.data_envio = timezone.now() p.save() HistoricoProposicao.objects.create( @@ -1000,6 +1082,46 @@ class ProposicaoCrud(Crud): messages.success(request, _( 'Proposição Retornada com sucesso.')) + elif action == 'send_setor': + app_config = sapl.base.models.AppConfig.objects.all().last() + if not app_config or not app_config.revisao_setor_legislativo: + msg_error = _('Revisão pelo Setor Legislativo não está habilitada.') + elif p.data_envio: + msg_error = _('Proposição já foi enviada ao protocolo.') + elif not p.texto_original and not p.texto_articulado.exists(): + msg_error = _( + 'Proposição não possui texto. Crie o documento antes de enviar ao setor.') + else: + p.data_envio_setor = timezone.now() + p.data_retorno_setor = None + p.usuario_envio_setor = request.user + p.save() + HistoricoProposicao.objects.create( + proposicao=p, + status='S', + ip=get_client_ip(self.request), + user=self.request.user) + self.logger.info("User={}. Proposição (id={}) enviada ao Setor Legislativo." + .format(username, p.pk)) + messages.success(request, _( + 'Proposição enviada ao Setor Legislativo com sucesso.')) + + elif action == 'return_from_setor': + app_config = sapl.base.models.AppConfig.objects.all().last() + if not app_config or not app_config.revisao_setor_legislativo: + msg_error = _('Revisão pelo Setor Legislativo não está habilitada.') + elif not p.data_envio_setor: + msg_error = _('Proposição não está com o Setor Legislativo.') + elif p.data_retorno_setor: + msg_error = _('Proposição já foi devolvida pelo setor.') + else: + p.data_envio_setor = None + p.save() + self.logger.info("User={}. Proposição (id={}) retornada do Setor Legislativo." + .format(username, p.pk)) + messages.success(request, _( + 'Proposição retornada do Setor Legislativo com sucesso.')) + if msg_error: messages.error(request, msg_error) @@ -1021,17 +1143,22 @@ class ProposicaoCrud(Crud): return self.handle_no_permission() if not p.autor.operadores.filter(id=request.user.id).exists(): - if not p.data_envio and not p.data_devolucao: - raise Http404() + # Allow Setor Legislativo users to access proposições sent to them + from sapl.rules import SGVP_GROUP_SETOR_LEGISLATIVO + is_setor = request.user.groups.filter( + name=SGVP_GROUP_SETOR_LEGISLATIVO).exists() - if p.data_devolucao and not request.user.has_perm('materia.detail_proposicao_devolvida'): + if is_setor and p.data_envio_setor and not p.data_envio: + # Setor Legislativo can view proposições sent to them + pass + elif not p.data_envio and not p.data_devolucao: raise Http404() - - if p.data_envio and not p.data_recebimento \ + elif p.data_devolucao and not request.user.has_perm('materia.detail_proposicao_devolvida'): + raise Http404() + elif p.data_envio and not p.data_recebimento \ and not request.user.has_perm('materia.detail_proposicao_enviada'): raise Http404() - - if p.data_envio and p.data_recebimento \ + elif p.data_envio and p.data_recebimento \ and not request.user.has_perm('materia.detail_proposicao_incorporada'): raise Http404() diff --git a/sapl/rules/__init__.py b/sapl/rules/__init__.py index 223046a6a..4867d2ff3 100644 --- a/sapl/rules/__init__.py +++ b/sapl/rules/__init__.py @@ -67,6 +67,7 @@ SGVP_GROUP_GERAL = _("Operador Geral") SGVP_GROUP_AUTOR = _("Autor") SGVP_GROUP_VOTANTE = _("Votante") SGVP_GROUP_PRESIDENTE_MESA = _("Presidente da Mesa Diretora") +SGVP_GROUP_SETOR_LEGISLATIVO = _("Operador do Setor Legislativo") # TODO - funcionalidade ainda não existe mas está aqui para efeito de anotação SGVP_GROUP_LOGIN_SOCIAL = _("Usuários com Login Social") @@ -88,6 +89,7 @@ SGVP_GROUPS = [ SGVP_GROUP_AUTOR, SGVP_GROUP_VOTANTE, SGVP_GROUP_PRESIDENTE_MESA, + SGVP_GROUP_SETOR_LEGISLATIVO, SGVP_GROUP_LOGIN_SOCIAL, SGVP_GROUP_ANONYMOUS, ] diff --git a/sapl/rules/group_setor_legislativo.py b/sapl/rules/group_setor_legislativo.py new file mode 100644 index 000000000..07089a3fa --- /dev/null +++ b/sapl/rules/group_setor_legislativo.py @@ -0,0 +1,17 @@ +from sapl.compilacao import models as compilacao +from sapl.materia import models as materia +from sapl.rules import SGVP_GROUP_SETOR_LEGISLATIVO, RP_LIST, RP_DETAIL, RP_CHANGE, \ + __listdetailchange__, __perms_publicas__ + +rules_group_setor_legislativo = { + 'group': SGVP_GROUP_SETOR_LEGISLATIVO, + 'rules': [ + (materia.Proposicao, __listdetailchange__ + + ['detail_proposicao_enviada', + 'detail_proposicao_devolvida', + 'detail_proposicao_incorporada', + 'detail_proposicao_em_revisao_setor'], set()), + (materia.HistoricoProposicao, [RP_LIST, RP_DETAIL], set()), + (compilacao.TextoArticulado, ['view_restricted_textoarticulado'], __perms_publicas__), + ] +} diff --git a/sapl/rules/map_rules.py b/sapl/rules/map_rules.py index 3f86ada1f..138e826b4 100644 --- a/sapl/rules/map_rules.py +++ b/sapl/rules/map_rules.py @@ -9,6 +9,7 @@ from sapl.rules.group_materia import rules_group_materia from sapl.rules.group_norma import rules_group_norma from sapl.rules.group_painel import rules_group_painel from sapl.rules.group_protocolo import rules_group_protocolo +from sapl.rules.group_setor_legislativo import rules_group_setor_legislativo from sapl.rules.group_sessao import rules_group_sessao from sapl.rules.group_votante import rules_group_votante @@ -84,6 +85,7 @@ rules_group_geral['rules'] = (rules_group_geral['rules'] + rules_group_norma['rules'] + rules_group_sessao['rules'] + rules_group_painel['rules'] + + rules_group_setor_legislativo['rules'] + rules_group_login_social['rules']) rules_patterns = [ @@ -99,6 +101,7 @@ rules_patterns = [ rules_group_autor, rules_group_votante, rules_group_presidente_mesa, + rules_group_setor_legislativo, rules_group_anonymous, # anotação para validação do teste de rules rules_group_login_social # TODO não implementado diff --git a/sapl/templates/base/layouts.yaml b/sapl/templates/base/layouts.yaml index d3c2ca791..ebf1e43eb 100644 --- a/sapl/templates/base/layouts.yaml +++ b/sapl/templates/base/layouts.yaml @@ -34,6 +34,7 @@ AppConfig: {% trans 'Módulo Proposições' %}: - sequencia_numeracao_proposicao receber_recibo_proposicao proposicao_incorporacao_obrigatoria escolher_numero_materia_proposicao + - revisao_setor_legislativo {% trans 'Módulo Matéria Legislativa' %}: - tramitacao_origem_fixa:5 tramitacao_materia:4 ordenacao_pesquisa_materia diff --git a/sapl/templates/materia/prop_pendentes_setor_list.html b/sapl/templates/materia/prop_pendentes_setor_list.html new file mode 100644 index 000000000..91bf0302a --- /dev/null +++ b/sapl/templates/materia/prop_pendentes_setor_list.html @@ -0,0 +1,76 @@ +{% extends "materia/proposicao_base.html" %} +{% load i18n %} +{% load tz %} +{% load common_tags %} +{% block base_content %} +
+
+

{% trans "Revisão do Setor Legislativo" %}

+

{% trans "Proposições enviadas ao setor aguardando revisão" %}

+
+ {% if not object_list %} +

{{ NO_ENTRIES_MSG }}

+ {% else %} + + + + {% with 'Data Envio ao Setor,Tipo,Descrição,Autor' as list %} + {% for name in list|split:"," %} + + {% endfor %} + + {% endwith %} + + + + {% if 'o' in request.GET %} + {% define object_list|sort_by_keys:request.GET.o as list %} + {% else %} + {% define object_list as list %} + {% endif %} + + {% if 'page' in request.GET %} + {% define request.GET.page as pagina %} + {% else %} + {% define '1' as pagina %} + {% endif %} + + {% for prop in list %} + + {% if forloop.counter > pagina|paginacao_limite_inferior and forloop.counter <= pagina|paginacao_limite_superior %} + + + + + + + + {% endif %} + {% endfor %} + +
+ + {{ name }} + {% if 'o' in request.GET %} + {% if 'o' not in request.GET and forloop.counter == 1 or 'o' in request.GET and forloop.counter|safe == request.GET.o %} + + {% elif 'o' in request.GET and forloop.counter == request.GET.o|str2intabs %} + + {%endif%} + {%endif%} + + {% trans "Ações" %}
+ {{ prop.data_envio_setor|localtime|date:"d/m/Y H:i:s" }} + {{ prop.tipo.descricao }}{{ prop.descricao }}{{ prop.autor }} + + {% trans "Revisar" %} + + + + +
+ {% endif %} +
+ + {% include 'paginacao.html'%} +{% endblock %} diff --git a/sapl/templates/materia/proposicao_base.html b/sapl/templates/materia/proposicao_base.html index 99733a5e2..b5ac85367 100644 --- a/sapl/templates/materia/proposicao_base.html +++ b/sapl/templates/materia/proposicao_base.html @@ -27,6 +27,13 @@ Incorporadas + {% if perms.materia.detail_proposicao_em_revisao_setor %} + + + Revisão Setor + + {% endif %} diff --git a/sapl/templates/materia/proposicao_detail.html b/sapl/templates/materia/proposicao_detail.html index efa563687..c477ce82e 100644 --- a/sapl/templates/materia/proposicao_detail.html +++ b/sapl/templates/materia/proposicao_detail.html @@ -64,6 +64,8 @@ .prop-status-badge.incorporada { background: #e8f5e9; color: #388e3c; } .prop-status-badge.devolvida { background: #fff3e0; color: #f57c00; } .prop-status-badge.cancelada { background: #f5f5f5; color: #999; } + .prop-status-badge.aguardando-setor { background: #f3e5f5; color: #7b1fa2; } + .prop-status-badge.revisada-setor { background: #e0f2f1; color: #00695c; } .prop-alert { padding: 14px 18px; @@ -283,6 +285,10 @@ Incorporada {% elif object.data_envio %} Aguardando Recebimento + {% elif revisao_setor_legislativo and object.data_envio_setor and not object.data_retorno_setor %} + Aguardando Revisão do Setor + {% elif revisao_setor_legislativo and object.data_retorno_setor %} + Revisada pelo Setor {% else %} Em Elaboração {% endif %} @@ -306,23 +312,63 @@ {% endif %} + {% if revisao_setor_legislativo and object.data_retorno_setor and not object.data_envio %} +
+ {% trans "Proposição revisada pelo Setor Legislativo" %} + {% if object.observacao_setor %} + {{ object.observacao_setor }} + {% else %} + {% trans "O setor legislativo revisou esta proposição. Você pode agora enviar ao protocolo ou reenviar ao setor." %} + {% endif %} +
+ {% endif %} + + {% if revisao_setor_legislativo and object.data_envio_setor and not object.data_retorno_setor and not object.data_envio %} +
+ {% trans "Proposição enviada ao Setor Legislativo e aguardando revisão." %} +
+ {% endif %} +
{% if not object.data_envio %} - - {% trans "Editar Documento" %} - - {% if object.texto_original or object.texto_articulado.exists %} - - {% trans "Enviar Proposição" %} - + {% if object.data_envio_setor and not object.data_retorno_setor %} + {# Proposição está com o setor - autor pode retirar #} + {% if user in object.autor.operadores.all or user.is_superuser %} + + {% trans "Retirar do Setor" %} + + {% endif %} + {# Setor Legislativo pode revisar #} + {% if is_setor_legislativo %} + + {% trans "Revisar Proposição" %} + + {% endif %} + {% else %} + {# Proposição em elaboração ou revisada pelo setor #} + {% if user in object.autor.operadores.all or user.is_superuser %} + + {% trans "Editar Documento" %} + + {% if object.texto_original or object.texto_articulado.exists %} + + {% trans "Enviar Proposição" %} + + {% if revisao_setor_legislativo %} + + {% trans "Enviar ao Setor Legislativo" %} + + {% endif %} + {% endif %} + + {% trans "Editar Dados" %} + + + {% trans "Excluir" %} + + {% endif %} {% endif %} - - {% trans "Editar Dados" %} - - - {% trans "Excluir" %} - {% else %} {% trans "Ver Recibo" %} @@ -379,6 +425,18 @@ {{ object.data_devolucao|date:"d/m/Y H:i" }}
{% endif %} + {% if revisao_setor_legislativo and object.data_envio_setor %} +
+ + {{ object.data_envio_setor|date:"d/m/Y H:i" }} +
+ {% endif %} + {% if revisao_setor_legislativo and object.data_retorno_setor %} +
+ + {{ object.data_retorno_setor|date:"d/m/Y H:i" }} +
+ {% endif %}