Browse Source

Refatora Tramitação em Lote usando Forms (#2863)

pull/2874/head
Cesar Augusto de Carvalho 6 years ago
committed by Cesar Carvalho
parent
commit
5062de9335
  1. 197
      sapl/materia/forms.py
  2. 171
      sapl/materia/views.py
  3. 2
      sapl/protocoloadm/views.py
  4. 140
      sapl/templates/materia/em_lote/tramitacao.html

197
sapl/materia/forms.py

@ -1511,6 +1511,203 @@ class TipoProposicaoSelect(Select):
return option return option
class TramitacaoEmLoteForm(ModelForm):
logger = logging.getLogger(__name__)
class Meta:
model = Tramitacao
fields = ['data_tramitacao',
'unidade_tramitacao_local',
'status',
'urgente',
'turno',
'unidade_tramitacao_destino',
'data_encaminhamento',
'data_fim_prazo',
'texto',
'user',
'ip']
widgets = {'user': forms.HiddenInput(),
'ip': forms.HiddenInput()}
def __init__(self, *args, **kwargs):
super(TramitacaoEmLoteForm, self).__init__(*args, **kwargs)
self.fields['data_tramitacao'].initial = timezone.now().date()
ust = UnidadeTramitacao.objects.select_related().all()
unidade_tramitacao_destino = [('', '---------')] + [(ut.pk, ut)
for ut in ust if ut.comissao and ut.comissao.ativa]
unidade_tramitacao_destino.extend(
[(ut.pk, ut) for ut in ust if ut.orgao])
unidade_tramitacao_destino.extend(
[(ut.pk, ut) for ut in ust if ut.parlamentar])
self.fields['unidade_tramitacao_destino'].choices = unidade_tramitacao_destino
self.fields['urgente'].label = "Urgente? *"
row1 = to_row([
('data_tramitacao', 4),
('data_encaminhamento', 4),
('data_fim_prazo', 4)
])
row2 = to_row([
('unidade_tramitacao_local', 6),
('unidade_tramitacao_destino', 6),
])
row3 = to_row([
('status', 4),
('urgente', 4),
('turno', 4)
])
row4 = to_row([
('texto', 12)
])
documentos_checkbox_HTML = '''
<br\><br\><br\>
<fieldset>
<legend style="font-size: 24px;">Selecione as matérias para tramitação:</legend>
<table class="table table-striped table-hover">
<div class="controls">
<div class="checkbox">
<label for="id_check_all">
<input type="checkbox" id="id_check_all" onchange="checkAll(this)" /> Marcar/Desmarcar Todos
</label>
</div>
</div>
<thead>
<tr><th>Matéria</th></tr>
</thead>
<tbody>
{% for materia in object_list %}
<tr>
<td>
<input type="checkbox" name="materias" value="{{materia.id}}" {% if check %} checked {% endif %}/>
<a href="{% url 'sapl.materia:materialegislativa_detail' materia.id %}">
{{materia.tipo.sigla}} {{materia.tipo.descricao}} {{materia.numero}}/{{materia.ano}}
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</fieldset>
'''
self.helper = SaplFormHelper()
self.helper.layout = Layout(
Fieldset(
'Detalhes da tramitação:',
row1, row2, row3, row4,
HTML(documentos_checkbox_HTML),
form_actions(label='Salvar')
)
)
def clean(self):
cleaned_data = super(TramitacaoEmLoteForm, self).clean()
if not self.is_valid():
return self.cleaned_data
if 'data_encaminhamento' in cleaned_data:
data_enc_form = cleaned_data['data_encaminhamento']
if 'data_fim_prazo' in cleaned_data:
data_prazo_form = cleaned_data['data_fim_prazo']
if 'data_tramitacao' in cleaned_data:
data_tram_form = cleaned_data['data_tramitacao']
if not self.instance.data_tramitacao:
if cleaned_data['data_tramitacao'] > timezone.now().date():
self.logger.error('A data de tramitação ({}) deve ser '
'menor ou igual a data de hoje ({})!'
.format(cleaned_data['data_tramitacao'], timezone.now().date()))
msg = _(
'A data de tramitação deve ser ' +
'menor ou igual a data de hoje!')
raise ValidationError(msg)
if data_enc_form:
if data_enc_form < data_tram_form:
self.logger.error('A data de encaminhamento ({}) deve ser '
'maior que a data de tramitação ({})!'
.format(data_enc_form, data_tram_form))
msg = _('A data de encaminhamento deve ser ' +
'maior que a data de tramitação!')
raise ValidationError(msg)
if data_prazo_form:
if data_prazo_form < data_tram_form:
self.logger.error('A data fim de prazo ({}) deve ser '
'maior que a data de tramitação ({})!'
.format(data_prazo_form, data_tram_form))
msg = _('A data fim de prazo deve ser ' +
'maior que a data de tramitação!')
raise ValidationError(msg)
if cleaned_data['unidade_tramitacao_local'] == cleaned_data['unidade_tramitacao_destino']:
msg = _('Unidade tramitação local deve ser diferente da unidade tramitação destino.')
self.logger.error('Unidade tramitação local ({}) deve ser diferente da unidade tramitação destino'
.format(cleaned_data['unidade_tramitacao_local']))
raise ValidationError(msg)
return cleaned_data
@transaction.atomic
def save(self, commit=True):
cd = self.cleaned_data
materias = self.initial['materias']
user = self.initial['user'] if 'user' in self.initial else None
ip = self.initial['ip'] if 'ip' in self.initial else ''
tramitar_anexadas = AppConfig.attr('tramitacao_materia')
for mat_id in materias:
mat = MateriaLegislativa.objects.get(id=mat_id)
tramitacao = Tramitacao.objects.create(
status=cd['status'],
materia=mat,
data_tramitacao=cd['data_tramitacao'],
unidade_tramitacao_local=cd['unidade_tramitacao_local'],
unidade_tramitacao_destino=cd['unidade_tramitacao_destino'],
data_encaminhamento=cd['data_encaminhamento'],
urgente=cd['urgente'],
turno=cd['turno'],
texto=cd['texto'],
data_fim_prazo=cd['data_fim_prazo'],
user=user,
ip=ip
)
mat.em_tramitacao = False if tramitacao.status.indicador == "F" else True
mat.save()
if tramitar_anexadas:
lista_tramitacao = []
anexadas = lista_anexados(mat)
for ml in anexadas:
if not ml.tramitacao_set.all() \
or ml.tramitacao_set.last() \
.unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local:
ml.em_tramitacao = False if tramitacao.status.indicador == "F" else True
ml.save()
lista_tramitacao.append(Tramitacao(
status=tramitacao.status,
materia=ml,
data_tramitacao=tramitacao.data_tramitacao,
unidade_tramitacao_local=tramitacao.unidade_tramitacao_local,
data_encaminhamento=tramitacao.data_encaminhamento,
unidade_tramitacao_destino=tramitacao.unidade_tramitacao_destino,
urgente=tramitacao.urgente,
turno=tramitacao.turno,
texto=tramitacao.texto,
data_fim_prazo=tramitacao.data_fim_prazo,
user=tramitacao.user,
ip=tramitacao.ip
))
Tramitacao.objects.bulk_create(lista_tramitacao)
return tramitacao
class ProposicaoForm(FileFieldCheckMixin, forms.ModelForm): class ProposicaoForm(FileFieldCheckMixin, forms.ModelForm):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

171
sapl/materia/views.py

@ -69,7 +69,8 @@ from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
filtra_tramitacao_destino, filtra_tramitacao_destino,
filtra_tramitacao_destino_and_status, filtra_tramitacao_destino_and_status,
filtra_tramitacao_status, filtra_tramitacao_status,
ExcluirTramitacaoEmLote, compara_tramitacoes_mat) ExcluirTramitacaoEmLote, compara_tramitacoes_mat,
TramitacaoEmLoteForm)
from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria, from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria,
DespachoInicial, DocumentoAcessorio, MateriaAssunto, DespachoInicial, DocumentoAcessorio, MateriaAssunto,
MateriaLegislativa, Numeracao, Orgao, Origem, Proposicao, MateriaLegislativa, Numeracao, Orgao, Origem, Proposicao,
@ -2254,39 +2255,34 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(PrimeiraTramitacaoEmLoteView, context = super(PrimeiraTramitacaoEmLoteView,
self).get_context_data(**kwargs) self).get_context_data(**kwargs)
context['subnav_template_name'] = 'materia/em_lote/subnav_em_lote.yaml' context['subnav_template_name'] = 'materia/em_lote/subnav_em_lote.yaml'
context['primeira_tramitacao'] = self.primeira_tramitacao
# Verifica se os campos foram preenchidos # Verifica se os campos foram preenchidos
if not self.filterset.form.is_valid(): if not self.filterset.form.is_valid():
return context return context
context['title'] = _('Primeira Tramitação em Lote') context['object_list'] = context['object_list'].order_by(
'ano', 'numero')
qr = self.request.GET.copy() qr = self.request.GET.copy()
context['unidade_destino'] = UnidadeTramitacao.objects.all()
context['status_tramitacao'] = StatusTramitacao.objects.all()
context['turnos_tramitacao'] = Tramitacao.TURNO_CHOICES
context['urgente_tramitacao'] = YES_NO_CHOICES
context['unidade_local'] = UnidadeTramitacao.objects.all()
context['primeira_tramitacao'] = True form = TramitacaoEmLoteForm()
context['form'] = form
# Pega somente matéria que não possuem tramitação if self.primeira_tramitacao:
if (type(self.__dict__['filterset']).__name__ == context['title'] = _('Primeira Tramitação em Lote')
'PrimeiraTramitacaoEmLoteFilterSet'): # Pega somente documentos que não possuem tramitação
context['object_list'] = context['object_list'].filter( context['object_list'] = [obj for obj in context['object_list']
tramitacao__isnull=True) if obj.tramitacao_set.all().count() == 0]
else: else:
context['title'] = _('Tramitação em Lote') context['title'] = _('Tramitação em Lote')
context['unidade_local'] = [UnidadeTramitacao.objects.get( context['form'].fields['unidade_tramitacao_local'].initial = UnidadeTramitacao.objects.get(
id=qr['tramitacao__unidade_tramitacao_destino'])] id=qr['tramitacao__unidade_tramitacao_destino'])
context['object_list'] = context['object_list'].order_by(
'ano', 'numero')
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else '' context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
@ -2295,127 +2291,42 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
return context return context
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
user = request.user
ip = get_client_ip(request)
marcadas = request.POST.getlist('materia_id') materias_ids = request.POST.getlist('materias')
if not materias_ids:
tz = timezone.get_current_timezone() msg = _("Escolha alguma matéria para ser tramitada.")
username = request.user.username
if len(marcadas) == 0:
msg = _('Nenhuma máteria foi selecionada.')
messages.add_message(request, messages.ERROR, msg) messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs) return self.get(request, self.kwargs)
obrigatorios = {'data_tramitacao': 'Data da Tramitação',
'unidade_tramitacao_local': 'Unidade Local',
'unidade_tramitacao_destino': 'Unidade Destino',
'status': 'Status',
'urgente': 'Urgente',
'texto': 'Texto da Ação'}
for field, nome in obrigatorios.items():
if not request.POST[field]:
msg = _('Campo {} deve ser preenchido.'.format(nome))
messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs)
if not request.POST['data_encaminhamento']: form = TramitacaoEmLoteForm(request.POST,
data_encaminhamento = None initial= {'materias': materias_ids,
else: 'user': user, 'ip':ip})
try:
data_encaminhamento = tz.localize(datetime.strptime(
request.POST['data_encaminhamento'], "%d/%m/%Y"))
except ValueError:
msg = _('Formato da data de encaminhamento incorreto.')
messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs)
if request.POST['data_fim_prazo'] == '': if form.is_valid():
data_fim_prazo = None form.save()
else:
try:
data_fim_prazo = tz.localize(datetime.strptime(
request.POST['data_fim_prazo'], "%d/%m/%Y"))
except ValueError:
msg = _('Formato da data fim do prazo incorreto.')
messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs)
# issue https://github.com/interlegis/sapl/issues/1123 msg = _('Tramitação completa.')
# TODO: usar Form self.logger.info('user=' + user.username + '. Tramitação completa.')
urgente = request.POST['urgente'] == 'True' messages.add_message(request, messages.SUCCESS, msg)
flag_error = False return self.get_success_url()
materias_principais = [m for m in MateriaLegislativa.objects.filter(id__in=marcadas)] return self.form_invalid(form)
tramitar_anexadas = sapl.base.models.AppConfig.attr('tramitacao_materia')
materias_anexadas = []
if tramitar_anexadas:
for materia in materias_principais:
materias_anexadas = materias_anexadas + lista_anexados(materia)
materias = set(materias_principais + materias_anexadas)
def get_success_url(self):
return HttpResponseRedirect(reverse('sapl.materia:primeira_tramitacao_em_lote'))
for materia in materias:
try:
data_tramitacao = tz.localize(datetime.strptime(
request.POST['data_tramitacao'], "%d/%m/%Y"))
except ValueError:
msg = _('Formato da data da tramitação incorreto.')
messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs)
user = request.user def form_invalid(self, form, *args, **kwargs):
ip = get_client_ip(request) for key, erros in form.errors.items():
t = Tramitacao( if not key=='__all__':
materia=materia, [messages.add_message(self.request, messages.ERROR, form.fields[key].label + ": " + e) for e in erros]
data_tramitacao=data_tramitacao, else:
data_encaminhamento=data_encaminhamento, [messages.add_message(self.request, messages.ERROR, e) for e in erros]
data_fim_prazo=data_fim_prazo, return self.get(self.request, kwargs, {'form':form})
unidade_tramitacao_local_id=request.POST[
'unidade_tramitacao_local'],
unidade_tramitacao_destino_id=request.POST[
'unidade_tramitacao_destino'],
urgente=urgente,
status_id=request.POST['status'],
turno=request.POST['turno'],
texto=request.POST['texto'],
user=user,
ip=ip
)
t.save()
try:
self.logger.debug("user=" + username +
". Tentando enviar tramitação.")
tramitacao_signal.send(sender=Tramitacao,
post=t,
request=self.request)
except Exception as e:
self.logger.error('user=' + username + '. Tramitação criada , mas e-mail de acompanhamento '
'de matéria não enviado. Há problemas na configuração '
'do e-mail. ' + str(e))
flag_error = True
if flag_error:
msg = _('Tramitação criada, mas e-mail de acompanhamento '
'de matéria não enviado. A não configuração do servidor de e-mail '
'impede o envio de aviso de tramitação')
messages.add_message(self.request, messages.WARNING, msg)
status = StatusTramitacao.objects.get(id=request.POST['status'])
for materia in materias:
if status.indicador == 'F':
materia.em_tramitacao = False
elif self.primeira_tramitacao:
materia.em_tramitacao = True
materia.save()
msg = _('Tramitação completa. ' + "Foram tramitadas " + str(len(materias)) + " matéria(s).")
self.logger.info('user=' + username + '. Tramitação completa.')
messages.add_message(request, messages.SUCCESS, msg)
if self.primeira_tramitacao:
return HttpResponseRedirect(reverse('sapl.materia:primeira_tramitacao_em_lote'))
return HttpResponseRedirect(reverse('sapl.materia:tramitacao_em_lote'))
class TramitacaoEmLoteView(PrimeiraTramitacaoEmLoteView): class TramitacaoEmLoteView(PrimeiraTramitacaoEmLoteView):
filterset_class = TramitacaoEmLoteFilterSet filterset_class = TramitacaoEmLoteFilterSet
@ -2428,7 +2339,7 @@ class TramitacaoEmLoteView(PrimeiraTramitacaoEmLoteView):
qr = self.request.GET.copy() qr = self.request.GET.copy()
context['primeira_tramitacao'] = False context['primeira_tramitacao'] = self.primeira_tramitacao
if ('tramitacao__status' in qr and if ('tramitacao__status' in qr and
'tramitacao__unidade_tramitacao_destino' in qr and 'tramitacao__unidade_tramitacao_destino' in qr and

2
sapl/protocoloadm/views.py

@ -1545,7 +1545,7 @@ class TramitacaoEmLoteAdmView(PrimeiraTramitacaoEmLoteAdmView):
qr = self.request.GET.copy() qr = self.request.GET.copy()
context['primeira_tramitacao'] = False context['primeira_tramitacao'] = self.primeira_tramitacao
if ('tramitacao__status' in qr and if ('tramitacao__status' in qr and
'tramitacao__unidade_tramitacao_destino' in qr and 'tramitacao__unidade_tramitacao_destino' in qr and

140
sapl/templates/materia/em_lote/tramitacao.html

@ -1,134 +1,28 @@
{% extends "crud/detail.html" %} {% extends "crud/detail.html" %}
{% load i18n crispy_forms_tags %} {% load i18n crispy_forms_tags %}
{% block actions %}{% endblock %}
{% block detail_content %} {% block detail_content %}
{% if not show_results %} {% if not show_results %}
{% crispy filter.form %} {% crispy filter.form %}
{% endif %}
{% if show_results %}
{% if object_list|length > 0 %}
{% if object_list|length == 1 %}
<h3 style="text-align: right;">{% trans 'Pesquisa concluída com sucesso! Foi encontrada 1 matéria.'%}</h3>
{% else %}
<h3 style="text-align: right;">Foram encontradas {{object_list|length}} matérias.</h3>
{% endif %}
<form method="POST">
{% csrf_token %}
<fieldset>
<legend>1. Detalhes da tramitação:</legend>
<div class="row">
<div class="col-md-4">
<label>Data da Tramitação*</label>
<input type="text" name="data_tramitacao" class="form-control dateinput" required="True">
</div>
<div class="col-md-4">
<label>Data Encaminhamento</label>
<input type="text" name="data_encaminhamento" class="form-control dateinput">
</div>
<div class="col-md-4">
<label>Data Fim do Prazo</label>
<input type="text" name="data_fim_prazo" class="form-control dateinput">
</div>
</div>
<div class="row">
<div class="col-md-6">
<label>Unidade Local*</label>
<select id="id_unidade_tramitacao_local" name="unidade_tramitacao_local" class="form-control" required="True">
{% if unidade_local|length > 1 %}<option></option>{% endif %}
{% for u in unidade_local %} <option value="{{u.id}}">{{u}}</option> {% endfor %}
</select>
</div>
<div class="col-md-6">
<label>Unidade Destino*</label>
<select name="unidade_tramitacao_destino" class="form-control" required="True">
<option></option>
{% for u in unidade_destino %} <option value="{{u.id}}">{{u}}</option> {% endfor %}
</select>
</div>
</div>
<div class="row">
<div class="col-md-4">
<label>Status*</label>
<select name="status" class="form-control" required="True">
<option></option>
{% for s in status_tramitacao %} <option value="{{s.id}}">{{s}}</option> {% endfor %}
</select>
</div>
<div class="col-md-4">
<label>Urgente?*</label>
<select name="urgente" class="form-control" required="True">
<option></option>
{% for u in urgente_tramitacao %} <option value="{{u|first}}">{{u|last}}</option> {% endfor %}
</select>
</div>
<div class="col-md-4">
<label>Turno</label>
<select name="turno" class="form-control">
<option></option>
{% for t in turnos_tramitacao %} <option value="{{t|first}}">{{t|last}}</option> {% endfor %}
</select>
</div>
</div>
<div class="row">
<div class="col-md-12">
<label>Texto da Ação*</label>
<textarea name="texto" class="textarea form-control" cols="40" rows="10" required="True"></textarea>
</div>
</div>
</fieldset>
<br /><br /><br />
<fieldset>
<legend>2. Selecione as matérias para tramitação:</legend>
<table class="table table-striped table-hover">
<div class="controls">
<div class="checkbox">
<label for="id_check_all">
<input type="checkbox" id="id_check_all" onchange="checkAll(this)" /> Marcar/Desmarcar Todos
</label>
</div>
</div>
<thead>
<tr><th>Matéria</th></tr>
</thead>
<tbody>
{% for materia in object_list %}
<tr>
<td>
<input type="checkbox" name="materia_id" value="{{materia.id}}" {% if check %} checked {% endif %}/>
<a href="{% url 'sapl.materia:materialegislativa_detail' materia.id %}">
{{materia.tipo.sigla}} {{materia.tipo.descricao}} {{materia.numero}}/{{materia.ano}}
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</fieldset>
<input type="submit" value="Salvar" class="btn btn-primary"S>
</form>
{% else %} {% else %}
<tr><td><h3 style="text-align: right;">Nenhuma matéria encontrada.</h3></td></tr> {% if object_list|length > 0 %}
{% endif %} {% if object_list|length == 1 %}
{% endif %} <h3 style="text-align: right;">{% trans 'Pesquisa concluída com sucesso! Foi encontrada 1 matéria.'%}</h3>
{% else %}
<h3 style="text-align: right;">Foram encontradas {{object_list|length}} matérias.</h3>
{% endif %}
{% crispy form %}
{% else %}
<tr><td><h3 style="text-align: right;">Nenhuma matéria encontrada.</h3></td></tr>
{% endif %}
{% endif%}
{% endblock detail_content %} {% endblock detail_content %}
{% block extra_js %} {% block extra_js %}
<script language="JavaScript"> <script language="JavaScript">
function checkAll(elem) { function checkAll(elem) {
let checkboxes = document.getElementsByName('materia_id'); let checkboxes = document.getElementsByName('materias');
for (let i = 0; i < checkboxes.length; i++) { for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox') if (checkboxes[i].type == 'checkbox')
checkboxes[i].checked = elem.checked; checkboxes[i].checked = elem.checked;

Loading…
Cancel
Save