Skip to content

Views

hypha.apply.projects.reports.views

Module for handling project reporting functionality in the Hypha application.

This module provides views and utilities for managing project reports, including creating, viewing, updating, and administering reports. It implements access control, form handling, and notification systems for the reporting workflow.

Dependencies: - Django (including django-filters, django-htmx, django-tables2) - Hypha application modules (activity, projects, stream_forms, users, utils)

ReportingMixin

Mixin that ensures a project has a report configuration.

If a project is in progress but doesn't have a report_config, this mixin creates one before proceeding with the view.

dispatch

dispatch(*args, **kwargs)

Ensure project has a report configuration if it's in progress.

Parameters:

  • *args –

    Variable length argument list.

  • **kwargs –

    Arbitrary keyword arguments.

Returns:

  • HttpResponse –

    The response from the parent class's dispatch method.

Source code in hypha/apply/projects/reports/views.py
def dispatch(self, *args, **kwargs):
    """
    Ensure project has a report configuration if it's in progress.

    Args:
        *args: Variable length argument list.
        **kwargs: Arbitrary keyword arguments.

    Returns:
        HttpResponse: The response from the parent class's dispatch method.
    """
    project = self.get_object()
    if project.is_in_progress:
        if not hasattr(project, "report_config"):
            ReportConfig.objects.create(project=project)

    return super().dispatch(*args, **kwargs)

ReportAccessMixin

Bases: UserPassesTestMixin

Mixin that controls access to report-related views.

Allows access to staff members, finance users, and the project owner.

model class-attribute instance-attribute

model = Report

permission_denied_message class-attribute instance-attribute

permission_denied_message = gettext('You do not have permission to access this report.')

test_func

test_func()

Test whether the current user has access to the report.

Returns:

  • bool –

    bool | None: True if user has permission to view the report, False otherwise.

Source code in hypha/apply/projects/reports/views.py
def test_func(self) -> bool:
    """
    Test whether the current user has access to the report.

    Returns:
        bool | None: True if user has permission to view the report, False otherwise.
    """
    return has_object_permission(
        "view_report", self.request.user, self.get_object()
    )

ReportDetailView

Bases: DetailView

View for displaying the details of a report.

model class-attribute instance-attribute

model = Report

template_name class-attribute instance-attribute

template_name = 'reports/report_detail.html'

permission_denied_message class-attribute instance-attribute

permission_denied_message = gettext('You do not have permission to access this report.')

dispatch

dispatch(*args, **kwargs)
Source code in hypha/apply/projects/reports/views.py
def dispatch(self, *args, **kwargs):
    report = self.get_object()
    if not has_object_permission("view_report", self.request.user, report):
        raise PermissionDenied(self.permission_denied_message)
    return super().dispatch(*args, **kwargs)

ReportUpdateView

Bases: BaseStreamForm, UpdateView

View for updating a report.

This view handles both creating new reports and editing existing ones. It supports draft saving and manages form field population from existing data.

model class-attribute instance-attribute

model = Report

object class-attribute instance-attribute

object = None

form_class class-attribute instance-attribute

form_class = None

form_fields class-attribute instance-attribute

form_fields = None

submission_form_class class-attribute instance-attribute

submission_form_class = ReportEditForm

template_name class-attribute instance-attribute

template_name = 'reports/report_form.html'

permission_denied_message class-attribute instance-attribute

permission_denied_message = gettext('You do not have permission to update this report.')

wagtail_reference_index_ignore class-attribute instance-attribute

wagtail_reference_index_ignore = True

dispatch

dispatch(request, *args, **kwargs)

Set up the report object and check permissions before proceeding.

Parameters:

  • request –

    The HttpRequest object.

  • *args –

    Variable length argument list.

  • **kwargs –

    Arbitrary keyword arguments.

Returns:

  • HttpResponse –

    The response from the parent class's dispatch method.

Raises:

  • PermissionDenied –

    If user doesn't have 'report_update' permission.

Source code in hypha/apply/projects/reports/views.py
def dispatch(self, request, *args, **kwargs):
    """
    Set up the report object and check permissions before proceeding.

    Args:
        request: The HttpRequest object.
        *args: Variable length argument list.
        **kwargs: Arbitrary keyword arguments.

    Returns:
        HttpResponse: The response from the parent class's dispatch method.

    Raises:
        PermissionDenied: If user doesn't have 'report_update' permission.
    """
    report = self.get_object()
    self.object = report
    if not has_object_permission("update_report", self.request.user, report):
        raise PermissionDenied(self.permission_denied_message)
    # super().dispatch calls get_context_data() which calls the rest to get the form fully ready for use.
    return super().dispatch(request, *args, **kwargs)

get_context_data

get_context_data(*args, **kwargs)

Prepare the context data for the template.

Django note: super().dispatch calls get_context_data.

Parameters:

  • *args –

    Variable length argument list.

  • **kwargs –

    Arbitrary keyword arguments.

Returns:

  • dict –

    The context data dictionary.

Source code in hypha/apply/projects/reports/views.py
def get_context_data(self, *args, **kwargs):
    """
    Prepare the context data for the template.

    Django note: super().dispatch calls get_context_data.

    Args:
        *args: Variable length argument list.
        **kwargs: Arbitrary keyword arguments.

    Returns:
        dict: The context data dictionary.
    """
    # Is this where we need to get the associated form fields? Not in the form itself but up here? Yes. But in a
    # roundabout way: get_form (here) gets fields and calls get_form_class (here) which calls get_form_fields
    # (super) which sets up the fields in the returned form.
    form = self.get_form()
    context_data = {
        "form": form,
        "object": self.object,
        "report_form": True
        if self.object.project.submission.page.specific.report_forms.first()
        else False,
        **kwargs,
    }
    return context_data

get_form

get_form(form_class=None, draft=False)

Return an instance of the form to be used in this view.

Handles setting up form fields based on the report configuration or previous data.

Parameters:

  • form_class –

    The form class to use, if not using the default.

  • draft –

    Boolean indicating if this is a draft form.

Returns:

  • Form –

    An instance of the form to be used.

Source code in hypha/apply/projects/reports/views.py
def get_form(self, form_class=None, draft=False):
    """
    Return an instance of the form to be used in this view.

    Handles setting up form fields based on the report configuration or previous data.

    Args:
        form_class: The form class to use, if not using the default.
        draft: Boolean indicating if this is a draft form.

    Returns:
        Form: An instance of the form to be used.
    """
    if self.object.current is None or self.object.form_fields is None:
        # Here is where we get the form_fields, the ProjectReportForm associated with the Fund:
        report_form = (
            self.object.project.submission.page.specific.report_forms.first()
        )
        if report_form:
            self.form_fields = report_form.form.form_fields
        else:
            self.form_fields = {}
    else:
        self.form_fields = self.object.form_fields

    if form_class is None:
        form_class = self.get_form_class(draft=draft)
    report_instance = form_class(**self.get_form_kwargs())
    return report_instance

get_initial

get_initial()

Get initial data for the form.

Populates the form with existing data from draft or current report version. Handles file fields specially to properly display them.

Returns:

  • dict –

    Initial data for the form.

Source code in hypha/apply/projects/reports/views.py
def get_initial(self):
    """
    Get initial data for the form.

    Populates the form with existing data from draft or current report version.
    Handles file fields specially to properly display them.

    Returns:
        dict: Initial data for the form.
    """
    initial = {}
    if self.object.draft:
        current = self.object.draft
    else:
        current = self.object.current

    # current here is a ReportVersion which should already have the data associated.
    if current:
        # The following allows existing data to populate the form. This code was inspired by (aka copied from)
        # ProjectFormEditView.get_paf_form_kwargs().
        initial = current.raw_data
        # Is the following needed to see the file in a friendly URL? Does not appear so. But needed to not blow up.
        for field_id in current.file_field_ids:
            initial.pop(field_id + "-uploads", False)
            initial[field_id] = get_placeholder_file(current.raw_data.get(field_id))

    return initial

get_form_kwargs

get_form_kwargs()

Get the keyword arguments for instantiating the form.

Adds the current user to the form kwargs.

Returns:

  • dict ( dict ) –

    The keyword arguments for the form.

Source code in hypha/apply/projects/reports/views.py
def get_form_kwargs(self) -> dict:
    """
    Get the keyword arguments for instantiating the form.

    Adds the current user to the form kwargs.

    Returns:
        dict: The keyword arguments for the form.
    """
    kwargs = super().get_form_kwargs()
    kwargs["user"] = self.request.user
    return kwargs

post

post(request, *args, **kwargs)

Handle POST requests: instantiate a form instance with the passed POST variables and then check if it's valid.

Handles saving drafts, form validation, and sending notifications.

Parameters:

  • request –

    The HttpRequest object.

  • *args –

    Variable length argument list.

  • **kwargs –

    Arbitrary keyword arguments.

Returns:

  • HttpResponse –

    Redirect to success URL or redisplay form if invalid.

Source code in hypha/apply/projects/reports/views.py
def post(self, request, *args, **kwargs):
    """
    Handle POST requests: instantiate a form instance with the passed
    POST variables and then check if it's valid.

    Handles saving drafts, form validation, and sending notifications.

    Args:
        request: The HttpRequest object.
        *args: Variable length argument list.
        **kwargs: Arbitrary keyword arguments.

    Returns:
        HttpResponse: Redirect to success URL or redisplay form if invalid.
    """
    save_draft = "save" in request.POST  # clicked on save button?
    form = self.get_form(draft=save_draft)
    if form.is_valid():
        form.save(form_fields=self.form_fields)
        form.delete_temporary_files()

        should_notify = True
        if self.object.draft:
            # It was a draft submission
            should_notify = False
        else:
            if self.object.submitted != self.object.current.submitted:
                # It was a staff edit - post submission
                should_notify = False

        if should_notify:
            messenger(
                MESSAGES.SUBMIT_REPORT,
                request=self.request,
                user=self.request.user,
                source=self.object.project,
                related=self.object,
            )
        response = HttpResponseRedirect(self.get_success_url())
    else:
        response = self.form_invalid(form)
    return response

get_success_url

get_success_url()
Source code in hypha/apply/projects/reports/views.py
def get_success_url(self) -> str:
    return self.object.project.get_absolute_url()

from_db classmethod

from_db(db, field_names, values)

Deserialize form data when loading from database.

Parameters:

  • db –

    Database connection

  • field_names –

    List of field names being loaded

  • values –

    Values for the fields

Returns:

  • –

    Instance with deserialized form data

Source code in hypha/apply/stream_forms/models.py
@classmethod
def from_db(cls, db, field_names, values):
    """Deserialize form data when loading from database.

    Args:
        db: Database connection
        field_names: List of field names being loaded
        values: Values for the fields

    Returns:
        Instance with deserialized form data
    """
    instance = super().from_db(db, field_names, values)
    if "form_data" in field_names:
        instance.form_data = cls.deserialize_form_data(
            instance, instance.form_data, instance.form_fields
        )
    return instance

deserialize_form_data classmethod

deserialize_form_data(instance, form_data, form_fields)

Convert stored form data back into Python objects.

Parameters:

  • instance –

    Form instance

  • form_data –

    Raw form data from database

  • form_fields –

    Form field definitions

Returns:

  • –

    Deserialized form data

Source code in hypha/apply/stream_forms/models.py
@classmethod
def deserialize_form_data(cls, instance, form_data, form_fields):
    """Convert stored form data back into Python objects.

    Args:
        instance: Form instance
        form_data: Raw form data from database
        form_fields: Form field definitions

    Returns:
        Deserialized form data
    """
    data = form_data.copy()
    # PERFORMANCE NOTE:
    # Do not attempt to iterate over form_fields - that will fully instantiate the form_fields
    # including any sub queries that they do
    for _i, field_data in enumerate(form_fields.raw_data):
        block = form_fields.stream_block.child_blocks[field_data["type"]]
        field_id = field_data.get("id")
        try:
            value = data[field_id]
        except KeyError:
            pass
        else:
            data[field_id] = block.decode(value)
    return data

get_defined_fields

get_defined_fields()

Get the form field definitions.

Returns:

  • –

    StreamField containing form field blocks

Raises:

  • AttributeError –

    If form_fields attribute is not defined on instance

Source code in hypha/apply/stream_forms/models.py
def get_defined_fields(self):
    """Get the form field definitions.

    Returns:
        StreamField containing form field blocks

    Raises:
        AttributeError: If form_fields attribute is not defined on instance
    """
    try:
        return self.form_fields  # type: ignore
    except AttributeError as err:
        raise AttributeError(
            "form_fields attribute not found. "
            "Make sure form_fields is defined on the implementing class."
        ) from err

get_form_fields

get_form_fields(draft=False, form_data=None, user=None)

Generate form fields with applied logic and grouping.

Parameters:

  • draft –

    Whether this is a draft form. When True, fields that are not marked as ApplicationMustIncludeFieldBlock will have their required flag set to False, allowing incomplete form submissions to be saved as drafts.

  • form_data –

    Existing form data

  • user –

    User completing the form

Returns:

  • –

    OrderedDict of form fields

Source code in hypha/apply/stream_forms/models.py
def get_form_fields(self, draft=False, form_data=None, user=None):
    """Generate form fields with applied logic and grouping.

    Args:
        draft: Whether this is a draft form. When True, fields that are not
              marked as ApplicationMustIncludeFieldBlock will have their
              required flag set to False, allowing incomplete form submissions
              to be saved as drafts.
        form_data: Existing form data
        user: User completing the form

    Returns:
        OrderedDict of form fields
    """
    if form_data is None:
        form_data = {}

    form_fields = OrderedDict()
    field_blocks = self.get_defined_fields()
    group_counter = 1
    is_in_group = False

    # If true option 1 is selected
    grouped_fields_visible = False
    for struct_child in field_blocks:
        block = struct_child.block
        struct_value = struct_child.value
        if isinstance(block, FormFieldBlock):
            field_from_block = block.get_field(struct_value)
            disabled_help_text = _(
                "You are logged in so this information is fetched from your user account."
            )
            if isinstance(block, FullNameBlock) and user and user.is_authenticated:
                if user.full_name:
                    field_from_block.disabled = True
                    field_from_block.initial = user.full_name
                    field_from_block.help_text = disabled_help_text
                else:
                    field_from_block.help_text = _(
                        "You are logged in but your user account does not have a "
                        "full name. We'll update your user account with the name you provide here."
                    )
            if isinstance(block, EmailBlock) and user and user.is_authenticated:
                field_from_block.disabled = True
                field_from_block.initial = user.email
                field_from_block.help_text = disabled_help_text
            if draft and not issubclass(
                block.__class__, ApplicationMustIncludeFieldBlock
            ):
                field_from_block.required = False
            field_from_block.group_number = group_counter if is_in_group else 1
            if isinstance(block, GroupToggleBlock) and not is_in_group:
                field_from_block.group_number = 1
                field_from_block.grouper_for = group_counter + 1
                group_counter += 1
                is_in_group = True
                grouped_fields_visible = (
                    form_data.get(struct_child.id) == field_from_block.choices[0][0]
                )
            if isinstance(block, TextFieldBlock):
                field_from_block.word_limit = struct_value.get("word_limit")
            if isinstance(block, MultiInputCharFieldBlock):
                number_of_inputs = struct_value.get("number_of_inputs")
                for index in range(number_of_inputs):
                    form_fields[struct_child.id + "_" + str(index)] = (
                        field_from_block
                    )
                    field_from_block.multi_input_id = struct_child.id
                    field_from_block.add_button_text = struct_value.get(
                        "add_button_text"
                    )
                    if (
                        index == number_of_inputs - 1
                    ):  # Add button after last input field
                        field_from_block.multi_input_add_button = True
                        # Index for field until which fields will be visible to applicant.
                        # Initially only the first field with id UUID_0 will be visible.
                        field_from_block.visibility_index = 0
                        field_from_block.max_index = index
                    if index != 0:
                        field_from_block.multi_input_field = True
                        field_from_block.required = False
                        field_from_block.initial = None
                    field_from_block = copy.copy(field_from_block)
            else:
                if is_in_group and not isinstance(block, GroupToggleBlock):
                    field_from_block.required_when_visible = (
                        field_from_block.required
                    )
                    field_from_block.required = (
                        field_from_block.required & grouped_fields_visible
                    )
                    field_from_block.visible = grouped_fields_visible
                form_fields[struct_child.id] = field_from_block
        elif isinstance(block, GroupToggleEndBlock):
            # Group toggle end block is used only to group fields and not used in actual form.
            # Todo: Use streamblock to create nested form field blocks, a more elegant method to group form fields.
            is_in_group = False
        else:
            field_wrapper = BlockFieldWrapper(struct_child)
            field_wrapper.group_number = group_counter if is_in_group else 1
            form_fields[struct_child.id] = field_wrapper

    return form_fields

get_form_class

get_form_class(draft=False, form_data=None, user=None)

Dynamically creates and returns a form class based on the field configuration.

Creates a new form class that inherits from submission_form_class (PageStreamBaseForm) and includes all the dynamically generated form fields.

Parameters:

  • draft –

    Whether this is a draft form

  • form_data –

    Existing form data for pre-populating form fields

  • user –

    User completing the form, used for auto-populating user fields.

Returns:

  • –

    A dynamically generated form class

Source code in hypha/apply/stream_forms/models.py
def get_form_class(self, draft=False, form_data=None, user=None):
    """Dynamically creates and returns a form class based on the field configuration.

    Creates a new form class that inherits from submission_form_class (PageStreamBaseForm)
    and includes all the dynamically generated form fields.

    Args:
        draft: Whether this is a draft form
        form_data: Existing form data for pre-populating form fields
        user: User completing the form, used for auto-populating user fields.

    Returns:
        A dynamically generated form class
    """
    return type(
        "WagtailStreamForm",
        (self.submission_form_class,),
        self.get_form_fields(draft=draft, form_data=form_data, user=user),
    )

ReportPrivateMedia

Bases: ReportAccessMixin, PrivateMediaView

View for handling private media files attached to reports.

Ensures proper access control and redirects users to the latest report version if they try to access an outdated document.

storage class-attribute instance-attribute

storage = PrivateStorage()

model class-attribute instance-attribute

model = Report

permission_denied_message class-attribute instance-attribute

permission_denied_message = gettext('You do not have permission to access this report.')

dispatch

dispatch(*args, **kwargs)
Source code in hypha/apply/projects/reports/views.py
def dispatch(self, *args, **kwargs):
    report_pk = self.kwargs["pk"]
    self.report = get_object_or_404(Report, pk=report_pk)
    file_pk = kwargs.get("file_pk")
    self.document = get_object_or_404(
        ReportPrivateFiles.objects, report__report=self.report, pk=file_pk
    )

    if not hasattr(self.document.report, "live_for_report"):
        # this is not a document in the live report
        # send the user to the report page to see latest version
        return redirect(self.report.get_absolute_url())

    return super().dispatch(*args, **kwargs)

get_media

get_media(*args, **kwargs)
Source code in hypha/apply/projects/reports/views.py
def get_media(self, *args, **kwargs):
    return self.document.document

get

get(*args, **kwargs)
Source code in hypha/apply/utils/storage.py
def get(self, *args, **kwargs):
    file_to_serve = self.get_media(*args, **kwargs)
    return FileResponse(file_to_serve)

test_func

test_func()

Test whether the current user has access to the report.

Returns:

  • bool –

    bool | None: True if user has permission to view the report, False otherwise.

Source code in hypha/apply/projects/reports/views.py
def test_func(self) -> bool:
    """
    Test whether the current user has access to the report.

    Returns:
        bool | None: True if user has permission to view the report, False otherwise.
    """
    return has_object_permission(
        "view_report", self.request.user, self.get_object()
    )

ReportSkipView

Bases: SingleObjectMixin, View

View for marking a report as skipped.

Only staff can skip reports, and only unsubmitted reports that aren't the current due report can be skipped.

model class-attribute instance-attribute

model = Report

post

post(*args, **kwargs)

Handle POST requests to toggle the skipped status of a report.

Parameters:

  • *args –

    Variable length argument list.

  • **kwargs –

    Arbitrary keyword arguments.

Returns:

  • HttpResponseClientRefresh –

    A response that refreshes the client.

Source code in hypha/apply/projects/reports/views.py
def post(self, *args, **kwargs):
    """
    Handle POST requests to toggle the skipped status of a report.

    Args:
        *args: Variable length argument list.
        **kwargs: Arbitrary keyword arguments.

    Returns:
        HttpResponseClientRefresh: A response that refreshes the client.
    """
    report = self.get_object()
    unsubmitted = not report.current
    not_current = report.project.report_config.current_due_report() != report
    if unsubmitted and not_current:
        report.skipped = not report.skipped
        report.save()
        messenger(
            MESSAGES.SKIPPED_REPORT,
            request=self.request,
            user=self.request.user,
            source=report.project,
            related=report,
        )
    return HttpResponseClientRefresh()

ReportFrequencyUpdate

Bases: View

View for updating the reporting frequency configuration for a project.

Allows staff to set when reports are due and to enable/disable reporting for a project.

form_class class-attribute instance-attribute

form_class = ReportFrequencyForm

model class-attribute instance-attribute

model = ReportConfig

template_name class-attribute instance-attribute

template_name = 'reports/modals/report_frequency_config.html'

permission_denied_message class-attribute instance-attribute

permission_denied_message = gettext('You do not have permission to update reporting configurations.')

dispatch

dispatch(request, *args, **kwargs)

Set up the project and report configuration objects.

Parameters:

  • request –

    The HttpRequest object.

  • *args –

    Variable length argument list.

  • **kwargs –

    Arbitrary keyword arguments.

Returns:

  • HttpResponse –

    The response from the parent class's dispatch method.

Source code in hypha/apply/projects/reports/views.py
def dispatch(self, request, *args, **kwargs):
    """
    Set up the project and report configuration objects.

    Args:
        request: The HttpRequest object.
        *args: Variable length argument list.
        **kwargs: Arbitrary keyword arguments.

    Returns:
        HttpResponse: The response from the parent class's dispatch method.
    """
    self.project = get_object_or_404(Project, submission__id=kwargs.get("pk"))
    if not has_object_permission(
        "update_report_config", self.request.user, self.project
    ):
        raise PermissionDenied(self.permission_denied_message)
    self.object = self.project.report_config
    return super().dispatch(request, *args, **kwargs)

get_due_report_data

get_due_report_data()

Get data about the current due report for the project.

Returns:

  • dict –

    Data containing start date and project end date if reporting is enabled, empty dict otherwise.

Source code in hypha/apply/projects/reports/views.py
def get_due_report_data(self):
    """
    Get data about the current due report for the project.

    Returns:
        dict: Data containing start date and project end date if reporting is enabled,
              empty dict otherwise.
    """
    report_data = {}
    if not self.object.disable_reporting:
        project_end_date = self.project.end_date
        if self.object.current_due_report():
            start_date = self.object.current_due_report().start_date
        else:
            start_date = self.object.last_report().start_date
        report_data = {"startDate": start_date, "projectEndDate": project_end_date}
    return report_data

get

get(*args, **kwargs)

Handle GET requests to display the form.

Parameters:

  • *args –

    Variable length argument list.

  • **kwargs –

    Arbitrary keyword arguments.

Returns:

  • HttpResponse –

    Rendered template with form and context data.

Source code in hypha/apply/projects/reports/views.py
def get(self, *args, **kwargs):
    """
    Handle GET requests to display the form.

    Args:
        *args: Variable length argument list.
        **kwargs: Arbitrary keyword arguments.

    Returns:
        HttpResponse: Rendered template with form and context data.
    """
    form = self.get_form()
    report_data = self.get_due_report_data()

    return render(
        self.request,
        self.template_name,
        context={
            "form": form,
            "object": self.object,
            "report_data": report_data,
        },
    )

get_form_kwargs

get_form_kwargs(**kwargs)

Get the keyword arguments for instantiating the form.

Sets initial start date based on current reporting configuration.

Parameters:

  • **kwargs –

    Additional keyword arguments.

Returns:

  • dict –

    The keyword arguments for the form.

Source code in hypha/apply/projects/reports/views.py
def get_form_kwargs(self, **kwargs):
    """
    Get the keyword arguments for instantiating the form.

    Sets initial start date based on current reporting configuration.

    Args:
        **kwargs: Additional keyword arguments.

    Returns:
        dict: The keyword arguments for the form.
    """
    kwargs = kwargs or {}
    kwargs["instance"] = self.object
    if not self.object.disable_reporting:
        # Current due report can be none for ONE_TIME(does not repeat),
        # In case of ONE_TIME, either reporting is already completed(last_report exists)
        # or there should be a current_due_report.
        if self.object.current_due_report():
            kwargs["initial"] = {
                "start": self.object.current_due_report().end_date,
            }
        else:
            kwargs["initial"] = {
                "start": self.object.last_report().end_date,
            }
    else:
        kwargs["initial"] = {
            "start": self.project.start_date,
        }
    return kwargs

get_form

get_form(*args, **kwargs)
Source code in hypha/apply/projects/reports/views.py
def get_form(self, *args, **kwargs):
    if self.project.is_in_progress:
        return self.form_class(*args, **(self.get_form_kwargs(**kwargs)))
    return None

post

post(*args, **kwargs)

Handle POST requests to update reporting configuration.

Parameters:

  • *args –

    Variable length argument list.

  • **kwargs –

    Arbitrary keyword arguments.

Returns:

  • HttpResponse –

    Client refresh response or form with errors.

Source code in hypha/apply/projects/reports/views.py
def post(self, *args, **kwargs):
    """
    Handle POST requests to update reporting configuration.

    Args:
        *args: Variable length argument list.
        **kwargs: Arbitrary keyword arguments.

    Returns:
        HttpResponse: Client refresh response or form with errors.
    """
    form = self.get_form(self.request.POST)
    if form.is_valid():
        if "disable-reporting" in self.request.POST:
            form.instance.disable_reporting = True
            form.instance.schedule_start = None
            form.save()
            messages.success(self.request, _("Reporting disabled"))
        else:
            form.instance.disable_reporting = False
            form.instance.schedule_start = form.cleaned_data["start"]
            form.save()
            messenger(
                MESSAGES.REPORT_FREQUENCY_CHANGED,
                request=self.request,
                user=self.request.user,
                source=self.project,
                related=self.object,
            )
        return HttpResponseClientRefresh()

    report_data = self.get_due_report_data()
    return render(
        self.request,
        self.template_name,
        context={
            "form": form,
            "object": self.object,
            "report_data": report_data,
        },
    )

ReportListView

Bases: SingleTableMixin, FilterView

View for displaying a table of submitted reports.

Only accessible to staff and finance users.

queryset class-attribute instance-attribute

queryset = for_table()

filterset_class class-attribute instance-attribute

filterset_class = ReportListFilter

table_class class-attribute instance-attribute

table_class = ReportListTable

template_name class-attribute instance-attribute

template_name = 'reports/report_list.html'

ReportingView

Bases: SingleTableMixin, FilterView

View for displaying a table of projects with reporting information.

Only accessible to staff and finance users.

queryset class-attribute instance-attribute

queryset = for_reporting_table()

filterset_class class-attribute instance-attribute

filterset_class = ReportingFilter

table_class class-attribute instance-attribute

table_class = ReportingTable

template_name class-attribute instance-attribute

template_name = 'reports/reporting.html'