Skip to content

Commit b389175

Browse files
committed
Added missing migration, fixed/added docstrings, inital implementation of unit tests
1 parent f366fcb commit b389175

10 files changed

Lines changed: 589 additions & 31 deletions

File tree

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Generated by Django 5.2.11 on 2026-02-27 16:14
2+
3+
import django.db.models.deletion
4+
from django.conf import settings
5+
from django.db import migrations, models
6+
7+
8+
class Migration(migrations.Migration):
9+
dependencies = [
10+
("activity", "0088_activity_deleted"),
11+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
12+
]
13+
14+
operations = [
15+
migrations.AlterField(
16+
model_name="activity",
17+
name="user",
18+
field=models.ForeignKey(
19+
on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
20+
),
21+
),
22+
migrations.AlterField(
23+
model_name="event",
24+
name="by",
25+
field=models.ForeignKey(
26+
null=True,
27+
on_delete=django.db.models.deletion.CASCADE,
28+
to=settings.AUTH_USER_MODEL,
29+
),
30+
),
31+
migrations.AlterField(
32+
model_name="event",
33+
name="type",
34+
field=models.CharField(
35+
choices=[
36+
("UPDATE_LEAD", "updated lead"),
37+
("BATCH_UPDATE_LEAD", "batch updated lead"),
38+
("EDIT_SUBMISSION", "edited submission"),
39+
("APPLICANT_EDIT", "edited applicant"),
40+
("NEW_SUBMISSION", "submitted new submission"),
41+
("DRAFT_SUBMISSION", "submitted new draft submission"),
42+
("SCREENING", "screened"),
43+
("TRANSITION", "transitioned"),
44+
("BATCH_TRANSITION", "batch transitioned"),
45+
("DETERMINATION_OUTCOME", "sent determination outcome"),
46+
("BATCH_DETERMINATION_OUTCOME", "sent batch determination outcome"),
47+
("INVITED_TO_PROPOSAL", "invited to proposal"),
48+
("REVIEWERS_UPDATED", "updated reviewers"),
49+
("BATCH_REVIEWERS_UPDATED", "batch updated reviewers"),
50+
("PARTNERS_UPDATED", "updated partners"),
51+
("PARTNERS_UPDATED_PARTNER", "partners updated partner"),
52+
("READY_FOR_REVIEW", "marked ready for review"),
53+
("BATCH_READY_FOR_REVIEW", "marked batch ready for review"),
54+
("NEW_REVIEW", "added new review"),
55+
("COMMENT", "added comment"),
56+
("PROPOSAL_SUBMITTED", "submitted proposal"),
57+
("OPENED_SEALED", "opened sealed submission"),
58+
("REVIEW_OPINION", "reviewed opinion"),
59+
("DELETE_SUBMISSION", "deleted submission"),
60+
("ANONYMIZE_SUBMISSION", "anonymized submission"),
61+
("DELETE_REVIEW", "deleted review"),
62+
("DELETE_REVIEW_OPINION", "deleted review opinion"),
63+
("CREATED_PROJECT", "created project"),
64+
("UPDATE_PROJECT_LEAD", "updated project lead"),
65+
("UPDATE_PROJECT_TITLE", "updated project title"),
66+
("EDIT_REVIEW", "edited review"),
67+
("SEND_FOR_APPROVAL", "sent for approval"),
68+
("APPROVE_PROJECT", "approved project"),
69+
("ASSIGN_PAF_APPROVER", "assign project form approver"),
70+
("APPROVE_PAF", "approved project form"),
71+
("PROJECT_TRANSITION", "transitioned project"),
72+
("REQUEST_PROJECT_CHANGE", "requested project change"),
73+
("SUBMIT_CONTRACT_DOCUMENTS", "submitted contract documents"),
74+
("UPLOAD_DOCUMENT", "uploaded document to project"),
75+
("UPLOAD_CONTRACT", "uploaded contract to project"),
76+
("APPROVE_CONTRACT", "approved contract"),
77+
("CREATE_INVOICE", "created invoice for project"),
78+
("UPDATE_INVOICE_STATUS", "updated invoice status"),
79+
("APPROVE_INVOICE", "approve invoice"),
80+
("DELETE_INVOICE", "deleted invoice"),
81+
("SENT_TO_COMPLIANCE", "sent project to compliance"),
82+
("UPDATE_INVOICE", "updated invoice"),
83+
("SUBMIT_REPORT", "submitted report"),
84+
("SKIPPED_REPORT", "skipped report"),
85+
("REPORT_FREQUENCY_CHANGED", "changed report frequency"),
86+
("DISABLED_REPORTING", "disabled reporting"),
87+
("REPORT_NOTIFY", "notified report"),
88+
("REVIEW_REMINDER", "reminder to review"),
89+
("BATCH_DELETE_SUBMISSION", "batch deleted submissions"),
90+
("BATCH_SKELETON_SUBMISSION", "batch anonymized submissions"),
91+
("BATCH_ARCHIVE_SUBMISSION", "batch archive submissions"),
92+
("BATCH_INVOICE_STATUS_UPDATE", "batch update invoice status"),
93+
("STAFF_ACCOUNT_CREATED", "created new account"),
94+
("STAFF_ACCOUNT_EDITED", "edited account"),
95+
("ARCHIVE_SUBMISSION", "archived submission"),
96+
("UNARCHIVE_SUBMISSION", "unarchived submission"),
97+
("REMOVE_TASK", "remove task"),
98+
("INVITE_COAPPLICANT", "invite co-applicant"),
99+
],
100+
max_length=50,
101+
verbose_name="verb",
102+
),
103+
),
104+
]
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
# Generated by Django 5.2.11 on 2026-02-27 16:55
2+
3+
import django.contrib.postgres.fields
4+
import django.db.models.deletion
5+
from django.conf import settings
6+
from django.db import migrations, models
7+
8+
9+
class Migration(migrations.Migration):
10+
dependencies = [
11+
("funds", "0131_delete_orphaned_attachments"),
12+
("wagtailcore", "0094_alter_page_locale"),
13+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
14+
]
15+
16+
operations = [
17+
migrations.AlterField(
18+
model_name="applicationsubmission",
19+
name="user",
20+
field=models.ForeignKey(
21+
null=True,
22+
on_delete=django.db.models.deletion.CASCADE,
23+
to=settings.AUTH_USER_MODEL,
24+
),
25+
),
26+
migrations.CreateModel(
27+
name="ApplicationSubmissionSkeleton",
28+
fields=[
29+
(
30+
"id",
31+
models.AutoField(
32+
auto_created=True,
33+
primary_key=True,
34+
serialize=False,
35+
verbose_name="ID",
36+
),
37+
),
38+
("value", models.FloatField(null=True)),
39+
(
40+
"status",
41+
models.CharField(
42+
choices=[
43+
("accepted", "Accepted"),
44+
("almost", "Accepted but additional info required"),
45+
("com_accepted", "Accepted"),
46+
("com_almost", "Accepted but additional info required"),
47+
("com_community_review", "Community Review"),
48+
("com_determination", "Ready for Determination"),
49+
("com_external_review", "External Review"),
50+
("com_internal_review", "Internal Review"),
51+
("com_more_info", "More information required"),
52+
("com_open_call", "Open Call (public)"),
53+
(
54+
"com_post_external_review_discussion",
55+
"Ready For Discussion",
56+
),
57+
(
58+
"com_post_external_review_more_info",
59+
"More information required",
60+
),
61+
("com_post_review_discussion", "Ready For Discussion"),
62+
("com_post_review_more_info", "More information required"),
63+
("com_rejected", "Dismissed"),
64+
(
65+
"concept_determination",
66+
"Ready for Preliminary Determination",
67+
),
68+
("concept_internal_review", "Internal Review"),
69+
("concept_more_info", "More information required"),
70+
("concept_rejected", "Dismissed"),
71+
("concept_review_discussion", "Ready For Discussion"),
72+
("concept_review_more_info", "More information required"),
73+
("determination", "Ready for Determination"),
74+
("draft", "Draft"),
75+
("draft_proposal", "Invited for Proposal"),
76+
("ext_accepted", "Accepted"),
77+
("ext_almost", "Accepted but additional info required"),
78+
("ext_determination", "Ready for Determination"),
79+
("ext_external_review", "External Review"),
80+
("ext_internal_review", "Internal Review"),
81+
("ext_more_info", "More information required"),
82+
(
83+
"ext_post_external_review_discussion",
84+
"Ready For Discussion",
85+
),
86+
(
87+
"ext_post_external_review_more_info",
88+
"More information required",
89+
),
90+
("ext_post_review_discussion", "Ready For Discussion"),
91+
("ext_post_review_more_info", "More information required"),
92+
("ext_rejected", "Dismissed"),
93+
("external_review", "External Review"),
94+
("in_discussion", "Need screening"),
95+
("internal_review", "Internal Review"),
96+
("invited_to_proposal", "Concept Accepted"),
97+
("more_info", "More information required"),
98+
("post_external_review_discussion", "Ready For Discussion"),
99+
(
100+
"post_external_review_more_info",
101+
"More information required",
102+
),
103+
("post_proposal_review_discussion", "Ready For Discussion"),
104+
(
105+
"post_proposal_review_more_info",
106+
"More information required",
107+
),
108+
("post_review_discussion", "Ready For Discussion"),
109+
("post_review_more_info", "More information required"),
110+
("proposal_accepted", "Accepted"),
111+
(
112+
"proposal_almost",
113+
"Accepted but additional info required",
114+
),
115+
("proposal_determination", "Ready for Final Determination"),
116+
("proposal_discussion", "Proposal Received"),
117+
("proposal_internal_review", "Internal Review"),
118+
("proposal_more_info", "More information required"),
119+
("proposal_rejected", "Dismissed"),
120+
("rejected", "Dismissed"),
121+
("same_accepted", "Accepted"),
122+
("same_almost", "Accepted but additional info required"),
123+
("same_determination", "Ready for Determination"),
124+
("same_internal_review", "Review"),
125+
("same_more_info", "More information required"),
126+
("same_post_review_discussion", "Ready For Discussion"),
127+
("same_post_review_more_info", "More information required"),
128+
("same_rejected", "Dismissed"),
129+
],
130+
default="in_discussion",
131+
max_length=100,
132+
),
133+
),
134+
(
135+
"category",
136+
django.contrib.postgres.fields.ArrayField(
137+
base_field=models.CharField(), null=True, size=None
138+
),
139+
),
140+
("submit_time", models.DateTimeField(verbose_name="submit time")),
141+
(
142+
"page",
143+
models.ForeignKey(
144+
on_delete=django.db.models.deletion.PROTECT,
145+
to="wagtailcore.page",
146+
),
147+
),
148+
(
149+
"round",
150+
models.ForeignKey(
151+
null=True,
152+
on_delete=django.db.models.deletion.PROTECT,
153+
related_name="skeleton_submissions",
154+
to="wagtailcore.page",
155+
),
156+
),
157+
(
158+
"screening_status",
159+
models.ForeignKey(
160+
blank=True,
161+
null=True,
162+
on_delete=django.db.models.deletion.PROTECT,
163+
related_name="skeleton_submissions",
164+
to="funds.screeningstatus",
165+
),
166+
),
167+
(
168+
"user",
169+
models.ForeignKey(
170+
null=True,
171+
on_delete=django.db.models.deletion.SET_NULL,
172+
to=settings.AUTH_USER_MODEL,
173+
),
174+
),
175+
],
176+
),
177+
]

hypha/apply/funds/models/submissions.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,8 +1122,12 @@ class ApplicationSubmissionSkeleton(models.Model):
11221122
verbose_name=_("submit time"), auto_now_add=False
11231123
)
11241124

1125-
screening_statuses = models.ManyToManyField(
1126-
"funds.ScreeningStatus", related_name="skeleton_submissions", blank=True
1125+
screening_status = models.ForeignKey(
1126+
"funds.ScreeningStatus",
1127+
related_name="skeleton_submissions",
1128+
null=True,
1129+
blank=True,
1130+
on_delete=models.PROTECT,
11271131
)
11281132

11291133
@classmethod
@@ -1168,8 +1172,9 @@ def from_dict(
11681172
value=value,
11691173
status=dict_submission.get("status")
11701174
or dict_submission.get("applicationsubmission__status"),
1171-
submit_time=dict_submission.get("submit_time")
1172-
or dict_submission.get("applicationsubmission__submit_time"),
1175+
submit_time=dict_submission.get("submit_time"),
1176+
screening_status_id=dict_submission.get("screening_statuses")
1177+
or dict_submission.get("applicationsubmission__screening_statuses"),
11731178
)
11741179

11751180
return skeleton
@@ -1200,12 +1205,11 @@ def from_submission(
12001205
value=submission.form_data.get("value", None),
12011206
status=submission.status,
12021207
submit_time=submission.submit_time,
1208+
screening_status=submission.get_current_screening_status(),
12031209
)
12041210

12051211
# TODO: Handle categories here
12061212

1207-
skeleton.screening_statuses.set(submission.screening_statuses.all())
1208-
12091213
skeleton.save()
12101214

12111215
return skeleton

hypha/apply/funds/services.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,20 +96,29 @@ def bulk_covert_to_skeleton_submissions(
9696
9797
Args:
9898
submissions: queryset of submissions to convert to skeleton applications
99-
user: user who is archiving the submissions
99+
user: user who is anonymizing the submissions
100100
request: django request object
101101
102102
Returns:
103103
QuerySet of submissions that have been archived
104104
"""
105+
print("REQUEST PATH")
106+
print(request.path)
105107
ApplicationSubmission = apps.get_model("funds", "ApplicationSubmission")
106108
ApplicationSubmissionSkeleton = apps.get_model(
107109
"funds", "ApplicationSubmissionSkeleton"
108110
)
109111

110112
# delete NEW_SUBMISSION events for all submissions
111113
submission_dict_list = submissions.values(
112-
"id", "form_data", "page_id", "round_id", "status", "submit_time"
114+
"id",
115+
"form_data",
116+
"page_id",
117+
"round_id",
118+
"status",
119+
"submit_time",
120+
"user_id",
121+
"screening_statuses",
113122
)
114123

115124
submission_ids = [x["id"] for x in submission_dict_list]
@@ -118,9 +127,12 @@ def bulk_covert_to_skeleton_submissions(
118127
type=MESSAGES.NEW_SUBMISSION, object_id__in=submission_ids
119128
).delete()
120129

130+
skeletons = []
121131
for submission_dict in submission_dict_list:
122132
if submission_dict["status"] != DRAFT_STATE:
123-
ApplicationSubmissionSkeleton.from_dict(submission_dict)
133+
skeletons.append(
134+
ApplicationSubmissionSkeleton.from_dict(submission_dict, save_user=True)
135+
)
124136

125137
# delete submissions
126138
submissions = ApplicationSubmission.objects.filter(id__in=submission_ids)
@@ -142,7 +154,7 @@ def bulk_covert_to_skeleton_submissions(
142154
sources=submissions,
143155
)
144156

145-
return submissions
157+
return skeletons
146158

147159

148160
def bulk_update_lead(

0 commit comments

Comments
 (0)