From 7b249c4c9ec0567dedc9c479e8878bf12a33f7fd Mon Sep 17 00:00:00 2001 From: rangelbruno Date: Tue, 10 Feb 2026 12:35:34 -0300 Subject: [PATCH] =?UTF-8?q?Feat(OnlyOffice):=20Criar=20Documento=20Acess?= =?UTF-8?q?=C3=B3rio=20direto=20no=20editor=20OnlyOffice?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adiciona botão "Criar e Editar no OnlyOffice" no formulário de criação de Documento Acessório, permitindo criar o documento sem upload de arquivo e redirecionar para o editor OnlyOffice. Corrige também NoReverseMatch na URL de detalhe do documento acessório no editor. Co-Authored-By: rangelbruno --- sapl/materia/forms.py | 9 ++++-- sapl/materia/onlyoffice_materia_views.py | 4 +-- sapl/materia/views.py | 39 +++++++++++++++++++++--- 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 7a86cfc7d..c932f36b2 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -345,12 +345,15 @@ class DocumentoAcessorioForm(FileFieldCheckMixin, ModelForm): arquivo = self.cleaned_data.get('arquivo') + # Quando criando via OnlyOffice, arquivo não é obrigatório + if self.data.get('action') == 'onlyoffice': + if arquivo: + validar_arquivo(arquivo, "Texto Integral") + return self.cleaned_data + if arquivo: validar_arquivo(arquivo, "Texto Integral") else: - # TODO: definir arquivo no form e preservar o nome do campo - # que gerou a mensagem de erro. - ## arquivo = forms.FileField(required=True, label="Texto Integral") nome_arquivo = self.fields['arquivo'].label raise ValidationError(f'Favor anexar arquivo em {nome_arquivo}') diff --git a/sapl/materia/onlyoffice_materia_views.py b/sapl/materia/onlyoffice_materia_views.py index a25b677f5..4543b142c 100644 --- a/sapl/materia/onlyoffice_materia_views.py +++ b/sapl/materia/onlyoffice_materia_views.py @@ -654,7 +654,7 @@ def docacessorio_onlyoffice_editor(request, pk): if not (request.user.is_superuser or request.user.has_perm('materia.change_documentoacessorio')): messages.error(request, 'Você não tem permissão para editar este documento.') - return redirect('sapl.materia:documentoacessorio_detail', pk=documento.materia.pk, zpk=pk) + return redirect('sapl.materia:documentoacessorio_detail', pk=pk) # URL do OnlyOffice acessível pelo navegador do usuário onlyoffice_url = get_onlyoffice_browser_url(request) @@ -666,7 +666,7 @@ def docacessorio_onlyoffice_editor(request, pk): 'documento_descricao': documento.ementa or f'Matéria: {documento.materia}', 'onlyoffice_url': onlyoffice_url, 'config_url': reverse('sapl.materia:docacessorio_onlyoffice_config', kwargs={'pk': pk}), - 'voltar_url': reverse('sapl.materia:documentoacessorio_detail', kwargs={'pk': documento.materia.pk, 'zpk': pk}), + 'voltar_url': reverse('sapl.materia:documentoacessorio_detail', kwargs={'pk': pk}), 'check_url': reverse('sapl.materia:docacessorio_check_doc', kwargs={'pk': pk}), 'forcesave_url': reverse('sapl.materia:docacessorio_forcesave', kwargs={'pk': pk}), } diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 5552322b9..3f68fa312 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -10,7 +10,8 @@ import time import zipfile from PyPDF4 import PdfFileReader, PdfFileMerger -from crispy_forms.layout import HTML +from crispy_forms.bootstrap import FormActions +from crispy_forms.layout import Div, HTML, Submit from django.conf import settings from django.contrib import messages from django.contrib.auth.decorators import permission_required @@ -1703,18 +1704,46 @@ class DocumentoAcessorioCrud(MasterDetailCrud): class CreateView(MasterDetailCrud.CreateView): form_class = DocumentoAcessorioForm - def __init__(self, **kwargs): - super(MasterDetailCrud.CreateView, self).__init__(**kwargs) - def get_initial(self): initial = super(CreateView, self).get_initial() initial['data'] = timezone.now().date() - return initial + def get_success_url(self): + if self.request.POST.get('action') == 'onlyoffice': + messages.info(self.request, _( + 'Documento Acessório criado com sucesso! ' + 'Você será redirecionado para o Editor OnlyOffice.')) + return reverse('sapl.materia:docacessorio_onlyoffice_editor', + kwargs={'pk': self.object.pk}) + return super().get_success_url() + def get_context_data(self, **kwargs): context = super( MasterDetailCrud.CreateView, self).get_context_data(**kwargs) + form = context.get('form') + if form and hasattr(form, 'helper') and form.helper.layout: + btns = FormActions( + HTML('%s' % _('Cancelar')), + Submit('action', _('Criar e Editar no OnlyOffice'), + css_class='btn-primary', + onclick="this.value='onlyoffice';"), + Submit('salvar', _('Salvar'), css_class='float-right', + onclick='this.form.submit();this.disabled=true;'), + css_class='form-group row justify-content-between' + ) + # Layout: Div(row) > Div(col) > FormActions + def replace_form_actions(fields): + for i, field in enumerate(fields): + if isinstance(field, FormActions): + fields[i] = btns + return True + if hasattr(field, 'fields'): + if replace_form_actions(field.fields): + return True + return False + replace_form_actions(form.helper.layout.fields) return context class UpdateView(MasterDetailCrud.UpdateView):