Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate SOW & PAF form editing #4261

Merged
merged 10 commits into from
Dec 17, 2024
11 changes: 9 additions & 2 deletions hypha/apply/funds/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
from hypha.apply.projects.forms import ProjectCreateForm
from hypha.apply.review.models import Review
from hypha.apply.stream_forms.blocks import GroupToggleBlock
from hypha.apply.todo.options import PROJECT_WAITING_PAF
from hypha.apply.todo.options import PROJECT_WAITING_PF, PROJECT_WAITING_SOW
from hypha.apply.todo.views import add_task_to_user
from hypha.apply.users.decorators import (
is_apply_staff,
Expand Down Expand Up @@ -286,10 +286,17 @@ def post(self, *args, **kwargs):
)
# add task for staff to add PAF to the project
add_task_to_user(
code=PROJECT_WAITING_PAF,
code=PROJECT_WAITING_PF,
user=project.lead,
related_obj=project,
)
if self.submission.page.specific.sow_forms.first():
# Add SOW task if one exists on the parent
add_task_to_user(
code=PROJECT_WAITING_SOW,
user=project.lead,
related_obj=project,
)
return HttpResponseClientRedirect(project.get_absolute_url())
return render(
self.request,
Expand Down
3 changes: 1 addition & 2 deletions hypha/apply/projects/forms/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,13 @@ def clean(self):
return cleaned_data

def save(self, *args, **kwargs):
self.instance.form_fields = kwargs.pop("paf_form_fields", {})
self.instance.form_fields = kwargs.pop("pf_form_fields", {})
self.instance.form_data = {
field: self.cleaned_data[field]
for field in self.instance.question_field_ids
if field in self.cleaned_data
}
self.instance.process_file_data(self.cleaned_data)
self.instance.user_has_updated_details = True
return super().save(*args, **kwargs)


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Generated by Django 4.2.16 on 2024-12-06 16:39

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("application_projects", "0093_remove_reportversion_form_fields"),
]

operations = [
migrations.RemoveField(
model_name="project",
name="user_has_updated_details",
),
]
19 changes: 16 additions & 3 deletions hypha/apply/projects/models/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,6 @@ class Project(BaseStreamForm, AccessFormData, models.Model):
# tracks read/write state of the Project
is_locked = models.BooleanField(default=False)

# tracks updates to the Projects fields via the Project Application Form.
user_has_updated_details = models.BooleanField(default=False)
submitted_contract_documents = models.BooleanField(
"Submit Contracting Documents", default=False
)
Expand Down Expand Up @@ -412,6 +410,21 @@ def editable_by(self, user):
return True
return False

@property
def user_has_updated_pf_details(self) -> bool:
"""Determines if the user has updated the Project Form"""
return bool(self.form_fields)

@property
def user_has_updated_sow_details(self) -> bool | None:
"""Determines if the user has updated the SOW form

If there is no configured SOW, None will be returned
"""
if self.submission.page.specific.sow_forms.first() and hasattr(self, "sow"):
return bool(self.sow.form_data)
return None

@property
def editable(self):
if self.is_locked:
Expand Down Expand Up @@ -456,7 +469,7 @@ def can_send_for_approval(self):
being locked.
"""
correct_state = self.status == DRAFT and not self.is_locked
return correct_state and self.user_has_updated_details
return correct_state and self.user_has_updated_pf_details

@property
def is_in_progress(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,44 +77,61 @@ <h2 class="text-lg font-semibold m-0">

<li class="docs-block__row">
<div class="docs-block__row-inner">
{% if object.user_has_updated_details %}
{% if object.user_has_updated_pf_details %}
{% heroicon_outline "check-circle" class="stroke-light-blue me-1" aria_hidden=true %}
{% else %}
{% heroicon_outline "check-circle" class="stroke-gray-400 me-1" aria_hidden=true %}
{% endif %}
<p class="docs-block__title">{% trans "Project Form" %}</p>
<p class="docs-block__title">{% trans "Project form" %}</p>
</div>
<div class="docs-block__row-inner">
{% user_can_edit_paf object user as can_edit_paf %}
{% if can_edit_paf %}
<a class="{% if not object.user_has_updated_details %}button button--project-action{% else %}docs-block__icon-link{% endif %}" href="{% url 'apply:projects:edit' pk=object.pk %}">
{% if object.user_has_updated_details %}
{% user_can_edit_pfs object user as can_edit_pfs %}
{% if can_edit_pfs %}
<a class="{% if not object.user_has_updated_pf_details %}button button--project-action{% else %}docs-block__icon-link{% endif %}" href="{% url 'apply:projects:edit_pf' pk=object.pk %}">
{% if object.user_has_updated_pf_details %}
{% heroicon_micro "pencil-square" class="inline me-1 w-4 h-4" aria_hidden=true %}
{% trans "Edit" %}
{% else %}
{% trans "Fill in" %}
{% endif %}
</a>
{% endif %}
{% if object.user_has_updated_details and not user.is_applicant %}
{% if object.user_has_updated_pf_details and not user.is_applicant %}
<a class="docs-block__icon-link" href="{% url 'apply:projects:approval' pk=project.pk %}">
{% heroicon_micro "eye" class="inline me-1 w-4 h-4" aria_hidden=true %}
{% trans "View" %}
</a>
{% endif %}
</div>
{% has_project_sow_form object as project_sow %}
{% if project_sow and object.user_has_updated_details and not user.is_applicant %}
<ul class="mt-2 w-full ps-7">
{% if project_sow and not user.is_applicant %}
<ul class="mt-2 w-full">
<li class="docs-block__document">
{% if object.user_has_updated_sow_details %}
{% heroicon_outline "check-circle" class="stroke-light-blue me-1" aria_hidden=true %}
{% else %}
{% heroicon_outline "check-circle" class="stroke-gray-400 me-1" aria_hidden=true %}
{% endif %}
<div class="docs-block__document-inner">
<p class="docs-block__document-info">{% trans "Scope of work (SOW)" %}</p>
<p class="docs-block__document-info">{% trans "Scope of work" %}</p>
</div>
<div class="docs-block__document-inner__actions">
<a class="docs-block__icon-link" href="{% url 'apply:projects:sow' pk=project.pk %}">
{% heroicon_micro "eye" class="inline me-1 w-4 h-4" aria_hidden=true %}
{% trans "View" %}
</a>
{% if can_edit_pfs %}
<a class="{% if not object.user_has_updated_sow_details %}button button--project-action{% else %}docs-block__icon-link{% endif %}" href="{% url 'apply:projects:edit_sow' pk=object.pk %}">
{% if object.user_has_updated_sow_details %}
{% heroicon_micro "pencil-square" class="inline me-1 w-4 h-4" aria_hidden=true %}
{% trans "Edit" %}
{% else %}
{% trans "Fill in" %}
{% endif %}
</a>
{% endif %}
{% if object.user_has_updated_sow_details %}
<a class="docs-block__icon-link" href="{% url 'apply:projects:sow' pk=project.pk %}">
{% heroicon_micro "eye" class="inline me-1 w-4 h-4" aria_hidden=true %}
{% trans "View" %}
</a>
{% endif %}
</div>
</li>
</ul>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@ <h1>{{ org_name }} {% trans "Project Form" %}</h1>
<p>{{ field_value|safe|default:"-" }}</p>
{% endfor %}

<!-- SOW fields data in paragraph format-->
{% for field_name, field_value in sow_data.items %}
<p><b>{{ field_name }}</b></p>
<p>{{ field_value|safe|default:"-" }}</p>
{% endfor %}

<!-- Approvers data in list format -->
<h2>{% trans "Approvals" %}</h2>
{% if approvals %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,9 @@ <h4 class="mb-2">{% trans "Supporting Documents" %}</h4>
<aside class="sidebar sidebar__project">
<div class="sidebar__inner sidebar__inner--light-blue sidebar__inner--actions" data-testid="sidebar-primary-actions">
<h5>{% trans "Actions to take" %}</h5>
{% user_can_edit_paf object user as can_edit_paf %}
{% if can_edit_paf %}
<a class="button button--bottom-space button--primary button--full-width {% if user_can_approve %} is-disabled {% endif %}" href="{% url 'apply:projects:edit' pk=object.pk %}">{% trans "Edit PAF" %}</a>
{% user_can_edit_pfs object user as can_edit_pfs %}
{% if can_edit_pfs %}
<a class="button button--bottom-space button--primary button--full-width {% if user_can_approve %} is-disabled {% endif %}" href="{% url 'apply:projects:edit_pf' pk=object.pk %}">{% trans "Edit" %}</a>
{% endif %}
<div x-data="{ show: false }" class="relative">
<button x-on:click="show = ! show" class="button button--bottom-space button--primary button--full-width" type="button">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,14 @@
{% endadminbar %}

{% if approval_form_exists %}

{% include "forms/includes/form_errors.html" with form=paf_form %}
{% if sow_form_exists %}
{% include "forms/includes/form_errors.html" with form=sow_form %}
{% endif %}
{% include "forms/includes/form_errors.html" with form=pf_form %}

<div class="pt-8 pb-8 mx-auto mt-4 mb-12 wrapper wrapper--default-bg wrapper--sidebar ps-20 ">
<div class="wrapper--sidebar--inner">
<form class="form application-form" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ paf_form.media }}
{% if sow_form_exists %}
{{ sow_form.media }}
{% endif %}

{% for field in paf_form %}
{{ pf_form.media }}
{% for field in pf_form %}
{% if field.field %}
{% if field.field.multi_input_field %}
{% include "forms/includes/multi_input_field.html" %}
Expand All @@ -41,43 +33,25 @@
{% endfor %}

{# Hidden fields needed e.g. for django-file-form. See `StreamBaseForm.hidden_fields` #}
{% for hidden_field in paf_form.hidden_fields %}
{% for hidden_field in pf_form.hidden_fields %}
{{ hidden_field }}
{% endfor %}

{% if sow_form_exists %}
<hr class="mt-6 border-2 border-dotted">
{% for field in sow_form %}
{% if field.field %}
{% if field.field.multi_input_field %}
{% include "forms/includes/multi_input_field.html" %}
{% else %}
{% include "forms/includes/field.html" %}
{% endif %}
{% else %}
{{ field.block }}
{% endif %}
{% endfor %}


{% for hidden_field in sow_form.hidden_fields %}
{{ hidden_field }}
{% endfor %}
{% endif %}

{% trans "Save draft" as save_draft %}
{% for button_name, button_type, button_value in buttons %}
<button class="button button--submit button--top-space button--{{ button_type }}" type="submit" name="{{ button_name }}" {% if button_value == save_draft %}formnovalidate{% endif %}>{{ button_value }}</button>
{% endfor %}
</form>
</div>
<aside class="sidebar sidebar__project">
<div class="sidebar__inner sidebar__inner--actions">
<h5>{% trans "Proposal attachments" %}</h5>
{% for file in submissions_attachments %}
<p><b><a href="{{ file.url }}" target="_blank">{{ file.filename }}</a></b></p>
{% endfor %}
</div>
{% if submissions_attachments %}
<div class="sidebar__inner sidebar__inner--actions">
<h5>{% trans "Proposal attachments" %}</h5>
{% for file in submissions_attachments %}
<p><b><a href="{{ file.url }}" target="_blank">{{ file.filename }}</a></b></p>
{% endfor %}
</div>
{% endif %}
</aside>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<div class="wrapper wrapper--large wrapper--tabs">
<div class="wrapper wrapper--sidebar">
<article class="wrapper--sidebar--inner">
<h4 class="mb-2">{% trans "Project scope of work (SOW)" %}</h4>
<h4 class="mb-2">{% trans "Scope of Work" %}</h4>
<div class="card card--solid">
{% if object.sow.output_answers %}
<div class="rich-text rich-text--answers">
Expand All @@ -38,8 +38,12 @@ <h4 class="mb-2">{% trans "Project scope of work (SOW)" %}</h4>
<aside class="sidebar sidebar__project">
<div class="sidebar__inner sidebar__inner--light-blue sidebar__inner--actions">
<h5>{% trans "Actions to take" %}</h5>
<div x-data="{ show: false }" class="dropdown">
<button x-on:click="show = ! show" class="button button--primary" type="button">
{% user_can_edit_pfs object user as can_edit_pfs %}
{% if can_edit_pfs %}
<a class="button button--bottom-space button--primary button--full-width {% if user_can_approve %} is-disabled {% endif %}" href="{% url 'apply:projects:edit_sow' pk=object.pk %}">{% trans "Edit" %}</a>
{% endif %}
<div x-data="{ show: false }" class="relative">
<button x-on:click="show = ! show" class="button button--bottom-space button--primary button--full-width" type="button">
{% trans 'Download SOW' %}
</button>
<div x-show="show" x-transition class="dropdown__content">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{% extends "base-apply.html" %}
{% load i18n static %}
{% block title %}{% trans "Editing" %}: {{object.title }}{% endblock %}
{% block content %}

{% adminbar %}
{% slot back_link %}
<a class="simplified__projects-link" href="{{ object.get_absolute_url }}">
{% trans "View project page" %}
</a>
{% endslot %}
{% slot header %}{% trans "Editing" %}: {{ object.title }}{% endslot %}
{% endadminbar %}

{% if sow_form_exists %}
{% include "forms/includes/form_errors.html" with form=sow_form %}
<div class="pt-8 pb-8 mx-auto mt-4 mb-12 wrapper wrapper--default-bg wrapper--sidebar ps-20 ">
<div class="wrapper--sidebar--inner">
<form class="form application-form" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ sow_form.media }}
{% for field in sow_form %}
{% if field.field %}
{% if field.field.multi_input_field %}
{% include "forms/includes/multi_input_field.html" %}
{% else %}
{% include "forms/includes/field.html" %}
{% endif %}
{% else %}
{{ field.block }}
{% endif %}
{% endfor %}


{% for hidden_field in sow_form.hidden_fields %}
{{ hidden_field }}
{% endfor %}
{% trans "Save draft" as save_draft %}
{% for button_name, button_type, button_value in buttons %}
<button class="button button--submit button--top-space button--{{ button_type }}" type="submit" name="{{ button_name }}" {% if button_value == save_draft %}formnovalidate{% endif %}>{{ button_value }}</button>
{% endfor %}
</form>
</div>
<aside class="sidebar sidebar__project">
{% if submissions_attachments %}
<div class="js-actions-sidebar sidebar__inner sidebar__inner--actions {% if mobile %}sidebar__inner--mobile{% endif %}">
<h5>{% trans "Proposal attachments" %}</h5>
{% for file in submissions_attachments %}
<p><b><a href="{{ file.url }}" target="_blank">{{ file.filename }}</a></b></p>
{% endfor %}
</div>
{% endif %}
</aside>
</div>
{% else %}
<div class="wrapper wrapper--default-bg wrapper--form wrapper--sidebar">
<div class="wrapper--sidebar--inner">
<p>
{% trans "Scope of work form not configured. Please add it in the" %}
<a href="{% url 'wagtailadmin_pages:edit' object.submission.page.id %}" target="_blank">{% trans "fund settings" %}</a>.
</p>
</div>
</div>
{% endif %}

{% endblock %}

{% block extra_js %}
<script src="{% static 'js/file-uploads.js' %}"></script>
<script src="{% static 'js/tinymce-word-count.js' %}"></script>
<script src="{% static 'js/multi-input-fields.js' %}"></script>
<script src="{% static 'js/application-form-links-new-window.js' %}"></script>
{% if not show_all_group_fields %}
<script src="{% static 'js/form-group-toggle.js' %}"></script>
{% endif %}
{% endblock %}
Loading
Loading