From c6772a27034d217c2513f0caa9e11356ba31696e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Caux?= <git@jscaux.org> Date: Mon, 28 Nov 2022 19:22:16 +0100 Subject: [PATCH] Cleanup stages, properties and managers --- scipost_django/production/models.py | 8 -- scipost_django/scipost/views.py | 3 +- scipost_django/submissions/forms.py | 10 +-- .../submissions/managers/submission.py | 81 +++++++++-------- .../submissions/models/assignment.py | 5 -- .../submissions/models/communication.py | 9 -- .../submissions/models/recommendation.py | 5 -- .../submissions/models/referee_invitation.py | 5 -- scipost_django/submissions/models/report.py | 19 ---- .../submissions/models/submission.py | 90 ++++++++++--------- .../_hx_submission_workflow_diagram.html | 6 +- .../pool/_hx_submission_details.html | 2 +- .../submissions/pool/_hx_submission_li.html | 2 +- 13 files changed, 103 insertions(+), 142 deletions(-) diff --git a/scipost_django/production/models.py b/scipost_django/production/models.py index 549155d31..65ef71658 100644 --- a/scipost_django/production/models.py +++ b/scipost_django/production/models.py @@ -118,10 +118,6 @@ class ProductionStream(models.Model): def completed(self): return self.status == PRODUCTION_STREAM_COMPLETED - @property - def notification_name(self): - return self.submission.preprint.identifier_w_vn_nr - @property def latest_activity(self): if self.events.last(): @@ -168,10 +164,6 @@ class ProductionEvent(models.Model): and not self.stream.completed ) - @property - def notification_name(self): - return self.stream.notification_name - def production_event_upload_location(instance, filename): submission = instance.production_event.stream.submission diff --git a/scipost_django/scipost/views.py b/scipost_django/scipost/views.py index 3b9be1f43..0023801d2 100644 --- a/scipost_django/scipost/views.py +++ b/scipost_django/scipost/views.py @@ -1137,7 +1137,8 @@ def personal_page_hx_edadmin(request): Report.objects.accepted().filter(pdf_report="").count() ) context["nr_treated_submissions_without_pdf"] = ( - Submission.objects.treated().public().filter(pdf_refereeing_pack="").count() + Submission.objects.treated().public( + ).filter(pdf_refereeing_pack="").count() ) return render(request, "scipost/personal_page/_hx_edadmin.html", context) diff --git a/scipost_django/submissions/forms.py b/scipost_django/submissions/forms.py index e10ec3709..106fec3df 100644 --- a/scipost_django/submissions/forms.py +++ b/scipost_django/submissions/forms.py @@ -230,9 +230,11 @@ class SubmissionPoolSearchForm(forms.Form): ), ), ( - "Revision requested", + "Awaiting resubmission", ( - ("revision_requested", "Minor or major revision requested, awaiting resubmission"), + ( + Submission.AWAITING_RESUBMISSION, + "Awaiting resubmission (minor or major revision requested)"), ), ), ( @@ -450,8 +452,6 @@ class SubmissionPoolSearchForm(forms.Form): timezone.now() - datetime.timedelta(days=90) ) ).distinct().exclude(eicrecommendations__isnull=False) - elif status == "revision_requested": - submissions = submissions.revision_requested() elif status == "voting_prepare": submissions = submissions.voting_in_preparation() elif status == "voting_ongoing": @@ -1462,7 +1462,7 @@ class SubmissionForm(forms.ModelForm): EditorialAssignment.objects.create( submission=submission, to=previous_submission.editor_in_charge, - status=Submission.ACCEPTED, + status=STATUS_ACCEPTED, ) def set_fellowship(self, submission): diff --git a/scipost_django/submissions/managers/submission.py b/scipost_django/submissions/managers/submission.py index e5fbe1ad7..9c02988ef 100644 --- a/scipost_django/submissions/managers/submission.py +++ b/scipost_django/submissions/managers/submission.py @@ -77,11 +77,54 @@ class SubmissionQuerySet(models.QuerySet): def published(self): return self.filter(status=self.model.PUBLISHED) - #### Managers mixing statuses #### + ### Managers for stages #### + def in_stage_incoming(self): + return self.filter(status=self.model.STAGE_INCOMING) + + def stage_incoming_completed(self): + return self.filter(status__in=self.model.stage_incoming_completed_statuses) + + def in_stage_preassignment(self): + return self.filter(status__in=self.model.STAGE_PREASSIGNMENT) + + def stage_preassignment_completed(self): + return self.filter(status__in=self.model.stage_preassignment_completed_statuses) + + def in_stage_assignment(self): + return self.filter(status__in=self.model.STAGE_ASSIGNMENT) + + def stage_assignment_completed(self): + return self.filter(status__in=self.model.stage_assignment_completed_statuses) + + def in_stage_refereeing_in_preparation(self): + return self.filter(status__in=self.model.STAGE_REFEREEING_IN_PREPARATION) + + def stage_refereeing_in_preparation_completed(self): + return self.filter( + status__in=self.model.stage_refereeing_in_preparation_completed_statuses + ) + + def in_stage_in_refereeing(self): + return self.filter(status__in=self.model.STAGE_IN_REFEREEING) + + def stage_in_refereeing_completed(self): + return self.filter(status__in=self.model.stage_in_refereeing_completed_statuses) + + def in_stage_decisionmaking(self): + return self.filter(status__in=self.model.STAGE_DECISIONMAKING) + + def stage_decisionmaking_completed(self): + return self.filter(status__in=self.model.STAGE_DECIDED) + + #### Other managers mixing statuses #### def under_consideration(self): return self.filter(status__in=self.model.UNDER_CONSIDERATION) + def treated(self): + """Returns Submissions (stream heads) whose streams are fully processed.""" + return self.filter(status__in=self.model.TREATED) + def accepted(self): return self.filter(status__in=[ self.model.ACCEPTED_IN_TARGET, @@ -197,17 +240,6 @@ class SubmissionQuerySet(models.QuerySet): """ return self.latest().public() - def treated(self): - """This query returns all Submissions that are presumed to be 'done'.""" - return self.filter( - status__in=[ - self.model.ACCEPTED, - self.model.REJECTED, - self.model.PUBLISHED, - self.model.RESUBMITTED, - ] - ) - def originally_submitted(self, from_date, until_date): """ Returns the submissions originally received between from_date and until_date @@ -221,22 +253,6 @@ class SubmissionQuerySet(models.QuerySet): thread_hashes.append(sub.thread_hash) return self.filter(thread_hash__in=thread_hashes) - def awaiting_puboffer_acceptance(self): - """Return Submissions for which an outstanding publication offer exists.""" - return self.filter( - status=self.model.ACCEPTED_AWAITING_PUBOFFER_ACCEPTANCE - ) - - def revision_requested(self): - """Return Submissions with a fixed EICRecommendation: minor or major revision.""" - return self.filter( - eicrecommendations__status=constants.DECISION_FIXED, - eicrecommendations__recommendation__in=[ - constants.REPORT_MINOR_REV, - constants.REPORT_MAJOR_REV, - ], - ) - def unpublished(self): """Return unpublished Submissions.""" return self.exclude(status=self.model.PUBLISHED) @@ -285,15 +301,6 @@ class SubmissionQuerySet(models.QuerySet): authors=user.contributor, ) - # CLEANUP 2022-11-27 - # def voting_in_preparation(self): - # from submissions.models import EICRecommendation - - # ids_list = [ - # r.submission.id for r in EICRecommendation.objects.voting_in_preparation() - # ] - # return self.filter(id__in=ids_list) - def undergoing_voting(self, longer_than_days=None): from submissions.models import EICRecommendation diff --git a/scipost_django/submissions/models/assignment.py b/scipost_django/submissions/models/assignment.py index d7e549fd0..436f24023 100644 --- a/scipost_django/submissions/models/assignment.py +++ b/scipost_django/submissions/models/assignment.py @@ -64,11 +64,6 @@ class EditorialAssignment(SubmissionRelatedObjectMixin, models.Model): """Return the url of the assignment's processing page.""" return reverse("submissions:assignment_request", args=(self.id,)) - @property - def notification_name(self): - """Return string representation of this EditorialAssigment as shown in Notifications.""" - return self.submission.preprint.identifier_w_vn_nr - @property def preassigned(self): return self.status == STATUS_PREASSIGNED diff --git a/scipost_django/submissions/models/communication.py b/scipost_django/submissions/models/communication.py index b01a52f2e..1ec6e6f5a 100644 --- a/scipost_django/submissions/models/communication.py +++ b/scipost_django/submissions/models/communication.py @@ -43,12 +43,3 @@ class EditorialCommunication(SubmissionRelatedObjectMixin, models.Model): def get_absolute_url(self): """Return the url of the related Submission detail page.""" return self.submission.get_absolute_url() - - def get_notification_url(self, url_code): - """Return url related to the Communication by the `url_code` meant for Notifications.""" - if url_code == "editorial_page": - return reverse( - "submissions:editorial_page", - args=(self.submission.preprint.identifier_w_vn_nr,), - ) - return self.get_absolute_url() diff --git a/scipost_django/submissions/models/recommendation.py b/scipost_django/submissions/models/recommendation.py index a38dbb2a5..fd24cf38b 100644 --- a/scipost_django/submissions/models/recommendation.py +++ b/scipost_django/submissions/models/recommendation.py @@ -89,11 +89,6 @@ class EICRecommendation(SubmissionRelatedObjectMixin, models.Model): """ return self.submission.get_absolute_url() - @property - def notification_name(self): - """Return string representation of this EICRecommendation as shown in Notifications.""" - return self.submission.preprint.identifier_w_vn_nr - @property def nr_for(self): """Return the number of votes 'for'.""" diff --git a/scipost_django/submissions/models/referee_invitation.py b/scipost_django/submissions/models/referee_invitation.py index bcd67cd06..d700bff8c 100644 --- a/scipost_django/submissions/models/referee_invitation.py +++ b/scipost_django/submissions/models/referee_invitation.py @@ -106,11 +106,6 @@ class RefereeInvitation(SubmissionRelatedObjectMixin, models.Model): return str(self.referee) return self.last_name + ", " + self.first_name - @property - def notification_name(self): - """Return string representation of this RefereeInvitation as shown in Notifications.""" - return self.submission.preprint.identifier_w_vn_nr - @property def related_report(self): """Return the Report that's been created for this invitation.""" diff --git a/scipost_django/submissions/models/report.py b/scipost_django/submissions/models/report.py index 86ec84b77..85e5fb9d0 100644 --- a/scipost_django/submissions/models/report.py +++ b/scipost_django/submissions/models/report.py @@ -171,20 +171,6 @@ class Report(SubmissionRelatedObjectMixin, models.Model): """Return url of the Report on the Submission detail page.""" return self.submission.get_absolute_url() + "#report_" + str(self.report_nr) - def get_notification_url(self, url_code): - """Return url related to the Report by the `url_code` meant for Notifications.""" - if url_code == "report_form": - return reverse( - "submissions:submit_report", - args=(self.submission.preprint.identifier_w_vn_nr,), - ) - elif url_code == "editorial_page": - return reverse( - "submissions:editorial_page", - args=(self.submission.preprint.identifier_w_vn_nr,), - ) - return self.get_absolute_url() - def get_attachment_url(self): """Return url of the Report its attachment if exists.""" return reverse( @@ -220,11 +206,6 @@ class Report(SubmissionRelatedObjectMixin, models.Model): STATUS_NOT_ACADEMIC, ] - @property - def notification_name(self): - """Return string representation of this Report as shown in Notifications.""" - return self.submission.preprint.identifier_w_vn_nr - @property def doi_string(self): """Return the doi with the registrant identifier prefix.""" diff --git a/scipost_django/submissions/models/submission.py b/scipost_django/submissions/models/submission.py index 6a4d0123c..5ad4514e1 100644 --- a/scipost_django/submissions/models/submission.py +++ b/scipost_django/submissions/models/submission.py @@ -141,7 +141,13 @@ class Submission(models.Model): WITHDRAWN, PUBLISHED, ) - + TREATED = ( + ACCEPTED_IN_TARGET, + ACCEPTED_IN_ALTERNATIVE, + REJECTED, + WITHDRAWN, + PUBLISHED, + ) # Fields preprint = models.OneToOneField( "preprints.Preprint", on_delete=models.CASCADE, related_name="submission" @@ -322,8 +328,8 @@ class Submission(models.Model): return self.status in self.STAGE_INCOMING @property - def stage_incoming_completed(self): - return self.status in ( + def stage_incoming_completed_statuses(self): + return ( self.STAGE_PREASSIGNMENT + self.STAGE_ASSIGNMENT + self.STAGE_REFEREEING_IN_PREPARATION + @@ -332,59 +338,84 @@ class Submission(models.Model): self.STAGE_DECIDED ) + @property + def stage_incoming_completed(self): + return self.status in self.stage_incoming_completed_statuses + @property def in_stage_preassignment(self): return self.status in self.STAGE_PREASSIGNMENT @property - def stage_preassignment_completed(self): - return self.status in ( + def stage_preassignment_completed_statuses(self): + return ( self.STAGE_ASSIGNMENT + self.STAGE_REFEREEING_IN_PREPARATION + self.STAGE_IN_REFEREEING + self.STAGE_DECISIONMAKING + self.STAGE_DECIDED ) + + @property + def stage_preassignment_completed(self): + return self.status in self.stage_preassignment_completed_statuses + @property def in_stage_assignment(self): return self.status in self.STAGE_ASSIGNMENT @property - def stage_assignment_completed(self): - return self.status in ( + def stage_assignment_completed_statuses(self): + return ( self.STAGE_REFEREEING_IN_PREPARATION + self.STAGE_IN_REFEREEING + self.STAGE_DECISIONMAKING + self.STAGE_DECIDED ) + @property + def stage_assignment_completed(self): + return self.status in self.stage_assignment_completed_statuses + @property def in_stage_refereeing_in_preparation(self): return self.status in self.STAGE_REFEREEING_IN_PREPARATION @property - def stage_refereeing_in_preparation_completed(self): - return self.status in ( + def stage_refereeing_in_preparation_completed_statuses(self): + return ( self.STAGE_IN_REFEREEING + self.STAGE_DECISIONMAKING + self.STAGE_DECIDED ) + @property + def stage_refereeing_in_preparation_completed(self): + return self.status in self.stage_refereeing_in_preparation_completed_statuses + @property def in_stage_in_refereeing(self): return self.status in self.STAGE_IN_REFEREEING @property - def stage_in_refereeing_completed(self): - return self.status in ( + def stage_in_refereeing_completed_statuses(self): + return ( self.STAGE_DECISIONMAKING + self.STAGE_DECIDED ) + @property + def stage_in_refereeing_completed(self): + return self.status in self.stage_in_refereeing_completed_statuses + @property def in_stage_decisionmaking(self): return self.status in self.STAGE_DECISIONMAKING + @property + def stage_decisionmaking_completed_statuses(self): # include for completeness + return self.STAGE_DECIDED + @property def stage_decisionmaking_completed(self): return self.in_stage_decided @@ -453,23 +484,10 @@ class Submission(models.Model): "submissions:submission", args=(self.preprint.identifier_w_vn_nr,) ) - def get_notification_url(self, url_code): - """Return url related to the Submission by the `url_code` meant for Notifications.""" - if url_code == "editorial_page": - return reverse( - "submissions:editorial_page", args=(self.preprint.identifier_w_vn_nr,) - ) - return self.get_absolute_url() - @property def is_resubmission(self): return self.is_resubmission_of is not None - @property - def notification_name(self): - """Return string representation of this Submission as shown in Notifications.""" - return self.preprint.identifier_w_vn_nr - @property def eic_recommendation_required(self): """Return if Submission requires a EICRecommendation to be formulated.""" @@ -535,22 +553,10 @@ class Submission(models.Model): .submission_date ) - @property - def in_preassignment(self): - return self.status == self.INCOMING - @property def can_reset_reporting_deadline(self): """Check if reporting deadline is allowed to be reset.""" - blocked_statuses = [ - self.PREASSIGNMENT_FAILED, - self.RESUBMITTED, - self.ACCEPTED, - self.REJECTED, - self.WITHDRAWN, - self.PUBLISHED, - ] - if self.status in blocked_statuses: + if self.status in STAGE_DECIDED: return False if self.refereeing_cycle == CYCLE_DIRECT_REC: @@ -658,20 +664,18 @@ class Submission(models.Model): return self.editorial_assignments.filter(status=STATUS_PREASSIGNED).exists() - def has_inadequate_pool_composition(self): + def has_inadequate_fellowship_composition(self): """ - Check whether the EIC actually in the pool of the Submission. - - (Could happen on resubmission or reassignment after wrong Journal selection) + Check whether the EIC is actually in the fellowship of the Submission. """ if not self.editor_in_charge: # None assigned yet. return False - pool_contributors_ids = Contributor.objects.filter( + contributors_ids = Contributor.objects.filter( fellowships__pool=self ).values_list("id", flat=True) - return self.editor_in_charge.id not in pool_contributors_ids + return self.editor_in_charge.id not in contributors_ids @property def editorial_decision(self): diff --git a/scipost_django/submissions/templates/submissions/_hx_submission_workflow_diagram.html b/scipost_django/submissions/templates/submissions/_hx_submission_workflow_diagram.html index 6630a2e40..be09739fe 100644 --- a/scipost_django/submissions/templates/submissions/_hx_submission_workflow_diagram.html +++ b/scipost_django/submissions/templates/submissions/_hx_submission_workflow_diagram.html @@ -35,7 +35,7 @@ flowchart LR end Sub --> Admiss Admiss --fail--> AdmissFailed("Admission<br>failed ✉<small>A</small>") --> Close([Processing<br>closed]) - Admiss --pass--> AdmissPassed("Admission<br>passed ✉<small>A</small>") --> Preassignment[[Goto:<br>preassignment]] + Admiss --pass--> AdmissPassed("Admission<br>passed ✉<small>A</small>") --> Preassignment[[Goto:<br>Preassignment]] </pre> </details> </div> @@ -48,13 +48,13 @@ flowchart LR <pre class="mermaid workflowDiagram"> flowchart LR AdmissPassed([Admission<br>passed]) - subgraph preassignment + subgraph Preassignment PreTop(Submission<br>Topics<br>specification) --> ProfMatch(Author<br>Profiles<br>matching) ProfMatch --> PreCOI(Conflict<br>of interest<br>checks) PreCOI --> PrePa(Listing of<br>potential<br>Editors-in-charge) end AdmissPassed --> PreTop - PrePa --no qualified<br>Fellows--> PreFail("preassignment<br>failed ✉<small>A</small>") --> Close([Processing<br>closed]) + PrePa --no qualified<br>Fellows--> PreFail("Preassignment<br>failed ✉<small>A</small>") --> Close([Processing<br>closed]) PrePa --"∃ qualified<br>Fellows"--> PrePass("Preassignment<br>passed ✉<small>A</small>") --> Assignment[[Goto:<br>Assignment]] </pre> </details> diff --git a/scipost_django/submissions/templates/submissions/pool/_hx_submission_details.html b/scipost_django/submissions/templates/submissions/pool/_hx_submission_details.html index a4882c528..952c644e1 100644 --- a/scipost_django/submissions/templates/submissions/pool/_hx_submission_details.html +++ b/scipost_django/submissions/templates/submissions/pool/_hx_submission_details.html @@ -97,7 +97,7 @@ </ul> </li> <li class="pb-2"> - {% if submission.in_preassignment %} + {% if submission.in_stage_preassignment %} <a href="{% url 'submissions:do_preassignment' submission.preprint.identifier_w_vn_nr %}">Preassignment</a> {% else %} Preassignment completed diff --git a/scipost_django/submissions/templates/submissions/pool/_hx_submission_li.html b/scipost_django/submissions/templates/submissions/pool/_hx_submission_li.html index ea37e5a42..b572b3ae8 100644 --- a/scipost_django/submissions/templates/submissions/pool/_hx_submission_li.html +++ b/scipost_django/submissions/templates/submissions/pool/_hx_submission_li.html @@ -84,7 +84,7 @@ {% endif %} </div> </div> - {% if is_ed_admin and submission.has_inadequate_pool_composition %} + {% if is_ed_admin and submission.has_inadequate_fellowship_composition %} <div class="border border-danger text-danger mt-1 py-1 px-2"> <strong> {% include 'bi/exclamation-triangle-fill.html' %} -- GitLab