{% trans "Project Information" %}
-
-
-
-
- {% trans "Contractor" %}
-{{ object.user |default:"-" }}
-
-
+ {% trans "E-mail" %}
- {% if object.user.email %} - {{ object.user.email }} - {% else %} - - - {% endif %} -
+
+
+
+
{% user_can_view_invoices object user as can_view_invoices %}
@@ -99,9 +94,9 @@ {% trans "E-mail" %}
{% user_next_step_on_project object user request=request as next_step %} {% if next_step %}
-
- {% heroicon_solid "sparkles" class="inline align-text-top me-1 fill-orange-500" aria_hidden=true %}
- {{ next_step.heading }}
+
- {% heroicon_solid "sparkles" class="inline align-text-top me-1 fill-orange-500" aria_hidden=true %}
- {{ next_step.heading }}
+
+ {% heroicon_solid "sparkles" class="align-text-top me-1 fill-orange-500" aria_hidden=true %}
+ {{ next_step.heading }}
{{ next_step.text }}
{% user_next_step_instructions object user as instructions %} diff --git a/hypha/apply/projects/templatetags/project_tags.py b/hypha/apply/projects/templatetags/project_tags.py index 5c4d66093c..b8ea6e9431 100644 --- a/hypha/apply/projects/templatetags/project_tags.py +++ b/hypha/apply/projects/templatetags/project_tags.py @@ -341,3 +341,12 @@ def display_project_status(project, user): if user.is_apply_staff or user.is_contracting or user.is_finance: return project.status_display return get_project_public_status(project_status=project.status) + + +@register.simple_tag +def show_start_date(project) -> bool: + return not settings.PROJECTS_START_AFTER_CONTRACTING or project.status in [ + INVOICING_AND_REPORTING, + CLOSING, + COMPLETE, + ] diff --git a/hypha/apply/projects/tests/factories.py b/hypha/apply/projects/tests/factories.py index 243111058f..b78e15c681 100644 --- a/hypha/apply/projects/tests/factories.py +++ b/hypha/apply/projects/tests/factories.py @@ -98,8 +98,8 @@ class ProjectFactory(factory.django.DjangoModelFactory): title = factory.Sequence("name {}".format) lead = factory.SubFactory(StaffFactory) value = decimal.Decimal("100") - proposed_start = factory.LazyFunction(timezone.now) - proposed_end = factory.LazyFunction(timezone.now) + proposed_start = factory.LazyFunction(timezone.now().date) + proposed_end = factory.LazyFunction(timezone.now().date) is_locked = False diff --git a/hypha/apply/projects/urls.py b/hypha/apply/projects/urls.py index 7b483fa762..f8e07f262f 100644 --- a/hypha/apply/projects/urls.py +++ b/hypha/apply/projects/urls.py @@ -43,9 +43,11 @@ partial_get_invoice_detail_actions, partial_get_invoice_status, partial_get_invoice_status_table, + partial_project_information, partial_project_lead, partial_project_title, partial_supporting_documents, + update_project_dates, update_project_title, ) @@ -76,6 +78,11 @@ ), path("partial/lead/", partial_project_lead, name="project_lead"), path("partial/title/", partial_project_title, name="project_title"), + path( + "partial/information/", + partial_project_information, + name="project_information", + ), path("lead/update/", UpdateLeadView.as_view(), name="lead_update"), path( "status/update/", @@ -87,6 +94,11 @@ update_project_title, name="project_title_update", ), + path( + "dates/update/", + update_project_dates, + name="project_dates_update", + ), path( "edit/project-form", ProjectFormEditView.as_view(), name="edit_pf" ), diff --git a/hypha/apply/projects/views/__init__.py b/hypha/apply/projects/views/__init__.py index be7f487dca..42317ac617 100644 --- a/hypha/apply/projects/views/__init__.py +++ b/hypha/apply/projects/views/__init__.py @@ -37,6 +37,7 @@ UploadContractDocumentView, UploadContractView, UploadDocumentView, + update_project_dates, update_project_title, ) from .project_partials import ( @@ -46,12 +47,14 @@ partial_get_invoice_detail_actions, partial_get_invoice_status, partial_get_invoice_status_table, + partial_project_information, partial_project_lead, partial_project_title, partial_supporting_documents, ) __all__ = [ + "partial_project_information", "partial_project_lead", "partial_project_title", "partial_supporting_documents", @@ -69,6 +72,7 @@ "SubmitContractDocumentsView", "UpdatePAFApproversView", "update_project_title", + "update_project_dates", "UploadContractDocumentView", "ChangePAFStatusView", "UploadDocumentView", diff --git a/hypha/apply/projects/views/project.py b/hypha/apply/projects/views/project.py index 2679d041b3..46b0f443ad 100644 --- a/hypha/apply/projects/views/project.py +++ b/hypha/apply/projects/views/project.py @@ -83,6 +83,7 @@ SetPendingForm, SkipPAFApprovalProcessForm, SubmitContractDocumentsForm, + UpdateProjectDatesForm, UpdateProjectLeadForm, UpdateProjectTitleForm, UploadContractDocumentForm, @@ -503,6 +504,42 @@ def update_project_title(request, pk): return render(request, template_name, ctx) +@login_required +def update_project_dates(request, pk): + if not request.user.is_apply_staff: + raise PermissionDenied + + project = get_object_or_404(Project, submission__id=pk) + template_name = "application_projects/modals/project_dates_update.html" + + form = UpdateProjectDatesForm(instance=project) + + if request.method == "POST": + form = UpdateProjectDatesForm(request.POST, instance=project) + + if form.is_valid(): + form.save() + + return HttpResponse( + status=204, + headers={ + "HX-Trigger": json.dumps( + { + "informationUpdated": None, + "showMessage": _("Dates has been updated"), + } + ), + }, + ) + + ctx = { + "form": form, + "value": _("Update"), + "object": project, + } + return render(request, template_name, ctx) + + # CONTRACTS @@ -702,6 +739,10 @@ def post(self, *args, **kwargs): self.project.save(update_fields=["status"]) old_stage = CONTRACTING + if settings.PROJECTS_START_AFTER_CONTRACTING: + self.project.proposed_start = datetime.date.today() + self.project.save() + messenger( MESSAGES.PROJECT_TRANSITION, request=self.request, diff --git a/hypha/apply/projects/views/project_partials.py b/hypha/apply/projects/views/project_partials.py index 50307b43c7..45dcfcbda0 100644 --- a/hypha/apply/projects/views/project_partials.py +++ b/hypha/apply/projects/views/project_partials.py @@ -22,7 +22,7 @@ def partial_project_lead(request, pk): project = get_object_or_404(Project, submission__pk=pk) return render( - request, "application_projects/partials/project-lead.html", {"object": project} + request, "application_projects/partials/project_lead.html", {"object": project} ) @@ -34,6 +34,16 @@ def partial_project_title(request, pk): ) +@login_required +def partial_project_information(request, pk): + project = get_object_or_404(Project, submission__pk=pk) + return render( + request, + "application_projects/partials/project_information.html", + {"object": project}, + ) + + @login_required @require_GET def partial_supporting_documents(request, pk): diff --git a/hypha/settings/base.py b/hypha/settings/base.py index 1810932838..afd2adaa75 100644 --- a/hypha/settings/base.py +++ b/hypha/settings/base.py @@ -85,6 +85,8 @@ ORG_SHORT_NAME = env.str("ORG_SHORT_NAME", "ACME") ORG_URL = env.str("ORG_URL", "https://www.example.org/") +# Project settings. + # Enable Projects in Hypha. Contracts and invoicing that comes after a submission is approved. PROJECTS_ENABLED = env.bool("PROJECTS_ENABLED", False) @@ -95,6 +97,9 @@ # Will be used for auto-create or be the default selection in the project creation form PROJECTS_DEFAULT_STATUS = env.str("PROJECTS_DEFAULT_STATUS", "draft") +# When enabled, the project start date will be set and displayed after the contracting phase, if disabled it is set on project creation +PROJECTS_START_AFTER_CONTRACTING = env.bool("PROJECTS_START_AFTER_CONTRACTING", True) + # Send out e-mail, slack messages etc. from Hypha. Set to true for production. SEND_MESSAGES = env.bool("SEND_MESSAGES", False) @@ -166,8 +171,6 @@ # Require an applicant to view their rendered application before submitting SUBMISSION_PREVIEW_REQUIRED = env.bool("SUBMISSION_PREVIEW_REQUIRED", True) -# Project settings. - # SECRET_KEY is required SECRET_KEY = env.str("SECRET_KEY", None) diff --git a/hypha/static_src/sass/components/_form.scss b/hypha/static_src/sass/components/_form.scss index 5789f1a18b..b8a984d3f4 100644 --- a/hypha/static_src/sass/components/_form.scss +++ b/hypha/static_src/sass/components/_form.scss @@ -88,10 +88,6 @@ } } } - - input[type="date"]:last-child { - max-width: 385px; - } } &__question {