Skip to content
Open
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
3 changes: 3 additions & 0 deletions hypha/apply/activity/adapters/activity_feed.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ class ActivityAdapter(AdapterBase):
MESSAGES.UPDATE_PROJECT_TITLE: _(
"updated the project title from {old_title} to {source.title}"
),
MESSAGES.UPDATE_PROJECT_CONTRACT_NUMBER: _(
"updated contract number to {source.contract_number}"
),
MESSAGES.UPDATE_PROJECT_LEAD: _("update Lead from {old_lead} to {source.lead}"),
MESSAGES.SEND_FOR_APPROVAL: _("Requested approval"),
MESSAGES.APPROVE_PAF: "handle_paf_assignment",
Expand Down
3 changes: 3 additions & 0 deletions hypha/apply/activity/adapters/slack.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ class SlackAdapter(AdapterBase):
MESSAGES.UPDATE_PROJECT_TITLE: _(
"The project title has been updated from <{link}|{old_title}> to <{link}|{source.title}> by {user}"
),
MESSAGES.UPDATE_PROJECT_CONTRACT_NUMBER: _(
"The contract number of project <{link}|{source.title}> has been updated to {source.contract_number} by {user}"
),
MESSAGES.EDIT_REVIEW: _(
"{user} has edited {review.author} review for <{link}|{source.title_text_display}>"
),
Expand Down
89 changes: 89 additions & 0 deletions hypha/apply/activity/migrations/0095_alter_event_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Generated by Django 5.2.16 on 2026-07-15 09:19

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("activity", "0094_alter_event_type"),
]

operations = [
migrations.AlterField(
model_name="event",
name="type",
field=models.CharField(
choices=[
("UPDATE_LEAD", "updated lead"),
("BATCH_UPDATE_LEAD", "batch updated lead"),
("EDIT_SUBMISSION", "edited submission"),
("APPLICANT_EDIT", "edited applicant"),
("NEW_SUBMISSION", "submitted new submission"),
("DRAFT_SUBMISSION", "submitted new draft submission"),
("SCREENING", "screened"),
("TRANSITION", "transitioned"),
("BATCH_TRANSITION", "batch transitioned"),
("DETERMINATION_OUTCOME", "sent determination outcome"),
("BATCH_DETERMINATION_OUTCOME", "sent batch determination outcome"),
("INVITED_TO_PROPOSAL", "invited to proposal"),
("REVIEWERS_UPDATED", "updated reviewers"),
("BATCH_REVIEWERS_UPDATED", "batch updated reviewers"),
("READY_FOR_REVIEW", "marked ready for review"),
("BATCH_READY_FOR_REVIEW", "marked batch ready for review"),
("NEW_REVIEW", "added new review"),
("COMMENT", "added comment"),
("PROPOSAL_SUBMITTED", "submitted proposal"),
("OPENED_SEALED", "opened sealed submission"),
("REVIEW_OPINION", "reviewed opinion"),
("DELETE_SUBMISSION", "deleted submission"),
("ANONYMIZE_SUBMISSION", "anonymized submission"),
("DELETE_REVIEW", "deleted review"),
("DELETE_REVIEW_OPINION", "deleted review opinion"),
("CREATED_PROJECT", "created project"),
("UPDATE_PROJECT_LEAD", "updated project lead"),
("UPDATE_PROJECT_TITLE", "updated project title"),
(
"UPDATE_PROJECT_CONTRACT_NUMBER",
"updated project contract number",
),
("EDIT_REVIEW", "edited review"),
("SEND_FOR_APPROVAL", "sent for approval"),
("APPROVE_PROJECT", "approved project"),
("ASSIGN_PAF_APPROVER", "assign project form approver"),
("APPROVE_PAF", "approved project form"),
("PROJECT_TRANSITION", "transitioned project"),
("REQUEST_PROJECT_CHANGE", "requested project change"),
("SUBMIT_CONTRACT_DOCUMENTS", "submitted contract documents"),
("UPLOAD_DOCUMENT", "uploaded document to project"),
("UPLOAD_CONTRACT", "uploaded contract to project"),
("APPROVE_CONTRACT", "approved contract"),
("CREATE_INVOICE", "created invoice for project"),
("UPDATE_INVOICE_STATUS", "updated invoice status"),
("APPROVE_INVOICE", "approve invoice"),
("DELETE_INVOICE", "deleted invoice"),
("SENT_TO_COMPLIANCE", "sent project to compliance"),
("UPDATE_INVOICE", "updated invoice"),
("SUBMIT_REPORT", "submitted report"),
("DELETE_REPORT", "deleted report"),
("SKIPPED_REPORT", "skipped report"),
("REPORT_FREQUENCY_CHANGED", "changed report frequency"),
("DISABLED_REPORTING", "disabled reporting"),
("REPORT_NOTIFY", "notified report"),
("REVIEW_REMINDER", "reminder to review"),
("BATCH_DELETE_SUBMISSION", "batch deleted submissions"),
("BATCH_ANONYMIZE_SUBMISSION", "batch anonymized submissions"),
("BATCH_ARCHIVE_SUBMISSION", "batch archive submissions"),
("BATCH_INVOICE_STATUS_UPDATE", "batch update invoice status"),
("STAFF_ACCOUNT_CREATED", "created new account"),
("STAFF_ACCOUNT_EDITED", "edited account"),
("ARCHIVE_SUBMISSION", "archived submission"),
("UNARCHIVE_SUBMISSION", "unarchived submission"),
("REMOVE_TASK", "remove task"),
("INVITE_COAPPLICANT", "invite co-applicant"),
("UPDATE_AUTHOR", "updated author"),
],
max_length=50,
verbose_name="verb",
),
),
]
4 changes: 4 additions & 0 deletions hypha/apply/activity/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ class MESSAGES(TextChoices):
CREATED_PROJECT = "CREATED_PROJECT", _("created project")
UPDATE_PROJECT_LEAD = "UPDATE_PROJECT_LEAD", _("updated project lead")
UPDATE_PROJECT_TITLE = "UPDATE_PROJECT_TITLE", _("updated project title")
UPDATE_PROJECT_CONTRACT_NUMBER = (
"UPDATE_PROJECT_CONTRACT_NUMBER",
_("updated project contract number"),
)
EDIT_REVIEW = "EDIT_REVIEW", _("edited review")
SEND_FOR_APPROVAL = "SEND_FOR_APPROVAL", _("sent for approval")
APPROVE_PROJECT = "APPROVE_PROJECT", _("approved project")
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 @@ -19,6 +19,7 @@
SkipPAFApprovalProcessForm,
StaffUploadContractForm,
SubmitContractDocumentsForm,
UpdateProjectContractNumberForm,
UpdateProjectDatesForm,
UpdateProjectLeadForm,
UpdateProjectTitleForm,
Expand Down Expand Up @@ -46,6 +47,7 @@
"UploadContractDocumentForm",
"StaffUploadContractForm",
"UploadDocumentForm",
"UpdateProjectContractNumberForm",
"UpdateProjectDatesForm",
"UpdateProjectLeadForm",
"CreateInvoiceForm",
Expand Down
9 changes: 9 additions & 0 deletions hypha/apply/projects/forms/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -490,3 +490,12 @@ def __init__(self, *args, user=None, **kwargs):
proposed_start.disabled = True
proposed_start.required = False
proposed_start.widget = proposed_start.hidden_widget()


class UpdateProjectContractNumberForm(forms.ModelForm):
class Meta:
fields = ["contract_number"]
model = Project

def __init__(self, *args, user=None, **kwargs):
super().__init__(*args, **kwargs)
19 changes: 19 additions & 0 deletions hypha/apply/projects/migrations/0105_project_contract_number.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 5.2.16 on 2026-07-15 09:01

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("application_projects", "0104_invoice_tags"),
]

operations = [
migrations.AddField(
model_name="project",
name="contract_number",
field=models.CharField(
blank=True, max_length=255, verbose_name="contract number"
),
),
]
2 changes: 2 additions & 0 deletions hypha/apply/projects/models/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,8 @@ class Project(BaseStreamForm, AccessFormData, models.Model):
)
proposed_end = models.DateField(_("proposed end date"), null=True)

contract_number = models.CharField(_("contract number"), max_length=255, blank=True)

status = models.TextField(
_("status"), choices=PROJECT_STATUS_CHOICES, default=DRAFT
)
Expand Down
2 changes: 2 additions & 0 deletions hypha/apply/projects/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ class BaseProjectsTable(tables.Table):
verbose_name=_("Status"), accessor="get_status_display", order_by=("status",)
)
fund = tables.Column(verbose_name=_("Fund"), accessor="submission__page")
contract_number = tables.Column(verbose_name=_("Contract nr."), default="-")
reporting = tables.Column(verbose_name=_("Reporting"), accessor="pk")
last_payment_request = RelativeTimeColumn()
end_date = RelativeTimeColumn(verbose_name=_("End date"), accessor="proposed_end")
Expand Down Expand Up @@ -315,6 +316,7 @@ class Meta:
"status",
"lead",
"fund",
"contract_number",
"reporting",
"last_payment_request",
"end_date",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{% load i18n %}
<c-modal.header>{% trans "Update contract number" %}</c-modal.header>

<div class="p-4">
{% include 'includes/dialog_form_base.html' with form=form value=value %}
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
hx-get="{% url 'apply:projects:project_dates_update' object.submission.id %}"
hx-target="#htmx-modal"
>
{% heroicon_micro "pencil-square" aria_hidden=true size=20 %}
{% heroicon_micro "pencil-square" class="text-gray-500" aria_hidden=true size=20 %}
<span class="sr-only">{% trans "edit dates" %}</span>
</a>
{% endif %}
Expand All @@ -53,10 +53,43 @@
hx-get="{% url 'apply:projects:project_dates_update' object.submission.id %}"
hx-target="#htmx-modal"
>
{% heroicon_micro "pencil-square" aria_hidden=true size=20 %}
{% heroicon_micro "pencil-square" class="text-gray-500" aria_hidden=true size=20 %}
<span class="sr-only">{% trans "edit dates" %}</span>
</a>
{% endif %}
</dt>
<dd>{{ object.proposed_end|date:"SHORT_DATE_FORMAT"|default:"-" }}</dd>
</div>

<div class="fieldset">
<dt class="font-semibold">
{% trans "Contract number" %}
{% if request.user.is_org_faculty %}
<a
class="btn btn-xs btn-ghost btn-square"
href="{% url 'apply:projects:project_contract_number_update' object.submission.id %}"
hx-get="{% url 'apply:projects:project_contract_number_update' object.submission.id %}"
hx-target="#htmx-modal"
>
{% heroicon_micro "pencil-square" class="text-gray-500" aria_hidden=true size=20 %}
<span class="sr-only">{% trans "edit contract number" %}</span>
</a>
{% endif %}
</dt>
<dd>
{{ object.contract_number|default:"-" }}
{% if object.contract_number %}
<button
type="button"
class="btn btn-xs btn-ghost btn-square"
x-data="{ copied: false }"
@click="navigator.clipboard.writeText('{{ object.contract_number|escapejs }}'); copied = true; setTimeout(() => copied = false, 2000)"
:title="copied ? '{% trans 'Copied!' %}' : '{% trans 'Copy contract number' %}'"
>
<span x-show="!copied">{% heroicon_micro "clipboard-document" class="text-gray-500" aria_hidden=true size=20 %}</span>
<span x-show="copied" x-cloak>{% heroicon_micro "check" aria_hidden=true size=20 %}</span>
<span class="sr-only">{% trans "copy contract number" %}</span>
</button>
{% endif %}
</dd>
</div>
6 changes: 6 additions & 0 deletions hypha/apply/projects/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
partial_project_lead,
partial_project_title,
partial_supporting_documents,
update_project_contract_number,
update_project_dates,
update_project_title,
)
Expand Down Expand Up @@ -95,6 +96,11 @@
update_project_dates,
name="project_dates_update",
),
path(
"contract-number/update/",
update_project_contract_number,
name="project_contract_number_update",
),
path(
"edit/project-form", ProjectFormEditView.as_view(), name="edit_pf"
),
Expand Down
2 changes: 2 additions & 0 deletions hypha/apply/projects/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
UploadContractDocumentView,
UploadContractView,
UploadDocumentView,
update_project_contract_number,
update_project_dates,
update_project_title,
)
Expand Down Expand Up @@ -72,6 +73,7 @@
"UpdatePAFApproversView",
"update_project_title",
"update_project_dates",
"update_project_contract_number",
"UploadContractDocumentView",
"ChangePAFStatusView",
"UploadDocumentView",
Expand Down
43 changes: 43 additions & 0 deletions hypha/apply/projects/views/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
SetPendingForm,
SkipPAFApprovalProcessForm,
SubmitContractDocumentsForm,
UpdateProjectContractNumberForm,
UpdateProjectDatesForm,
UpdateProjectLeadForm,
UpdateProjectTitleForm,
Expand Down Expand Up @@ -545,6 +546,48 @@ def update_project_dates(request, pk):
return render(request, template_name, ctx)


@login_required
def update_project_contract_number(request, pk):
if not (request.user.is_org_faculty):
raise PermissionDenied

project = get_object_or_404(Project, submission__id=pk)
template_name = "application_projects/modals/project_contract_number_update.html"

form = UpdateProjectContractNumberForm(instance=project)

if request.method == "POST":
form = UpdateProjectContractNumberForm(request.POST, instance=project)

if form.is_valid():
form.save()
messenger(
MESSAGES.UPDATE_PROJECT_CONTRACT_NUMBER,
request=request,
user=request.user,
source=project,
)

return HttpResponse(
status=204,
headers={
"HX-Trigger": json.dumps(
{
"informationUpdated": None,
"showMessage": _("Contract number has been updated"),
}
),
},
)

ctx = {
"form": form,
"value": _("Update"),
"object": project,
}
return render(request, template_name, ctx)


# CONTRACTS


Expand Down
4 changes: 3 additions & 1 deletion hypha/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,9 @@
# Columns/filters to exclude from the projects table.
# Each value hides both the table column and its matching filter (where one exists).
# Possible values are: status, lead, fund, reporting, last_payment_request, end_date
PROJECTS_TABLE_EXCLUDED_FIELDS = env.list("PROJECTS_TABLE_EXCLUDED_FIELDS", [])
PROJECTS_TABLE_EXCLUDED_FIELDS = env.list(
"PROJECTS_TABLE_EXCLUDED_FIELDS", ["contract_number"]
)

# No of co-applicants can be added to a submission (default 10)
SUBMISSIONS_COAPPLICANT_INVITES_LIMIT = env.int(
Expand Down