From c0e30c30241080d61f89fe723a235f9f930313d8 Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Thu, 24 Aug 2023 14:32:50 +0200 Subject: [PATCH 01/52] First structure for creating a dict --- proposals/utils/proposal_utils.py | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/proposals/utils/proposal_utils.py b/proposals/utils/proposal_utils.py index 2a8e51a19..fadc76d19 100644 --- a/proposals/utils/proposal_utils.py +++ b/proposals/utils/proposal_utils.py @@ -302,7 +302,34 @@ def _get_next_proposal_number(current_year) -> int: except Proposal.DoesNotExist: return 1 - +def generate_relevant_data_pdf(proposal): + empty_dict = {} + + empty_dict[_('Algemene informatie over de aanvraag')] = {} + empty_dict[_('Ethische toetsing nodig door een Medische Ethische Toetsingscommissie (METC)?')] = {} + + if proposal.wmo.status != proposal.wmo.NO_WMO: + empty_dict[_("Aanmelding bij de METC")] = {} + + empty_dict[_('Eén of meerdere trajecten?')] = {} + + '''Note to self: this will be a huge pain of nesting ... only scratch surface for now ...''' + if proposal.wmo.status == proposal.wmo.NO_WMO: + for study in proposal.study_set.all(): + if proposal.studies_number > 1: + empty_dict['studies'] = {} + if study.name: + empty_dict['studies'][_(f'traject { study.order } { study.name }')] = {} + else: + empty_dict['studies'][_(f'traject { study.order }')] = {} + else: + empty_dict['study'] = {} + + empty_dict['extra documents'] = [] + + empty_dict['Aanmelding versturen'] = {} + + return empty_dict def generate_pdf(proposal, template=False): """Grandfathered function for pdf saving. The template arg currently From b1d1ee34f02baa4bb934f61d045f63127168b5d5 Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Mon, 28 Aug 2023 15:44:51 +0200 Subject: [PATCH 02/52] Some groundwork and a bit of RowValueClass --- proposals/utils/proposal_utils.py | 108 +++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 1 deletion(-) diff --git a/proposals/utils/proposal_utils.py b/proposals/utils/proposal_utils.py index fadc76d19..b36d3410e 100644 --- a/proposals/utils/proposal_utils.py +++ b/proposals/utils/proposal_utils.py @@ -1,6 +1,6 @@ # -*- encoding: utf-8 -*- -from collections import defaultdict +from collections import defaultdict, OrderedDict from datetime import datetime from io import BytesIO import os @@ -306,6 +306,20 @@ def generate_relevant_data_pdf(proposal): empty_dict = {} empty_dict[_('Algemene informatie over de aanvraag')] = {} + empty_dict[_('Algemene informatie over de aanvraag')][proposal._meta.get_field('relation').verbose_name] = proposal.relation + if proposal.relation.needs_supervisor: + empty_dict[_('Algemene informatie over de aanvraag')][proposal._meta.get_field('supervisor').verbose_name] = proposal.supervisor.get_full_name + if proposal.relation.check_in_course: + empty_dict[_('Algemene informatie over de aanvraag')][proposal._meta.get_field('student_program').verbose_name] = proposal.student_program + empty_dict[_('Algemene informatie over de aanvraag')][proposal._meta.get_field('student_context').verbose_name] = proposal.student_context + if proposal.student_context.needs_detail: + empty_dict[_('Algemene informatie over de aanvraag')][proposal._meta.get_field('student_context_detail').verbose_name] = proposal.student_context_details + empty_dict[_('Algemene informatie over de aanvraag')][proposal._meta.get_field('student_justification').verbose_name] = proposal.student_justification + #I am not quite sure how to add translation to the boolean value resulting here ... + empty_dict[_('Algemene informatie over de aanvraag')][proposal._meta.get_field('other_applicants').verbose_name] = proposal.other_applicants + if proposal.other_applicants: + empty_dict[_('Algemene informatie over de aanvraag')][proposal._meta.get_field('applicants').verbose_name] = [applicant.get_full_name for applicant in proposal.applicants] + empty_dict[_('Ethische toetsing nodig door een Medische Ethische Toetsingscommissie (METC)?')] = {} if proposal.wmo.status != proposal.wmo.NO_WMO: @@ -331,6 +345,97 @@ def generate_relevant_data_pdf(proposal): return empty_dict +class PDFSection: + + section_title = None + row_fields = None + + def __init__(self, object): + self.object = object + # Create a copy of the class level row_fields, such that we can safely manipulate it without changing the class value + self._row_fields = self.row_fields + + def get_rows(self): + rows = OrderedDict() + for row_field in self._row_fields: + rows[row_field] = { + 'label': self.object._meta.get_field(row_field).verbose_name, + 'value': RowValueClass(self.object, row_field) + } + return rows + + def render(self, context): + template = get_template("proposals/pdf/table_with_header.html") + context.update( + { + "section_title": self.section_title, + "rows": self.get_rows(), + } + ) + return template.render(context) + +class GeneralSection(PDFSection): + # This class inherits from the above + + section_title = _("Algemene informatie over de aanvraag") + row_fields = ['metc', 'metc_details', 'metc_institution'] + + def get_rows(self): + # Remove the metc_details if no METC review is needed + if not self.object.metc: + del self._row_fields['metc_details'] + del self._row_fields['metc_institution'] + # Use the get_rows from PDFSection to get the actual rows, the code above should have filtered out everything we don't need + return super().get_rows() + +class RowValueClass: + + def __init__(self, object, field): + + self.object = object + self.field = field + + def render(self, context): + + value = getattr(self.object, self.field) + + if type(value) in (str, int, datetime.date): + return value + elif type(value) == bool: + return _('Ja') if value else _('Nee') + elif type(value) == User: + return self.handle_user(value) + elif value.__class__.__name__ == 'ManyRelatedManager': + if value.all().model == User: + return self.get_applicants_names(value) + elif value.all().model == Funding: + return self.get_funding_list() + elif callable(value): + return value() + + def handle_user(self, user): + return user.get_full_name() + + def get_applicants_names(self, applicants): + applicant_names = [applicant.get_full_name() for applicant in applicants.all()] + return self.create_unordered_html_list(applicant_names) + + def get_funding_list(self, funding): + list_of_funds = [fund for fund in funding.all()] + return self.create_unordered_html_list(list_of_funds) + + def create_unordered_html_list(list): + html_output = '' + + return html_output + + + def generate_pdf(proposal, template=False): """Grandfathered function for pdf saving. The template arg currently only exists for backwards compatibility.""" @@ -355,6 +460,7 @@ def generate_pdf(proposal, template=False): return proposal.pdf + def pdf_link_callback(uri, rel): """ Convert HTML URIs to absolute system paths so xhtml2pdf can access those From 158c62bbe35c506e2128376be8caa74edfebd44b Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Tue, 29 Aug 2023 10:39:38 +0200 Subject: [PATCH 03/52] Furthering test build --- .../proposals/pdf/table_with_header.html | 8 +++ proposals/utils/proposal_utils.py | 50 ++++++++++++++++--- 2 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 proposals/templates/proposals/pdf/table_with_header.html diff --git a/proposals/templates/proposals/pdf/table_with_header.html b/proposals/templates/proposals/pdf/table_with_header.html new file mode 100644 index 000000000..68c62ac5d --- /dev/null +++ b/proposals/templates/proposals/pdf/table_with_header.html @@ -0,0 +1,8 @@ +

{{ section_title }}

+ +{% for key, value rows.items() %} + + + +{% endfor %} +
{{value.label}}{{ value.value }}
\ No newline at end of file diff --git a/proposals/utils/proposal_utils.py b/proposals/utils/proposal_utils.py index b36d3410e..7aad0c73a 100644 --- a/proposals/utils/proposal_utils.py +++ b/proposals/utils/proposal_utils.py @@ -19,6 +19,8 @@ from main.utils import AvailableURL, get_secretary from studies.utils import study_urls +from proposals.templatetags.proposal_filters import needs_details + __all__ = ['available_urls', 'generate_ref_number', 'generate_revision_ref_number', 'generate_pdf', @@ -360,7 +362,7 @@ def get_rows(self): for row_field in self._row_fields: rows[row_field] = { 'label': self.object._meta.get_field(row_field).verbose_name, - 'value': RowValueClass(self.object, row_field) + 'value': RowValueClass(self.object, row_field).render() } return rows @@ -375,16 +377,48 @@ def render(self, context): return template.render(context) class GeneralSection(PDFSection): - # This class inherits from the above + '''This class generates the data for the general section of + the PDF page.''' section_title = _("Algemene informatie over de aanvraag") - row_fields = ['metc', 'metc_details', 'metc_institution'] + row_fields = [ + 'relation', + 'supervisor', + 'student program', + 'student_context', + 'student_context_details', + 'student_justification', + 'other_applicants', + 'applicants', + 'other_stakeholders', + 'stakeholders', + 'date_start', + 'title', + 'funding' + 'funding_details', + 'funding_name', + 'self_assessment' + ] def get_rows(self): - # Remove the metc_details if no METC review is needed - if not self.object.metc: - del self._row_fields['metc_details'] - del self._row_fields['metc_institution'] + obj = self.object + rows = self._row_fields + if not obj.needs_supervisor: + del rows['supervisor'] + if not obj.check_in_course: + del rows['student_program'] + del rows['student_context'] + if not obj.student_context.needs_details: + del rows['student_context_details'] + del rows['student_justification'] + if not obj.other_applicants: + del rows['applicants'] + if not obj.other_stakeholders: + del rows['stakeholders'] + if not needs_details(obj.funding.all()): + del rows['funding_details'] + if not needs_details(obj.funding.all(), 'needs_name'): + del rows['funding_name'] # Use the get_rows from PDFSection to get the actual rows, the code above should have filtered out everything we don't need return super().get_rows() @@ -395,7 +429,7 @@ def __init__(self, object, field): self.object = object self.field = field - def render(self, context): + def render(self): value = getattr(self.object, self.field) From 41b9c34dcdc36b5b2024df968298f722bc45bc06 Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Tue, 29 Aug 2023 16:50:40 +0200 Subject: [PATCH 04/52] First working test, plus extra stuff --- .../templates/proposals/pdf/new_pdf_test.html | 18 ++ .../proposals/pdf/table_with_header.html | 4 +- proposals/utils/proposal_utils.py | 178 ++++++++++++------ proposals/views/proposal_views.py | 15 +- 4 files changed, 154 insertions(+), 61 deletions(-) create mode 100644 proposals/templates/proposals/pdf/new_pdf_test.html diff --git a/proposals/templates/proposals/pdf/new_pdf_test.html b/proposals/templates/proposals/pdf/new_pdf_test.html new file mode 100644 index 000000000..c03c57358 --- /dev/null +++ b/proposals/templates/proposals/pdf/new_pdf_test.html @@ -0,0 +1,18 @@ +{% extends "base/base.html" %} + +{% load static %} +{% load proposal_filters %} +{% load fetc_filters %} +{% load i18n %} +{% load compare_tags %} +{% load uil_filters %} + +{% block header_title %} + New PDF test +{% endblock %} + +{% block content %} + + {% include test %} + +{% endblock %} \ No newline at end of file diff --git a/proposals/templates/proposals/pdf/table_with_header.html b/proposals/templates/proposals/pdf/table_with_header.html index 68c62ac5d..0f0e00c65 100644 --- a/proposals/templates/proposals/pdf/table_with_header.html +++ b/proposals/templates/proposals/pdf/table_with_header.html @@ -1,8 +1,8 @@

{{ section_title }}

-{% for key, value rows.items() %} +{% for label, value in rows.items %} - + {% endfor %}
{{value.label}}{{ value.value }}{{ value.label }}{{ value.value }}
\ No newline at end of file diff --git a/proposals/utils/proposal_utils.py b/proposals/utils/proposal_utils.py index 7aad0c73a..13e70911d 100644 --- a/proposals/utils/proposal_utils.py +++ b/proposals/utils/proposal_utils.py @@ -1,7 +1,7 @@ # -*- encoding: utf-8 -*- from collections import defaultdict, OrderedDict -from datetime import datetime +from datetime import datetime, date from io import BytesIO import os @@ -347,23 +347,36 @@ def generate_relevant_data_pdf(proposal): return empty_dict +from django.contrib.auth import get_user_model +from django.utils.safestring import mark_safe +from django.utils.html import format_html +from copy import copy class PDFSection: section_title = None row_fields = None + verbose_name_diff_field_dict = { + 'get_metc_display': ('wmo', 'metc') + 'get_is_medical_display': ('wmo','is_medical') + + } def __init__(self, object): self.object = object # Create a copy of the class level row_fields, such that we can safely manipulate it without changing the class value - self._row_fields = self.row_fields + self._row_fields = copy(self.row_fields) def get_rows(self): rows = OrderedDict() for row_field in self._row_fields: - rows[row_field] = { - 'label': self.object._meta.get_field(row_field).verbose_name, - 'value': RowValueClass(self.object, row_field).render() - } + if type(row_field) == str: + rows[row_field] = { + 'label': self.object._meta.get_field(row_field).verbose_name, + 'value': RowValueClass(self.object, row_field).render() + } + #TODO: finish this + if type(row_field) == tuple: + return rows def render(self, context): @@ -374,7 +387,7 @@ def render(self, context): "rows": self.get_rows(), } ) - return template.render(context) + return template.render(context.flatten()) class GeneralSection(PDFSection): '''This class generates the data for the general section of @@ -384,7 +397,7 @@ class GeneralSection(PDFSection): row_fields = [ 'relation', 'supervisor', - 'student program', + 'student_program', 'student_context', 'student_context_details', 'student_justification', @@ -394,79 +407,128 @@ class GeneralSection(PDFSection): 'stakeholders', 'date_start', 'title', - 'funding' + 'funding', 'funding_details', 'funding_name', - 'self_assessment' + 'self_assessment', ] def get_rows(self): obj = self.object rows = self._row_fields - if not obj.needs_supervisor: - del rows['supervisor'] - if not obj.check_in_course: - del rows['student_program'] - del rows['student_context'] - if not obj.student_context.needs_details: - del rows['student_context_details'] - del rows['student_justification'] + if not obj.relation.needs_supervisor: + rows.remove('supervisor') + if not obj.relation.check_in_course: + rows.remove('student_program') + rows.remove('student_context') + if obj.student_context is not None: + if not obj.student_context.needs_details: + rows.remove('student_context_details') + else: + rows.remove('student_context_details') + rows.remove('student_justification') if not obj.other_applicants: - del rows['applicants'] + rows.remove('applicants') if not obj.other_stakeholders: - del rows['stakeholders'] + rows.remove('stakeholders') if not needs_details(obj.funding.all()): - del rows['funding_details'] + rows.remove('funding_details') if not needs_details(obj.funding.all(), 'needs_name'): - del rows['funding_name'] + rows.remove('funding_name') # Use the get_rows from PDFSection to get the actual rows, the code above should have filtered out everything we don't need return super().get_rows() +class WMOSection(PDFSection): + + section_title = _("Ethische toetsing nodig door een Medische Ethische Toetsingscommissie (METC)?") + row_fields = [ + 'get_metc_display', + 'metc_details', + 'metc_institution', + 'get_is_medical_display' + ] + + def __init__(self, object): + super().__init__(self, object) + self.object = self.object.wmo + + def get_rows(self): + obj = self.object + rows = self._row_fields + if not obj.metc == 'Y': + rows.remove('metc_details') + rows.remove('metc_institution') + else: + rows.remove('get_is_medical') + + + class RowValueClass: - def __init__(self, object, field): + def __init__(self, object, field): - self.object = object - self.field = field + self.object = object + self.field = field - def render(self): + def render(self): + from ..models import Funding, Relation + if type(self.field) == str: value = getattr(self.object, self.field) - - if type(value) in (str, int, datetime.date): - return value - elif type(value) == bool: - return _('Ja') if value else _('Nee') - elif type(value) == User: - return self.handle_user(value) - elif value.__class__.__name__ == 'ManyRelatedManager': - if value.all().model == User: - return self.get_applicants_names(value) - elif value.all().model == Funding: - return self.get_funding_list() - elif callable(value): - return value() - - def handle_user(self, user): - return user.get_full_name() + '''A workaround for accessing subclasses: + For a subclass provide a tuple like so: + ('wmo', 'metc')''' + if type(self.field) == tuple: + #TODO: create a separate method for this! + obj = self.object + for item in self.field: + value = getattr(obj, item) + obj = value + + User = get_user_model() + + if type(value) in (str, int, date): + return value + if value is None: + return _('Onbekend') + elif type(value) == bool: + return _('Ja') if value else _('Nee') + elif type(value) == User: + return self.handle_user(value) + elif type(value) == Relation: + return value.description + elif value.__class__.__name__ == 'ManyRelatedManager': + if value.all().model == User: + return self.get_applicants_names(value) + elif value.all().model == Funding: + return self.get_funding_list(value) + elif callable(value): + return value() - def get_applicants_names(self, applicants): - applicant_names = [applicant.get_full_name() for applicant in applicants.all()] - return self.create_unordered_html_list(applicant_names) - - def get_funding_list(self, funding): - list_of_funds = [fund for fund in funding.all()] - return self.create_unordered_html_list(list_of_funds) + def handle_user(self, user): + return user.get_full_name() + + def get_applicants_names(self, applicants): + applicant_names = [applicant.get_full_name() for applicant in applicants.all()] + return self.create_unordered_html_list(applicant_names) + + def get_funding_list(self, funding): + list_of_funds = [fund for fund in funding.all()] + return self.create_unordered_html_list(list_of_funds) + + def create_unordered_html_list(self, list): + html_output = mark_safe('
    ') + + for item in list: + html_output += format_html('{}{}{}', + mark_safe('
  • '), + item, + mark_safe('
  • ') + ) - def create_unordered_html_list(list): - html_output = '
      ' - - for item in list: - html_output += f'
    • {item}
    • ' - - html_output += '
    ' + html_output += mark_safe('
') - return html_output + return html_output diff --git a/proposals/views/proposal_views.py b/proposals/views/proposal_views.py index 96f96379b..ef1e70df2 100644 --- a/proposals/views/proposal_views.py +++ b/proposals/views/proposal_views.py @@ -445,7 +445,7 @@ def get_next_url(self): def get_back_url(self): """Return to the data management view""" - return reverse('proposals:data_management', args=(self.object.pk,)) + return reverse('proposals:data_management', aPdfrgs=(self.object.pk,)) def _get_page_number(self): if self.object.is_pre_assessment: @@ -578,6 +578,19 @@ class ProposalDifference(LoginRequiredMixin, generic.DetailView): model = Proposal template_name = 'proposals/proposal_diff.html' +from proposals.utils.proposal_utils import GeneralSection +class NewPDFViewTest(generic.TemplateView): + + template_name = 'proposals/pdf/new_pdf_test.html' + + def get_context_data(self, **kwargs): + model = Proposal.objects.last() + test = GeneralSection(model) + context = super().get_context_data(**kwargs) + context['test'] = test + return context + + ######################## # Preliminary assessment From ba1ab48bfde0bdb47122f37f146b4645dbe4c857 Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Wed, 30 Aug 2023 11:36:54 +0200 Subject: [PATCH 05/52] workaround for nested field values --- proposals/utils/proposal_utils.py | 35 +++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/proposals/utils/proposal_utils.py b/proposals/utils/proposal_utils.py index 13e70911d..5b1f5726a 100644 --- a/proposals/utils/proposal_utils.py +++ b/proposals/utils/proposal_utils.py @@ -351,12 +351,19 @@ def generate_relevant_data_pdf(proposal): from django.utils.safestring import mark_safe from django.utils.html import format_html from copy import copy + +'''('created_by', 'email')''' + +# def access_foreignkey_getattr(object, field_tuple): + + +# return value, verbose_name class PDFSection: section_title = None row_fields = None verbose_name_diff_field_dict = { - 'get_metc_display': ('wmo', 'metc') + 'get_metc_display': ('wmo', 'metc'), 'get_is_medical_display': ('wmo','is_medical') } @@ -374,9 +381,11 @@ def get_rows(self): 'label': self.object._meta.get_field(row_field).verbose_name, 'value': RowValueClass(self.object, row_field).render() } - #TODO: finish this - if type(row_field) == tuple: - + elif type(row_field) == tuple: + rows[row_field[-1]] = { + 'label': self.get_nested_verbose_name(self.object, row_field), + 'value': RowValueClass(self.object, row_field).render() + } return rows def render(self, context): @@ -388,6 +397,15 @@ def render(self, context): } ) return template.render(context.flatten()) + + def get_nested_verbose_name(object, tuple_field): + for item in tuple_field: + if item == tuple_field[-1]: + verbose_name = object._meta_get_field(item).verbose_name + break + new_object = getattr(object, item) + object = new_object + return verbose_name class GeneralSection(PDFSection): '''This class generates the data for the general section of @@ -445,7 +463,7 @@ class WMOSection(PDFSection): 'get_metc_display', 'metc_details', 'metc_institution', - 'get_is_medical_display' + 'get_is_medical_display', ] def __init__(self, object): @@ -479,11 +497,10 @@ def render(self): For a subclass provide a tuple like so: ('wmo', 'metc')''' if type(self.field) == tuple: - #TODO: create a separate method for this! - obj = self.object + object = self.object for item in self.field: - value = getattr(obj, item) - obj = value + value = getattr(object, item) + object = value User = get_user_model() From 027fa7cf21f547538496a0825654712aaea96ada Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Wed, 30 Aug 2023 12:14:54 +0200 Subject: [PATCH 06/52] workaround for different label & value + metc sect --- .../templates/proposals/pdf/new_pdf_test.html | 1 + proposals/urls.py | 4 +- proposals/utils/proposal_utils.py | 82 ++++++++++++------- proposals/views/proposal_views.py | 4 +- 4 files changed, 59 insertions(+), 32 deletions(-) diff --git a/proposals/templates/proposals/pdf/new_pdf_test.html b/proposals/templates/proposals/pdf/new_pdf_test.html index c03c57358..581889e8d 100644 --- a/proposals/templates/proposals/pdf/new_pdf_test.html +++ b/proposals/templates/proposals/pdf/new_pdf_test.html @@ -14,5 +14,6 @@ {% block content %} {% include test %} + {% include wmo_test %} {% endblock %} \ No newline at end of file diff --git a/proposals/urls.py b/proposals/urls.py index d7dcd56e5..7a4e5e3d5 100644 --- a/proposals/urls.py +++ b/proposals/urls.py @@ -15,7 +15,8 @@ ProposalSubmitPreApproved, ProposalUpdatePreApproved, \ ProposalUsersOnlyArchiveView, \ ProposalCopyAmendment, ProposalsPublicArchiveView, \ - ProposalUpdateDataManagement, TranslatedConsentFormsView + ProposalUpdateDataManagement, TranslatedConsentFormsView, \ + NewPDFViewTest from .views.study_views import StudyStart, StudyConsent from .views.wmo_views import WmoCreate, WmoUpdate, \ @@ -121,6 +122,7 @@ path('diff//', ProposalDifference.as_view(), name='diff'), path('pdf//', ProposalAsPdf.as_view(), name='pdf'), + path('new_pdf/', NewPDFViewTest.as_view(), name='new_pdf'), # WMO path('wmo/create//', include([ diff --git a/proposals/utils/proposal_utils.py b/proposals/utils/proposal_utils.py index 5b1f5726a..0d970c7dc 100644 --- a/proposals/utils/proposal_utils.py +++ b/proposals/utils/proposal_utils.py @@ -354,18 +354,13 @@ def generate_relevant_data_pdf(proposal): '''('created_by', 'email')''' -# def access_foreignkey_getattr(object, field_tuple): - - -# return value, verbose_name class PDFSection: section_title = None row_fields = None verbose_name_diff_field_dict = { - 'get_metc_display': ('wmo', 'metc'), - 'get_is_medical_display': ('wmo','is_medical') - + ('wmo', 'get_metc_display'): ('wmo', 'metc'), + ('wmo', 'get_is_medical_display'): ('wmo','is_medical') } def __init__(self, object): @@ -376,16 +371,42 @@ def __init__(self, object): def get_rows(self): rows = OrderedDict() for row_field in self._row_fields: - if type(row_field) == str: - rows[row_field] = { - 'label': self.object._meta.get_field(row_field).verbose_name, - 'value': RowValueClass(self.object, row_field).render() - } - elif type(row_field) == tuple: - rows[row_field[-1]] = { - 'label': self.get_nested_verbose_name(self.object, row_field), - 'value': RowValueClass(self.object, row_field).render() - } + if row_field in self.verbose_name_diff_field_dict: + verbose_name = self.verbose_name_diff_field_dict[row_field] + '''This sequence checks for all combinations of tuples and strings + in the dict. Might not be neccessary, but is nice to account + for all possibilities''' + if type(row_field) == str and type(verbose_name) == str: + rows[row_field] = { + 'label': self.object._meta.get_field(verbose_name).verbose_name, + 'value': RowValueClass(self.object, row_field).render() + } + elif type(row_field) == tuple and type(verbose_name) == str: + rows[row_field[-1]] = { + 'label': self.object._meta.get_field(verbose_name).verbose_name, + 'value': RowValueClass(self.object, row_field).render() + } + elif type(row_field) == str and type(verbose_name) == tuple: + rows[row_field] = { + 'label': self.get_nested_verbose_name(self.object, verbose_name), + 'value': RowValueClass(self.object, row_field).render() + } + else: + rows[row_field[-1]] = { + 'label': self.get_nested_verbose_name(self.object, verbose_name), + 'value': RowValueClass(self.object, row_field).render() + } + else: + if type(row_field) == str: + rows[row_field] = { + 'label': self.object._meta.get_field(row_field).verbose_name, + 'value': RowValueClass(self.object, row_field).render() + } + elif type(row_field) == tuple: + rows[row_field[-1]] = { + 'label': self.get_nested_verbose_name(self.object, row_field), + 'value': RowValueClass(self.object, row_field).render() + } return rows def render(self, context): @@ -398,10 +419,10 @@ def render(self, context): ) return template.render(context.flatten()) - def get_nested_verbose_name(object, tuple_field): + def get_nested_verbose_name(self, object, tuple_field): for item in tuple_field: if item == tuple_field[-1]: - verbose_name = object._meta_get_field(item).verbose_name + verbose_name = object._meta.get_field(item).verbose_name break new_object = getattr(object, item) object = new_object @@ -460,24 +481,25 @@ class WMOSection(PDFSection): section_title = _("Ethische toetsing nodig door een Medische Ethische Toetsingscommissie (METC)?") row_fields = [ - 'get_metc_display', - 'metc_details', - 'metc_institution', - 'get_is_medical_display', + ('wmo', 'get_metc_display'), + ('wmo', 'metc_details'), + ('wmo', 'metc_institution'), + ('wmo', 'get_is_medical_display'), ] - def __init__(self, object): - super().__init__(self, object) - self.object = self.object.wmo + # def __init__(self, object): + # super().__init__(self, object) + # self.object = self.object.wmo def get_rows(self): obj = self.object rows = self._row_fields - if not obj.metc == 'Y': - rows.remove('metc_details') - rows.remove('metc_institution') + if not obj.wmo.metc == 'Y': + rows.remove(('wmo', 'metc_details')) + rows.remove(('wmo', 'metc_institution')) else: - rows.remove('get_is_medical') + rows.remove(('wmo', 'get_is_medical_display')) + return super().get_rows() diff --git a/proposals/views/proposal_views.py b/proposals/views/proposal_views.py index ef1e70df2..fd5dd3450 100644 --- a/proposals/views/proposal_views.py +++ b/proposals/views/proposal_views.py @@ -578,7 +578,7 @@ class ProposalDifference(LoginRequiredMixin, generic.DetailView): model = Proposal template_name = 'proposals/proposal_diff.html' -from proposals.utils.proposal_utils import GeneralSection +from proposals.utils.proposal_utils import GeneralSection, WMOSection class NewPDFViewTest(generic.TemplateView): template_name = 'proposals/pdf/new_pdf_test.html' @@ -586,8 +586,10 @@ class NewPDFViewTest(generic.TemplateView): def get_context_data(self, **kwargs): model = Proposal.objects.last() test = GeneralSection(model) + wmo_test = WMOSection(model) context = super().get_context_data(**kwargs) context['test'] = test + context['wmo_test'] = wmo_test return context From b5b9b059507d7602ec65c1ba6a13b0334ee415ac Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Wed, 30 Aug 2023 14:48:40 +0200 Subject: [PATCH 07/52] metc section --- proposals/utils/proposal_utils.py | 32 ++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/proposals/utils/proposal_utils.py b/proposals/utils/proposal_utils.py index 0d970c7dc..e67dd68e6 100644 --- a/proposals/utils/proposal_utils.py +++ b/proposals/utils/proposal_utils.py @@ -351,6 +351,7 @@ def generate_relevant_data_pdf(proposal): from django.utils.safestring import mark_safe from django.utils.html import format_html from copy import copy +from django.conf import settings '''('created_by', 'email')''' @@ -484,12 +485,8 @@ class WMOSection(PDFSection): ('wmo', 'get_metc_display'), ('wmo', 'metc_details'), ('wmo', 'metc_institution'), - ('wmo', 'get_is_medical_display'), + ('wmo', 'get_is_medical_display'), ] - - # def __init__(self, object): - # super().__init__(self, object) - # self.object = self.object.wmo def get_rows(self): obj = self.object @@ -501,8 +498,16 @@ def get_rows(self): rows.remove(('wmo', 'get_is_medical_display')) return super().get_rows() +class METCSection(PDFSection): + section_title = _("Aanmelding bij de METC") + row_fields = [ + ('wmo', 'metc_application'), + ('wmo', 'metc_decision'), + ('wmo', 'metc_decision_pdf') + ] + class RowValueClass: def __init__(self, object, field): @@ -541,6 +546,8 @@ def render(self): return self.get_applicants_names(value) elif value.all().model == Funding: return self.get_funding_list(value) + elif value.__class__.__name__ == 'FieldFile': + return self.handle_field_file(value, self.object) elif callable(value): return value() @@ -568,8 +575,19 @@ def create_unordered_html_list(self, list): html_output += mark_safe('') return html_output - - + + def handle_field_file(self, field_file, object): + if object.wmo.metc_decision_pdf and not object.is_practice(): + output = format_html('{}{}{}{}{}', + mark_safe(''), + _('Download'), + mark_safe('') + ) + else: + output = _('Niet aangeleverd') + return output def generate_pdf(proposal, template=False): """Grandfathered function for pdf saving. The template arg currently From 2d907d9b04c9c4e3c13f9884953fdc04c8ae93ad Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Wed, 30 Aug 2023 14:52:52 +0200 Subject: [PATCH 08/52] include metc in template and view --- proposals/templates/proposals/pdf/new_pdf_test.html | 1 + proposals/views/proposal_views.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/proposals/templates/proposals/pdf/new_pdf_test.html b/proposals/templates/proposals/pdf/new_pdf_test.html index 581889e8d..7db055344 100644 --- a/proposals/templates/proposals/pdf/new_pdf_test.html +++ b/proposals/templates/proposals/pdf/new_pdf_test.html @@ -15,5 +15,6 @@ {% include test %} {% include wmo_test %} + {% include metc_test %} {% endblock %} \ No newline at end of file diff --git a/proposals/views/proposal_views.py b/proposals/views/proposal_views.py index fd5dd3450..9a2ba873d 100644 --- a/proposals/views/proposal_views.py +++ b/proposals/views/proposal_views.py @@ -578,7 +578,7 @@ class ProposalDifference(LoginRequiredMixin, generic.DetailView): model = Proposal template_name = 'proposals/proposal_diff.html' -from proposals.utils.proposal_utils import GeneralSection, WMOSection +from proposals.utils.proposal_utils import GeneralSection, WMOSection, METCSection class NewPDFViewTest(generic.TemplateView): template_name = 'proposals/pdf/new_pdf_test.html' @@ -590,6 +590,9 @@ def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['test'] = test context['wmo_test'] = wmo_test + if model.wmo.status != model.wmo.NO_WMO: + metc_test = METCSection(model) + context['metc_test'] = metc_test return context From 18f29fe5759d2e8b5d8e5da1c0410d9bfce31f5b Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Thu, 31 Aug 2023 14:40:32 +0200 Subject: [PATCH 09/52] first groundwork for studies --- .../templates/proposals/pdf/new_pdf_test.html | 7 +- .../proposals/pdf/table_with_header.html | 3 + proposals/utils/proposal_utils.py | 201 ++++++++++++------ proposals/views/proposal_views.py | 12 +- 4 files changed, 152 insertions(+), 71 deletions(-) diff --git a/proposals/templates/proposals/pdf/new_pdf_test.html b/proposals/templates/proposals/pdf/new_pdf_test.html index 7db055344..51a390651 100644 --- a/proposals/templates/proposals/pdf/new_pdf_test.html +++ b/proposals/templates/proposals/pdf/new_pdf_test.html @@ -14,7 +14,10 @@ {% block content %} {% include test %} - {% include wmo_test %} - {% include metc_test %} + {% include wmo_test %}studies_similar + {% if metc_test %} + {% include metc_test %} + {% endif %} + {% include trajectories_test %} {% endblock %} \ No newline at end of file diff --git a/proposals/templates/proposals/pdf/table_with_header.html b/proposals/templates/proposals/pdf/table_with_header.html index 0f0e00c65..5a1475941 100644 --- a/proposals/templates/proposals/pdf/table_with_header.html +++ b/proposals/templates/proposals/pdf/table_with_header.html @@ -1,3 +1,6 @@ +{% if study_title %} +

{{ study_title }}

+{% endif %}

{{ section_title }}

{% for label, value in rows.items %} diff --git a/proposals/utils/proposal_utils.py b/proposals/utils/proposal_utils.py index e67dd68e6..f2ccabbde 100644 --- a/proposals/utils/proposal_utils.py +++ b/proposals/utils/proposal_utils.py @@ -19,8 +19,6 @@ from main.utils import AvailableURL, get_secretary from studies.utils import study_urls -from proposals.templatetags.proposal_filters import needs_details - __all__ = ['available_urls', 'generate_ref_number', 'generate_revision_ref_number', 'generate_pdf', @@ -304,64 +302,26 @@ def _get_next_proposal_number(current_year) -> int: except Proposal.DoesNotExist: return 1 -def generate_relevant_data_pdf(proposal): - empty_dict = {} - - empty_dict[_('Algemene informatie over de aanvraag')] = {} - empty_dict[_('Algemene informatie over de aanvraag')][proposal._meta.get_field('relation').verbose_name] = proposal.relation - if proposal.relation.needs_supervisor: - empty_dict[_('Algemene informatie over de aanvraag')][proposal._meta.get_field('supervisor').verbose_name] = proposal.supervisor.get_full_name - if proposal.relation.check_in_course: - empty_dict[_('Algemene informatie over de aanvraag')][proposal._meta.get_field('student_program').verbose_name] = proposal.student_program - empty_dict[_('Algemene informatie over de aanvraag')][proposal._meta.get_field('student_context').verbose_name] = proposal.student_context - if proposal.student_context.needs_detail: - empty_dict[_('Algemene informatie over de aanvraag')][proposal._meta.get_field('student_context_detail').verbose_name] = proposal.student_context_details - empty_dict[_('Algemene informatie over de aanvraag')][proposal._meta.get_field('student_justification').verbose_name] = proposal.student_justification - #I am not quite sure how to add translation to the boolean value resulting here ... - empty_dict[_('Algemene informatie over de aanvraag')][proposal._meta.get_field('other_applicants').verbose_name] = proposal.other_applicants - if proposal.other_applicants: - empty_dict[_('Algemene informatie over de aanvraag')][proposal._meta.get_field('applicants').verbose_name] = [applicant.get_full_name for applicant in proposal.applicants] - - empty_dict[_('Ethische toetsing nodig door een Medische Ethische Toetsingscommissie (METC)?')] = {} - - if proposal.wmo.status != proposal.wmo.NO_WMO: - empty_dict[_("Aanmelding bij de METC")] = {} - - empty_dict[_('Eén of meerdere trajecten?')] = {} - - '''Note to self: this will be a huge pain of nesting ... only scratch surface for now ...''' - if proposal.wmo.status == proposal.wmo.NO_WMO: - for study in proposal.study_set.all(): - if proposal.studies_number > 1: - empty_dict['studies'] = {} - if study.name: - empty_dict['studies'][_(f'traject { study.order } { study.name }')] = {} - else: - empty_dict['studies'][_(f'traject { study.order }')] = {} - else: - empty_dict['study'] = {} - - empty_dict['extra documents'] = [] - - empty_dict['Aanmelding versturen'] = {} - - return empty_dict - from django.contrib.auth import get_user_model from django.utils.safestring import mark_safe from django.utils.html import format_html from copy import copy from django.conf import settings +from proposals.templatetags.proposal_filters import needs_details, medical_traits, \ +necessity_required, has_adults -'''('created_by', 'email')''' +'''NOTE TO SELF: +Might not have to have the whole tuple system ... +Would streamline code a lot.''' class PDFSection: section_title = None + study_title = None row_fields = None verbose_name_diff_field_dict = { - ('wmo', 'get_metc_display'): ('wmo', 'metc'), - ('wmo', 'get_is_medical_display'): ('wmo','is_medical') + 'get_metc_display': 'metc', + 'get_is_medical_display': 'is_medical' } def __init__(self, object): @@ -479,35 +439,144 @@ def get_rows(self): return super().get_rows() class WMOSection(PDFSection): - + '''Object for this section is proposal.wmo''' section_title = _("Ethische toetsing nodig door een Medische Ethische Toetsingscommissie (METC)?") row_fields = [ - ('wmo', 'get_metc_display'), - ('wmo', 'metc_details'), - ('wmo', 'metc_institution'), - ('wmo', 'get_is_medical_display'), + 'get_metc_display', + 'metc_details', + 'metc_institution', + 'get_is_medical_display', ] def get_rows(self): obj = self.object rows = self._row_fields if not obj.wmo.metc == 'Y': - rows.remove(('wmo', 'metc_details')) - rows.remove(('wmo', 'metc_institution')) + rows.remove('metc_details') + rows.remove('metc_institution') else: - rows.remove(('wmo', 'get_is_medical_display')) + rows.remove('get_is_medical_display') return super().get_rows() class METCSection(PDFSection): - + '''Object for this section is proposal.wmo''' section_title = _("Aanmelding bij de METC") row_fields = [ - ('wmo', 'metc_application'), - ('wmo', 'metc_decision'), - ('wmo', 'metc_decision_pdf') + 'metc_application', + 'metc_decision', + 'metc_decision_pdf' + ] + +class TrajectoriesSection(PDFSection): + + section_title = _("Eén of meerdere trajecten?") + + row_fields = [ + 'studies_similar', + 'studies_number' + ] + + def get_rows(self): + obj = self.object + rows = self._row_fields + if obj.studies_similar: + rows.remove('studies_number') + return super().get_rows() + +class StudySection(PDFSection): + '''object for this study is proposal.study''' + section_title = _('De Deelnemers') + row_fields = [ + 'age_groups', + 'legally_incapable', + 'legally_incapable_details', + 'has_special_details', + 'special_details', + 'traits', + 'traits_details', + 'necessity', + 'necessity_reason', + 'recruitment', + 'recruitment_details', + 'compensation', + 'compensation_details', + 'hierarchy', + 'hierarchy_details', + ] + + def get_rows(self): + obj = self.object + rows = self._row_fields + if not has_adults(obj): + rows.remove('legally_incapable') + rows.remove('legally_incapable_details') + elif not obj.legally_incapable: + rows.remove('legally_incapable_details') + if not obj.has_special_details: + rows.remove('special_details') + rows.remove('traits') + rows.remove('traits_details') + elif not medical_traits(obj.special_details.all()): + rows.remove('traits') + rows.remove('traits_details') + elif not needs_details(obj.traits.all()): + rows.remove('traits_details') + if not necessity_required(obj): + rows.remove('necessity') + rows.remove('necessity_reason') + if not needs_details(obj.recruitment.all()): + rows.remove('recruitment_details') + if not obj.compensation.needs_details: + rows.remove('compensation_details') + if not obj.hierarchy: + rows.remove('hierarchy_details') + return super().get_rows() + + def get_study_title(study): + if study.name: + study_title = format_html('{}{}{}{}{}', + _('Traject'), + study.order, + mark_safe(''), + study.name, + mark_safe('') + ) + else: + study_title = format_html('{}{}', + _('Traject'), + {study.order} + ) + return study_title + + def render(self, context): + template = get_template("proposals/pdf/table_with_header.html") + context.update( + { + "section_title": self.section_title, + '''Will this work? I dont know ...''' + "rows": self.get_rows(), + } + ) + if self.object.proposal.studies_number > 1: + context.update( + { + 'study_title': self.get_study_title(self.object) + } + ) + return template.render(context.flatten()) + +class TasksSection(PDFSection): + + row_fields = [ + 'setting', + 'setting_details', + 'supervision', + 'leader_has_coc', + 'tasks_number', ] + class RowValueClass: def __init__(self, object, field): @@ -544,8 +613,8 @@ def render(self): elif value.__class__.__name__ == 'ManyRelatedManager': if value.all().model == User: return self.get_applicants_names(value) - elif value.all().model == Funding: - return self.get_funding_list(value) + else: + return self.get_object_list(value) elif value.__class__.__name__ == 'FieldFile': return self.handle_field_file(value, self.object) elif callable(value): @@ -558,9 +627,9 @@ def get_applicants_names(self, applicants): applicant_names = [applicant.get_full_name() for applicant in applicants.all()] return self.create_unordered_html_list(applicant_names) - def get_funding_list(self, funding): - list_of_funds = [fund for fund in funding.all()] - return self.create_unordered_html_list(list_of_funds) + def get_object_list(self, object): + list_of_objects = [obj for obj in object.all()] + return self.create_unordered_html_list(list_of_objects) def create_unordered_html_list(self, list): html_output = mark_safe('
    ') @@ -580,7 +649,7 @@ def handle_field_file(self, field_file, object): if object.wmo.metc_decision_pdf and not object.is_practice(): output = format_html('{}{}{}{}{}', mark_safe(''), _('Download'), mark_safe('') diff --git a/proposals/views/proposal_views.py b/proposals/views/proposal_views.py index 9a2ba873d..868bf4344 100644 --- a/proposals/views/proposal_views.py +++ b/proposals/views/proposal_views.py @@ -578,7 +578,8 @@ class ProposalDifference(LoginRequiredMixin, generic.DetailView): model = Proposal template_name = 'proposals/proposal_diff.html' -from proposals.utils.proposal_utils import GeneralSection, WMOSection, METCSection +from proposals.utils.proposal_utils import GeneralSection, WMOSection, METCSection, \ +TrajectoriesSection, StudySection class NewPDFViewTest(generic.TemplateView): template_name = 'proposals/pdf/new_pdf_test.html' @@ -586,13 +587,18 @@ class NewPDFViewTest(generic.TemplateView): def get_context_data(self, **kwargs): model = Proposal.objects.last() test = GeneralSection(model) - wmo_test = WMOSection(model) + wmo_test = WMOSection(model.wmo) + trajectories_test = TrajectoriesSection(model) context = super().get_context_data(**kwargs) context['test'] = test context['wmo_test'] = wmo_test if model.wmo.status != model.wmo.NO_WMO: - metc_test = METCSection(model) + metc_test = METCSection(model.wmo) context['metc_test'] = metc_test + if model.wmo.status == model.wmo.NO_WMO: + for study in model.study_set.all(): + study_test = StudySection(study) + context['trajectories_test'] = trajectories_test return context From d68b8750e7034666cf21198d5407bd12ef45c867 Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Mon, 4 Sep 2023 16:04:03 +0200 Subject: [PATCH 10/52] A lot of changes ... Started implementing studies --- .../templates/proposals/pdf/new_pdf_test.html | 12 +- .../proposals/pdf/table_with_header.html | 3 + proposals/utils/proposal_utils.py | 196 ++++++++++++++++-- proposals/views/proposal_views.py | 13 +- 4 files changed, 199 insertions(+), 25 deletions(-) diff --git a/proposals/templates/proposals/pdf/new_pdf_test.html b/proposals/templates/proposals/pdf/new_pdf_test.html index 51a390651..156dd3703 100644 --- a/proposals/templates/proposals/pdf/new_pdf_test.html +++ b/proposals/templates/proposals/pdf/new_pdf_test.html @@ -14,10 +14,20 @@ {% block content %} {% include test %} - {% include wmo_test %}studies_similar + {% include wmo_test %} + {% if metc_test %} {% include metc_test %} {% endif %} + {% include trajectories_test %} + {% if studies %} + {% for study in studies %} + {% for study_section in study %} + {% include study_section %} + {% endfor %} + {% endfor %} + {% endif %} + {% endblock %} \ No newline at end of file diff --git a/proposals/templates/proposals/pdf/table_with_header.html b/proposals/templates/proposals/pdf/table_with_header.html index 5a1475941..838900091 100644 --- a/proposals/templates/proposals/pdf/table_with_header.html +++ b/proposals/templates/proposals/pdf/table_with_header.html @@ -2,6 +2,9 @@

    {{ study_title }}

    {% endif %}

    {{ section_title }}

    +{% if sub_study_title %} +

    {{ sub_study_title }}

    +{% endif %}
{% for label, value in rows.items %} diff --git a/proposals/utils/proposal_utils.py b/proposals/utils/proposal_utils.py index f2ccabbde..177d4c1d3 100644 --- a/proposals/utils/proposal_utils.py +++ b/proposals/utils/proposal_utils.py @@ -314,6 +314,8 @@ def _get_next_proposal_number(current_year) -> int: Might not have to have the whole tuple system ... Would streamline code a lot.''' +'''TODO: Test multiple studies proposal''' + class PDFSection: section_title = None @@ -378,6 +380,7 @@ def render(self, context): "rows": self.get_rows(), } ) + return template.render(context.flatten()) def get_nested_verbose_name(self, object, tuple_field): @@ -451,7 +454,7 @@ class WMOSection(PDFSection): def get_rows(self): obj = self.object rows = self._row_fields - if not obj.wmo.metc == 'Y': + if not obj.metc == 'Y': rows.remove('metc_details') rows.remove('metc_institution') else: @@ -533,7 +536,7 @@ def get_rows(self): rows.remove('hierarchy_details') return super().get_rows() - def get_study_title(study): + def get_study_title(self, study): if study.name: study_title = format_html('{}{}{}{}{}', _('Traject'), @@ -550,23 +553,162 @@ def get_study_title(study): return study_title def render(self, context): - template = get_template("proposals/pdf/table_with_header.html") - context.update( - { - "section_title": self.section_title, - '''Will this work? I dont know ...''' - "rows": self.get_rows(), - } - ) if self.object.proposal.studies_number > 1: context.update( { 'study_title': self.get_study_title(self.object) } ) - return template.render(context.flatten()) + return super().render(context) + +class InterventionSection(StudySection): + '''This class will receive a study object''' + section_title = _('Het interventieonderzoek') + row_fields = [ + 'setting', + 'setting_details', + 'supervision', + 'leader_has_coc', + 'period', + 'multiple_sessions', + 'session_frequency', + 'amount_per_week', + 'duration', + 'measurement', + 'experimenter', + 'description', + 'has_controls', + 'controls_description', + 'extra_task' + ] + + def get_rows(self): + obj = self.object + rows = self._row_fields + + if obj.version == 1: + fields_to_remove = ['multiple_sessions', + 'session_frequency', + 'extra_task'] + rows = [field for field in rows if field not in fields_to_remove] + else: + rows.remove('amount_per_week') + if not obj.multiple_sessions: + rows.remove('session_frequency') + if obj.settings_contains_schools: + rows.remove('extra_task') + + if not needs_details(obj.setting.all()): + rows.remove('setting_details') + if not obj.study.has_children() or \ + not needs_details(obj.setting.all(), 'needs_supervision'): + rows.remove('supervision') + rows.remove('leader_has_coc') + elif obj.supervision: + rows.remove('leader_has_coc') + if not obj.has_controls: + rows.remove('controls_description') + + return super(StudySection, self).get_rows() -class TasksSection(PDFSection): + def render(self, context): + if self.object.study.proposal.studies_number > 1: + context.update( + { + 'sub_study_title': super().get_study_title(self.object.study) + } + ) + return super(StudySection, self).render(context) + +class ObservationSection(StudySection): + '''Gets passed an observation object''' + section_title = _('Het observatieonderzoek') + row_fields = [ + 'setting', + 'setting_details', + 'supervision', + 'leader_has_coc', + 'days', + 'mean_hours', + 'details_who', + 'details_why', + 'details_frequency', + 'is_anonymous', + 'is_anonymous_details', + 'is_in_target_group', + 'is_in_target_group_details', + 'is_nonpublic_space', + 'is_nonpublic_space_details', + 'has_advanced_consent', + 'has_advanced_consent_details', + 'needs_approval', + 'approval_institution', + 'approval_document', + 'registrations', + 'registrations_details' + ] + + def get_rows(self): + obj = self.object + rows = self._row_fields + + if obj.version == 1: + to_remove_if_v1 = ['details_who', + 'details_why', + 'is_anonymous_details', + 'is_in_target_group_details', + 'is_nonpublic_space_details', + 'has_advanced_consent_details' + ] + rows = [field for field in rows if field not in to_remove_if_v1] + if not obj.is_nonpublic_space: + rows.remove('has_advanced_consent') + if not obj.needs_approval: + rows.remove('approval_institution') + rows.remove('approval_document') + elif obj.study.proposal.is_practice(): + rows.remove('approval_document') + else: + to_remove_if_v2 = ['days', 'mean_hours', 'approval_document'] + rows = [field for field in rows if field not in to_remove_if_v2] + + if not obj.is_anonymous: + rows.remove('is_anonymous_details') + if not obj.is_in_target_group: + rows.remove('is_in_target_group_details') + if not obj.is_nonpublic_space: + rows.remove('is_nonpublic_space_details') + rows.remove('has_advanced_consent') + rows.remove('has_advanced_consent_details') + elif obj.has_advanced_consent: + rows.remove('has_advanced_consent_details') + if not needs_details(obj.setting.all(), 'is_school'): + rows.remove('needs_approval') + if not obj.needs_approval: + rows.remove('approval_institution') + + if not needs_details(obj.setting.all()): + rows.remove('setting_details') + if not obj.study.has_children() or \ + not needs_details(obj.setting.all(), 'needs_supervision'): + rows.remove('supervision') + rows.remove('leader_has_coc') + elif obj.supervision: + rows.remove('leader_has_coc') + if not needs_details(obj.registrations.all()): + rows.remove('registrations_details') + return super(StudySection, self).get_rows() + + def render(self, context): + if self.object.study.proposal.studies_number > 1: + context.update( + { + 'sub_study_title': super().get_study_title(self.object.study) + } + ) + return super(StudySection, self).render(context) + +class SessionSection(PDFSection): row_fields = [ 'setting', @@ -577,6 +719,7 @@ class TasksSection(PDFSection): ] + class RowValueClass: def __init__(self, object, field): @@ -646,16 +789,27 @@ def create_unordered_html_list(self, list): return html_output def handle_field_file(self, field_file, object): - if object.wmo.metc_decision_pdf and not object.is_practice(): - output = format_html('{}{}{}{}{}', - mark_safe(''), - _('Download'), - mark_safe('') - ) + from ..models import Proposal + if type(object) == Proposal: + if object.wmo.metc_decision_pdf and not object.is_practice(): + output = format_html('{}{}{}{}{}', + mark_safe(''), + _('Download'), + mark_safe('') + ) + else: + output = _('Niet aangeleverd') else: - output = _('Niet aangeleverd') + #if obj == Observation + output = format_html('{}{}{}{}{}', + mark_safe(''), + _('Download'), + mark_safe('') + ) return output def generate_pdf(proposal, template=False): diff --git a/proposals/views/proposal_views.py b/proposals/views/proposal_views.py index 868bf4344..e90a038a7 100644 --- a/proposals/views/proposal_views.py +++ b/proposals/views/proposal_views.py @@ -579,7 +579,7 @@ class ProposalDifference(LoginRequiredMixin, generic.DetailView): template_name = 'proposals/proposal_diff.html' from proposals.utils.proposal_utils import GeneralSection, WMOSection, METCSection, \ -TrajectoriesSection, StudySection +TrajectoriesSection, StudySection, InterventionSection, ObservationSection class NewPDFViewTest(generic.TemplateView): template_name = 'proposals/pdf/new_pdf_test.html' @@ -595,10 +595,17 @@ def get_context_data(self, **kwargs): if model.wmo.status != model.wmo.NO_WMO: metc_test = METCSection(model.wmo) context['metc_test'] = metc_test + context['trajectories_test'] = trajectories_test if model.wmo.status == model.wmo.NO_WMO: + context['studies'] = [] for study in model.study_set.all(): - study_test = StudySection(study) - context['trajectories_test'] = trajectories_test + study_sections = [] + study_sections.append(StudySection(study)) + if study.has_intervention: + study_sections.append(InterventionSection(study.intervention)) + if study.has_observation: + study_sections.append(ObservationSection(study.observation)) + context['studies'].append(study_sections) return context From 7dda34d2a535cf0bab7d4fe6bbe96d52f975a7f8 Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Mon, 11 Sep 2023 14:08:26 +0200 Subject: [PATCH 11/52] Bugfixes and implementing sessions and tasks --- .../templates/proposals/pdf/new_pdf_test.html | 14 +- .../proposals/pdf/table_with_header.html | 7 +- proposals/templatetags/proposal_filters.py | 3 + proposals/utils/proposal_utils.py | 184 ++++++++++++++---- proposals/views/proposal_views.py | 14 +- 5 files changed, 178 insertions(+), 44 deletions(-) diff --git a/proposals/templates/proposals/pdf/new_pdf_test.html b/proposals/templates/proposals/pdf/new_pdf_test.html index 156dd3703..2bb8844d0 100644 --- a/proposals/templates/proposals/pdf/new_pdf_test.html +++ b/proposals/templates/proposals/pdf/new_pdf_test.html @@ -20,12 +20,22 @@ {% include metc_test %} {% endif %} - {% include trajectories_test %} + {% include trajectories_test %} {% if studies %} {% for study in studies %} {% for study_section in study %} - {% include study_section %} + {% if study_section | get_type == 'list' %} + {% for session in study_section %} + {% if session | get_type == 'list' %} + {% for task in session %} + {% include task %} + {% else %} + {% include session %} + {% endfor %} + {% else %} + {% include study_section %} + {% endif %} {% endfor %} {% endfor %} {% endif %} diff --git a/proposals/templates/proposals/pdf/table_with_header.html b/proposals/templates/proposals/pdf/table_with_header.html index 838900091..7511d8fe6 100644 --- a/proposals/templates/proposals/pdf/table_with_header.html +++ b/proposals/templates/proposals/pdf/table_with_header.html @@ -1,10 +1,9 @@ +{% if section_title is not None %} +

{{ section_title }}

+{% endif %} {% if study_title %}

{{ study_title }}

{% endif %} -

{{ section_title }}

-{% if sub_study_title %} -

{{ sub_study_title }}

-{% endif %}
{% for label, value in rows.items %} diff --git a/proposals/templatetags/proposal_filters.py b/proposals/templatetags/proposal_filters.py index a323e32e5..12ff09a67 100644 --- a/proposals/templatetags/proposal_filters.py +++ b/proposals/templatetags/proposal_filters.py @@ -33,6 +33,9 @@ def necessity_required(study): age_groups = study.age_groups.values_list('id', flat=True) return check_necessity_required(study.proposal, age_groups, study.legally_incapable) +@register.filter +def get_type(value): + return type(value) @register.simple_tag def show_yesno(doubt=False): diff --git a/proposals/utils/proposal_utils.py b/proposals/utils/proposal_utils.py index 177d4c1d3..e33addf92 100644 --- a/proposals/utils/proposal_utils.py +++ b/proposals/utils/proposal_utils.py @@ -369,7 +369,7 @@ def get_rows(self): rows[row_field[-1]] = { 'label': self.get_nested_verbose_name(self.object, row_field), 'value': RowValueClass(self.object, row_field).render() - } + } return rows def render(self, context): @@ -390,7 +390,83 @@ def get_nested_verbose_name(self, object, tuple_field): break new_object = getattr(object, item) object = new_object - return verbose_name + return verbose_name + + def get_study_title(self, study): + if study.name: + study_title = format_html('{}{}{}{}{}', + _('Traject '), + study.order, + mark_safe(' '), + study.name, + mark_safe(' ') + ) + else: + study_title = format_html('{}{}', + _('Traject'), + {study.order} + ) + return study_title + + def get_session_title(self, session): + + order = session.order + study_order = session.study.order + study_name = session.study.name + studies_number = session.study.proposal.studies_number + sessions_number = session.study.sessions_number + + if studies_number > 1 and sessions_number > 1: + session_title = format_html('{}{}{}{}{}{}{}', + _('Traject '), + study_order, + mark_safe(' '), + study_name, + mark_safe(' , '), + _('sessie '), + order + ) + elif studies_number > 1: + session_title = format_html('{}{}{}{}{}', + _('Traject '), + study_order, + mark_safe(' '), + study_name, + mark_safe(' ') + ) + elif sessions_number >= 1: + session_title = format_html('{}{}', + _('Sessie '), + order + ) + return session_title + + def get_task_title(task): + order=task.order + session_order=task.session.order + study_order=task.session.study.order + study_name=task.session.study.name + studies_number=task.session.study.proposal.studies_number + if studies_number > 1: + task_title = format_html('{}{}{}{}{}{}{}{}{}', + _('Traject '), + study_order, + mark_safe(' '), + study_name, + mark_safe(' , '), + _('sessie '), + session_order, + _(', taak '), + order + ) + else: + task_title = format_html('{}{}{}{}', + _('Sessie '), + session_order, + _(', taak '), + order + ) + return task_title class GeneralSection(PDFSection): '''This class generates the data for the general section of @@ -535,34 +611,18 @@ def get_rows(self): if not obj.hierarchy: rows.remove('hierarchy_details') return super().get_rows() - - def get_study_title(self, study): - if study.name: - study_title = format_html('{}{}{}{}{}', - _('Traject'), - study.order, - mark_safe(''), - study.name, - mark_safe('') - ) - else: - study_title = format_html('{}{}', - _('Traject'), - {study.order} - ) - return study_title def render(self, context): if self.object.proposal.studies_number > 1: context.update( { - 'study_title': self.get_study_title(self.object) + 'study_title': super().get_study_title(self.object) } ) return super().render(context) -class InterventionSection(StudySection): - '''This class will receive a study object''' +class InterventionSection(PDFSection): + '''This class will receive a intervention object''' section_title = _('Het interventieonderzoek') row_fields = [ 'setting', @@ -590,7 +650,8 @@ def get_rows(self): fields_to_remove = ['multiple_sessions', 'session_frequency', 'extra_task'] - rows = [field for field in rows if field not in fields_to_remove] + for field in fields_to_remove: + rows.remove(field) else: rows.remove('amount_per_week') if not obj.multiple_sessions: @@ -609,18 +670,18 @@ def get_rows(self): if not obj.has_controls: rows.remove('controls_description') - return super(StudySection, self).get_rows() + return super().get_rows() def render(self, context): if self.object.study.proposal.studies_number > 1: context.update( { - 'sub_study_title': super().get_study_title(self.object.study) + 'study_title': super().get_study_title(self.object.study) } ) - return super(StudySection, self).render(context) + return super().render(context) -class ObservationSection(StudySection): +class ObservationSection(InterventionSection): '''Gets passed an observation object''' section_title = _('Het observatieonderzoek') row_fields = [ @@ -660,7 +721,9 @@ def get_rows(self): 'is_nonpublic_space_details', 'has_advanced_consent_details' ] - rows = [field for field in rows if field not in to_remove_if_v1] + for field in to_remove_if_v1: + rows.remove(field) + if not obj.is_nonpublic_space: rows.remove('has_advanced_consent') if not obj.needs_approval: @@ -670,7 +733,8 @@ def get_rows(self): rows.remove('approval_document') else: to_remove_if_v2 = ['days', 'mean_hours', 'approval_document'] - rows = [field for field in rows if field not in to_remove_if_v2] + for field in to_remove_if_v2: + rows.remove(field) if not obj.is_anonymous: rows.remove('is_anonymous_details') @@ -697,18 +761,19 @@ def get_rows(self): rows.remove('leader_has_coc') if not needs_details(obj.registrations.all()): rows.remove('registrations_details') + + return super(InterventionSection, self).get_rows() + +class SessionsSection(StudySection): + '''Gets passed a study object''' + section_title = _("Het takenonderzoek en interviews") + row_fields = ['sessions_number'] + + def get_rows(self): return super(StudySection, self).get_rows() - - def render(self, context): - if self.object.study.proposal.studies_number > 1: - context.update( - { - 'sub_study_title': super().get_study_title(self.object.study) - } - ) - return super(StudySection, self).render(context) class SessionSection(PDFSection): + '''Gets passed a session object''' row_fields = [ 'setting', @@ -718,6 +783,51 @@ class SessionSection(PDFSection): 'tasks_number', ] + def get_rows(self): + obj = self.object + rows = self._row_fields + + if not needs_details(obj.setting.all()): + rows.remove('setting_details') + if not obj.study.has_children() or \ + not needs_details(obj.setting.all(), 'needs_supervision'): + rows.remove('supervision') + rows.remove('leader_has_coc') + elif obj.supervision: + rows.remove('leader_has_coc') + + return super().get_rows() + + def render(self, context): + context.update( + { + 'study_title': super().get_session_title(self.object) + } + ) + return super().render(context) + +class TaskSection(PDFSection): + '''Gets passed a task object''' + + row_fields = [ + + ] + + def get_rows(self): + obj = self.object + rows = self._row_fields + + return super().get_rows() + + def render(self, context): + context.update( + { + 'study_title': super().get_task_title(self.object) + } + ) + return super().render(context) + + class RowValueClass: diff --git a/proposals/views/proposal_views.py b/proposals/views/proposal_views.py index e90a038a7..2a0f69541 100644 --- a/proposals/views/proposal_views.py +++ b/proposals/views/proposal_views.py @@ -579,7 +579,9 @@ class ProposalDifference(LoginRequiredMixin, generic.DetailView): template_name = 'proposals/proposal_diff.html' from proposals.utils.proposal_utils import GeneralSection, WMOSection, METCSection, \ -TrajectoriesSection, StudySection, InterventionSection, ObservationSection +TrajectoriesSection, StudySection, InterventionSection, ObservationSection, SessionsSection, \ +SessionSection, TaskSection + class NewPDFViewTest(generic.TemplateView): template_name = 'proposals/pdf/new_pdf_test.html' @@ -605,6 +607,16 @@ def get_context_data(self, **kwargs): study_sections.append(InterventionSection(study.intervention)) if study.has_observation: study_sections.append(ObservationSection(study.observation)) + if study.has_sessions: + study_sections.append(SessionsSection(study)) + sessions = [] + for session in study.session_set.all(): + sessions.append(SessionSection(session)) + tasks = [] + for task in session.task_set.all(): + tasks.append(TaskSection(task)) + sessions.append(tasks) + study_sections.append(sessions) context['studies'].append(study_sections) return context From f95bc493ebf1c5c2954d107510a2f371b71c7db8 Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Mon, 11 Sep 2023 15:52:00 +0200 Subject: [PATCH 12/52] Implemented session, tasks still produces bug --- .../templates/proposals/pdf/new_pdf_test.html | 14 +------ proposals/templatetags/proposal_filters.py | 4 -- proposals/utils/proposal_utils.py | 41 +++++++++++++++++-- proposals/views/proposal_views.py | 12 +++--- 4 files changed, 44 insertions(+), 27 deletions(-) diff --git a/proposals/templates/proposals/pdf/new_pdf_test.html b/proposals/templates/proposals/pdf/new_pdf_test.html index 2bb8844d0..6134cbbf3 100644 --- a/proposals/templates/proposals/pdf/new_pdf_test.html +++ b/proposals/templates/proposals/pdf/new_pdf_test.html @@ -25,19 +25,9 @@ {% if studies %} {% for study in studies %} {% for study_section in study %} - {% if study_section | get_type == 'list' %} - {% for session in study_section %} - {% if session | get_type == 'list' %} - {% for task in session %} - {% include task %} - {% else %} - {% include session %} - {% endfor %} - {% else %} - {% include study_section %} - {% endif %} + {% include study_section %} {% endfor %} - {% endfor %} + {% endfor %} {% endif %} {% endblock %} \ No newline at end of file diff --git a/proposals/templatetags/proposal_filters.py b/proposals/templatetags/proposal_filters.py index 12ff09a67..c243b42a4 100644 --- a/proposals/templatetags/proposal_filters.py +++ b/proposals/templatetags/proposal_filters.py @@ -33,10 +33,6 @@ def necessity_required(study): age_groups = study.age_groups.values_list('id', flat=True) return check_necessity_required(study.proposal, age_groups, study.legally_incapable) -@register.filter -def get_type(value): - return type(value) - @register.simple_tag def show_yesno(doubt=False): result = '
    ' diff --git a/proposals/utils/proposal_utils.py b/proposals/utils/proposal_utils.py index e33addf92..1b9657cf2 100644 --- a/proposals/utils/proposal_utils.py +++ b/proposals/utils/proposal_utils.py @@ -314,7 +314,6 @@ def _get_next_proposal_number(current_year) -> int: Might not have to have the whole tuple system ... Would streamline code a lot.''' -'''TODO: Test multiple studies proposal''' class PDFSection: @@ -441,7 +440,7 @@ def get_session_title(self, session): ) return session_title - def get_task_title(task): + def get_task_title(self, task): order=task.order session_order=task.session.order study_order=task.session.study.order @@ -810,13 +809,32 @@ class TaskSection(PDFSection): '''Gets passed a task object''' row_fields = [ - + 'name', + 'durations', + 'registrations', + 'registrations_details', + 'registration_kinds', + 'registration_kinds_details', + 'feedback', + 'feedback_details', + 'desctiption' ] def get_rows(self): obj = self.object rows = self._row_fields + if not needs_details(obj.registrations.all()): + rows.remove['registrations_details'] + if not needs_details(obj.registrations.all(), 'needs_kind') or \ + not needs_details(obj.registration_kinds.all()): + rows.remove('registration_kinds') + rows.remove('registration_kinds_details') + elif not needs_details(obj.registration_kinds.all()): + rows.remove('registration_kinds_details') + if not obj.feedback: + rows.remove['feedback_details'] + return super().get_rows() def render(self, context): @@ -826,9 +844,24 @@ def render(self, context): } ) return super().render(context) + +class TasksOverviewSection(PDFSection): + '''Gets passed a session object''' + '''TODO: how to pass the net_duration to the verbose name?''' + row_fields = [ + 'tasks_duration' + ] - + def render(self, context): + '''Here I am just overriding the render function, to get the correct formatting + The naming is a bit confusing, might fix later''' + context.update( + { + 'study_title': _('Overzicht van het takenonderzoek') + } + ) + return super().render(context) class RowValueClass: diff --git a/proposals/views/proposal_views.py b/proposals/views/proposal_views.py index 2a0f69541..e9251778d 100644 --- a/proposals/views/proposal_views.py +++ b/proposals/views/proposal_views.py @@ -609,15 +609,13 @@ def get_context_data(self, **kwargs): study_sections.append(ObservationSection(study.observation)) if study.has_sessions: study_sections.append(SessionsSection(study)) - sessions = [] + # sessions = [] for session in study.session_set.all(): - sessions.append(SessionSection(session)) - tasks = [] - for task in session.task_set.all(): - tasks.append(TaskSection(task)) - sessions.append(tasks) - study_sections.append(sessions) + study_sections.append(SessionSection(session)) + # for task in session.task_set.all(): + # study_sections.append(TaskSection(task)) context['studies'].append(study_sections) + return context From 29889434d9453f3bd832b74c40912ed8d1c88bc5 Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Mon, 11 Sep 2023 16:17:41 +0200 Subject: [PATCH 13/52] minor thing --- proposals/views/proposal_views.py | 1 - 1 file changed, 1 deletion(-) diff --git a/proposals/views/proposal_views.py b/proposals/views/proposal_views.py index e9251778d..58b19ad95 100644 --- a/proposals/views/proposal_views.py +++ b/proposals/views/proposal_views.py @@ -609,7 +609,6 @@ def get_context_data(self, **kwargs): study_sections.append(ObservationSection(study.observation)) if study.has_sessions: study_sections.append(SessionsSection(study)) - # sessions = [] for session in study.session_set.all(): study_sections.append(SessionSection(session)) # for task in session.task_set.all(): From 7dab89535cd640e14805536e47524aca346e228d Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Tue, 12 Sep 2023 10:43:24 +0200 Subject: [PATCH 14/52] Fixed tasks and renamed to make rows --- proposals/utils/proposal_utils.py | 43 ++++++++++++++++++------------- proposals/views/proposal_views.py | 4 +-- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/proposals/utils/proposal_utils.py b/proposals/utils/proposal_utils.py index 1b9657cf2..d2d18bb19 100644 --- a/proposals/utils/proposal_utils.py +++ b/proposals/utils/proposal_utils.py @@ -330,9 +330,9 @@ def __init__(self, object): # Create a copy of the class level row_fields, such that we can safely manipulate it without changing the class value self._row_fields = copy(self.row_fields) - def get_rows(self): + def make_rows(self): rows = OrderedDict() - for row_field in self._row_fields: + for row_field in self.get_rows(): if row_field in self.verbose_name_diff_field_dict: verbose_name = self.verbose_name_diff_field_dict[row_field] '''This sequence checks for all combinations of tuples and strings @@ -376,12 +376,15 @@ def render(self, context): context.update( { "section_title": self.section_title, - "rows": self.get_rows(), + "rows": self.make_rows(), } ) return template.render(context.flatten()) + def get_rows(self): + raise Exception('You forgot to define the get_rows function for your subclass!') + def get_nested_verbose_name(self, object, tuple_field): for item in tuple_field: if item == tuple_field[-1]: @@ -513,8 +516,7 @@ def get_rows(self): rows.remove('funding_details') if not needs_details(obj.funding.all(), 'needs_name'): rows.remove('funding_name') - # Use the get_rows from PDFSection to get the actual rows, the code above should have filtered out everything we don't need - return super().get_rows() + return rows class WMOSection(PDFSection): '''Object for this section is proposal.wmo''' @@ -534,10 +536,12 @@ def get_rows(self): rows.remove('metc_institution') else: rows.remove('get_is_medical_display') - return super().get_rows() + return rows class METCSection(PDFSection): - '''Object for this section is proposal.wmo''' + '''Object for this section is proposal.wmo + This class exists because the RowValueClass does some + funky things for working with the metc_decision_pdf field''' section_title = _("Aanmelding bij de METC") row_fields = [ @@ -545,6 +549,9 @@ class METCSection(PDFSection): 'metc_decision', 'metc_decision_pdf' ] + + def get_rows(self): + return self._row_fields class TrajectoriesSection(PDFSection): @@ -560,7 +567,7 @@ def get_rows(self): rows = self._row_fields if obj.studies_similar: rows.remove('studies_number') - return super().get_rows() + return rows class StudySection(PDFSection): '''object for this study is proposal.study''' @@ -609,7 +616,7 @@ def get_rows(self): rows.remove('compensation_details') if not obj.hierarchy: rows.remove('hierarchy_details') - return super().get_rows() + return rows def render(self, context): if self.object.proposal.studies_number > 1: @@ -669,7 +676,7 @@ def get_rows(self): if not obj.has_controls: rows.remove('controls_description') - return super().get_rows() + return rows def render(self, context): if self.object.study.proposal.studies_number > 1: @@ -761,7 +768,7 @@ def get_rows(self): if not needs_details(obj.registrations.all()): rows.remove('registrations_details') - return super(InterventionSection, self).get_rows() + return rows class SessionsSection(StudySection): '''Gets passed a study object''' @@ -769,7 +776,7 @@ class SessionsSection(StudySection): row_fields = ['sessions_number'] def get_rows(self): - return super(StudySection, self).get_rows() + return self._row_fields class SessionSection(PDFSection): '''Gets passed a session object''' @@ -795,7 +802,7 @@ def get_rows(self): elif obj.supervision: rows.remove('leader_has_coc') - return super().get_rows() + return rows def render(self, context): context.update( @@ -810,14 +817,14 @@ class TaskSection(PDFSection): row_fields = [ 'name', - 'durations', + 'duration', 'registrations', 'registrations_details', 'registration_kinds', 'registration_kinds_details', 'feedback', 'feedback_details', - 'desctiption' + 'description' ] def get_rows(self): @@ -825,7 +832,7 @@ def get_rows(self): rows = self._row_fields if not needs_details(obj.registrations.all()): - rows.remove['registrations_details'] + rows.remove('registrations_details') if not needs_details(obj.registrations.all(), 'needs_kind') or \ not needs_details(obj.registration_kinds.all()): rows.remove('registration_kinds') @@ -833,9 +840,9 @@ def get_rows(self): elif not needs_details(obj.registration_kinds.all()): rows.remove('registration_kinds_details') if not obj.feedback: - rows.remove['feedback_details'] + rows.remove('feedback_details') - return super().get_rows() + return rows def render(self, context): context.update( diff --git a/proposals/views/proposal_views.py b/proposals/views/proposal_views.py index 58b19ad95..8fcaf634a 100644 --- a/proposals/views/proposal_views.py +++ b/proposals/views/proposal_views.py @@ -611,8 +611,8 @@ def get_context_data(self, **kwargs): study_sections.append(SessionsSection(study)) for session in study.session_set.all(): study_sections.append(SessionSection(session)) - # for task in session.task_set.all(): - # study_sections.append(TaskSection(task)) + for task in session.task_set.all(): + study_sections.append(TaskSection(task)) context['studies'].append(study_sections) return context From 995449f9edb2662f7db31a55344c1c0ba40b9986 Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Tue, 12 Sep 2023 10:46:18 +0200 Subject: [PATCH 15/52] Simplified the make_rows function --- proposals/utils/proposal_utils.py | 41 ++++++------------------------- 1 file changed, 8 insertions(+), 33 deletions(-) diff --git a/proposals/utils/proposal_utils.py b/proposals/utils/proposal_utils.py index d2d18bb19..22213a206 100644 --- a/proposals/utils/proposal_utils.py +++ b/proposals/utils/proposal_utils.py @@ -335,40 +335,15 @@ def make_rows(self): for row_field in self.get_rows(): if row_field in self.verbose_name_diff_field_dict: verbose_name = self.verbose_name_diff_field_dict[row_field] - '''This sequence checks for all combinations of tuples and strings - in the dict. Might not be neccessary, but is nice to account - for all possibilities''' - if type(row_field) == str and type(verbose_name) == str: - rows[row_field] = { - 'label': self.object._meta.get_field(verbose_name).verbose_name, - 'value': RowValueClass(self.object, row_field).render() - } - elif type(row_field) == tuple and type(verbose_name) == str: - rows[row_field[-1]] = { - 'label': self.object._meta.get_field(verbose_name).verbose_name, - 'value': RowValueClass(self.object, row_field).render() - } - elif type(row_field) == str and type(verbose_name) == tuple: - rows[row_field] = { - 'label': self.get_nested_verbose_name(self.object, verbose_name), - 'value': RowValueClass(self.object, row_field).render() - } - else: - rows[row_field[-1]] = { - 'label': self.get_nested_verbose_name(self.object, verbose_name), - 'value': RowValueClass(self.object, row_field).render() - } + rows[row_field] = { + 'label': mark_safe(self.object._meta.get_field(verbose_name).verbose_name), + 'value': RowValueClass(self.object, row_field).render() + } else: - if type(row_field) == str: - rows[row_field] = { - 'label': self.object._meta.get_field(row_field).verbose_name, - 'value': RowValueClass(self.object, row_field).render() - } - elif type(row_field) == tuple: - rows[row_field[-1]] = { - 'label': self.get_nested_verbose_name(self.object, row_field), - 'value': RowValueClass(self.object, row_field).render() - } + rows[row_field] = { + 'label': mark_safe(self.object._meta.get_field(row_field).verbose_name), + 'value': RowValueClass(self.object, row_field).render() + } return rows def render(self, context): From f63799187ef68a96dd5b72a14e11938ef77173a1 Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Tue, 12 Sep 2023 10:48:16 +0200 Subject: [PATCH 16/52] Removed all implementation of the tuple nesting --- proposals/utils/proposal_utils.py | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/proposals/utils/proposal_utils.py b/proposals/utils/proposal_utils.py index 22213a206..cd35d6a9b 100644 --- a/proposals/utils/proposal_utils.py +++ b/proposals/utils/proposal_utils.py @@ -360,15 +360,6 @@ def render(self, context): def get_rows(self): raise Exception('You forgot to define the get_rows function for your subclass!') - def get_nested_verbose_name(self, object, tuple_field): - for item in tuple_field: - if item == tuple_field[-1]: - verbose_name = object._meta.get_field(item).verbose_name - break - new_object = getattr(object, item) - object = new_object - return verbose_name - def get_study_title(self, study): if study.name: study_title = format_html('{}{}{}{}{}', @@ -855,16 +846,8 @@ def __init__(self, object, field): def render(self): from ..models import Funding, Relation - if type(self.field) == str: - value = getattr(self.object, self.field) - '''A workaround for accessing subclasses: - For a subclass provide a tuple like so: - ('wmo', 'metc')''' - if type(self.field) == tuple: - object = self.object - for item in self.field: - value = getattr(object, item) - object = value + + value = getattr(self.object, self.field) User = get_user_model() From d880b1c9078fb36a32905effc57c2521e3729398 Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Tue, 12 Sep 2023 16:28:24 +0200 Subject: [PATCH 17/52] Implemented a RowClass. Much better --- .../proposals/pdf/table_with_header.html | 4 +- proposals/utils/proposal_utils.py | 152 +++++++++++++++--- proposals/views/proposal_views.py | 4 +- 3 files changed, 131 insertions(+), 29 deletions(-) diff --git a/proposals/templates/proposals/pdf/table_with_header.html b/proposals/templates/proposals/pdf/table_with_header.html index 7511d8fe6..d7560b7eb 100644 --- a/proposals/templates/proposals/pdf/table_with_header.html +++ b/proposals/templates/proposals/pdf/table_with_header.html @@ -5,9 +5,9 @@

    {{ section_title }}

    {{ study_title }}

    {% endif %}
-{% for label, value in rows.items %} +{% for row in rows %} - + {% endfor %}
{{ value.label }}{{ value.value }}{{ row.verbose_name }}{{ row.value }}
\ No newline at end of file diff --git a/proposals/utils/proposal_utils.py b/proposals/utils/proposal_utils.py index cd35d6a9b..5a5ca617d 100644 --- a/proposals/utils/proposal_utils.py +++ b/proposals/utils/proposal_utils.py @@ -329,29 +329,13 @@ def __init__(self, object): self.object = object # Create a copy of the class level row_fields, such that we can safely manipulate it without changing the class value self._row_fields = copy(self.row_fields) - - def make_rows(self): - rows = OrderedDict() - for row_field in self.get_rows(): - if row_field in self.verbose_name_diff_field_dict: - verbose_name = self.verbose_name_diff_field_dict[row_field] - rows[row_field] = { - 'label': mark_safe(self.object._meta.get_field(verbose_name).verbose_name), - 'value': RowValueClass(self.object, row_field).render() - } - else: - rows[row_field] = { - 'label': mark_safe(self.object._meta.get_field(row_field).verbose_name), - 'value': RowValueClass(self.object, row_field).render() - } - return rows def render(self, context): template = get_template("proposals/pdf/table_with_header.html") context.update( { "section_title": self.section_title, - "rows": self.make_rows(), + "rows": self.get_rows(), } ) @@ -463,6 +447,7 @@ class GeneralSection(PDFSection): def get_rows(self): obj = self.object rows = self._row_fields + if not obj.relation.needs_supervisor: rows.remove('supervisor') if not obj.relation.check_in_course: @@ -482,6 +467,9 @@ def get_rows(self): rows.remove('funding_details') if not needs_details(obj.funding.all(), 'needs_name'): rows.remove('funding_name') + + rows = [RowClass(obj, field) for field in rows] + return rows class WMOSection(PDFSection): @@ -497,11 +485,15 @@ class WMOSection(PDFSection): def get_rows(self): obj = self.object rows = self._row_fields + if not obj.metc == 'Y': rows.remove('metc_details') rows.remove('metc_institution') else: rows.remove('get_is_medical_display') + + rows = [RowClass(obj, field) for field in rows] + return rows class METCSection(PDFSection): @@ -517,7 +509,10 @@ class METCSection(PDFSection): ] def get_rows(self): - return self._row_fields + + rows = [RowClass(self.object, field) for field in self._row_fields] + + return rows class TrajectoriesSection(PDFSection): @@ -531,8 +526,12 @@ class TrajectoriesSection(PDFSection): def get_rows(self): obj = self.object rows = self._row_fields + if obj.studies_similar: rows.remove('studies_number') + + rows = [RowClass(obj, field) for field in rows] + return rows class StudySection(PDFSection): @@ -559,6 +558,7 @@ class StudySection(PDFSection): def get_rows(self): obj = self.object rows = self._row_fields + if not has_adults(obj): rows.remove('legally_incapable') rows.remove('legally_incapable_details') @@ -582,6 +582,9 @@ def get_rows(self): rows.remove('compensation_details') if not obj.hierarchy: rows.remove('hierarchy_details') + + rows = [RowClass(obj, field) for field in rows] + return rows def render(self, context): @@ -640,7 +643,9 @@ def get_rows(self): elif obj.supervision: rows.remove('leader_has_coc') if not obj.has_controls: - rows.remove('controls_description') + rows.remove('controls_description') + + rows = [RowClass(obj, field) for field in rows] return rows @@ -733,17 +738,22 @@ def get_rows(self): rows.remove('leader_has_coc') if not needs_details(obj.registrations.all()): rows.remove('registrations_details') + + rows = [RowClass(obj, field) for field in rows] return rows class SessionsSection(StudySection): - '''Gets passed a study object''' + '''Gets passed a study object + This Section looks maybe a bit unnecessary, but it does remove some logic, plus + the study_title.html from the template.''' section_title = _("Het takenonderzoek en interviews") - row_fields = ['sessions_number'] def get_rows(self): - return self._row_fields + rows = [RowValueClass(self.object, 'sessions_number')] + + return rows class SessionSection(PDFSection): '''Gets passed a session object''' @@ -767,6 +777,8 @@ def get_rows(self): rows.remove('leader_has_coc') elif obj.supervision: rows.remove('leader_has_coc') + + rows = [RowClass(obj, field) for field in rows] return rows @@ -807,6 +819,8 @@ def get_rows(self): rows.remove('registration_kinds_details') if not obj.feedback: rows.remove('feedback_details') + + rows = [RowClass(obj, field) for field in rows] return rows @@ -819,13 +833,21 @@ def render(self, context): return super().render(context) class TasksOverviewSection(PDFSection): - '''Gets passed a session object''' - '''TODO: how to pass the net_duration to the verbose name?''' + '''Gets passed a session object + This might be unecessary ... Maybe just use the existing template language ... + Because the verbose name of this field is formatted, the method for retrieving + the verbose name in the RowClass is quite convoluded.''' row_fields = [ 'tasks_duration' ] + def get_rows(self): + + rows = [RowClass(self.object, field) for field in self._row_fields] + + return rows + def render(self, context): '''Here I am just overriding the render function, to get the correct formatting The naming is a bit confusing, might fix later''' @@ -835,6 +857,78 @@ def render(self, context): } ) return super().render(context) + +class StudyOverviewSection(StudySection): + '''Receives a Study object''' + + section_title = _('Overzicht en eigen beoordeling van het gehele onderzoek') + row_fields = [ + 'deception', + 'deception_details', + 'negativity', + 'negativity_details', + 'stressful', + 'stressful_details', + 'risk', + 'risk_details' + ] + + def get_rows(self): + obj = self.object + rows = self._row_fields + + rows_to_remove = [] + for x in range(0, 7, 2): + if getattr(obj, rows[x]) == 'N': + rows_to_remove.append(rows[x+1]) + rows = [row for row in rows if row not in rows_to_remove] + + if not obj.has_sessions and not obj.deception == 'N': + rows.remove('deception') + rows.remove('deception_details') + elif not obj.has_sessions: + rows.remove('deception') + + rows = [RowClass(obj, field) for field in rows] + + return rows + +class InformedConsentFormsSection(StudySection): + '''Receives a Documents object''' + + section_title = _('Informed consent formulieren') + + def get_rows(self): + rows = [] + rows.append(RowClass(obj, field)) + +class RowClass: + + verbose_name_diff_field_dict = { + 'get_metc_display': 'metc', + 'get_is_medical_display': 'is_medical' + } + + def __init__(self, object, field): + self.object = object + self.field = field + + def verbose_name(self): + if self.field in self.verbose_name_diff_field_dict: + verbose_name_field = self.verbose_name_diff_field_dict[self.field] + verbose_name = self.get_verbose_name(verbose_name_field), + else: + verbose_name= self.get_verbose_name(self.field) + return verbose_name + + def value(self): + return RowValueClass(self.object, self.field).render() + + def get_verbose_name(self, field): + if field != 'tasks_duration': + return mark_safe(self.object._meta.get_field(field).verbose_name) + else: + return mark_safe(self.object._meta.get_field(field).verbose_name % self.object.net_duration()) class RowValueClass: @@ -851,9 +945,11 @@ def render(self): User = get_user_model() + if value in ('Y', 'N', '?'): + return self.yes_no_doubt(value) if type(value) in (str, int, date): return value - if value is None: + elif value is None: return _('Onbekend') elif type(value) == bool: return _('Ja') if value else _('Nee') @@ -910,7 +1006,6 @@ def handle_field_file(self, field_file, object): else: output = _('Niet aangeleverd') else: - #if obj == Observation output = format_html('{}{}{}{}{}', mark_safe(' Date: Tue, 12 Sep 2023 17:00:47 +0200 Subject: [PATCH 18/52] informedConsent section --- proposals/utils/proposal_utils.py | 24 +++++++++++++++++++++--- proposals/views/proposal_views.py | 4 +++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/proposals/utils/proposal_utils.py b/proposals/utils/proposal_utils.py index 5a5ca617d..e1c00b329 100644 --- a/proposals/utils/proposal_utils.py +++ b/proposals/utils/proposal_utils.py @@ -893,15 +893,33 @@ def get_rows(self): return rows -class InformedConsentFormsSection(StudySection): +class InformedConsentFormsSection(InterventionSection): '''Receives a Documents object''' section_title = _('Informed consent formulieren') + '''TODO: Debug''' def get_rows(self): + obj = self.object rows = [] - rows.append(RowClass(obj, field)) - + rows.append(RowClass(obj.proposal, 'translated_forms')) + if obj.proposal.translated_forms: + rows.append(RowClass(obj.proposal, 'translated_forms_languages')) + if not obj.proposal.is_practice and obj.informed_consent: + rows.append(RowClass(obj, 'informed_consent')) + rows.append(RowClass(obj, 'briefing')) + if obj.study.passive_consent is not None: + rows.append(RowClass(obj.study, 'passive_consent')) + if obj.study.passive_consent: + rows.append(RowClass(obj.study, 'passive_consent_details')) + if obj.director_consent_declaration: + rows.append(RowClass(obj, 'director_consent_declaration')) + if obj.director_consent_information: + rows.append(RowClass(obj, 'director_consent_information')) + if obj.parents_information: + rows.append(RowClass(obj, 'parents_information')) + breakpoint() + return rows class RowClass: verbose_name_diff_field_dict = { diff --git a/proposals/views/proposal_views.py b/proposals/views/proposal_views.py index 825907de8..41b877610 100644 --- a/proposals/views/proposal_views.py +++ b/proposals/views/proposal_views.py @@ -580,7 +580,8 @@ class ProposalDifference(LoginRequiredMixin, generic.DetailView): from proposals.utils.proposal_utils import GeneralSection, WMOSection, METCSection, \ TrajectoriesSection, StudySection, InterventionSection, ObservationSection, SessionsSection, \ -SessionSection, TaskSection, TasksOverviewSection, StudyOverviewSection +SessionSection, TaskSection, TasksOverviewSection, StudyOverviewSection, \ +InformedConsentFormsSection class NewPDFViewTest(generic.TemplateView): @@ -615,6 +616,7 @@ def get_context_data(self, **kwargs): study_sections.append(TaskSection(task)) study_sections.append(TasksOverviewSection(session)) study_sections.append(StudyOverviewSection(study)) + study_sections.append(InformedConsentFormsSection(study.documents)) context['studies'].append(study_sections) return context From f3cce5685a761126e0fa5446d50f1c1d698f914f Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Thu, 14 Sep 2023 11:16:51 +0200 Subject: [PATCH 19/52] Finishing touches and reorganizing --- main/models.py | 6 +- .../templates/proposals/pdf/new_pdf_test.html | 12 + .../proposals/pdf/table_with_header.html | 2 +- proposals/utils/__init__.py | 3 +- proposals/utils/pdf_diff_logic.py | 779 ++++++++++++++++++ proposals/utils/proposal_utils.py | 744 +---------------- proposals/views/proposal_views.py | 15 +- 7 files changed, 813 insertions(+), 748 deletions(-) create mode 100644 proposals/utils/pdf_diff_logic.py diff --git a/main/models.py b/main/models.py index 18d5d409a..bdbcac5a5 100644 --- a/main/models.py +++ b/main/models.py @@ -5,9 +5,9 @@ NO = 'N' DOUBT = '?' YES_NO_DOUBT = ( - (YES, _('ja')), - (NO, _('nee')), - (DOUBT, _('twijfel')), + (YES, _('Ja')), + (NO, _('Nee')), + (DOUBT, _('Twijfel')), ) diff --git a/proposals/templates/proposals/pdf/new_pdf_test.html b/proposals/templates/proposals/pdf/new_pdf_test.html index 6134cbbf3..8bda7801e 100644 --- a/proposals/templates/proposals/pdf/new_pdf_test.html +++ b/proposals/templates/proposals/pdf/new_pdf_test.html @@ -30,4 +30,16 @@ {% endfor %} {% endif %} + {% if extra_documents %} + {% for document in extra_documents %} + {% include document %} + {% endfor %} + {% endif %} + + {% if dmp_file %} + {% include dmp_file %} + {% endif %} + + {% include embargo %} + {% endblock %} \ No newline at end of file diff --git a/proposals/templates/proposals/pdf/table_with_header.html b/proposals/templates/proposals/pdf/table_with_header.html index d7560b7eb..6b491d820 100644 --- a/proposals/templates/proposals/pdf/table_with_header.html +++ b/proposals/templates/proposals/pdf/table_with_header.html @@ -1,4 +1,4 @@ -{% if section_title is not None %} +{% if section_title %}

{{ section_title }}

{% endif %} {% if study_title %} diff --git a/proposals/utils/__init__.py b/proposals/utils/__init__.py index 4661c3735..583297b59 100644 --- a/proposals/utils/__init__.py +++ b/proposals/utils/__init__.py @@ -1 +1,2 @@ -from .proposal_utils import * \ No newline at end of file +from .proposal_utils import * +from .pdf_diff_logic import * \ No newline at end of file diff --git a/proposals/utils/pdf_diff_logic.py b/proposals/utils/pdf_diff_logic.py new file mode 100644 index 000000000..a018005db --- /dev/null +++ b/proposals/utils/pdf_diff_logic.py @@ -0,0 +1,779 @@ + +from datetime import date +from copy import copy + +from django.conf import settings +from django.contrib.auth import get_user_model +from django.template.loader import get_template +from django.utils.html import format_html +from django.utils.safestring import mark_safe +from django.utils.translation import ugettext as _ + +from proposals.templatetags.proposal_filters import needs_details, medical_traits, \ +necessity_required, has_adults + +class PDFSection: + + section_title = None + row_fields = None + + def __init__(self, object): + self.object = object + # Create a copy of the class level row_fields, such that we can safely manipulate it without changing the class value + self._row_fields = copy(self.row_fields) + + def render(self, context): + context = context.flatten() + template = get_template("proposals/pdf/table_with_header.html") + context.update( + { + "section_title": self.section_title, + "rows": self.get_rows(), + } + ) + return template.render(context) + + def get_rows(self): + + rows = [RowClass(self.object, field) for field in self._row_fields] + + return rows + + def get_study_title(self, study): + if study.name: + study_title = format_html('{}{}{}{}{}', + _('Traject '), + study.order, + mark_safe(' '), + study.name, + mark_safe(' ') + ) + else: + study_title = format_html('{}{}', + _('Traject'), + {study.order} + ) + return study_title + + def get_session_title(self, session): + + order = session.order + study_order = session.study.order + study_name = session.study.name + studies_number = session.study.proposal.studies_number + sessions_number = session.study.sessions_number + + if studies_number > 1 and sessions_number > 1: + session_title = format_html('{}{}{}{}{}{}{}', + _('Traject '), + study_order, + mark_safe(' '), + study_name, + mark_safe(' , '), + _('sessie '), + order + ) + elif studies_number > 1: + session_title = format_html('{}{}{}{}{}', + _('Traject '), + study_order, + mark_safe(' '), + study_name, + mark_safe(' ') + ) + elif sessions_number >= 1: + session_title = format_html('{}{}', + _('Sessie '), + order + ) + return session_title + + def get_task_title(self, task): + order=task.order + session_order=task.session.order + study_order=task.session.study.order + study_name=task.session.study.name + studies_number=task.session.study.proposal.studies_number + if studies_number > 1: + task_title = format_html('{}{}{}{}{}{}{}{}{}', + _('Traject '), + study_order, + mark_safe(' '), + study_name, + mark_safe(' , '), + _('sessie '), + session_order, + _(', taak '), + order + ) + else: + task_title = format_html('{}{}{}{}', + _('Sessie '), + session_order, + _(', taak '), + order + ) + return task_title + +class GeneralSection(PDFSection): + '''This class generates the data for the general section of + the PDF page.''' + + section_title = _("Algemene informatie over de aanvraag") + row_fields = [ + 'relation', + 'supervisor', + 'student_program', + 'student_context', + 'student_context_details', + 'student_justification', + 'other_applicants', + 'applicants', + 'other_stakeholders', + 'stakeholders', + 'date_start', + 'title', + 'funding', + 'funding_details', + 'funding_name', + 'self_assessment', + ] + + def get_rows(self): + obj = self.object + rows = self._row_fields + + if not obj.relation.needs_supervisor: + rows.remove('supervisor') + if not obj.relation.check_in_course: + rows.remove('student_program') + rows.remove('student_context') + if obj.student_context is not None: + if not obj.student_context.needs_details: + rows.remove('student_context_details') + else: + rows.remove('student_context_details') + rows.remove('student_justification') + if not obj.other_applicants: + rows.remove('applicants') + if not obj.other_stakeholders: + rows.remove('stakeholders') + if not needs_details(obj.funding.all()): + rows.remove('funding_details') + if not needs_details(obj.funding.all(), 'needs_name'): + rows.remove('funding_name') + + rows = [RowClass(obj, field) for field in rows] + + return rows + +class WMOSection(PDFSection): + '''Object for this section is proposal.wmo''' + section_title = _("Ethische toetsing nodig door een Medische Ethische Toetsingscommissie (METC)?") + row_fields = [ + 'get_metc_display', + 'metc_details', + 'metc_institution', + 'get_is_medical_display', + ] + + def get_rows(self): + obj = self.object + rows = self._row_fields + + if not obj.metc == 'Y': + rows.remove('metc_details') + rows.remove('metc_institution') + else: + rows.remove('get_is_medical_display') + + rows = [RowClass(obj, field) for field in rows] + + return rows + +class METCSection(PDFSection): + '''Object for this section is proposal.wmo + This class exists because the RowValueClass does some + funky things for working with the metc_decision_pdf field''' + section_title = _("Aanmelding bij de METC") + + row_fields = [ + 'metc_application', + 'metc_decision', + 'metc_decision_pdf' + ] + +class TrajectoriesSection(PDFSection): + + section_title = _("Eén of meerdere trajecten?") + + row_fields = [ + 'studies_similar', + 'studies_number' + ] + + def get_rows(self): + obj = self.object + rows = self._row_fields + + if obj.studies_similar: + rows.remove('studies_number') + + rows = [RowClass(obj, field) for field in rows] + + return rows + +class StudySection(PDFSection): + '''object for this study is proposal.study''' + section_title = _('De Deelnemers') + row_fields = [ + 'age_groups', + 'legally_incapable', + 'legally_incapable_details', + 'has_special_details', + 'special_details', + 'traits', + 'traits_details', + 'necessity', + 'necessity_reason', + 'recruitment', + 'recruitment_details', + 'compensation', + 'compensation_details', + 'hierarchy', + 'hierarchy_details', + ] + + def get_rows(self): + obj = self.object + rows = self._row_fields + + if not has_adults(obj): + rows.remove('legally_incapable') + rows.remove('legally_incapable_details') + elif not obj.legally_incapable: + rows.remove('legally_incapable_details') + if not obj.has_special_details: + rows.remove('special_details') + rows.remove('traits') + rows.remove('traits_details') + elif not medical_traits(obj.special_details.all()): + rows.remove('traits') + rows.remove('traits_details') + elif not needs_details(obj.traits.all()): + rows.remove('traits_details') + if not necessity_required(obj): + rows.remove('necessity') + rows.remove('necessity_reason') + if not needs_details(obj.recruitment.all()): + rows.remove('recruitment_details') + if not obj.compensation.needs_details: + rows.remove('compensation_details') + if not obj.hierarchy: + rows.remove('hierarchy_details') + + rows = [RowClass(obj, field) for field in rows] + + return rows + + def render(self, context): + if self.object.proposal.studies_number > 1: + context.update( + { + 'study_title': super().get_study_title(self.object) + } + ) + return super().render(context) + +class InterventionSection(PDFSection): + '''This class will receive a intervention object''' + section_title = _('Het interventieonderzoek') + row_fields = [ + 'setting', + 'setting_details', + 'supervision', + 'leader_has_coc', + 'period', + 'multiple_sessions', + 'session_frequency', + 'amount_per_week', + 'duration', + 'measurement', + 'experimenter', + 'description', + 'has_controls', + 'controls_description', + 'extra_task' + ] + + def get_rows(self): + obj = self.object + rows = self._row_fields + + if obj.version == 1: + fields_to_remove = ['multiple_sessions', + 'session_frequency', + 'extra_task'] + for field in fields_to_remove: + rows.remove(field) + else: + rows.remove('amount_per_week') + if not obj.multiple_sessions: + rows.remove('session_frequency') + if obj.settings_contains_schools: + rows.remove('extra_task') + + if not needs_details(obj.setting.all()): + rows.remove('setting_details') + if not obj.study.has_children() or \ + not needs_details(obj.setting.all(), 'needs_supervision'): + rows.remove('supervision') + rows.remove('leader_has_coc') + elif obj.supervision: + rows.remove('leader_has_coc') + if not obj.has_controls: + rows.remove('controls_description') + + rows = [RowClass(obj, field) for field in rows] + + return rows + + def render(self, context): + if self.object.study.proposal.studies_number > 1: + context.update( + { + 'study_title': super().get_study_title(self.object.study) + } + ) + return super().render(context) + +class ObservationSection(InterventionSection): + '''Gets passed an observation object''' + section_title = _('Het observatieonderzoek') + row_fields = [ + 'setting', + 'setting_details', + 'supervision', + 'leader_has_coc', + 'days', + 'mean_hours', + 'details_who', + 'details_why', + 'details_frequency', + 'is_anonymous', + 'is_anonymous_details', + 'is_in_target_group', + 'is_in_target_group_details', + 'is_nonpublic_space', + 'is_nonpublic_space_details', + 'has_advanced_consent', + 'has_advanced_consent_details', + 'needs_approval', + 'approval_institution', + 'approval_document', + 'registrations', + 'registrations_details' + ] + + def get_rows(self): + obj = self.object + rows = self._row_fields + + if obj.version == 1: + to_remove_if_v1 = ['details_who', + 'details_why', + 'is_anonymous_details', + 'is_in_target_group_details', + 'is_nonpublic_space_details', + 'has_advanced_consent_details' + ] + for field in to_remove_if_v1: + rows.remove(field) + + if not obj.is_nonpublic_space: + rows.remove('has_advanced_consent') + if not obj.needs_approval: + rows.remove('approval_institution') + rows.remove('approval_document') + elif obj.study.proposal.is_practice(): + rows.remove('approval_document') + else: + to_remove_if_v2 = ['days', 'mean_hours', 'approval_document'] + for field in to_remove_if_v2: + rows.remove(field) + + if not obj.is_anonymous: + rows.remove('is_anonymous_details') + if not obj.is_in_target_group: + rows.remove('is_in_target_group_details') + if not obj.is_nonpublic_space: + rows.remove('is_nonpublic_space_details') + rows.remove('has_advanced_consent') + rows.remove('has_advanced_consent_details') + elif obj.has_advanced_consent: + rows.remove('has_advanced_consent_details') + if not needs_details(obj.setting.all(), 'is_school'): + rows.remove('needs_approval') + if not obj.needs_approval: + rows.remove('approval_institution') + + if not needs_details(obj.setting.all()): + rows.remove('setting_details') + if not obj.study.has_children() or \ + not needs_details(obj.setting.all(), 'needs_supervision'): + rows.remove('supervision') + rows.remove('leader_has_coc') + elif obj.supervision: + rows.remove('leader_has_coc') + if not needs_details(obj.registrations.all()): + rows.remove('registrations_details') + + rows = [RowClass(obj, field) for field in rows] + + return rows + +class SessionsSection(StudySection): + '''Gets passed a study object + This Section looks maybe a bit unnecessary, but it does remove some logic, plus + the study_title.html from the template.''' + + section_title = _("Het takenonderzoek en interviews") + + def get_rows(self): + + rows = [RowValueClass(self.object, 'sessions_number')] + + return rows + +class SessionSection(PDFSection): + '''Gets passed a session object''' + + row_fields = [ + 'setting', + 'setting_details', + 'supervision', + 'leader_has_coc', + 'tasks_number', + ] + + def get_rows(self): + obj = self.object + rows = self._row_fields + + if not needs_details(obj.setting.all()): + rows.remove('setting_details') + if not obj.study.has_children() or \ + not needs_details(obj.setting.all(), 'needs_supervision'): + rows.remove('supervision') + rows.remove('leader_has_coc') + elif obj.supervision: + rows.remove('leader_has_coc') + + rows = [RowClass(obj, field) for field in rows] + + return rows + + def render(self, context): + context.update( + { + 'study_title': super().get_session_title(self.object) + } + ) + return super().render(context) + +class TaskSection(PDFSection): + '''Gets passed a task object''' + + row_fields = [ + 'name', + 'duration', + 'registrations', + 'registrations_details', + 'registration_kinds', + 'registration_kinds_details', + 'feedback', + 'feedback_details', + 'description' + ] + + def get_rows(self): + obj = self.object + rows = self._row_fields + + if not needs_details(obj.registrations.all()): + rows.remove('registrations_details') + if not needs_details(obj.registrations.all(), 'needs_kind') or \ + not needs_details(obj.registration_kinds.all()): + rows.remove('registration_kinds') + rows.remove('registration_kinds_details') + elif not needs_details(obj.registration_kinds.all()): + rows.remove('registration_kinds_details') + if not obj.feedback: + rows.remove('feedback_details') + + rows = [RowClass(obj, field) for field in rows] + + return rows + + def render(self, context): + context.update( + { + 'study_title': super().get_task_title(self.object) + } + ) + return super().render(context) + +class TasksOverviewSection(PDFSection): + '''Gets passed a session object + This might be unecessary ... Maybe just use the existing template language ... + Because the verbose name of this field is formatted, the method for retrieving + the verbose name in the RowClass is quite convoluded.''' + + row_fields = [ + 'tasks_duration' + ] + + def render(self, context): + '''Here I am just overriding the render function, to get the correct formatting + The naming is a bit confusing, might fix later''' + context.update( + { + 'study_title': _('Overzicht van het takenonderzoek') + } + ) + return super().render(context) + +class StudyOverviewSection(StudySection): + '''Receives a Study object''' + + section_title = _('Overzicht en eigen beoordeling van het gehele onderzoek') + row_fields = [ + 'deception', + 'deception_details', + 'negativity', + 'negativity_details', + 'stressful', + 'stressful_details', + 'risk', + 'risk_details' + ] + + def get_rows(self): + obj = self.object + rows = self._row_fields + + rows_to_remove = [] + for x in range(0, 7, 2): + if getattr(obj, rows[x]) == 'N': + rows_to_remove.append(rows[x+1]) + rows = [row for row in rows if row not in rows_to_remove] + + if not obj.has_sessions and not obj.deception == 'N': + rows.remove('deception') + rows.remove('deception_details') + elif not obj.has_sessions: + rows.remove('deception') + + rows = [RowClass(obj, field) for field in rows] + + return rows + +class InformedConsentFormsSection(InterventionSection): + '''Receives a Documents object''' + + section_title = _('Informed consent formulieren') + + def get_rows(self): + obj = self.object + + rows = [] + + rows.append(RowClass(obj.proposal, 'translated_forms')) + if obj.proposal.translated_forms: + rows.append(RowClass(obj.proposal, 'translated_forms_languages')) + if not obj.proposal.is_practice() and obj.informed_consent: + rows.append(RowClass(obj, 'informed_consent')) + rows.append(RowClass(obj, 'briefing')) + if obj.study.passive_consent is not None: + rows.append(RowClass(obj.study, 'passive_consent')) + if obj.study.passive_consent: + rows.append(RowClass(obj.study, 'passive_consent_details')) + if obj.director_consent_declaration: + rows.append(RowClass(obj, 'director_consent_declaration')) + if obj.director_consent_information: + rows.append(RowClass(obj, 'director_consent_information')) + if obj.parents_information: + rows.append(RowClass(obj, 'parents_information')) + + return rows + +class ExtraDocumentsSection(PDFSection): + '''gets a documents object''' + + row_fields = [ + 'informed_consent', + 'briefing' + ] + + def __init__(self, object, count): + super().__init__(object) + self.section_title = _('Extra formulieren ') + str(count) + + def get_rows(self): + obj = self.object + rows = self._row_fields + + if not obj.informed_consent: + rows.remove('informed_consent') + if not obj.briefing: + rows.remove('briefing') + + rows = [RowClass(obj, field) for field in rows] + + return rows + +class DMPFileSection(PDFSection): + '''Gets passed a proposal object.''' + + section_title = _('Data Management Plan') + + row_fields = ['dmp_file'] + +class EmbargoSection(PDFSection): + '''Gets passed a proposal object''' + + section_title = _('Aanmelding Versturen') + + row_fields = [ + 'embargo', + 'embargo_end_date' + ] + + def get_rows(self): + obj = self.object + rows = self._row_fields + + if not obj.embargo: + rows.remove('embargo_end_date') + + rows = [RowClass(obj, field) for field in rows] + + return rows + +class RowClass: + + verbose_name_diff_field_dict = { + 'get_metc_display': 'metc', + 'get_is_medical_display': 'is_medical' + } + + def __init__(self, object, field): + self.object = object + self.field = field + + def verbose_name(self): + if self.field in self.verbose_name_diff_field_dict: + verbose_name_field = self.verbose_name_diff_field_dict[self.field] + verbose_name = self.get_verbose_name(verbose_name_field) + else: + verbose_name= self.get_verbose_name(self.field) + return verbose_name + + def value(self): + return RowValueClass(self.object, self.field).render() + + def get_verbose_name(self, field): + if field != 'tasks_duration': + return mark_safe(self.object._meta.get_field(field).verbose_name) + else: + return mark_safe(self.object._meta.get_field(field).verbose_name % self.object.net_duration()) + +class RowValueClass: + + def __init__(self, object, field): + + self.object = object + self.field = field + + def render(self): + from ..models import Funding, Relation + + + value = getattr(self.object, self.field) + + User = get_user_model() + + if value in ('Y', 'N', '?'): + return self.yes_no_doubt(value) + if type(value) in (str, int, date): + return value + elif value is None: + return _('Onbekend') + elif type(value) == bool: + return _('Ja') if value else _('Nee') + elif type(value) == User: + return self.handle_user(value) + elif type(value) == Relation: + return value.description + elif value.__class__.__name__ == 'ManyRelatedManager': + if value.all().model == User: + return self.get_applicants_names(value) + else: + return self.get_object_list(value) + elif value.__class__.__name__ == 'FieldFile': + return self.handle_field_file(value, self.object) + elif callable(value): + return value() + + def handle_user(self, user): + return user.get_full_name() + + def get_applicants_names(self, applicants): + applicant_names = [applicant.get_full_name() for applicant in applicants.all()] + return self.create_unordered_html_list(applicant_names) + + def get_object_list(self, object): + list_of_objects = [obj for obj in object.all()] + return self.create_unordered_html_list(list_of_objects) + + def create_unordered_html_list(self, list): + html_output = mark_safe('
    ') + + for item in list: + html_output += format_html('{}{}{}', + mark_safe('
  • '), + item, + mark_safe('
  • ') + ) + + html_output += mark_safe('
') + + return html_output + + def handle_field_file(self, field_file, object): + from ..models import Proposal + if object == Proposal and field_file == object.wmo.metc_decision_pdf: + if object.wmo.metc_decision_pdf and not object.is_practice(): + output = format_html('{}{}{}{}{}', + mark_safe('
'), + _('Download'), + mark_safe('') + ) + else: + output = _('Niet aangeleverd') + else: + output = format_html('{}{}{}{}{}', + mark_safe(''), + _('Download'), + mark_safe('') + ) + return output + + def yes_no_doubt(self, value): + from main.models import YES_NO_DOUBT + d = dict(YES_NO_DOUBT) + return d[value] diff --git a/proposals/utils/proposal_utils.py b/proposals/utils/proposal_utils.py index e1c00b329..79c3bbb21 100644 --- a/proposals/utils/proposal_utils.py +++ b/proposals/utils/proposal_utils.py @@ -1,7 +1,7 @@ # -*- encoding: utf-8 -*- -from collections import defaultdict, OrderedDict -from datetime import datetime, date +from collections import defaultdict +from datetime import datetime from io import BytesIO import os @@ -12,7 +12,7 @@ from django.core.mail import send_mail from django.db.models import Q from django.urls import reverse -from django.template.loader import render_to_string, get_template +from django.template.loader import render_to_string, from django.utils.translation import activate, get_language, ugettext as _ from django.utils.deconstruct import deconstructible @@ -302,742 +302,6 @@ def _get_next_proposal_number(current_year) -> int: except Proposal.DoesNotExist: return 1 -from django.contrib.auth import get_user_model -from django.utils.safestring import mark_safe -from django.utils.html import format_html -from copy import copy -from django.conf import settings -from proposals.templatetags.proposal_filters import needs_details, medical_traits, \ -necessity_required, has_adults - -'''NOTE TO SELF: -Might not have to have the whole tuple system ... -Would streamline code a lot.''' - - -class PDFSection: - - section_title = None - study_title = None - row_fields = None - verbose_name_diff_field_dict = { - 'get_metc_display': 'metc', - 'get_is_medical_display': 'is_medical' - } - - def __init__(self, object): - self.object = object - # Create a copy of the class level row_fields, such that we can safely manipulate it without changing the class value - self._row_fields = copy(self.row_fields) - - def render(self, context): - template = get_template("proposals/pdf/table_with_header.html") - context.update( - { - "section_title": self.section_title, - "rows": self.get_rows(), - } - ) - - return template.render(context.flatten()) - - def get_rows(self): - raise Exception('You forgot to define the get_rows function for your subclass!') - - def get_study_title(self, study): - if study.name: - study_title = format_html('{}{}{}{}{}', - _('Traject '), - study.order, - mark_safe(' '), - study.name, - mark_safe(' ') - ) - else: - study_title = format_html('{}{}', - _('Traject'), - {study.order} - ) - return study_title - - def get_session_title(self, session): - - order = session.order - study_order = session.study.order - study_name = session.study.name - studies_number = session.study.proposal.studies_number - sessions_number = session.study.sessions_number - - if studies_number > 1 and sessions_number > 1: - session_title = format_html('{}{}{}{}{}{}{}', - _('Traject '), - study_order, - mark_safe(' '), - study_name, - mark_safe(' , '), - _('sessie '), - order - ) - elif studies_number > 1: - session_title = format_html('{}{}{}{}{}', - _('Traject '), - study_order, - mark_safe(' '), - study_name, - mark_safe(' ') - ) - elif sessions_number >= 1: - session_title = format_html('{}{}', - _('Sessie '), - order - ) - return session_title - - def get_task_title(self, task): - order=task.order - session_order=task.session.order - study_order=task.session.study.order - study_name=task.session.study.name - studies_number=task.session.study.proposal.studies_number - if studies_number > 1: - task_title = format_html('{}{}{}{}{}{}{}{}{}', - _('Traject '), - study_order, - mark_safe(' '), - study_name, - mark_safe(' , '), - _('sessie '), - session_order, - _(', taak '), - order - ) - else: - task_title = format_html('{}{}{}{}', - _('Sessie '), - session_order, - _(', taak '), - order - ) - return task_title - -class GeneralSection(PDFSection): - '''This class generates the data for the general section of - the PDF page.''' - - section_title = _("Algemene informatie over de aanvraag") - row_fields = [ - 'relation', - 'supervisor', - 'student_program', - 'student_context', - 'student_context_details', - 'student_justification', - 'other_applicants', - 'applicants', - 'other_stakeholders', - 'stakeholders', - 'date_start', - 'title', - 'funding', - 'funding_details', - 'funding_name', - 'self_assessment', - ] - - def get_rows(self): - obj = self.object - rows = self._row_fields - - if not obj.relation.needs_supervisor: - rows.remove('supervisor') - if not obj.relation.check_in_course: - rows.remove('student_program') - rows.remove('student_context') - if obj.student_context is not None: - if not obj.student_context.needs_details: - rows.remove('student_context_details') - else: - rows.remove('student_context_details') - rows.remove('student_justification') - if not obj.other_applicants: - rows.remove('applicants') - if not obj.other_stakeholders: - rows.remove('stakeholders') - if not needs_details(obj.funding.all()): - rows.remove('funding_details') - if not needs_details(obj.funding.all(), 'needs_name'): - rows.remove('funding_name') - - rows = [RowClass(obj, field) for field in rows] - - return rows - -class WMOSection(PDFSection): - '''Object for this section is proposal.wmo''' - section_title = _("Ethische toetsing nodig door een Medische Ethische Toetsingscommissie (METC)?") - row_fields = [ - 'get_metc_display', - 'metc_details', - 'metc_institution', - 'get_is_medical_display', - ] - - def get_rows(self): - obj = self.object - rows = self._row_fields - - if not obj.metc == 'Y': - rows.remove('metc_details') - rows.remove('metc_institution') - else: - rows.remove('get_is_medical_display') - - rows = [RowClass(obj, field) for field in rows] - - return rows - -class METCSection(PDFSection): - '''Object for this section is proposal.wmo - This class exists because the RowValueClass does some - funky things for working with the metc_decision_pdf field''' - section_title = _("Aanmelding bij de METC") - - row_fields = [ - 'metc_application', - 'metc_decision', - 'metc_decision_pdf' - ] - - def get_rows(self): - - rows = [RowClass(self.object, field) for field in self._row_fields] - - return rows - -class TrajectoriesSection(PDFSection): - - section_title = _("Eén of meerdere trajecten?") - - row_fields = [ - 'studies_similar', - 'studies_number' - ] - - def get_rows(self): - obj = self.object - rows = self._row_fields - - if obj.studies_similar: - rows.remove('studies_number') - - rows = [RowClass(obj, field) for field in rows] - - return rows - -class StudySection(PDFSection): - '''object for this study is proposal.study''' - section_title = _('De Deelnemers') - row_fields = [ - 'age_groups', - 'legally_incapable', - 'legally_incapable_details', - 'has_special_details', - 'special_details', - 'traits', - 'traits_details', - 'necessity', - 'necessity_reason', - 'recruitment', - 'recruitment_details', - 'compensation', - 'compensation_details', - 'hierarchy', - 'hierarchy_details', - ] - - def get_rows(self): - obj = self.object - rows = self._row_fields - - if not has_adults(obj): - rows.remove('legally_incapable') - rows.remove('legally_incapable_details') - elif not obj.legally_incapable: - rows.remove('legally_incapable_details') - if not obj.has_special_details: - rows.remove('special_details') - rows.remove('traits') - rows.remove('traits_details') - elif not medical_traits(obj.special_details.all()): - rows.remove('traits') - rows.remove('traits_details') - elif not needs_details(obj.traits.all()): - rows.remove('traits_details') - if not necessity_required(obj): - rows.remove('necessity') - rows.remove('necessity_reason') - if not needs_details(obj.recruitment.all()): - rows.remove('recruitment_details') - if not obj.compensation.needs_details: - rows.remove('compensation_details') - if not obj.hierarchy: - rows.remove('hierarchy_details') - - rows = [RowClass(obj, field) for field in rows] - - return rows - - def render(self, context): - if self.object.proposal.studies_number > 1: - context.update( - { - 'study_title': super().get_study_title(self.object) - } - ) - return super().render(context) - -class InterventionSection(PDFSection): - '''This class will receive a intervention object''' - section_title = _('Het interventieonderzoek') - row_fields = [ - 'setting', - 'setting_details', - 'supervision', - 'leader_has_coc', - 'period', - 'multiple_sessions', - 'session_frequency', - 'amount_per_week', - 'duration', - 'measurement', - 'experimenter', - 'description', - 'has_controls', - 'controls_description', - 'extra_task' - ] - - def get_rows(self): - obj = self.object - rows = self._row_fields - - if obj.version == 1: - fields_to_remove = ['multiple_sessions', - 'session_frequency', - 'extra_task'] - for field in fields_to_remove: - rows.remove(field) - else: - rows.remove('amount_per_week') - if not obj.multiple_sessions: - rows.remove('session_frequency') - if obj.settings_contains_schools: - rows.remove('extra_task') - - if not needs_details(obj.setting.all()): - rows.remove('setting_details') - if not obj.study.has_children() or \ - not needs_details(obj.setting.all(), 'needs_supervision'): - rows.remove('supervision') - rows.remove('leader_has_coc') - elif obj.supervision: - rows.remove('leader_has_coc') - if not obj.has_controls: - rows.remove('controls_description') - - rows = [RowClass(obj, field) for field in rows] - - return rows - - def render(self, context): - if self.object.study.proposal.studies_number > 1: - context.update( - { - 'study_title': super().get_study_title(self.object.study) - } - ) - return super().render(context) - -class ObservationSection(InterventionSection): - '''Gets passed an observation object''' - section_title = _('Het observatieonderzoek') - row_fields = [ - 'setting', - 'setting_details', - 'supervision', - 'leader_has_coc', - 'days', - 'mean_hours', - 'details_who', - 'details_why', - 'details_frequency', - 'is_anonymous', - 'is_anonymous_details', - 'is_in_target_group', - 'is_in_target_group_details', - 'is_nonpublic_space', - 'is_nonpublic_space_details', - 'has_advanced_consent', - 'has_advanced_consent_details', - 'needs_approval', - 'approval_institution', - 'approval_document', - 'registrations', - 'registrations_details' - ] - - def get_rows(self): - obj = self.object - rows = self._row_fields - - if obj.version == 1: - to_remove_if_v1 = ['details_who', - 'details_why', - 'is_anonymous_details', - 'is_in_target_group_details', - 'is_nonpublic_space_details', - 'has_advanced_consent_details' - ] - for field in to_remove_if_v1: - rows.remove(field) - - if not obj.is_nonpublic_space: - rows.remove('has_advanced_consent') - if not obj.needs_approval: - rows.remove('approval_institution') - rows.remove('approval_document') - elif obj.study.proposal.is_practice(): - rows.remove('approval_document') - else: - to_remove_if_v2 = ['days', 'mean_hours', 'approval_document'] - for field in to_remove_if_v2: - rows.remove(field) - - if not obj.is_anonymous: - rows.remove('is_anonymous_details') - if not obj.is_in_target_group: - rows.remove('is_in_target_group_details') - if not obj.is_nonpublic_space: - rows.remove('is_nonpublic_space_details') - rows.remove('has_advanced_consent') - rows.remove('has_advanced_consent_details') - elif obj.has_advanced_consent: - rows.remove('has_advanced_consent_details') - if not needs_details(obj.setting.all(), 'is_school'): - rows.remove('needs_approval') - if not obj.needs_approval: - rows.remove('approval_institution') - - if not needs_details(obj.setting.all()): - rows.remove('setting_details') - if not obj.study.has_children() or \ - not needs_details(obj.setting.all(), 'needs_supervision'): - rows.remove('supervision') - rows.remove('leader_has_coc') - elif obj.supervision: - rows.remove('leader_has_coc') - if not needs_details(obj.registrations.all()): - rows.remove('registrations_details') - - rows = [RowClass(obj, field) for field in rows] - - return rows - -class SessionsSection(StudySection): - '''Gets passed a study object - This Section looks maybe a bit unnecessary, but it does remove some logic, plus - the study_title.html from the template.''' - section_title = _("Het takenonderzoek en interviews") - - def get_rows(self): - - rows = [RowValueClass(self.object, 'sessions_number')] - - return rows -class SessionSection(PDFSection): - '''Gets passed a session object''' - - row_fields = [ - 'setting', - 'setting_details', - 'supervision', - 'leader_has_coc', - 'tasks_number', - ] - - def get_rows(self): - obj = self.object - rows = self._row_fields - - if not needs_details(obj.setting.all()): - rows.remove('setting_details') - if not obj.study.has_children() or \ - not needs_details(obj.setting.all(), 'needs_supervision'): - rows.remove('supervision') - rows.remove('leader_has_coc') - elif obj.supervision: - rows.remove('leader_has_coc') - - rows = [RowClass(obj, field) for field in rows] - - return rows - - def render(self, context): - context.update( - { - 'study_title': super().get_session_title(self.object) - } - ) - return super().render(context) - -class TaskSection(PDFSection): - '''Gets passed a task object''' - - row_fields = [ - 'name', - 'duration', - 'registrations', - 'registrations_details', - 'registration_kinds', - 'registration_kinds_details', - 'feedback', - 'feedback_details', - 'description' - ] - - def get_rows(self): - obj = self.object - rows = self._row_fields - - if not needs_details(obj.registrations.all()): - rows.remove('registrations_details') - if not needs_details(obj.registrations.all(), 'needs_kind') or \ - not needs_details(obj.registration_kinds.all()): - rows.remove('registration_kinds') - rows.remove('registration_kinds_details') - elif not needs_details(obj.registration_kinds.all()): - rows.remove('registration_kinds_details') - if not obj.feedback: - rows.remove('feedback_details') - - rows = [RowClass(obj, field) for field in rows] - - return rows - - def render(self, context): - context.update( - { - 'study_title': super().get_task_title(self.object) - } - ) - return super().render(context) - -class TasksOverviewSection(PDFSection): - '''Gets passed a session object - This might be unecessary ... Maybe just use the existing template language ... - Because the verbose name of this field is formatted, the method for retrieving - the verbose name in the RowClass is quite convoluded.''' - - row_fields = [ - 'tasks_duration' - ] - - def get_rows(self): - - rows = [RowClass(self.object, field) for field in self._row_fields] - - return rows - - def render(self, context): - '''Here I am just overriding the render function, to get the correct formatting - The naming is a bit confusing, might fix later''' - context.update( - { - 'study_title': _('Overzicht van het takenonderzoek') - } - ) - return super().render(context) - -class StudyOverviewSection(StudySection): - '''Receives a Study object''' - - section_title = _('Overzicht en eigen beoordeling van het gehele onderzoek') - row_fields = [ - 'deception', - 'deception_details', - 'negativity', - 'negativity_details', - 'stressful', - 'stressful_details', - 'risk', - 'risk_details' - ] - - def get_rows(self): - obj = self.object - rows = self._row_fields - - rows_to_remove = [] - for x in range(0, 7, 2): - if getattr(obj, rows[x]) == 'N': - rows_to_remove.append(rows[x+1]) - rows = [row for row in rows if row not in rows_to_remove] - - if not obj.has_sessions and not obj.deception == 'N': - rows.remove('deception') - rows.remove('deception_details') - elif not obj.has_sessions: - rows.remove('deception') - - rows = [RowClass(obj, field) for field in rows] - - return rows - -class InformedConsentFormsSection(InterventionSection): - '''Receives a Documents object''' - - section_title = _('Informed consent formulieren') - - '''TODO: Debug''' - def get_rows(self): - obj = self.object - rows = [] - rows.append(RowClass(obj.proposal, 'translated_forms')) - if obj.proposal.translated_forms: - rows.append(RowClass(obj.proposal, 'translated_forms_languages')) - if not obj.proposal.is_practice and obj.informed_consent: - rows.append(RowClass(obj, 'informed_consent')) - rows.append(RowClass(obj, 'briefing')) - if obj.study.passive_consent is not None: - rows.append(RowClass(obj.study, 'passive_consent')) - if obj.study.passive_consent: - rows.append(RowClass(obj.study, 'passive_consent_details')) - if obj.director_consent_declaration: - rows.append(RowClass(obj, 'director_consent_declaration')) - if obj.director_consent_information: - rows.append(RowClass(obj, 'director_consent_information')) - if obj.parents_information: - rows.append(RowClass(obj, 'parents_information')) - breakpoint() - return rows -class RowClass: - - verbose_name_diff_field_dict = { - 'get_metc_display': 'metc', - 'get_is_medical_display': 'is_medical' - } - - def __init__(self, object, field): - self.object = object - self.field = field - - def verbose_name(self): - if self.field in self.verbose_name_diff_field_dict: - verbose_name_field = self.verbose_name_diff_field_dict[self.field] - verbose_name = self.get_verbose_name(verbose_name_field), - else: - verbose_name= self.get_verbose_name(self.field) - return verbose_name - - def value(self): - return RowValueClass(self.object, self.field).render() - - def get_verbose_name(self, field): - if field != 'tasks_duration': - return mark_safe(self.object._meta.get_field(field).verbose_name) - else: - return mark_safe(self.object._meta.get_field(field).verbose_name % self.object.net_duration()) - -class RowValueClass: - - def __init__(self, object, field): - - self.object = object - self.field = field - - def render(self): - from ..models import Funding, Relation - - - value = getattr(self.object, self.field) - - User = get_user_model() - - if value in ('Y', 'N', '?'): - return self.yes_no_doubt(value) - if type(value) in (str, int, date): - return value - elif value is None: - return _('Onbekend') - elif type(value) == bool: - return _('Ja') if value else _('Nee') - elif type(value) == User: - return self.handle_user(value) - elif type(value) == Relation: - return value.description - elif value.__class__.__name__ == 'ManyRelatedManager': - if value.all().model == User: - return self.get_applicants_names(value) - else: - return self.get_object_list(value) - elif value.__class__.__name__ == 'FieldFile': - return self.handle_field_file(value, self.object) - elif callable(value): - return value() - - def handle_user(self, user): - return user.get_full_name() - - def get_applicants_names(self, applicants): - applicant_names = [applicant.get_full_name() for applicant in applicants.all()] - return self.create_unordered_html_list(applicant_names) - - def get_object_list(self, object): - list_of_objects = [obj for obj in object.all()] - return self.create_unordered_html_list(list_of_objects) - - def create_unordered_html_list(self, list): - html_output = mark_safe('
    ') - - for item in list: - html_output += format_html('{}{}{}', - mark_safe('
  • '), - item, - mark_safe('
  • ') - ) - - html_output += mark_safe('
') - - return html_output - - def handle_field_file(self, field_file, object): - from ..models import Proposal - if type(object) == Proposal: - if object.wmo.metc_decision_pdf and not object.is_practice(): - output = format_html('{}{}{}{}{}', - mark_safe(''), - _('Download'), - mark_safe('') - ) - else: - output = _('Niet aangeleverd') - else: - output = format_html('{}{}{}{}{}', - mark_safe(''), - _('Download'), - mark_safe('') - ) - return output - - def yes_no_doubt(self, value): - from main.models import YES_NO_DOUBT - d = dict(YES_NO_DOUBT) - return d[value] - def generate_pdf(proposal, template=False): """Grandfathered function for pdf saving. The template arg currently only exists for backwards compatibility.""" @@ -1061,8 +325,6 @@ def generate_pdf(proposal, template=False): return proposal.pdf - - def pdf_link_callback(uri, rel): """ Convert HTML URIs to absolute system paths so xhtml2pdf can access those diff --git a/proposals/views/proposal_views.py b/proposals/views/proposal_views.py index 41b877610..4c75ceb5f 100644 --- a/proposals/views/proposal_views.py +++ b/proposals/views/proposal_views.py @@ -581,7 +581,7 @@ class ProposalDifference(LoginRequiredMixin, generic.DetailView): from proposals.utils.proposal_utils import GeneralSection, WMOSection, METCSection, \ TrajectoriesSection, StudySection, InterventionSection, ObservationSection, SessionsSection, \ SessionSection, TaskSection, TasksOverviewSection, StudyOverviewSection, \ -InformedConsentFormsSection +InformedConsentFormsSection, ExtraDocumentsSection, DMPFileSection, EmbargoSection \ class NewPDFViewTest(generic.TemplateView): @@ -618,7 +618,18 @@ def get_context_data(self, **kwargs): study_sections.append(StudyOverviewSection(study)) study_sections.append(InformedConsentFormsSection(study.documents)) context['studies'].append(study_sections) - + extra_documents = [] + for count, document in enumerate(Documents.objects.filter( + proposal = model, + study__isnull = True + )): + extra_documents.append(ExtraDocumentsSection(document, count+1)) + if extra_documents: + context['extra_documents'] = extra_documents + if model.dmp_file: + context['dmp_file'] = DMPFileSection(model) + context['embargo'] = EmbargoSection(model) + return context From d1c55b5cb7212dce94abd40bd54c9bbfeb6b74f5 Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Thu, 14 Sep 2023 14:31:12 +0200 Subject: [PATCH 20/52] Started implementing it for diff + organizing --- .../proposals/new_proposal_diff.html | 180 +++++++++++ .../proposals/pdf/diff_table_with_header.html | 33 ++ .../templates/proposals/pdf/new_pdf_test.html | 48 ++- .../templates/proposals/proposal_pdf.html | 131 +------- proposals/utils/pdf_diff_logic.py | 281 ++++++++++-------- proposals/utils/proposal_utils.py | 2 +- proposals/views/proposal_views.py | 77 +++-- 7 files changed, 460 insertions(+), 292 deletions(-) create mode 100644 proposals/templates/proposals/new_proposal_diff.html create mode 100644 proposals/templates/proposals/pdf/diff_table_with_header.html diff --git a/proposals/templates/proposals/new_proposal_diff.html b/proposals/templates/proposals/new_proposal_diff.html new file mode 100644 index 000000000..e5fee7cad --- /dev/null +++ b/proposals/templates/proposals/new_proposal_diff.html @@ -0,0 +1,180 @@ +{% extends "base/base.html" %} + +{% load i18n %} +{% load proposal_filters %} +{% load static %} +{% load uil_filters %} +{% load get_field_name %} +{% load diff_tags %} + +{% block header_title %} + {% trans "Overzicht van wijzigingen" %} - {{ block.super }} +{% endblock %} + +{% block html_head %} + + +{% endblock %} + +{% block content %} +
+
+

{% trans "Overzicht van wijzigingen" %}

+

+ {% trans "Dit overzicht toont de gemaakte wijzigingen in de revisie/het amendement ten opzichte van de originele aanvraag." %} +

+
+
+
+
+
+ +
+ {% with p_proposal=proposal.parent %} + + {% include general %} + + {% with wmo=proposal.wmo %} + {% with p_wmo=p_proposal.wmo %} +

{% trans "Ethische toetsing nodig door een Medische Ethische Toetsingscommissie (METC)?" %}

+ + + + + + + + + + + + {% if wmo.metc == 'Y' or p_wmo.metc == 'Y' %} + + + + + + + + + + + {% else %} + + + + + + {% endif %} +
{% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
{% get_verbose_field_name "proposals" "wmo" "metc" %}{{ p_wmo.get_metc_display }}{{ wmo.get_metc_display }}
{% get_verbose_field_name "proposals" "wmo" "metc_details" %}{{ p_wmo.metc_details }}{{ wmo.metc_details }}
{% get_verbose_field_name "proposals" "wmo" "metc_institution" %}{{ p_wmo.metc_institution }}{{ wmo.metc_institution }}
{% get_verbose_field_name "proposals" "wmo" "is_medical" %}{{ p_wmo.get_is_medical_display }}{{ wmo.get_is_medical_display }}
+ + {% if wmo.status != wmo.NO_WMO or p_wmo.status != p_wmo.NO_WMO %} +

{% trans "Aanmelding bij de METC" %}

+ + + + + + + + + + + + + + + + + + + {% if p_wmo.metc_decision_pdf %} + + {% endif %} + {% if wmo.metc_decision_pdf %} + + {% endif %} + +
{% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
{% get_verbose_field_name "proposals" "wmo" "metc_application" %}{{ p_wmo.metc_application|yesno:_("ja,nee") }}{{ wmo.metc_application|yesno:_("ja,nee") }}
{% get_verbose_field_name "proposals" "wmo" "metc_decision" %}{{ p_wmo.metc_decision|yesno:_("ja,nee") }}{{ wmo.metc_decision|yesno:_("ja,nee") }}
{% get_verbose_field_name "proposals" "wmo" "metc_decision_pdf" %}{% trans "Download" %}{% trans "Download" %}
+ {% endif %} + {% endwith %} + {% endwith %} + +

{% trans "Eén of meerdere trajecten?" %}

+ + + + + + + + + + + + {% if not proposal.studies_similar or not p_proposal.studies_similar %} + + + + + + {% endif %} +
{% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
{% get_verbose_field_name "proposals" "proposal" "studies_similar" %}{{ p_proposal.studies_similar|yesno:_("ja,nee") }}{{ proposal.studies_similar|yesno:_("ja,nee") }}
{% get_verbose_field_name "proposals" "proposal" "studies_number" %}{{ p_proposal.studies_number }}{{ proposal.studies_number }}
+ + {% if proposal.wmo.status == proposal.wmo.NO_WMO or proposal.wmo.status == proposal.wmo.JUDGED %} + {% include 'proposals/diff/study.html' %} + +

{% trans "Concept-aanmelding versturen" %}

+ + + + + + + + + + + + {% if proposal.embargo or p_proposal.embargo %} + + + + + + {% endif %} + + + + + +
{% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
{% get_verbose_field_name "proposals" "proposal" "embargo" %}{{ p_proposal.embargo|yesno:_("ja,nee") }}{{ proposal.embargo|yesno:_("ja,nee") }}
{% get_verbose_field_name "proposals" "proposal" "embargo_end_date" %}{{ p_proposal.embargo_end_date }}{{ proposal.embargo_end_date }}
{% get_verbose_field_name "proposals" "proposal" "comments" %}{{ p_proposal.comments }}{{ proposal.comments }}
+ {% endif %} + {% endwith %} + +

+ +

+ +
+
+{% endblock %} diff --git a/proposals/templates/proposals/pdf/diff_table_with_header.html b/proposals/templates/proposals/pdf/diff_table_with_header.html new file mode 100644 index 000000000..6c7c0b787 --- /dev/null +++ b/proposals/templates/proposals/pdf/diff_table_with_header.html @@ -0,0 +1,33 @@ +{% load i18n %} +{% load proposal_filters %} +{% load static %} +{% load uil_filters %} +{% load get_field_name %} +{% load diff_tags %} + +{% if section_title %} +

{{ section_title }}

+{% endif %} +{% if study_title %} +

{{ study_title }}

+{% endif %} + + + + + + +{% for row in rows %} + + + +{% endfor %} +
{% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
{{ row.verbose_name }}{{ row.value }}{{row.value_2}}
+ +

{% trans "Algemene informatie over de aanvraag" %}

+ + + + + + \ No newline at end of file diff --git a/proposals/templates/proposals/pdf/new_pdf_test.html b/proposals/templates/proposals/pdf/new_pdf_test.html index 8bda7801e..74ed47785 100644 --- a/proposals/templates/proposals/pdf/new_pdf_test.html +++ b/proposals/templates/proposals/pdf/new_pdf_test.html @@ -13,14 +13,14 @@ {% block content %} - {% include test %} - {% include wmo_test %} + {% include general %} + {% comment %} {% include wmo %} - {% if metc_test %} - {% include metc_test %} + {% if metc %} + {% include metc %} {% endif %} - {% include trajectories_test %} + {% include trajectories %} {% if studies %} {% for study in studies %} @@ -42,4 +42,42 @@ {% include embargo %} + {% include general %} {% endcomment %} + + {% comment %} Code to copy into pdf file + +

{% get_verbose_field_name "proposals" "proposal" "summary" %}

+

{{ proposal.summary|linebreaks }}

+ + {% include wmo %} + + {% if metc %} + {% include metc %} + {% endif %} + + {% include trajectories %} + + {% if studies %} + {% for study in studies %} + {% for study_section in study %} + {% include study_section %} + {% endfor %} + {% endfor %} + {% endif %} + + {% if dmp_file %} + {% include dmp_file %} + {% endif %} + + {% if dmp_file %} + {% include dmp_file %} + {% endif %} + + {% include embargo %} + +

{% get_verbose_field_name "proposals" "proposal" "comments" %}

+

+ {{ proposal.comments }} +

{% endcomment %} + {% endblock %} \ No newline at end of file diff --git a/proposals/templates/proposals/proposal_pdf.html b/proposals/templates/proposals/proposal_pdf.html index dd3cc9f88..1dbbd27b0 100644 --- a/proposals/templates/proposals/proposal_pdf.html +++ b/proposals/templates/proposals/proposal_pdf.html @@ -79,136 +79,17 @@

{% trans 'Indiener' %}

{% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
{% trans 'E-mail' %}{{ proposal.created_by.email }}
-

{% trans "Algemene informatie over de aanvraag" %}

- - - - - {% if proposal.relation.needs_supervisor %} - - - - {% endif %} - {% if proposal.relation.check_in_course %} - - - - - - - {% if proposal.student_context.needs_details %} - - - - {% endif %} - - - - {% endif %} - - - - {% if proposal.other_applicants %} - - - - {% endif %} - - - - {% if proposal.other_stakeholders %} - - - - {% endif %} - - - - - - - - - - {% if proposal.funding.all|needs_details %} - - - - {% endif %} - {% if proposal.funding.all|needs_details:"needs_name" %} - - - - {% endif %} - - - -
{% get_verbose_field_name "proposals" "proposal" "relation" %}{{ proposal.relation }}
{% get_verbose_field_name "proposals" "proposal" "supervisor" %}{{ proposal.supervisor.get_full_name }}
{% get_verbose_field_name "proposals" "proposal" "student_program" %}{{ proposal.student_program }}
{% get_verbose_field_name "proposals" "proposal" "student_context" %}{{ proposal.student_context }}
{% get_verbose_field_name "proposals" "proposal" "student_context_details" %}{{ proposal.student_context_details }}
{% get_verbose_field_name "proposals" "proposal" "student_justification" %}{{ proposal.student_justification }}
{% get_verbose_field_name "proposals" "proposal" "other_applicants" %}{{ proposal.other_applicants|yesno:_("ja,nee") }}
{% get_verbose_field_name "proposals" "proposal" "applicants" %} -
    - {% for applicant in proposal.applicants.all %} -
  • - {{ applicant.get_full_name }} -
  • - {% endfor %} -
-
{% get_verbose_field_name "proposals" "proposal" "other_stakeholders" %}{{ proposal.other_stakeholders|yesno:_("ja,nee") }}
{% get_verbose_field_name "proposals" "proposal" "stakeholders" %}{{ proposal.stakeholders }}
{% get_verbose_field_name "proposals" "proposal" "date_start" %}{{ proposal.date_start|default:_("onbekend") }}
{% get_verbose_field_name "proposals" "proposal" "title" %}{{ proposal.title }}
{% get_verbose_field_name "proposals" "proposal" "funding" %}{{ proposal.funding.all|unordered_list }}
{% get_verbose_field_name "proposals" "proposal" "funding_details" %}{{ proposal.funding_details }}
{% get_verbose_field_name "proposals" "proposal" "funding_name" %}{{ proposal.funding_name }}
{% get_verbose_field_name "proposals" "proposal" "self_assessment" %}{{ proposal.self_assessment }}
+ {% include general %}

{% get_verbose_field_name "proposals" "proposal" "summary" %}

{{ proposal.summary|linebreaks }}

- {% with wmo=proposal.wmo %} -

{% trans "Ethische toetsing nodig door een Medische Ethische Toetsingscommissie (METC)?" %}

- - - - - {% if wmo.metc == 'Y' %} - - - - - - - {% else %} - - - - {% endif %} -
{% get_verbose_field_name "proposals" "wmo" "metc" %}{{ wmo.get_metc_display }}
{% get_verbose_field_name "proposals" "wmo" "metc_details" %}{{ wmo.metc_details }}
{% get_verbose_field_name "proposals" "wmo" "metc_institution" %}{{ wmo.metc_institution }}
{% get_verbose_field_name "proposals" "wmo" "is_medical" %}{{ wmo.get_is_medical_display }}
+ {% include wmo %} - {% if wmo.status != wmo.NO_WMO %} -

{% trans "Aanmelding bij de METC" %}

- - - - - - - - {% if wmo.metc_decision_pdf and not proposal.is_practice %} - - - - {% else %} - - - - - {% endif %} -
{% get_verbose_field_name "proposals" "wmo" "metc_application" %}{{ wmo.metc_application|yesno:_("ja,nee") }}
{% get_verbose_field_name "proposals" "wmo" "metc_decision" %}{{ wmo.metc_decision|yesno:_("ja,nee") }}
{% get_verbose_field_name "proposals" "wmo" "metc_decision_pdf" %}{% trans "Download" %}
{% get_verbose_field_name "proposals" "wmo" "metc_decision_pdf" %}{% trans "Niet aangeleverd" %}
- {% endif %} - {% endwith %} + {% if metc %} + {% include metc %} + {% endif %} -

{% trans "Eén of meerdere trajecten?" %}

- - - - - {% if not proposal.studies_similar %} - - - - {% endif %} -
{% get_verbose_field_name "proposals" "proposal" "studies_similar" %}{{ proposal.studies_similar|yesno:_("ja,nee") }}
{% get_verbose_field_name "proposals" "proposal" "studies_number" %}{{ proposal.studies_number }}
+ {% include trajectories %} {% if proposal.wmo.status == proposal.wmo.NO_WMO %} {% for study in proposal.study_set.all %} diff --git a/proposals/utils/pdf_diff_logic.py b/proposals/utils/pdf_diff_logic.py index a018005db..9f490713f 100644 --- a/proposals/utils/pdf_diff_logic.py +++ b/proposals/utils/pdf_diff_logic.py @@ -12,32 +12,53 @@ from proposals.templatetags.proposal_filters import needs_details, medical_traits, \ necessity_required, has_adults +from ..models import Relation + +'''NOTE: The current implementation does not account for page break formatting, present +in the previous pdf template''' + class PDFSection: section_title = None row_fields = None - def __init__(self, object): + def __init__(self, object, object_2 = None): self.object = object - # Create a copy of the class level row_fields, such that we can safely manipulate it without changing the class value - self._row_fields = copy(self.row_fields) + self.object_2 = object_2 def render(self, context): context = context.flatten() - template = get_template("proposals/pdf/table_with_header.html") + if self.object_2: + template = get_template("proposals/pdf/diff_table_with_header.html") + else: + template = get_template("proposals/pdf/table_with_header.html") context.update( { "section_title": self.section_title, - "rows": self.get_rows(), + "rows": self.make_rows(), } ) return template.render(context) - - def get_rows(self): - rows = [RowClass(self.object, field) for field in self._row_fields] + def make_rows(self): + if self.object_2: + row_fields_1 = self.get_row_fields(self.object) + row_fields_2 = self.get_row_fields(self.object_2) + + row_fields_both = list(set(row_fields_1) | set(row_fields_2)) + + #The merging above messes with the order, so I reorder it here + ordered_row_fields = [row for row in self.row_fields if row in row_fields_both] + + rows = [RowClass(self.object, field, self.object_2) for field in ordered_row_fields] + else: + row_fields = self.get_row_fields(self.object) + rows = [RowClass(self.object, field) for field in row_fields] return rows + + def get_row_fields(self): + return self.row_fields def get_study_title(self, study): if study.name: @@ -115,6 +136,125 @@ def get_task_title(self, task): ) return task_title +class RowClass: + + verbose_name_diff_field_dict = { + 'get_metc_display': 'metc', + 'get_is_medical_display': 'is_medical' + } + + def __init__(self, object, field, object_2 = None): + self.object = object + self.object_2 = object_2 + self.field = field + + def verbose_name(self): + if self.field in self.verbose_name_diff_field_dict: + verbose_name_field = self.verbose_name_diff_field_dict[self.field] + verbose_name = self.get_verbose_name(verbose_name_field) + else: + verbose_name= self.get_verbose_name(self.field) + return verbose_name + + def value(self): + return RowValueClass(self.object, self.field).render() + + def value_2(self): + return RowValueClass(self.object_2, self.field).render() + + def get_verbose_name(self, field): + if field != 'tasks_duration': + return mark_safe(self.object._meta.get_field(field).verbose_name) + else: + return mark_safe(self.object._meta.get_field(field).verbose_name % self.object.net_duration()) + +class RowValueClass: + + def __init__(self, object, field): + + self.object = object + self.field = field + + def render(self): + + value = getattr(self.object, self.field) + + User = get_user_model() + + if value in ('Y', 'N', '?'): + return self.yes_no_doubt(value) + if type(value) in (str, int, date): + return value + elif value is None: + return _('Onbekend') + elif type(value) == bool: + return _('Ja') if value else _('Nee') + elif type(value) == User: + return self.handle_user(value) + elif type(value) == Relation: + return value.description + elif value.__class__.__name__ == 'ManyRelatedManager': + if value.all().model == User: + return self.get_applicants_names(value) + else: + return self.get_object_list(value) + elif value.__class__.__name__ == 'FieldFile': + return self.handle_field_file(value, self.object) + elif callable(value): + return value() + + def handle_user(self, user): + return user.get_full_name() + + def get_applicants_names(self, applicants): + applicant_names = [applicant.get_full_name() for applicant in applicants.all()] + return self.create_unordered_html_list(applicant_names) + + def get_object_list(self, object): + list_of_objects = [obj for obj in object.all()] + return self.create_unordered_html_list(list_of_objects) + + def create_unordered_html_list(self, list): + html_output = mark_safe('
    ') + + for item in list: + html_output += format_html('{}{}{}', + mark_safe('
  • '), + item, + mark_safe('
  • ') + ) + + html_output += mark_safe('
') + + return html_output + + def handle_field_file(self, field_file, object): + from ..models import Proposal + if object == Proposal and field_file == object.wmo.metc_decision_pdf: + if object.wmo.metc_decision_pdf and not object.is_practice(): + output = format_html('{}{}{}{}{}', + mark_safe(''), + _('Download'), + mark_safe('') + ) + else: + output = _('Niet aangeleverd') + else: + output = format_html('{}{}{}{}{}', + mark_safe(''), + _('Download'), + mark_safe('') + ) + return output + + def yes_no_doubt(self, value): + from main.models import YES_NO_DOUBT + d = dict(YES_NO_DOUBT) + return d[value] class GeneralSection(PDFSection): '''This class generates the data for the general section of the PDF page.''' @@ -139,9 +279,9 @@ class GeneralSection(PDFSection): 'self_assessment', ] - def get_rows(self): - obj = self.object - rows = self._row_fields + def get_row_fields(self, object): + obj = object + rows = copy(self.row_fields) if not obj.relation.needs_supervisor: rows.remove('supervisor') @@ -163,8 +303,6 @@ def get_rows(self): if not needs_details(obj.funding.all(), 'needs_name'): rows.remove('funding_name') - rows = [RowClass(obj, field) for field in rows] - return rows class WMOSection(PDFSection): @@ -660,120 +798,3 @@ def get_rows(self): return rows -class RowClass: - - verbose_name_diff_field_dict = { - 'get_metc_display': 'metc', - 'get_is_medical_display': 'is_medical' - } - - def __init__(self, object, field): - self.object = object - self.field = field - - def verbose_name(self): - if self.field in self.verbose_name_diff_field_dict: - verbose_name_field = self.verbose_name_diff_field_dict[self.field] - verbose_name = self.get_verbose_name(verbose_name_field) - else: - verbose_name= self.get_verbose_name(self.field) - return verbose_name - - def value(self): - return RowValueClass(self.object, self.field).render() - - def get_verbose_name(self, field): - if field != 'tasks_duration': - return mark_safe(self.object._meta.get_field(field).verbose_name) - else: - return mark_safe(self.object._meta.get_field(field).verbose_name % self.object.net_duration()) - -class RowValueClass: - - def __init__(self, object, field): - - self.object = object - self.field = field - - def render(self): - from ..models import Funding, Relation - - - value = getattr(self.object, self.field) - - User = get_user_model() - - if value in ('Y', 'N', '?'): - return self.yes_no_doubt(value) - if type(value) in (str, int, date): - return value - elif value is None: - return _('Onbekend') - elif type(value) == bool: - return _('Ja') if value else _('Nee') - elif type(value) == User: - return self.handle_user(value) - elif type(value) == Relation: - return value.description - elif value.__class__.__name__ == 'ManyRelatedManager': - if value.all().model == User: - return self.get_applicants_names(value) - else: - return self.get_object_list(value) - elif value.__class__.__name__ == 'FieldFile': - return self.handle_field_file(value, self.object) - elif callable(value): - return value() - - def handle_user(self, user): - return user.get_full_name() - - def get_applicants_names(self, applicants): - applicant_names = [applicant.get_full_name() for applicant in applicants.all()] - return self.create_unordered_html_list(applicant_names) - - def get_object_list(self, object): - list_of_objects = [obj for obj in object.all()] - return self.create_unordered_html_list(list_of_objects) - - def create_unordered_html_list(self, list): - html_output = mark_safe('
    ') - - for item in list: - html_output += format_html('{}{}{}', - mark_safe('
  • '), - item, - mark_safe('
  • ') - ) - - html_output += mark_safe('
') - - return html_output - - def handle_field_file(self, field_file, object): - from ..models import Proposal - if object == Proposal and field_file == object.wmo.metc_decision_pdf: - if object.wmo.metc_decision_pdf and not object.is_practice(): - output = format_html('{}{}{}{}{}', - mark_safe(''), - _('Download'), - mark_safe('') - ) - else: - output = _('Niet aangeleverd') - else: - output = format_html('{}{}{}{}{}', - mark_safe(''), - _('Download'), - mark_safe('') - ) - return output - - def yes_no_doubt(self, value): - from main.models import YES_NO_DOUBT - d = dict(YES_NO_DOUBT) - return d[value] diff --git a/proposals/utils/proposal_utils.py b/proposals/utils/proposal_utils.py index 79c3bbb21..35bcc8136 100644 --- a/proposals/utils/proposal_utils.py +++ b/proposals/utils/proposal_utils.py @@ -12,7 +12,7 @@ from django.core.mail import send_mail from django.db.models import Q from django.urls import reverse -from django.template.loader import render_to_string, +from django.template.loader import render_to_string from django.utils.translation import activate, get_language, ugettext as _ from django.utils.deconstruct import deconstructible diff --git a/proposals/views/proposal_views.py b/proposals/views/proposal_views.py index 4c75ceb5f..78bc1e5e2 100644 --- a/proposals/views/proposal_views.py +++ b/proposals/views/proposal_views.py @@ -12,13 +12,14 @@ from django.utils.translation import ugettext_lazy as _ from django.views import generic #from easy_pdf.views import PDFTemplateResponseMixin, PDFTemplateView -from typing import Tuple, Union +from typing import Any, Tuple, Union from main.utils import get_document_contents, get_secretary, is_secretary from main.views import AllowErrorsOnBackbuttonMixin, CreateView, DeleteView, \ UpdateView, UserAllowedMixin from observations.models import Observation from proposals.utils.validate_proposal import get_form_errors +from proposals.utils.pdf_diff_logic import * from reviews.mixins import CommitteeMixin, UsersOrGroupsAllowedMixin from reviews.utils.review_utils import start_review, start_review_pre_assessment from studies.models import Documents @@ -552,36 +553,54 @@ class ProposalAsPdf(LoginRequiredMixin, PDFTemplateResponseMixin, def get_context_data(self, **kwargs): """Adds 'BASE_URL' to template context""" context = super(ProposalAsPdf, self).get_context_data(**kwargs) - context['BASE_URL'] = settings.BASE_URL - if self.object.is_pre_approved: - self.template_name = 'proposals/proposal_pdf_pre_approved.html' - elif self.object.is_pre_assessment: - self.template_name = 'proposals/proposal_pdf_pre_assessment.html' - - documents = { - 'extra': [] - } - - for document in Documents.objects.filter(proposal=self.object).all(): - if document.study: - documents[document.study.pk] = document - else: - documents['extra'].append(document) - - context['documents'] = documents + context['general'] = GeneralSection(self.object) + context['wmo'] = WMOSection(self.object.wmo) + if self.object.wmo.status != self.object.wmo.NO_WMO: + context['metc'] = METCSection(self.object.wmo) + context['trajectories'] = TrajectoriesSection(self.object) + if self.object.wmo.status == self.object.wmo.NO_WMO: + context['studies'] = [] + for study in self.object.study_set.all(): + study_sections = [] + study_sections.append(StudySection(study)) + if study.has_intervention: + study_sections.append(InterventionSection(study.intervention)) + if study.has_observation: + study_sections.append(ObservationSection(study.observation)) + if study.has_sessions: + study_sections.append(SessionsSection(study)) + for session in study.session_set.all(): + study_sections.append(SessionSection(session)) + for task in session.task_set.all(): + study_sections.append(TaskSection(task)) + study_sections.append(TasksOverviewSection(session)) + study_sections.append(StudyOverviewSection(study)) + study_sections.append(InformedConsentFormsSection(study.documents)) + context['studies'].append(study_sections) + extra_documents = [] + for count, document in enumerate(Documents.objects.filter( + proposal = self.object, + study__isnull = True + )): + extra_documents.append(ExtraDocumentsSection(document, count+1)) + if extra_documents: + context['extra_documents'] = extra_documents + if self.object.dmp_file: + context['dmp_file'] = DMPFileSection(self.object) + context['embargo'] = EmbargoSection(self.object) return context class ProposalDifference(LoginRequiredMixin, generic.DetailView): model = Proposal - template_name = 'proposals/proposal_diff.html' + template_name = 'proposals/new_proposal_diff.html' -from proposals.utils.proposal_utils import GeneralSection, WMOSection, METCSection, \ -TrajectoriesSection, StudySection, InterventionSection, ObservationSection, SessionsSection, \ -SessionSection, TaskSection, TasksOverviewSection, StudyOverviewSection, \ -InformedConsentFormsSection, ExtraDocumentsSection, DMPFileSection, EmbargoSection \ + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['general'] = GeneralSection(self.object.parent, self.object) + return context class NewPDFViewTest(generic.TemplateView): @@ -589,16 +608,12 @@ class NewPDFViewTest(generic.TemplateView): def get_context_data(self, **kwargs): model = Proposal.objects.last() - test = GeneralSection(model) - wmo_test = WMOSection(model.wmo) - trajectories_test = TrajectoriesSection(model) context = super().get_context_data(**kwargs) - context['test'] = test - context['wmo_test'] = wmo_test + context['general'] = GeneralSection(model) + context['wmo'] = WMOSection(model.wmo) if model.wmo.status != model.wmo.NO_WMO: - metc_test = METCSection(model.wmo) - context['metc_test'] = metc_test - context['trajectories_test'] = trajectories_test + context['metc'] = METCSection(model.wmo) + context['trajectories'] = TrajectoriesSection(model) if model.wmo.status == model.wmo.NO_WMO: context['studies'] = [] for study in model.study_set.all(): From c85dfa131f5cbadc181bf01c32d01f64f5688bdc Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Thu, 14 Sep 2023 15:59:52 +0200 Subject: [PATCH 21/52] seperate func for the sections logic + other improvements --- .../templates/proposals/pdf/new_pdf_test.html | 4 +- proposals/utils/pdf_diff_logic.py | 231 +++++++++++------- proposals/views/proposal_views.py | 37 +-- 3 files changed, 150 insertions(+), 122 deletions(-) diff --git a/proposals/templates/proposals/pdf/new_pdf_test.html b/proposals/templates/proposals/pdf/new_pdf_test.html index 74ed47785..917b9bc64 100644 --- a/proposals/templates/proposals/pdf/new_pdf_test.html +++ b/proposals/templates/proposals/pdf/new_pdf_test.html @@ -14,7 +14,7 @@ {% block content %} {% include general %} - {% comment %} {% include wmo %} + {% include wmo %} {% if metc %} {% include metc %} @@ -42,8 +42,6 @@ {% include embargo %} - {% include general %} {% endcomment %} - {% comment %} Code to copy into pdf file

{% get_verbose_field_name "proposals" "proposal" "summary" %}

diff --git a/proposals/utils/pdf_diff_logic.py b/proposals/utils/pdf_diff_logic.py index 9f490713f..0f2fe96ba 100644 --- a/proposals/utils/pdf_diff_logic.py +++ b/proposals/utils/pdf_diff_logic.py @@ -12,8 +12,6 @@ from proposals.templatetags.proposal_filters import needs_details, medical_traits, \ necessity_required, has_adults -from ..models import Relation - '''NOTE: The current implementation does not account for page break formatting, present in the previous pdf template''' @@ -22,9 +20,13 @@ class PDFSection: section_title = None row_fields = None - def __init__(self, object, object_2 = None): - self.object = object - self.object_2 = object_2 + def __init__(self, object): + if type(object) == list: + self.object = object[0] + self.object_2 = object[1] + else: + self.object = object + self.object_2 = None def render(self, context): context = context.flatten() @@ -57,7 +59,7 @@ def make_rows(self): rows = [RowClass(self.object, field) for field in row_fields] return rows - def get_row_fields(self): + def get_row_fields(self, obj): return self.row_fields def get_study_title(self, study): @@ -176,6 +178,7 @@ def __init__(self, object, field): self.field = field def render(self): + from ..models import Relation value = getattr(self.object, self.field) @@ -255,6 +258,7 @@ def yes_no_doubt(self, value): from main.models import YES_NO_DOUBT d = dict(YES_NO_DOUBT) return d[value] + class GeneralSection(PDFSection): '''This class generates the data for the general section of the PDF page.''' @@ -279,8 +283,7 @@ class GeneralSection(PDFSection): 'self_assessment', ] - def get_row_fields(self, object): - obj = object + def get_row_fields(self, obj): rows = copy(self.row_fields) if not obj.relation.needs_supervisor: @@ -315,9 +318,8 @@ class WMOSection(PDFSection): 'get_is_medical_display', ] - def get_rows(self): - obj = self.object - rows = self._row_fields + def get_row_fields(self, obj): + rows = copy(self.row_fields) if not obj.metc == 'Y': rows.remove('metc_details') @@ -325,8 +327,6 @@ def get_rows(self): else: rows.remove('get_is_medical_display') - rows = [RowClass(obj, field) for field in rows] - return rows class METCSection(PDFSection): @@ -350,15 +350,12 @@ class TrajectoriesSection(PDFSection): 'studies_number' ] - def get_rows(self): - obj = self.object - rows = self._row_fields + def get_row_fields(self, obj): + rows = copy(self.row_fields) if obj.studies_similar: rows.remove('studies_number') - rows = [RowClass(obj, field) for field in rows] - return rows class StudySection(PDFSection): @@ -382,9 +379,8 @@ class StudySection(PDFSection): 'hierarchy_details', ] - def get_rows(self): - obj = self.object - rows = self._row_fields + def get_row_fields(self, obj): + rows = copy(self.row_fields) if not has_adults(obj): rows.remove('legally_incapable') @@ -410,8 +406,6 @@ def get_rows(self): if not obj.hierarchy: rows.remove('hierarchy_details') - rows = [RowClass(obj, field) for field in rows] - return rows def render(self, context): @@ -444,9 +438,8 @@ class InterventionSection(PDFSection): 'extra_task' ] - def get_rows(self): - obj = self.object - rows = self._row_fields + def get_row_fields(self, obj): + rows = copy(self.row_fields) if obj.version == 1: fields_to_remove = ['multiple_sessions', @@ -472,8 +465,6 @@ def get_rows(self): if not obj.has_controls: rows.remove('controls_description') - rows = [RowClass(obj, field) for field in rows] - return rows def render(self, context): @@ -513,9 +504,8 @@ class ObservationSection(InterventionSection): 'registrations_details' ] - def get_rows(self): - obj = self.object - rows = self._row_fields + def get_row_fields(self, obj): + rows = copy(self.row_fields) if obj.version == 1: to_remove_if_v1 = ['details_who', @@ -565,8 +555,6 @@ def get_rows(self): rows.remove('leader_has_coc') if not needs_details(obj.registrations.all()): rows.remove('registrations_details') - - rows = [RowClass(obj, field) for field in rows] return rows @@ -577,11 +565,10 @@ class SessionsSection(StudySection): section_title = _("Het takenonderzoek en interviews") - def get_rows(self): - - rows = [RowValueClass(self.object, 'sessions_number')] + row_fields = ['sessions_number'] - return rows + def get_row_fields(self, obj): + return self.row_fields class SessionSection(PDFSection): '''Gets passed a session object''' @@ -594,9 +581,8 @@ class SessionSection(PDFSection): 'tasks_number', ] - def get_rows(self): - obj = self.object - rows = self._row_fields + def get_row_fields(self, obj): + rows = copy(self.row_fields) if not needs_details(obj.setting.all()): rows.remove('setting_details') @@ -606,8 +592,6 @@ def get_rows(self): rows.remove('leader_has_coc') elif obj.supervision: rows.remove('leader_has_coc') - - rows = [RowClass(obj, field) for field in rows] return rows @@ -634,9 +618,8 @@ class TaskSection(PDFSection): 'description' ] - def get_rows(self): - obj = self.object - rows = self._row_fields + def get_row_fields(self, obj): + rows = copy(self.row_fields) if not needs_details(obj.registrations.all()): rows.remove('registrations_details') @@ -648,8 +631,6 @@ def get_rows(self): rows.remove('registration_kinds_details') if not obj.feedback: rows.remove('feedback_details') - - rows = [RowClass(obj, field) for field in rows] return rows @@ -696,9 +677,8 @@ class StudyOverviewSection(StudySection): 'risk_details' ] - def get_rows(self): - obj = self.object - rows = self._row_fields + def get_row_fields(self, obj): + rows = copy(self.row_fields) rows_to_remove = [] for x in range(0, 7, 2): @@ -711,8 +691,6 @@ def get_rows(self): rows.remove('deception_details') elif not obj.has_sessions: rows.remove('deception') - - rows = [RowClass(obj, field) for field in rows] return rows @@ -721,27 +699,75 @@ class InformedConsentFormsSection(InterventionSection): section_title = _('Informed consent formulieren') - def get_rows(self): - obj = self.object - - rows = [] - - rows.append(RowClass(obj.proposal, 'translated_forms')) - if obj.proposal.translated_forms: - rows.append(RowClass(obj.proposal, 'translated_forms_languages')) - if not obj.proposal.is_practice() and obj.informed_consent: - rows.append(RowClass(obj, 'informed_consent')) - rows.append(RowClass(obj, 'briefing')) - if obj.study.passive_consent is not None: - rows.append(RowClass(obj.study, 'passive_consent')) - if obj.study.passive_consent: - rows.append(RowClass(obj.study, 'passive_consent_details')) - if obj.director_consent_declaration: - rows.append(RowClass(obj, 'director_consent_declaration')) - if obj.director_consent_information: - rows.append(RowClass(obj, 'director_consent_information')) - if obj.parents_information: - rows.append(RowClass(obj, 'parents_information')) + row_fields = [ + 'translated_forms', + 'translated_forms_languages', + 'informed_consent', + 'briefing', + 'passive_consent', + 'passive_consent_details', + 'director_consent_declaration', + 'director_consent_information', + 'parents_information' + ] + + def make_rows(self): + '''A few fields here need to access different objects, therefore this complex + overriding of the make_rows function ... :( ''' + + proposal_list = ['translated_forms', 'translated_forms_languages'] + study_list = ['passive_consent', 'passive_consent_details'] + if self.object_2: + row_fields_1 = self.get_row_fields(self.object) + row_fields_2 = self.get_row_fields(self.object_2) + + row_fields_both = list(set(row_fields_1) | set(row_fields_2)) + + ordered_row_fields = [row for row in self.row_fields if row in row_fields_both] + + rows = [] + + for field in ordered_row_fields: + if field in proposal_list: + rows.append(RowClass(self.object.proposal, field, self.object_2.proposal)) + if field in study_list: + rows.append(RowClass(self.object.study, field, self.object_2.study)) + else: + rows.append(RowClass(self.object, field, self.object_2)) + + else: + row_fields = self.get_row_fields(self.object) + + rows = [] + + for field in row_fields: + if field in proposal_list: + rows.append(RowClass(self.object.proposal, field)) + elif field in study_list: + rows.append(RowClass(self.object.study, field)) + else: + rows.append(RowClass(self.object, field)) + + return rows + + def get_row_fields(self, obj): + rows = copy(self.row_fields) + + if not obj.proposal.translated_forms: + rows.remove('translated_forms_languages') + if obj.proposal.is_practice() or not obj.informed_consent: + rows.remove('informed_consent') + rows.remove('briefing') + if obj.study.passive_consent is None: + rows.remove('passive_consent') + if not obj.study.passive_consent: + rows.remove('passive_consent_details') + if not obj.director_consent_declaration: + rows.remove('director_consent_declaration') + if not obj.director_consent_information: + rows.remove('director_consent_information') + if not obj.parents_information: + rows.remove('parents_information') return rows @@ -757,21 +783,19 @@ def __init__(self, object, count): super().__init__(object) self.section_title = _('Extra formulieren ') + str(count) - def get_rows(self): - obj = self.object - rows = self._row_fields + def get_row_fields(self, obj): + rows = copy(self.row_fields) if not obj.informed_consent: rows.remove('informed_consent') if not obj.briefing: rows.remove('briefing') - - rows = [RowClass(obj, field) for field in rows] return rows class DMPFileSection(PDFSection): - '''Gets passed a proposal object.''' + '''Gets passed a proposal object. + Also unnecessary I suppose. But I though why not ...''' section_title = _('Data Management Plan') @@ -787,14 +811,53 @@ class EmbargoSection(PDFSection): 'embargo_end_date' ] - def get_rows(self): - obj = self.object - rows = self._row_fields + def get_row_fields(self, obj): + rows = copy(self.row_fields) if not obj.embargo: rows.remove('embargo_end_date') - - rows = [RowClass(obj, field) for field in rows] return rows +def create_context_pdf_diff(context, model): + from studies.models import Documents + + context['general'] = GeneralSection(model) + context['wmo'] = WMOSection(model.wmo) + if model.wmo.status != model.wmo.NO_WMO: + context['metc'] = METCSection(model.wmo) + context['trajectories'] = TrajectoriesSection(model) + if model.wmo.status == model.wmo.NO_WMO: + context['studies'] = [] + for study in model.study_set.all(): + study_sections = [] + study_sections.append(StudySection(study)) + if study.has_intervention: + study_sections.append(InterventionSection(study.intervention)) + if study.has_observation: + study_sections.append(ObservationSection(study.observation)) + if study.has_sessions: + study_sections.append(SessionsSection(study)) + for session in study.session_set.all(): + study_sections.append(SessionSection(session)) + for task in session.task_set.all(): + study_sections.append(TaskSection(task)) + study_sections.append(TasksOverviewSection(session)) + study_sections.append(StudyOverviewSection(study)) + study_sections.append(InformedConsentFormsSection(study.documents)) + context['studies'].append(study_sections) + extra_documents = [] + for count, document in enumerate(Documents.objects.filter( + proposal = model, + study__isnull = True + )): + extra_documents.append(ExtraDocumentsSection(document, count+1)) + if extra_documents: + context['extra_documents'] = extra_documents + if model.dmp_file: + context['dmp_file'] = DMPFileSection(model) + context['embargo'] = EmbargoSection(model) + + return context + + diff --git a/proposals/views/proposal_views.py b/proposals/views/proposal_views.py index 78bc1e5e2..c7707a36c 100644 --- a/proposals/views/proposal_views.py +++ b/proposals/views/proposal_views.py @@ -609,41 +609,8 @@ class NewPDFViewTest(generic.TemplateView): def get_context_data(self, **kwargs): model = Proposal.objects.last() context = super().get_context_data(**kwargs) - context['general'] = GeneralSection(model) - context['wmo'] = WMOSection(model.wmo) - if model.wmo.status != model.wmo.NO_WMO: - context['metc'] = METCSection(model.wmo) - context['trajectories'] = TrajectoriesSection(model) - if model.wmo.status == model.wmo.NO_WMO: - context['studies'] = [] - for study in model.study_set.all(): - study_sections = [] - study_sections.append(StudySection(study)) - if study.has_intervention: - study_sections.append(InterventionSection(study.intervention)) - if study.has_observation: - study_sections.append(ObservationSection(study.observation)) - if study.has_sessions: - study_sections.append(SessionsSection(study)) - for session in study.session_set.all(): - study_sections.append(SessionSection(session)) - for task in session.task_set.all(): - study_sections.append(TaskSection(task)) - study_sections.append(TasksOverviewSection(session)) - study_sections.append(StudyOverviewSection(study)) - study_sections.append(InformedConsentFormsSection(study.documents)) - context['studies'].append(study_sections) - extra_documents = [] - for count, document in enumerate(Documents.objects.filter( - proposal = model, - study__isnull = True - )): - extra_documents.append(ExtraDocumentsSection(document, count+1)) - if extra_documents: - context['extra_documents'] = extra_documents - if model.dmp_file: - context['dmp_file'] = DMPFileSection(model) - context['embargo'] = EmbargoSection(model) + + context = create_context_pdf_diff(context, model) return context From 51fc86a6b07043f3344f63d7e4223389a5eaf200 Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Thu, 14 Sep 2023 16:15:48 +0200 Subject: [PATCH 22/52] last commit of the day --- proposals/templates/proposals/pdf/new_pdf_test.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/proposals/templates/proposals/pdf/new_pdf_test.html b/proposals/templates/proposals/pdf/new_pdf_test.html index 917b9bc64..deaa433ad 100644 --- a/proposals/templates/proposals/pdf/new_pdf_test.html +++ b/proposals/templates/proposals/pdf/new_pdf_test.html @@ -40,7 +40,9 @@ {% include dmp_file %} {% endif %} - {% include embargo %} + {% if embargo %} + {% include embargo %} + {% endif %} {% comment %} Code to copy into pdf file From 0577060770b7839e0cdc12a631d3dcc8c8a5f6ed Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Tue, 19 Sep 2023 17:01:25 +0200 Subject: [PATCH 23/52] Wooops. Forgot to commit a lot again ... Mainly implemented Diff --- .../templates/proposals/diff/sessions.html | 3 +- .../proposals/new_proposal_diff.html | 131 ++----- .../proposals/pdf/diff_table_with_header.html | 56 ++- .../pdf/single_object_diff_table.html | 23 ++ .../templates/proposals/proposal_pdf.html | 323 +----------------- proposals/templatetags/diff_tags.py | 11 +- proposals/utils/pdf_diff_logic.py | 214 +++++++++++- proposals/views/proposal_views.py | 53 +-- 8 files changed, 329 insertions(+), 485 deletions(-) create mode 100644 proposals/templates/proposals/pdf/single_object_diff_table.html diff --git a/proposals/templates/proposals/diff/sessions.html b/proposals/templates/proposals/diff/sessions.html index 84b1ec92c..0021a51d0 100644 --- a/proposals/templates/proposals/diff/sessions.html +++ b/proposals/templates/proposals/diff/sessions.html @@ -175,7 +175,8 @@

{% trans "Overzicht van het takenonderzoek" %}

{% trans "Revisie/amendement" %} - {% get_verbose_field_name "tasks" "session" "tasks_duration" session.net_duration %} + {% comment %} Hardcoded this, to get over an annoying error {% endcomment %} + {% get_verbose_field_name "tasks" "session" "tasks_duration" 45 %} {{ p_session.tasks_duration }} {{ session.tasks_duration }} diff --git a/proposals/templates/proposals/new_proposal_diff.html b/proposals/templates/proposals/new_proposal_diff.html index e5fee7cad..08e36f84a 100644 --- a/proposals/templates/proposals/new_proposal_diff.html +++ b/proposals/templates/proposals/new_proposal_diff.html @@ -48,76 +48,29 @@

{% trans "Overzicht van wijzigingen" %}

{% with p_proposal=proposal.parent %} {% include general %} - - {% with wmo=proposal.wmo %} - {% with p_wmo=p_proposal.wmo %} -

{% trans "Ethische toetsing nodig door een Medische Ethische Toetsingscommissie (METC)?" %}

- - - - - - - - - - - - {% if wmo.metc == 'Y' or p_wmo.metc == 'Y' %} - - - - - - - - - - - {% else %} - - - - - - {% endif %} -
{% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
{% get_verbose_field_name "proposals" "wmo" "metc" %}{{ p_wmo.get_metc_display }}{{ wmo.get_metc_display }}
{% get_verbose_field_name "proposals" "wmo" "metc_details" %}{{ p_wmo.metc_details }}{{ wmo.metc_details }}
{% get_verbose_field_name "proposals" "wmo" "metc_institution" %}{{ p_wmo.metc_institution }}{{ wmo.metc_institution }}
{% get_verbose_field_name "proposals" "wmo" "is_medical" %}{{ p_wmo.get_is_medical_display }}{{ wmo.get_is_medical_display }}
- {% if wmo.status != wmo.NO_WMO or p_wmo.status != p_wmo.NO_WMO %} -

{% trans "Aanmelding bij de METC" %}

- - - - - - - - - - - - - - - - - - - {% if p_wmo.metc_decision_pdf %} - - {% endif %} - {% if wmo.metc_decision_pdf %} - - {% endif %} - -
{% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
{% get_verbose_field_name "proposals" "wmo" "metc_application" %}{{ p_wmo.metc_application|yesno:_("ja,nee") }}{{ wmo.metc_application|yesno:_("ja,nee") }}
{% get_verbose_field_name "proposals" "wmo" "metc_decision" %}{{ p_wmo.metc_decision|yesno:_("ja,nee") }}{{ wmo.metc_decision|yesno:_("ja,nee") }}
{% get_verbose_field_name "proposals" "wmo" "metc_decision_pdf" %}{% trans "Download" %}{% trans "Download" %}
- {% endif %} - {% endwith %} - {% endwith %} + {% include wmo %} + + {% if metc %} + {% include metc %} + {% endif %} + + {% include trajectories %} -

{% trans "Eén of meerdere trajecten?" %}

+ {% if studies %} + {% for study in studies %} + {% for study_section in study %} + {% include study_section %} + {% endfor %} + {% endfor %} + + {% if dmp_file %} + {% include dmp_file %} + {% endif %} + + {% include embargo %} + +

{% trans "Eventuele opmerkingen" %}

@@ -125,47 +78,11 @@

{% trans "Eén of meerdere trajecten?" %}

- - - + + + - {% if not proposal.studies_similar or not p_proposal.studies_similar %} - - - - - - {% endif %}
{% trans "Revisie/amendement" %}
{% get_verbose_field_name "proposals" "proposal" "studies_similar" %}{{ p_proposal.studies_similar|yesno:_("ja,nee") }}{{ proposal.studies_similar|yesno:_("ja,nee") }}{% get_verbose_field_name "proposals" "proposal" "comments" %}{{ p_proposal.comments }}{{ proposal.comments }}
{% get_verbose_field_name "proposals" "proposal" "studies_number" %}{{ p_proposal.studies_number }}{{ proposal.studies_number }}
- - {% if proposal.wmo.status == proposal.wmo.NO_WMO or proposal.wmo.status == proposal.wmo.JUDGED %} - {% include 'proposals/diff/study.html' %} - -

{% trans "Concept-aanmelding versturen" %}

- - - - - - - - - - - - {% if proposal.embargo or p_proposal.embargo %} - - - - - - {% endif %} - - - - - -
{% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
{% get_verbose_field_name "proposals" "proposal" "embargo" %}{{ p_proposal.embargo|yesno:_("ja,nee") }}{{ proposal.embargo|yesno:_("ja,nee") }}
{% get_verbose_field_name "proposals" "proposal" "embargo_end_date" %}{{ p_proposal.embargo_end_date }}{{ proposal.embargo_end_date }}
{% get_verbose_field_name "proposals" "proposal" "comments" %}{{ p_proposal.comments }}{{ proposal.comments }}
{% endif %} {% endwith %} diff --git a/proposals/templates/proposals/pdf/diff_table_with_header.html b/proposals/templates/proposals/pdf/diff_table_with_header.html index 6c7c0b787..1f1d154e9 100644 --- a/proposals/templates/proposals/pdf/diff_table_with_header.html +++ b/proposals/templates/proposals/pdf/diff_table_with_header.html @@ -1,9 +1,5 @@ -{% load i18n %} -{% load proposal_filters %} -{% load static %} -{% load uil_filters %} -{% load get_field_name %} {% load diff_tags %} +{% load i18n %} {% if section_title %}

{{ section_title }}

@@ -17,17 +13,41 @@

{{ study_title }}

{% trans "Originele aanvraag" %} {% trans "Revisie/amendement" %} -{% for row in rows %} - -{{ row.verbose_name }}{{ row.value }}{{row.value_2}} - -{% endfor %} - - -

{% trans "Algemene informatie over de aanvraag" %}

- +{% if warning and missing_object == 0 %} - - - - \ No newline at end of file + + + + + {%for row in rows|slice:"1:"%} + + + {% endfor %} +{% elif warning and missing_object == 1 %} + + + + + + {%for row in rows|slice:"1:"%} + + + {% endfor %} +{% else %} + {% for row in rows %} + + + + {% endfor %} +{% endif %} +
{% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
{{ rows.0.verbose_name }} +
+ {{ warning }} +
+
{{rows.0.value_2}}
{{row.verbose_name}}{{row.value_2}} +
{{ rows.0.verbose_name }}{{rows.0.value}} +
+ {{ warning }} +
+
{{row.verbose_name}}{{row.value}} +
{{ row.verbose_name }}{{ row.value }}{{row.value_2}}
\ No newline at end of file diff --git a/proposals/templates/proposals/pdf/single_object_diff_table.html b/proposals/templates/proposals/pdf/single_object_diff_table.html new file mode 100644 index 000000000..dfbb1728b --- /dev/null +++ b/proposals/templates/proposals/pdf/single_object_diff_table.html @@ -0,0 +1,23 @@ +{% load diff_tags %} + + +{% if section_title %} +

{{ section_title }}

+{% endif %} +{% if study_title %} +

{{ study_title }}

+{% endif %} +
+ {{ warning }} +
+ + + + + +{% for row in rows %} + + + +{% endfor %} +
{{ diff_answer_header }}
{{ row.verbose_name }}{{ row.value }}
\ No newline at end of file diff --git a/proposals/templates/proposals/proposal_pdf.html b/proposals/templates/proposals/proposal_pdf.html index 1dbbd27b0..eed9d45bc 100644 --- a/proposals/templates/proposals/proposal_pdf.html +++ b/proposals/templates/proposals/proposal_pdf.html @@ -79,7 +79,9 @@

{% trans 'Indiener' %}

{% trans 'E-mail' %}{{ proposal.created_by.email }} + {% include general %} +

{% get_verbose_field_name "proposals" "proposal" "summary" %}

{{ proposal.summary|linebreaks }}

@@ -91,321 +93,30 @@

{% get_verbose_field_name "proposals" "proposal" "summary" %}

{% include trajectories %} - {% if proposal.wmo.status == proposal.wmo.NO_WMO %} - {% for study in proposal.study_set.all %} -

{% trans "De deelnemers" %}

- {% include "studies/study_title.html" %} - - - - - {% if study|has_adults %} - - - - {% if study.legally_incapable %} - - - - {% endif %} - {% endif %} - - - - {% if study.has_special_details %} - - - - {% if study.special_details.all|medical_traits %} - - - - {% if study.traits.all|needs_details %} - - - - {% endif %} - {% endif %} - {% endif %} - {% if study|necessity_required %} - - - - - - - {% endif %} - - - - {% if study.recruitment.all|needs_details %} - - - - {% endif %} - - - - {% if study.compensation.needs_details %} - - - - {% endif %} - - - - {% if study.hierarchy %} - - - - {% endif %} -
{% get_verbose_field_name "studies" "study" "age_groups" %}{{ study.age_groups.all|unordered_list }}
{% get_verbose_field_name "studies" "study" "legally_incapable" %}{{ study.legally_incapable|yesno:_("ja,nee") }}
{% get_verbose_field_name "studies" "study" "legally_incapable_details" %}{{ study.legally_incapable_details }}
{% get_verbose_field_name "studies" "study" "has_special_details" %}{{ study.has_special_details|yesno:_("ja,nee") }}
{% get_verbose_field_name "studies" "study" "special_details" %}{{ study.special_details.all|unordered_list }}
{% get_verbose_field_name "studies" "study" "traits" %}{{ study.traits.all|unordered_list }}
{% get_verbose_field_name "studies" "study" "traits_details" %}{{ study.traits_details }}
{% get_verbose_field_name "studies" "study" "necessity" %}{{ study.get_necessity_display }}
{% get_verbose_field_name "studies" "study" "necessity_reason" %}{{ study.necessity_reason }}
{% get_verbose_field_name "studies" "study" "recruitment" %}{{ study.recruitment.all|unordered_list }}
{% get_verbose_field_name "studies" "study" "recruitment_details" %}{{ study.recruitment_details }}
{% get_verbose_field_name "studies" "study" "compensation" %}{{ study.compensation }}
{% get_verbose_field_name "studies" "study" "compensation_details" %}{{ study.compensation_details }}
{% get_verbose_field_name "studies" "study" "hierarchy" %}{{ study.hierarchy|yesno:_("ja,nee") }}
{% get_verbose_field_name "studies" "study" "hierarchy_details" %}{{ study.hierarchy_details }}
- - {% if study.has_intervention %} - {% with intervention=study.intervention %} -

{% trans "Het interventieonderzoek" %}

- {% include "studies/study_title.html" %} - {% if intervention.version == 1 %} - {% include 'proposals/pdf/intervention_v1.html' %} - {% elif intervention.version == 2 %} - {% include 'proposals/pdf/intervention_v2.html' %} - {% endif %} - {% endwith %} - {% endif %} - - {% if study.has_observation %} - {% with observation=study.observation %} -

{% trans "Het observatieonderzoek" %}

- {% include "studies/study_title.html" %} - {% if observation.version == 1 %} - {% include 'proposals/pdf/observation_v1.html' %} - {% elif observation.version == 2 %} - {% include 'proposals/pdf/observation_v2.html' %} - {% endif %} - {% endwith %} - {% endif %} - - {% if study.has_sessions %} -

{% trans "Het takenonderzoek en interviews" %}

- {% include "studies/study_title.html" %} - - - - -
{% get_verbose_field_name "studies" "study" "sessions_number" %}{{ study.sessions_number }}
- - {% for session in study.session_set.all %} - {% include "tasks/session_title.html" %} - - - - - {% if session.setting.all|needs_details %} - - - - {% endif %} - {% if study.has_children and session.setting.all|needs_details:"needs_supervision" %} - - - - {% if not session.supervision %} - - - - {% endif %} - {% endif %} - - - -
{% get_verbose_field_name "tasks" "session" "setting" %}{{ session.setting.all|unordered_list }}
{% get_verbose_field_name "tasks" "session" "setting_details" %}{{ session.setting_details }}
{% get_verbose_field_name "tasks" "session" "supervision" %}{{ session.supervision|yesno:_("ja,nee") }}
{% get_verbose_field_name "tasks" "session" "leader_has_coc" %}{{ session.leader_has_coc|yesno:_("ja,nee") }}
{% get_verbose_field_name "tasks" "session" "tasks_number" %}{{ session.tasks_number }}
- {% for task in session.task_set.all %} - {% include "tasks/task_title.html" %} - - - - - - - - - - - {% if task.registrations.all|needs_details %} - - - - {% endif %} - {% if task.registrations.all|needs_details:"needs_kind" %} - - - - {% if task.registration_kinds.all|needs_details %} - - - - {% endif %} - {% endif %} - - - - {% if task.feedback %} - - - - {% endif %} -
{% get_verbose_field_name "tasks" "task" "name" %}{{ task.name }}
{% get_verbose_field_name "tasks" "task" "duration" %}{{ task.duration }}
{% get_verbose_field_name "tasks" "task" "registrations" %}{{ task.registrations.all|unordered_list }}
{% get_verbose_field_name "tasks" "task" "registrations_details" %}{{ task.registrations_details }}
{% get_verbose_field_name "tasks" "task" "registration_kinds" %}{{ task.registration_kinds.all|unordered_list }}
{% get_verbose_field_name "tasks" "task" "registration_kinds_details" %}{{ task.registration_kinds_details }}
{% get_verbose_field_name "tasks" "task" "feedback" %}{{ task.feedback|yesno:_("ja,nee") }}
{% get_verbose_field_name "tasks" "task" "feedback_details" %}{{ task.feedback_details }}
-

{% get_verbose_field_name "tasks" "task" "description" %}

-

{{ task.description|linebreaks }}

- {% endfor %} - -

{% trans "Overzicht van het takenonderzoek" %}

- - - - -
{% get_verbose_field_name "tasks" "session" "tasks_duration" session.net_duration %}{{ session.tasks_duration }}
- - {% endfor %} - {% endif %} - -

{% trans "Overzicht en eigen beoordeling van het gehele onderzoek" %}

- {% include "studies/study_title.html" %} - - {% if study.has_sessions %} - - - - {% if study.deception == 'Y' or study.deception == '?' %} - - - - {% endif %} - {% endif %} - - - - {% if study.negativity == 'Y' or study.negativity == '?' %} - - - - {% endif %} - - - - {% if study.stressful == 'Y' or study.stressful == '?' %} - - - - {% endif %} - - - - {% if study.risk == 'Y' or study.risk == '?' %} - - - - {% endif %} -
{% get_verbose_field_name "studies" "study" "deception" %}{{ study.get_deception_display }}
{% get_verbose_field_name "studies" "study" "deception_details" %}{{ study.deception_details }}
{% get_verbose_field_name "studies" "study" "negativity" %}{{ study.get_negativity_display }}
{% get_verbose_field_name "studies" "study" "negativity_details" %}{{ study.negativity_details }}
{% get_verbose_field_name "studies" "study" "stressful" %}{{ study.get_stressful_display }}
{% get_verbose_field_name "studies" "study" "stressful_details" %}{{ study.stressful_details }}
{% get_verbose_field_name "studies" "study" "risk" %}{{ study.get_risk_display }}
{% get_verbose_field_name "studies" "study" "risk_details" %}{{ study.risk_details }}
- -

{% trans "Informed consent formulieren" %}

- {% include "studies/study_title.html" %} - {% get_study_documents study_documents study %} - - - - - {% if proposal.translated_forms %} - - - - {% endif %} - {% if not proposal.is_practice and study_documents.informed_consent %} - - - - - - - {% endif %} - {% if study.passive_consent is not None %} - - - - {% if study.passive_consent %} - - - - {% endif %} - {% endif %} - {% if study_documents.director_consent_declaration %} - - - - {% endif %} - {% if study_documents.director_consent_information %} - - - - {% endif %} - {% if study_documents.parents_information %} - - - - {% endif %} -
{% get_verbose_field_name "proposals" "proposal" "translated_forms" %}{{ proposal.translated_forms|yesno:_("ja,nee") }}
{% get_verbose_field_name "proposals" "proposal" "translated_forms_languages" %}{{ proposal.translated_forms_languages }}
{% get_verbose_field_name "studies" "documents" "informed_consent" %}{% trans "Download" %}
{% get_verbose_field_name "studies" "documents" "briefing" %}{% trans "Download" %}
{% get_verbose_field_name "studies" "study" "passive_consent" %}{{ study.passive_consent|yesno:_("ja,nee") }}
{% get_verbose_field_name "studies" "study" "passive_consent_details" %}{{ study.passive_consent_details }}
{% get_verbose_field_name "studies" "documents" "director_consent_declaration" %}{% trans "Download" %}
{% get_verbose_field_name "studies" "documents" "director_consent_information" %}{% trans "Download" %}
{% get_verbose_field_name "studies" "documents" "parents_information" %}{% trans "Download" %}
+ {% if studies %} + {% for study in studies %} + {% for study_section in study %} + {% include study_section %} + {% endfor %} {% endfor %} - {% if documents.extra %} - {% counter extra_form_counter create 1 %} - {% for extra_documents in documents.extra %} -

{% trans 'Extra formulieren' %} {% counter extra_form_counter value %}

- {% counter extra_form_counter increment 1 %} - - {% if extra_documents.informed_consent %} - - - - {% endif %} - {% if extra_documents.briefing %} - - - - {% endif %} -
{% get_verbose_field_name "studies" "documents" "informed_consent" %}{% trans "Download" %}
{% get_verbose_field_name "studies" "documents" "briefing" %}{% trans "Download" %}
- {{ extra_form_counter.increment }} + {% if extra_documents %} + {% for document in extra_documents %} + {% include document %} {% endfor %} {% endif %} - {% if proposal.dmp_file %} -

{% trans "Data Management Plan" %}

- - - - - -
- {% get_verbose_field_name "proposals" "proposal" "dmp_file" %} - - - {% trans "Download" %} - -
+ + {% if dmp_file %} + {% include dmp_file %} {% endif %} -

{% trans "Aanmelding versturen" %}

- - - - - {%if proposal.embargo %} - - - - {% endif %} -
{% get_verbose_field_name "proposals" "proposal" "embargo" %}{{ proposal.embargo|yesno:_("ja,nee") }}
{% get_verbose_field_name "proposals" "proposal" "embargo_end_date" %}{{ proposal.date_start|default:_("onbekend") }}
+ + {% include embargo %} +

{% get_verbose_field_name "proposals" "proposal" "comments" %}

{{ proposal.comments }}

+ {% endif %} diff --git a/proposals/templatetags/diff_tags.py b/proposals/templatetags/diff_tags.py index 30ea8da32..c283f3b21 100644 --- a/proposals/templatetags/diff_tags.py +++ b/proposals/templatetags/diff_tags.py @@ -10,8 +10,15 @@ def zip_equalize_lists(a, b): A zip implementation which will not stop when reaching the end of the smallest list, but will append None's to the smaller list to fill the gap """ - a = list(a) - b = list(b) + try: + a = list(a) + except TypeError: + a = [a] + try: + b = list(b) + except TypeError: + b = [b] + a_len = len(a) b_len = len(b) diff = abs(a_len - b_len) diff --git a/proposals/utils/pdf_diff_logic.py b/proposals/utils/pdf_diff_logic.py index 0f2fe96ba..61ac43969 100644 --- a/proposals/utils/pdf_diff_logic.py +++ b/proposals/utils/pdf_diff_logic.py @@ -21,7 +21,7 @@ class PDFSection: row_fields = None def __init__(self, object): - if type(object) == list: + if type(object) == tuple: self.object = object[0] self.object_2 = object[1] else: @@ -50,9 +50,10 @@ def make_rows(self): row_fields_both = list(set(row_fields_1) | set(row_fields_2)) #The merging above messes with the order, so I reorder it here - ordered_row_fields = [row for row in self.row_fields if row in row_fields_both] + row_fields = [row for row in self.row_fields if row in row_fields_both] + - rows = [RowClass(self.object, field, self.object_2) for field in ordered_row_fields] + rows = [RowClass(self.object, field, self.object_2) for field in row_fields] else: row_fields = self.get_row_fields(self.object) @@ -416,6 +417,59 @@ def render(self, context): } ) return super().render(context) + +class DiffSectionPossibleMissingObjects(PDFSection): + '''This exists for instances of tables in the diff, where it is possible + for objects to be entirely missing from one version or the other. + Mostly used for studies and sub-sections of studies''' + + def __init__(self, objects_list): + '''The None object always needs to become object_2.''' + if objects_list[0] is None: + self.warning = _( + "Dit onderdeel is nieuw in de revisie en bestond niet in de originele aanvraag." + ) + self.missing_object = 0 + elif objects_list[1] is None: + self.warning = _( + "Dit onderdeel bestond in de originele aanvraag, maar niet meer in de revisie." + ) + self.missing_object = 1 + else: + self.warning = None + self.missing_object = None + self.object = objects_list[0] + self.object_2 = objects_list[1] + + def render(self, context): + context = context.flatten() + template = get_template("proposals/pdf/diff_table_with_header.html") + + if self.warning and self.missing_object: + context.update( + { + "warning": self.warning, + "missing_object": self.missing_object + } + ) + context.update( + { + "section_title": self.section_title, + "rows": self.make_rows(), + } + ) + return template.render(context) + +class StudySectionDiff(DiffSectionPossibleMissingObjects, StudySection): + + def render(self,context): + if self.object.proposal.studies_number > 1: + context.update( + { + 'study_title': super().get_study_title(self.object) + } + ) + return super().render(context) class InterventionSection(PDFSection): '''This class will receive a intervention object''' @@ -476,6 +530,17 @@ def render(self, context): ) return super().render(context) +class InterventionSectionDiff(DiffSectionPossibleMissingObjects, InterventionSection): + + def render(self, context): + if self.object.study.proposal.studies_number > 1: + context.update( + { + 'study_title': super().get_study_title(self.object.study) + } + ) + return super().render(context) + class ObservationSection(InterventionSection): '''Gets passed an observation object''' section_title = _('Het observatieonderzoek') @@ -557,8 +622,11 @@ def get_row_fields(self, obj): rows.remove('registrations_details') return rows + +class ObservationSectionDiff(InterventionSectionDiff, ObservationSection): + pass -class SessionsSection(StudySection): +class SessionsOverviewSection(StudySection): '''Gets passed a study object This Section looks maybe a bit unnecessary, but it does remove some logic, plus the study_title.html from the template.''' @@ -567,9 +635,11 @@ class SessionsSection(StudySection): row_fields = ['sessions_number'] +class SessionsSectionDiff(StudySectionDiff, SessionsOverviewSection): + def get_row_fields(self, obj): return self.row_fields - + class SessionSection(PDFSection): '''Gets passed a session object''' @@ -602,6 +672,16 @@ def render(self, context): } ) return super().render(context) + +class SessionSectionDiff(DiffSectionPossibleMissingObjects, SessionSection): + + def render(self, context): + context.update( + { + 'study_title': super().get_session_title(self.object) + } + ) + return super().render(context) class TaskSection(PDFSection): '''Gets passed a task object''' @@ -642,6 +722,16 @@ def render(self, context): ) return super().render(context) +class TaskSectionDiff(DiffSectionPossibleMissingObjects, TaskSection): + + def render(self, context): + context.update( + { + 'study_title': super().get_task_title(self.object) + } + ) + return super().render(context) + class TasksOverviewSection(PDFSection): '''Gets passed a session object This might be unecessary ... Maybe just use the existing template language ... @@ -653,8 +743,16 @@ class TasksOverviewSection(PDFSection): ] def render(self, context): - '''Here I am just overriding the render function, to get the correct formatting - The naming is a bit confusing, might fix later''' + context.update( + { + 'study_title': _('Overzicht van het takenonderzoek') + } + ) + return super().render(context) + +class TasksOverviewSectionDiff(DiffSectionPossibleMissingObjects, TaskSection): + + def render(self, context): context.update( { 'study_title': _('Overzicht van het takenonderzoek') @@ -693,6 +791,9 @@ def get_row_fields(self, obj): rows.remove('deception') return rows + +class StudyOverviewSectionDiff(StudySectionDiff, StudyOverviewSection): + pass class InformedConsentFormsSection(InterventionSection): '''Receives a Documents object''' @@ -714,7 +815,6 @@ class InformedConsentFormsSection(InterventionSection): def make_rows(self): '''A few fields here need to access different objects, therefore this complex overriding of the make_rows function ... :( ''' - proposal_list = ['translated_forms', 'translated_forms_languages'] study_list = ['passive_consent', 'passive_consent_details'] if self.object_2: @@ -730,7 +830,7 @@ def make_rows(self): for field in ordered_row_fields: if field in proposal_list: rows.append(RowClass(self.object.proposal, field, self.object_2.proposal)) - if field in study_list: + elif field in study_list: rows.append(RowClass(self.object.study, field, self.object_2.study)) else: rows.append(RowClass(self.object, field, self.object_2)) @@ -771,6 +871,9 @@ def get_row_fields(self, obj): return rows +class InformedConsentSectionDiff(InterventionSectionDiff, InformedConsentFormsSection): + pass + class ExtraDocumentsSection(PDFSection): '''gets a documents object''' @@ -818,17 +921,25 @@ def get_row_fields(self, obj): rows.remove('embargo_end_date') return rows - -def create_context_pdf_diff(context, model): + +def get_extra_documents(object): + pass + +def create_context_pdf(context, model): from studies.models import Documents context['general'] = GeneralSection(model) context['wmo'] = WMOSection(model.wmo) + if model.wmo.status != model.wmo.NO_WMO: context['metc'] = METCSection(model.wmo) + context['trajectories'] = TrajectoriesSection(model) + if model.wmo.status == model.wmo.NO_WMO: + context['studies'] = [] + for study in model.study_set.all(): study_sections = [] study_sections.append(StudySection(study)) @@ -837,7 +948,7 @@ def create_context_pdf_diff(context, model): if study.has_observation: study_sections.append(ObservationSection(study.observation)) if study.has_sessions: - study_sections.append(SessionsSection(study)) + study_sections.append(SessionsOverviewSection(study)) for session in study.session_set.all(): study_sections.append(SessionSection(session)) for task in session.task_set.all(): @@ -846,18 +957,97 @@ def create_context_pdf_diff(context, model): study_sections.append(StudyOverviewSection(study)) study_sections.append(InformedConsentFormsSection(study.documents)) context['studies'].append(study_sections) + extra_documents = [] + for count, document in enumerate(Documents.objects.filter( proposal = model, study__isnull = True )): extra_documents.append(ExtraDocumentsSection(document, count+1)) + if extra_documents: context['extra_documents'] = extra_documents if model.dmp_file: context['dmp_file'] = DMPFileSection(model) + context['embargo'] = EmbargoSection(model) return context + +from proposals.templatetags.diff_tags import zip_equalize_lists + +def create_context_diff(context, models): + p_proposal = models[0] + proposal = models[1] + + context['general'] = GeneralSection(models) + context['wmo'] = WMOSection((p_proposal.wmo, proposal.wmo)) + + if proposal.wmo.status != proposal.wmo.NO_WMO or p_proposal.wmo.status != p_proposal.wmo.NO_WMO: + context['metc'] = METCSection((p_proposal.wmo, proposal.wmo)) + + context['trajectories'] = TrajectoriesSection(models) + + if proposal.wmo.status == proposal.wmo.NO_WMO or proposal.wmo.status == proposal.wmo.JUDGED: + + context['studies'] = [] + + for diff_studies in zip_equalize_lists(p_proposal.study_set.all(), proposal.study_set.all()): + + p_study = diff_studies[0] + study = diff_studies[1] + + study_sections = [] + study_sections.append(StudySectionDiff((diff_studies))) + + if p_study is not None and p_study.has_intervention or \ + study is not None and study.has_intervention: + interventions = tuple((study.intervention if study is not None \ + else study for study in diff_studies)) + study_sections.append(InterventionSectionDiff(interventions)) + if p_study is not None and p_study.has_observation or \ + study is not None and study.has_observation: + observations = tuple((study.observation if study is not None \ + else study for study in diff_studies)) + study_sections.append(ObservationSectionDiff(observations)) + if p_study is not None and p_study.has_sessions or \ + study is not None and study.has_sessions: + study_sections.append(SessionsSectionDiff(diff_studies)) + p_sessions_set, sessions_set = tuple((study.session_set.all() if study is not None \ + else study for study in diff_studies)) + for diff_sessions in zip_equalize_lists(p_sessions_set, sessions_set): + p_sessions = diff_sessions[0] + sessions = diff_sessions[1] + study_sections.append(SessionSectionDiff(diff_sessions)) + p_tasks_set, tasks_set = tuple((session.task_set.all() if session is not None \ + else session for session in diff_sessions)) + for diff_tasks in zip_equalize_lists(p_tasks_set, tasks_set): + study_sections.append(TaskSectionDiff(diff_tasks)) + study_sections.append(TasksOverviewSection(diff_sessions)) + study_sections.append(StudyOverviewSectionDiff(diff_studies)) + documents = tuple(study.documents if study is not None \ + else study for study in diff_studies) + study_sections.append(InformedConsentSectionDiff(documents)) + context['studies'].append(study_sections) + + extra_documents = [] + + # for count, document in enumerate(Documents.objects.filter( + # proposal = models, + # study__isnull = True + # )): + # extra_documents.append(ExtraDocumentsSection(document, count+1)) + + # if extra_documents: + # context['extra_documents'] = extra_documents + if p_proposal.dmp_file or proposal.dmp_file: + context['dmp_file'] = DMPFileSection(models) + + context['embargo'] = EmbargoSection(models) + + return context + + diff --git a/proposals/views/proposal_views.py b/proposals/views/proposal_views.py index c7707a36c..7760a9dc0 100644 --- a/proposals/views/proposal_views.py +++ b/proposals/views/proposal_views.py @@ -552,43 +552,9 @@ class ProposalAsPdf(LoginRequiredMixin, PDFTemplateResponseMixin, def get_context_data(self, **kwargs): """Adds 'BASE_URL' to template context""" - context = super(ProposalAsPdf, self).get_context_data(**kwargs) - - context['general'] = GeneralSection(self.object) - context['wmo'] = WMOSection(self.object.wmo) - if self.object.wmo.status != self.object.wmo.NO_WMO: - context['metc'] = METCSection(self.object.wmo) - context['trajectories'] = TrajectoriesSection(self.object) - if self.object.wmo.status == self.object.wmo.NO_WMO: - context['studies'] = [] - for study in self.object.study_set.all(): - study_sections = [] - study_sections.append(StudySection(study)) - if study.has_intervention: - study_sections.append(InterventionSection(study.intervention)) - if study.has_observation: - study_sections.append(ObservationSection(study.observation)) - if study.has_sessions: - study_sections.append(SessionsSection(study)) - for session in study.session_set.all(): - study_sections.append(SessionSection(session)) - for task in session.task_set.all(): - study_sections.append(TaskSection(task)) - study_sections.append(TasksOverviewSection(session)) - study_sections.append(StudyOverviewSection(study)) - study_sections.append(InformedConsentFormsSection(study.documents)) - context['studies'].append(study_sections) - extra_documents = [] - for count, document in enumerate(Documents.objects.filter( - proposal = self.object, - study__isnull = True - )): - extra_documents.append(ExtraDocumentsSection(document, count+1)) - if extra_documents: - context['extra_documents'] = extra_documents - if self.object.dmp_file: - context['dmp_file'] = DMPFileSection(self.object) - context['embargo'] = EmbargoSection(self.object) + context = super().get_context_data(**kwargs) + + context = create_context_pdf(context, self.object) return context @@ -599,8 +565,17 @@ class ProposalDifference(LoginRequiredMixin, generic.DetailView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['general'] = GeneralSection(self.object.parent, self.object) + + context = create_context_diff(context, (self.object.parent, self.object)) + return context + + +# class ProposalDifference(LoginRequiredMixin, generic.DetailView): +# model = Proposal +# template_name = 'proposals/proposal_diff.html' + + class NewPDFViewTest(generic.TemplateView): @@ -610,7 +585,7 @@ def get_context_data(self, **kwargs): model = Proposal.objects.last() context = super().get_context_data(**kwargs) - context = create_context_pdf_diff(context, model) + context = create_context_pdf(context, model) return context From cffbf66566083402937ec1a41918f9246f684589 Mon Sep 17 00:00:00 2001 From: Edo Storm Date: Wed, 20 Sep 2023 16:14:47 +0200 Subject: [PATCH 24/52] Extra documents and documentation --- .../proposals/diff_table_with_header.html | 53 ++++ .../proposals/new_proposal_diff.html | 55 ++-- .../proposals/pdf/diff_table_with_header.html | 4 +- .../proposals/table_with_header.html | 13 + proposals/utils/pdf_diff_logic.py | 268 +++++++++++------- proposals/views/proposal_views.py | 22 -- 6 files changed, 271 insertions(+), 144 deletions(-) create mode 100644 proposals/templates/proposals/diff_table_with_header.html create mode 100644 proposals/templates/proposals/table_with_header.html diff --git a/proposals/templates/proposals/diff_table_with_header.html b/proposals/templates/proposals/diff_table_with_header.html new file mode 100644 index 000000000..46bcbea30 --- /dev/null +++ b/proposals/templates/proposals/diff_table_with_header.html @@ -0,0 +1,53 @@ +{% load diff_tags %} +{% load i18n %} + +{% if section_title %} +

{{ section_title }}

+{% endif %} +{% if study_title %} +

{{ study_title }}

+{% endif %} + + + + + + +{% if warning and missing_object == 0 %} + + + + + + {%for row in rows|slice:"1:"%} + + + {% endfor %} +{% elif warning and missing_object == 1 %} + + + + + + {%for row in rows|slice:"1:"%} + + + {% endfor %} +{% else %} + {% for row in rows %} + + + + {% endfor %} +{% endif %} +
{% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
{{ rows.0.verbose_name }} +
+ {{ warning }} +
+
{{rows.0.value}}
{{row.verbose_name}}{{row.value}} +
{{ rows.0.verbose_name }}{{rows.0.value}} +
+ {{ warning }} +
+
{{row.verbose_name}}{{row.value}} +
{{ row.verbose_name }}{{ row.value }}{{row.value_2}}
\ No newline at end of file diff --git a/proposals/templates/proposals/new_proposal_diff.html b/proposals/templates/proposals/new_proposal_diff.html index 08e36f84a..f7d1a3e15 100644 --- a/proposals/templates/proposals/new_proposal_diff.html +++ b/proposals/templates/proposals/new_proposal_diff.html @@ -45,7 +45,6 @@

{% trans "Overzicht van wijzigingen" %}

- {% with p_proposal=proposal.parent %} {% include general %} @@ -58,33 +57,39 @@

{% trans "Overzicht van wijzigingen" %}

{% include trajectories %} {% if studies %} - {% for study in studies %} - {% for study_section in study %} - {% include study_section %} - {% endfor %} - {% endfor %} + {% for study in studies %} + {% for study_section in study %} + {% include study_section %} + {% endfor %} + {% endfor %} - {% if dmp_file %} - {% include dmp_file %} - {% endif %} + {% if extra_documents %} + {% for document in extra_documents %} + {% include document %} + {% endfor %} + {% endif %} + + {% if dmp_file %} + {% include dmp_file %} + {% endif %} + + {% include embargo %} - {% include embargo %} - -

{% trans "Eventuele opmerkingen" %}

- - - - - - - - - - - -
{% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
{% get_verbose_field_name "proposals" "proposal" "comments" %}{{ p_proposal.comments }}{{ proposal.comments }}
+ +

{% trans "Eventuele opmerkingen" %}

+ + + + + + + + + + + +
{% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
{% get_verbose_field_name "proposals" "proposal" "comments" %}{{ p_proposal.comments }}{{ proposal.comments }}
{% endif %} - {% endwith %}

-

- - - -{% endblock %} diff --git a/proposals/templates/proposals/pdf/diff_table_with_header.html b/proposals/templates/proposals/pdf/diff_table_with_header.html deleted file mode 100644 index 46bcbea30..000000000 --- a/proposals/templates/proposals/pdf/diff_table_with_header.html +++ /dev/null @@ -1,53 +0,0 @@ -{% load diff_tags %} -{% load i18n %} - -{% if section_title %} -

{{ section_title }}

-{% endif %} -{% if study_title %} -

{{ study_title }}

-{% endif %} - - - - - - -{% if warning and missing_object == 0 %} - - - - - - {%for row in rows|slice:"1:"%} - - - {% endfor %} -{% elif warning and missing_object == 1 %} - - - - - - {%for row in rows|slice:"1:"%} - - - {% endfor %} -{% else %} - {% for row in rows %} - - - - {% endfor %} -{% endif %} -
{% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
{{ rows.0.verbose_name }} -
- {{ warning }} -
-
{{rows.0.value}}
{{row.verbose_name}}{{row.value}} -
{{ rows.0.verbose_name }}{{rows.0.value}} -
- {{ warning }} -
-
{{row.verbose_name}}{{row.value}} -
{{ row.verbose_name }}{{ row.value }}{{row.value_2}}
\ No newline at end of file diff --git a/proposals/templates/proposals/pdf/intervention_v1.html b/proposals/templates/proposals/pdf/intervention_v1.html deleted file mode 100644 index 462672fe3..000000000 --- a/proposals/templates/proposals/pdf/intervention_v1.html +++ /dev/null @@ -1,50 +0,0 @@ -{% load i18n %} -{% load proposal_filters %} -{% load get_field_name %} - - - - - - {% if intervention.setting.all|needs_details %} - - - - {% endif %} - {% if study.has_children and intervention.setting.all|needs_details:"needs_supervision" %} - - - - {% if not intervention.supervision %} - - - - {% endif %} - {% endif %} - - - - - - - - - - - - - - - - - - - - - - {% if intervention.has_controls %} - - - - {% endif %} -
{% get_verbose_field_name "interventions" "intervention" "setting" %}{{ intervention.setting.all|unordered_list }}
{% get_verbose_field_name "interventions" "intervention" "setting_details" %}{{ intervention.setting_details }}
{% get_verbose_field_name "interventions" "intervention" "supervision" %}{{ intervention.supervision|yesno:_("ja,nee") }}
{% get_verbose_field_name "interventions" "intervention" "leader_has_coc" %}{{ intervention.leader_has_coc|yesno:_("ja,nee") }}
{% get_verbose_field_name "interventions" "intervention" "period" %}{{ intervention.period }}
{% get_verbose_field_name "interventions" "intervention" "amount_per_week" %}{{ intervention.amount_per_week }}
{% get_verbose_field_name "interventions" "intervention" "duration" %}{{ intervention.duration }}
{% get_verbose_field_name "interventions" "intervention" "measurement" %}{{ intervention.measurement }}
{% get_verbose_field_name "interventions" "intervention" "experimenter" %}{{ intervention.experimenter }}
{% get_verbose_field_name "interventions" "intervention" "description" %}{{ intervention.description }}
{% get_verbose_field_name "interventions" "intervention" "has_controls" %}{{ intervention.has_controls|yesno:_("ja,nee") }}
{% get_verbose_field_name "interventions" "intervention" "controls_description" %}{{ intervention.controls_description }}
\ No newline at end of file diff --git a/proposals/templates/proposals/pdf/intervention_v2.html b/proposals/templates/proposals/pdf/intervention_v2.html deleted file mode 100644 index d5552ab83..000000000 --- a/proposals/templates/proposals/pdf/intervention_v2.html +++ /dev/null @@ -1,60 +0,0 @@ -{% load i18n %} -{% load proposal_filters %} -{% load get_field_name %} - - - - - - {% if intervention.setting.all|needs_details %} - - - - {% endif %} - {% if study.has_children and intervention.setting.all|needs_details:"needs_supervision" %} - - - - {% if not intervention.supervision %} - - - - {% endif %} - {% endif %} - - - - - - - {% if intervention.multiple_sessions %} - - - - {% endif %} - - - - - - - - - - - - - - - - {% if intervention.has_controls %} - - - - {% endif %} - {% if not intervention.settings_contains_schools %} - - - - {% endif %} -
{% get_verbose_field_name "interventions" "intervention" "setting" %}{{ intervention.setting.all|unordered_list }}
{% get_verbose_field_name "interventions" "intervention" "setting_details" %}{{ intervention.setting_details }}
{% get_verbose_field_name "interventions" "intervention" "supervision" %}{{ intervention.supervision|yesno:_("ja,nee") }}
{% get_verbose_field_name "interventions" "intervention" "leader_has_coc" %}{{ intervention.leader_has_coc|yesno:_("ja,nee") }}
{% get_verbose_field_name "interventions" "intervention" "period" %}{{ intervention.period }}
{% get_verbose_field_name "interventions" "intervention" "multiple_sessions" %}{{ intervention.multiple_sessions|yesno:_("ja,nee") }}
{% get_verbose_field_name "interventions" "intervention" "session_frequency" %}{{ intervention.session_frequency }}
{% get_verbose_field_name "interventions" "intervention" "duration" %}{{ intervention.duration }}
{% get_verbose_field_name "interventions" "intervention" "measurement" %}{{ intervention.measurement }}
{% get_verbose_field_name "interventions" "intervention" "experimenter" %}{{ intervention.experimenter }}
{% get_verbose_field_name "interventions" "intervention" "description" %}{{ intervention.description }}
{% get_verbose_field_name "interventions" "intervention" "has_controls" %}{{ intervention.has_controls|yesno:_("ja,nee") }}
{% get_verbose_field_name "interventions" "intervention" "controls_description" %}{{ intervention.controls_description }}
{% get_verbose_field_name "interventions" "intervention" "extra_task" %}{{ intervention.extra_task|yesno:_("ja,nee") }}
\ No newline at end of file diff --git a/proposals/templates/proposals/pdf/new_pdf_test.html b/proposals/templates/proposals/pdf/new_pdf_test.html deleted file mode 100644 index deaa433ad..000000000 --- a/proposals/templates/proposals/pdf/new_pdf_test.html +++ /dev/null @@ -1,83 +0,0 @@ -{% extends "base/base.html" %} - -{% load static %} -{% load proposal_filters %} -{% load fetc_filters %} -{% load i18n %} -{% load compare_tags %} -{% load uil_filters %} - -{% block header_title %} - New PDF test -{% endblock %} - -{% block content %} - - {% include general %} - {% include wmo %} - - {% if metc %} - {% include metc %} - {% endif %} - - {% include trajectories %} - - {% if studies %} - {% for study in studies %} - {% for study_section in study %} - {% include study_section %} - {% endfor %} - {% endfor %} - {% endif %} - - {% if extra_documents %} - {% for document in extra_documents %} - {% include document %} - {% endfor %} - {% endif %} - - {% if dmp_file %} - {% include dmp_file %} - {% endif %} - - {% if embargo %} - {% include embargo %} - {% endif %} - - {% comment %} Code to copy into pdf file - -

{% get_verbose_field_name "proposals" "proposal" "summary" %}

-

{{ proposal.summary|linebreaks }}

- - {% include wmo %} - - {% if metc %} - {% include metc %} - {% endif %} - - {% include trajectories %} - - {% if studies %} - {% for study in studies %} - {% for study_section in study %} - {% include study_section %} - {% endfor %} - {% endfor %} - {% endif %} - - {% if dmp_file %} - {% include dmp_file %} - {% endif %} - - {% if dmp_file %} - {% include dmp_file %} - {% endif %} - - {% include embargo %} - -

{% get_verbose_field_name "proposals" "proposal" "comments" %}

-

- {{ proposal.comments }} -

{% endcomment %} - -{% endblock %} \ No newline at end of file diff --git a/proposals/templates/proposals/pdf/observation_v1.html b/proposals/templates/proposals/pdf/observation_v1.html deleted file mode 100644 index b1eaca1bb..000000000 --- a/proposals/templates/proposals/pdf/observation_v1.html +++ /dev/null @@ -1,65 +0,0 @@ -{% load i18n %} -{% load proposal_filters %} -{% load get_field_name %} - - - - - - {% if observation.setting.all|needs_details %} - - - - {% endif %} - {% if study.has_children and observation.setting.all|needs_details:"needs_supervision" %} - - - - {% if not observation.supervision %} - - - - {% endif %} - {% endif %} - - - - - - - - - - - - - - - - {% if observation.is_nonpublic_space %} - - - - {% endif %} - - - - {% if observation.needs_approval %} - - - - {% if not proposal.is_practice %} - - - - {% endif %} - {% endif %} - - - - {% if observation.registrations.all|needs_details %} - - - - {% endif %} -
{% get_verbose_field_name "observations" "observation" "setting" %}{{ observation.setting.all|unordered_list }}
{% get_verbose_field_name "observations" "observation" "setting_details" %}{{ observation.setting_details }}
{% get_verbose_field_name "observations" "observation" "supervision" %}{{ observation.supervision|yesno:_("ja,nee") }}
{% get_verbose_field_name "observations" "observation" "leader_has_coc" %}{{ observation.leader_has_coc|yesno:_("ja,nee") }}
{% get_verbose_field_name "observations" "observation" "days" %}{{ observation.days }}
{% get_verbose_field_name "observations" "observation" "mean_hours" %}{{ observation.mean_hours }}
{% get_verbose_field_name "observations" "observation" "is_anonymous" %}{{ observation.is_anonymous|yesno:_("ja,nee") }}
{% get_verbose_field_name "observations" "observation" "is_in_target_group" %}{{ observation.is_in_target_group|yesno:_("ja,nee") }}
{% get_verbose_field_name "observations" "observation" "is_nonpublic_space" %}{{ observation.is_nonpublic_space|yesno:_("ja,nee") }}
{% get_verbose_field_name "observations" "observation" "has_advanced_consent" %}{{ observation.has_advanced_consent|yesno:_("ja,nee") }}
{% get_verbose_field_name "observations" "observation" "needs_approval" %}{{ observation.needs_approval|yesno:_("ja,nee") }}
{% get_verbose_field_name "observations" "observation" "approval_institution" %}{{ observation.approval_institution }}
{% get_verbose_field_name "observations" "observation" "approval_document" %}{% trans "Download" %}
{% get_verbose_field_name "observations" "observation" "registrations" %}{{ observation.registrations.all|unordered_list }}
{% get_verbose_field_name "observations" "observation" "registrations_details" %}{{ observation.registrations_details }}
\ No newline at end of file diff --git a/proposals/templates/proposals/pdf/observation_v2.html b/proposals/templates/proposals/pdf/observation_v2.html deleted file mode 100644 index ab49cc4bd..000000000 --- a/proposals/templates/proposals/pdf/observation_v2.html +++ /dev/null @@ -1,83 +0,0 @@ -{% load i18n %} -{% load proposal_filters %} -{% load get_field_name %} - - - - - - {% if observation.setting.all|needs_details %} - - - - {% endif %} - {% if study.has_children and observation.setting.all|needs_details:"needs_supervision" %} - - - - {% if not observation.supervision %} - - - - {% endif %} - {% endif %} - - - - - - - - - - - - - {% if observation.is_anonymous %} - - - - {% endif %} - - - - {% if observation.is_in_target_group %} - - - - {% endif %} - - - - {% if observation.is_nonpublic_space %} - - - - - - - {% if not observation.has_advanced_consent %} - - - - {% endif %} - {% endif %} - {% if observation.setting.all|needs_details:"is_school" %} - - - - {% endif %} - {% if observation.needs_approval %} - - - - {% endif %} - - - - {% if observation.registrations.all|needs_details %} - - - - {% endif %} -
{% get_verbose_field_name "observations" "observation" "setting" %}{{ observation.setting.all|unordered_list }}
{% get_verbose_field_name "observations" "observation" "setting_details" %}{{ observation.setting_details }}
{% get_verbose_field_name "observations" "observation" "supervision" %}{{ observation.supervision|yesno:_("ja,nee") }}
{% get_verbose_field_name "observations" "observation" "leader_has_coc" %}{{ observation.leader_has_coc|yesno:_("ja,nee") }}
{% get_verbose_field_name "observations" "observation" "details_who"|safe %}{{ observation.details_who }}
{% get_verbose_field_name "observations" "observation" "details_why"|safe %}{{ observation.details_why }}
{% get_verbose_field_name "observations" "observation" "details_frequency"|safe %}{{ observation.details_frequency }}
{% get_verbose_field_name "observations" "observation" "is_anonymous" %}{{ observation.is_anonymous|yesno:_("ja,nee") }}
{% get_verbose_field_name "observations" "observation" "is_anonymous_details" %}{{ observation.is_anonymous_details }}
{% get_verbose_field_name "observations" "observation" "is_in_target_group" %}{{ observation.is_in_target_group|yesno:_("ja,nee") }}
{% get_verbose_field_name "observations" "observation" "is_in_target_group_details" %}{{ observation.is_in_target_group_details }}
{% get_verbose_field_name "observations" "observation" "is_nonpublic_space" %}{{ observation.is_nonpublic_space|yesno:_("ja,nee") }}
{% get_verbose_field_name "observations" "observation" "is_nonpublic_space_details" %}{{ observation.is_nonpublic_space_details }}
{% get_verbose_field_name "observations" "observation" "has_advanced_consent" %}{{ observation.has_advanced_consent|yesno:_("ja,nee") }}
{% get_verbose_field_name "observations" "observation" "has_advanced_consent_details" %}{{ observation.has_advanced_consent_details }}
{% get_verbose_field_name "observations" "observation" "needs_approval" %}{{ observation.needs_approval|yesno:_("ja,nee") }}
{% get_verbose_field_name "observations" "observation" "approval_institution" %}{{ observation.approval_institution }}
{% get_verbose_field_name "observations" "observation" "registrations" %}{{ observation.registrations.all|unordered_list }}
{% get_verbose_field_name "observations" "observation" "registrations_details" %}{{ observation.registrations_details }}
\ No newline at end of file diff --git a/proposals/templates/proposals/pdf/single_object_diff_table.html b/proposals/templates/proposals/pdf/single_object_diff_table.html deleted file mode 100644 index dfbb1728b..000000000 --- a/proposals/templates/proposals/pdf/single_object_diff_table.html +++ /dev/null @@ -1,23 +0,0 @@ -{% load diff_tags %} - - -{% if section_title %} -

{{ section_title }}

-{% endif %} -{% if study_title %} -

{{ study_title }}

-{% endif %} -
- {{ warning }} -
- - - - - -{% for row in rows %} - - - -{% endfor %} -
{{ diff_answer_header }}
{{ row.verbose_name }}{{ row.value }}
\ No newline at end of file diff --git a/proposals/templates/proposals/pdf/table_with_header.html b/proposals/templates/proposals/pdf/table_with_header.html deleted file mode 100644 index 6b491d820..000000000 --- a/proposals/templates/proposals/pdf/table_with_header.html +++ /dev/null @@ -1,13 +0,0 @@ -{% if section_title %} -

{{ section_title }}

-{% endif %} -{% if study_title %} -

{{ study_title }}

-{% endif %} - -{% for row in rows %} - - - -{% endfor %} -
{{ row.verbose_name }}{{ row.value }}
\ No newline at end of file diff --git a/proposals/templates/proposals/proposal_diff.html b/proposals/templates/proposals/proposal_diff.html index 10927ac2b..d994b8249 100644 --- a/proposals/templates/proposals/proposal_diff.html +++ b/proposals/templates/proposals/proposal_diff.html @@ -14,6 +14,10 @@ {% block html_head %}