Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/uv-pre-commit
rev: "0.6.4"
rev: "0.6.14"
hooks:
- id: uv-export
name: uv-export requirements/prod.txt
Expand Down Expand Up @@ -36,7 +36,7 @@ repos:
]

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: "v0.9.10"
rev: "v0.11.6"
hooks:
# Run the linter.
- id: ruff
Expand All @@ -62,7 +62,7 @@ repos:
types_or: [html, css]

- repo: https://github.com/biomejs/pre-commit
rev: "v0.6.1"
rev: "v2.0.0-beta.1"
hooks:
- id: biome-check
additional_dependencies: ["@biomejs/biome@1.9.4"]
Expand All @@ -77,6 +77,6 @@ repos:
- stylelint@16.11.0
- stylelint-config-standard-scss@13.1.0
- repo: https://github.com/gitleaks/gitleaks
rev: v8.24.0
rev: v8.24.3
hooks:
- id: gitleaks
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ JS_ESM_DIR = ./hypha/static_src/javascript/esm
PIP := $(shell (command -v uv > /dev/null 2>&1 && echo "uv pip") || (command -v pip > /dev/null 2>&1 && echo "pip"))
UV_RUN := $(shell (command -v uv > /dev/null 2>&1 && echo "uv run ") || echo "")


.PHONY: autoupdate
autoupdate: ## Update uv, project dependencies and pre-commit hooks
uv self update
uv lock --upgrade
uv run pre-commit autoupdate
npm update
${MAKE} fmt

.PHONY: help
help: ## Show this help menu with a list of available commands and their descriptions
@echo "\nSpecify a command. The choices are:\n"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,11 @@ <h2 class="flex-1 font-light">{% trans "My active invoices" %}</h2>
<div class="wrapper wrapper--status-bar-outer">
<div class="flex flex-wrap justify-between wrapper ps-4 pe-4">
<div class="flex flex-col my-auto md:w-1/3 item-start">
<h4 class="font-bold heading heading--no-margin"><a class="link" href="{{ invoice.get_absolute_url }}">
{% if invoice.invoice_number %}{{ invoice.invoice_number }}{% else %}{{ invoice.vendor_document_number }}{% endif %}
</a></h4>
<h4 class="font-bold heading heading--no-margin">
<a class="link" href="{{ invoice.get_absolute_url }}">
{{ invoice.invoice_number }}
</a>
</h4>
<p class="m-0 text-sm text-fg-muted">{% trans "Date added: " %} {{ invoice.requested_at }}</p>
</div>
<div class="flex flex-col items-center my-auto text-center md:w-1/3">
Expand Down
1 change: 1 addition & 0 deletions hypha/apply/funds/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ def test_can_create_project(self):
"project_create_form": "",
"project_lead": self.user.id,
"project_initial_status": CONTRACTING,
"project_end": timezone.now().date(),
"submission": self.submission.id,
},
view_name="create_project",
Expand Down
2 changes: 1 addition & 1 deletion hypha/apply/funds/views/submission_edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ def post(self, *args, **kwargs):
return render(
self.request,
"funds/modals/create_project_form.html",
context={"form": form, "value": _("Confirm"), "object": self.object},
context={"form": form, "value": _("Confirm"), "object": self.submission},
status=400,
)

Expand Down
2 changes: 2 additions & 0 deletions hypha/apply/projects/forms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
SkipPAFApprovalProcessForm,
StaffUploadContractForm,
SubmitContractDocumentsForm,
UpdateProjectDatesForm,
UpdateProjectLeadForm,
UpdateProjectTitleForm,
UploadContractDocumentForm,
Expand All @@ -44,6 +45,7 @@
"UploadContractDocumentForm",
"StaffUploadContractForm",
"UploadDocumentForm",
"UpdateProjectDatesForm",
"UpdateProjectLeadForm",
"CreateInvoiceForm",
"ChangeInvoiceStatusForm",
Expand Down
39 changes: 36 additions & 3 deletions hypha/apply/projects/forms/project.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from datetime import date

from django import forms
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db.models import Count, Q
from django.utils.text import slugify
Expand Down Expand Up @@ -86,16 +89,20 @@ class ProjectCreateForm(forms.Form):
)

project_lead = forms.ModelChoiceField(
label=_("Select Project Lead"), queryset=User.objects.all()
label=_("Select project lead"), queryset=User.objects.all()
)

# Set the initial value to the settings default if valid, otherwise fall back to draft
project_initial_status = forms.ChoiceField(
label=_("Initial Project Status"),
label=_("Initial project status"),
choices=get_project_status_options(),
initial=get_project_default_status(),
)

project_end = forms.DateField(
label=_("Project end date"),
)

def __init__(self, *args, instance=None, **kwargs):
super().__init__(*args, **kwargs)

Expand All @@ -119,7 +126,24 @@ def save(self, *args, **kwargs):
submission = self.cleaned_data["submission"]
lead = self.cleaned_data["project_lead"]
status = self.cleaned_data["project_initial_status"]
return Project.create_from_submission(submission, lead=lead, status=status)
end_date = self.cleaned_data["project_end"]

start_date = None

if not settings.PROJECTS_START_AFTER_CONTRACTING or status in [
INVOICING_AND_REPORTING,
CLOSING,
COMPLETE,
]:
start_date = date.today()

return Project.create_from_submission(
submission,
lead=lead,
status=status,
end_date=end_date,
start_date=start_date,
)


class MixedMetaClass(type(StreamBaseForm), type(forms.ModelForm)):
Expand Down Expand Up @@ -444,3 +468,12 @@ class Meta:

def __init__(self, *args, user=None, **kwargs):
super().__init__(*args, **kwargs)


class UpdateProjectDatesForm(forms.ModelForm):
class Meta:
fields = ["proposed_start", "proposed_end"]
model = Project

def __init__(self, *args, user=None, **kwargs):
super().__init__(*args, **kwargs)
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Generated by Django 4.2.20 on 2025-04-10 17:27

import datetime
from django.db import migrations, models


def migration_set_project_start_date(apps, schema_editor):
Project = apps.get_model("application_projects", "Project")
for project in Project.objects.all():
if not project.proposed_start:
project.proposed_start = project.created_at
project.save(update_fields=["proposed_start"])


class Migration(migrations.Migration):
dependencies = [
("application_projects", "0099_remove_reportconfig_project_and_more"),
]

operations = [
migrations.RunPython(migration_set_project_start_date),
migrations.AlterField(
model_name="project",
name="proposed_end",
field=models.DateField(null=True, verbose_name="Proposed end date"),
),
migrations.AlterField(
model_name="project",
name="proposed_start",
field=models.DateField(
default=datetime.date.today,
null=True,
verbose_name="Proposed start date",
),
),
]
13 changes: 1 addition & 12 deletions hypha/apply/projects/models/payment.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import decimal
import os
from textwrap import wrap

from django.conf import settings
from django.core.validators import MinValueValidator
Expand Down Expand Up @@ -141,7 +140,7 @@ def __str__(self):
)
def transition_invoice_to_resubmitted(self):
"""
Tranistion invoice to resubmitted status.
Transition invoice to resubmitted status.
This method generally gets used on invoice edit.
"""
pass
Expand All @@ -154,16 +153,6 @@ def has_changes_requested(self):
def status_display(self):
return self.get_status_display()

@property
def vendor_document_number(self):
"""
Vendor document number is a required field to create invoices in IntAcct.

Formatting should be HP###### i.e. HP000001 and so on.
"""
prefix = "HP-"
return prefix + "-".join(wrap(f"{self.id:06}", 3))

def can_user_delete(self, user):
if user.is_applicant or user.is_apply_staff:
if self.status in (SUBMITTED):
Expand Down
40 changes: 11 additions & 29 deletions hypha/apply/projects/models/project.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
from datetime import date

from django import forms
from django.apps import apps
Expand All @@ -20,7 +21,7 @@
Value,
When,
)
from django.db.models.functions import Cast, Coalesce
from django.db.models.functions import Coalesce
from django.db.models.signals import post_delete
from django.dispatch.dispatcher import receiver
from django.urls import reverse
Expand Down Expand Up @@ -164,21 +165,6 @@ def with_outstanding_reports(self):
)
)

def with_start_date(self):
return self.annotate(
start=Cast(
Subquery(
Contract.objects.filter(
project=OuterRef("pk"),
)
.approved()
.order_by("approved_at")
.values("approved_at")[:1]
),
models.DateField(),
)
)

def for_table(self):
return (
self.with_amount_paid()
Expand Down Expand Up @@ -259,8 +245,10 @@ class Project(BaseStreamForm, AccessFormData, models.Model):
decimal_places=2,
validators=[MinValueValidator(limit_value=0)],
)
proposed_start = models.DateTimeField(_("Proposed Start Date"), null=True)
proposed_end = models.DateTimeField(_("Proposed End Date"), null=True)
proposed_start = models.DateField(
_("Proposed start date"), null=True, default=date.today
)
proposed_end = models.DateField(_("Proposed end date"), null=True)

status = models.TextField(choices=PROJECT_STATUS_CHOICES, default=DRAFT)

Expand Down Expand Up @@ -321,7 +309,9 @@ def get_address_display(self):
return "" # todo: need to figure out

@classmethod
def create_from_submission(cls, submission, lead=None, status=None):
def create_from_submission(
cls, submission, lead=None, status=None, end_date=None, start_date=None
):
"""
Create a Project from the given submission.

Expand Down Expand Up @@ -357,19 +347,11 @@ def create_from_submission(cls, submission, lead=None, status=None):
title=submission.title,
status=status,
lead=lead if lead else None,
proposed_end=end_date,
proposed_start=start_date,
value=submission.form_data.get("value", 0),
)

@property
def start_date(self):
# Assume project starts when OTF are happy with the first signed contract
first_approved_contract = (
self.contracts.approved().order_by("approved_at").first()
)
if not first_approved_contract:
return None
return first_approved_contract.approved_at.date()

@property
def end_date(self):
# Aiming for the proposed end date as the last day of the project
Expand Down
10 changes: 4 additions & 6 deletions hypha/apply/projects/reports/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,7 @@ def for_table(self):
project_start_date=Subquery(
Project.objects.filter(
pk=OuterRef("project_id"),
)
.with_start_date()
.values("start")[:1]
).values("proposed_start")[:1]
),
start=Case(
When(
Expand Down Expand Up @@ -176,7 +174,7 @@ def start_date(self):
if last_report:
return last_report.end_date + relativedelta(days=1)

return self.project.start_date
return self.project.proposed_start


class ReportVersion(BaseStreamForm, AccessFormData, models.Model):
Expand Down Expand Up @@ -329,14 +327,14 @@ def current_due_report(self):
return None

# Project not started - no reporting required
if not self.project.start_date:
if not self.project.proposed_start:
return None

today = timezone.now().date()

last_report = self.last_report()

schedule_date = self.schedule_start or self.project.start_date
schedule_date = self.schedule_start or self.project.proposed_start

if last_report:
# Frequency is one time and last report exists - no reporting required anymore
Expand Down
2 changes: 1 addition & 1 deletion hypha/apply/projects/reports/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ def get_form_kwargs(self, **kwargs):
}
else:
kwargs["initial"] = {
"start": self.project.start_date,
"start": self.project.proposed_start,
}
return kwargs

Expand Down
Loading
Loading