From 0e89fa7a300b2efd2cb61718805a1c4c2a6ac8b3 Mon Sep 17 00:00:00 2001
From: "J.-S. Caux" <J.S.Caux@uva.nl>
Date: Wed, 16 Jan 2019 13:18:34 +0100
Subject: [PATCH] Add withdrawal facilities for authors

---
 scipost/forms.py                              |  3 +-
 .../scipost/personal_page/submissions.html    | 21 +++++---
 submissions/constants.py                      |  5 ++
 submissions/managers.py                       |  5 +-
 submissions/models.py                         | 12 ++++-
 .../submissions/withdraw_manuscript.html      | 30 +++++++++++
 submissions/views.py                          | 52 ++++++++++++++++---
 .../inform_authors_manuscript_withdrawn.html  | 20 +++++++
 .../inform_authors_manuscript_withdrawn.json  |  8 +++
 .../eic/inform_eic_manuscript_withdrawn.html  | 19 +++++++
 .../eic/inform_eic_manuscript_withdrawn.json  |  8 +++
 .../inform_referee_manuscript_withdrawn.html  | 20 +++++++
 .../inform_referee_manuscript_withdrawn.json  |  8 +++
 13 files changed, 192 insertions(+), 19 deletions(-)
 create mode 100644 submissions/templates/submissions/withdraw_manuscript.html
 create mode 100644 templates/email/authors/inform_authors_manuscript_withdrawn.html
 create mode 100644 templates/email/authors/inform_authors_manuscript_withdrawn.json
 create mode 100644 templates/email/eic/inform_eic_manuscript_withdrawn.html
 create mode 100644 templates/email/eic/inform_eic_manuscript_withdrawn.json
 create mode 100644 templates/email/referees/inform_referee_manuscript_withdrawn.html
 create mode 100644 templates/email/referees/inform_referee_manuscript_withdrawn.json

diff --git a/scipost/forms.py b/scipost/forms.py
index 73f3edd60..ce06040a9 100644
--- a/scipost/forms.py
+++ b/scipost/forms.py
@@ -711,4 +711,5 @@ class SendPrecookedEmailForm(forms.Form):
 
 class ConfirmationForm(forms.Form):
     confirm = forms.ChoiceField(widget=forms.RadioSelect,
-                                choices=((True, 'Confirm'), (False, 'Abort')))
+                                choices=((True, 'Confirm'), (False, 'Abort')),
+                                label='')
diff --git a/scipost/templates/partials/scipost/personal_page/submissions.html b/scipost/templates/partials/scipost/personal_page/submissions.html
index db08f85fd..c46d0f976 100644
--- a/scipost/templates/partials/scipost/personal_page/submissions.html
+++ b/scipost/templates/partials/scipost/personal_page/submissions.html
@@ -28,14 +28,19 @@
                         {% include 'partials/submissions/submission_status.html' with submission=sub %}
 
                         {% if request.user.contributor == sub.submitted_by %}
-                            <p class="card-text mt-1">
-                                {% if sub.editor_in_charge %}
-                                    <a href="{% url 'submissions:communication' sub.preprint.identifier_w_vn_nr 'AtoE' %}">Write to the Editor-in-charge</a>
-                                {% endif %}
-                                {% if sub.open_for_resubmission %}
-                                    &middot; <a href="{% url 'submissions:prefill_using_identifier' %}?identifier={{ sub.preprint.identifier_wo_vn_nr }}">Resubmit this manuscript</a>
-                                {% endif %}
-                            </p>
+                        <p class="card-text mt-1">
+			  <ul>
+                            {% if sub.open_for_resubmission %}
+                            <li><a href="{% url 'submissions:prefill_using_identifier' %}?identifier={{ sub.preprint.identifier_wo_vn_nr }}">Resubmit this manuscript</a></li>
+                            {% endif %}
+			    {% if sub.under_consideration %}
+                            {% if sub.editor_in_charge %}
+                            <li><a href="{% url 'submissions:communication' sub.preprint.identifier_w_vn_nr 'AtoE' %}">Write to the Editor-in-charge</a></li>
+                            {% endif %}
+			    <li><a href="{% url 'submissions:withdraw_manuscript' sub.preprint.identifier_w_vn_nr %}"><span class="text-danger">Withdraw</span></a> (leads to confirmation page)</li>
+			    {% endif %}
+			  </ul>
+                        </p>
                         {% endif %}
                     </div>
                 </li>
diff --git a/submissions/constants.py b/submissions/constants.py
index 666b36e3e..c09a7b721 100644
--- a/submissions/constants.py
+++ b/submissions/constants.py
@@ -36,6 +36,11 @@ SUBMISSION_STATUS = (
     (STATUS_PUBLISHED, 'Published'),
 )
 
+# Submissions which are currently under consideration
+SUBMISSION_UNDER_CONSIDERATION = [
+    STATUS_INCOMING, STATUS_UNASSIGNED, STATUS_EIC_ASSIGNED, STATUS_RESUBMITTED
+]
+
 # Submissions with these statuses never have required actions.
 NO_REQUIRED_ACTION_STATUSES = [
     STATUS_UNASSIGNED,
diff --git a/submissions/managers.py b/submissions/managers.py
index 16325e83b..11bb6330c 100644
--- a/submissions/managers.py
+++ b/submissions/managers.py
@@ -394,9 +394,12 @@ class RefereeInvitationQuerySet(models.QuerySet):
     def declined(self):
         return self.filter(accepted=False)
 
-    def open(self):
+    def open(self): # WRONG: pending already filters for cancelled=False
         return self.pending().filter(cancelled=False)
 
+    def outstanding(self):
+        return self.filter(cancelled=False).exclude(accepted=False).exclude(fulfilled=True)
+
     def in_process(self):
         return self.accepted().filter(fulfilled=False, cancelled=False)
 
diff --git a/submissions/models.py b/submissions/models.py
index 771efd34b..b5d6ca7ae 100644
--- a/submissions/models.py
+++ b/submissions/models.py
@@ -18,7 +18,9 @@ from .behaviors import SubmissionRelatedObjectMixin
 from .constants import (
     ASSIGNMENT_REFUSAL_REASONS, ASSIGNMENT_NULLBOOL, SUBMISSION_TYPE, STATUS_PREASSIGNED,
     ED_COMM_CHOICES, REFEREE_QUALIFICATION, QUALITY_SPEC, RANKING_CHOICES, REPORT_REC,
-    SUBMISSION_STATUS, REPORT_STATUSES, STATUS_UNVETTED, STATUS_INCOMING, STATUS_EIC_ASSIGNED,
+    SUBMISSION_STATUS,
+    SUBMISSION_UNDER_CONSIDERATION,
+    REPORT_STATUSES, STATUS_UNVETTED, STATUS_INCOMING, STATUS_EIC_ASSIGNED,
     SUBMISSION_CYCLES, CYCLE_DEFAULT, CYCLE_SHORT, DECISION_FIXED, ASSIGNMENT_STATUSES,
     CYCLE_DIRECT_REC, EVENT_GENERAL, EVENT_TYPES, EVENT_FOR_AUTHOR, EVENT_FOR_EIC, REPORT_TYPES,
     REPORT_NORMAL, STATUS_DRAFT, STATUS_VETTED, EIC_REC_STATUSES, VOTING_IN_PREP, STATUS_UNASSIGNED,
@@ -217,6 +219,14 @@ class Submission(models.Model):
         """Check if Submission has fixed EICRecommendation asking for revision."""
         return self.eicrecommendations.fixed().asking_revision().exists()
 
+    @property
+    def under_consideration(self):
+        """
+        Check if the Submission is currently under consideration
+        (in other words: is undergoing editorial processing).
+        """
+        return self.status in SUBMISSION_UNDER_CONSIDERATION
+
     @property
     def open_for_resubmission(self):
         """Check if Submission has fixed EICRecommendation asking for revision."""
diff --git a/submissions/templates/submissions/withdraw_manuscript.html b/submissions/templates/submissions/withdraw_manuscript.html
new file mode 100644
index 000000000..8fb4603b1
--- /dev/null
+++ b/submissions/templates/submissions/withdraw_manuscript.html
@@ -0,0 +1,30 @@
+{% extends 'scipost/base.html' %}
+
+{% load bootstrap %}
+
+{% block pagetitle %}: withdraw manuscript{% endblock pagetitle %}
+
+{% block content %}
+
+<div class="row">
+  <div class="col-12">
+    <h3 class="mt-2">Submission summary</h3>
+    {% include 'partials/submissions/submission_summary.html' with submission=submission hide_title=1 show_abstract=0 %}
+    {% include 'partials/submissions/submission_status.html' with submission=submission %}
+  </div>
+</div>
+
+<div class="row">
+  <div class="col-12">
+    <h3 class="text-danger">Are you sure you want to withdraw this manuscript?</h3>
+    <p>This will terminate the editorial process for the above submission.</p>
+    <form action="{% url 'submissions:withdraw_manuscript' submission.preprint.identifier_w_vn_nr %}" method="post">
+      {% csrf_token %}
+      {{ form }}
+      <p class="text-danger">CAREFUL: ONE-CLICK, ONE-WAY ACTION!&nbsp;
+      <input class="btn btn-danger" type="submit" value="Submit"></p>
+    </form>
+  </div>
+</div>
+
+{% endblock content %}
diff --git a/submissions/views.py b/submissions/views.py
index d79e49f47..387591ae7 100644
--- a/submissions/views.py
+++ b/submissions/views.py
@@ -24,8 +24,10 @@ from django.views.generic.edit import CreateView, UpdateView
 from django.views.generic.list import ListView
 
 from .constants import (
-    STATUS_VETTED, STATUS_EIC_ASSIGNED, SUBMISSION_STATUS, STATUS_ASSIGNMENT_FAILED,
-    STATUS_DRAFT, CYCLE_DIRECT_REC, STATUS_ACCEPTED, STATUS_DEPRECATED)
+    STATUS_VETTED,
+    STATUS_EIC_ASSIGNED, SUBMISSION_STATUS, STATUS_ASSIGNMENT_FAILED, STATUS_WITHDRAWN,
+    STATUS_DRAFT, CYCLE_DIRECT_REC, STATUS_ACCEPTED, STATUS_COMPLETED, STATUS_DEPRECATED,
+    DEPRECATED)
 from .helpers import check_verified_author, check_unverified_author
 from .models import (
     Submission, EICRecommendation, EditorialAssignment, RefereeInvitation, Report, SubmissionEvent)
@@ -229,31 +231,65 @@ def withdraw_manuscript(request, identifier_w_vn_nr):
 
     This method performs the following actions:
     - makes the Submission and its previous versions publicly invisible
-    - marks any Editorial Assignment as completed, emailing the EIC
+    - marks any Editorial Assignment as completed
+    - deprecates any Editorial Recommendation
+    - emailing authors, EIC (cc to EdAdmin)
     - deprecates all outstanding refereeing requests (emailing referees)
-    - adds an event for the authors
+    - adds an event.
 
     GET shows the info/confirm page
     POST performs the action and returns to the personal page.
     """
     submission = get_object_or_404(Submission,
                                    preprint__identifier_w_vn_nr=identifier_w_vn_nr)
-    is_author = check_verified_author(submission, request.user)
 
-    if not is_author:
-        errormessage = ('You are not marked as an author of this Submission, '
+    if not (request.user.contributor.id == submission.submitted_by.id):
+        errormessage = ('You are not marked as the submitting author of this Submission, '
                         'and thus are not allowed to withdraw it.')
         return render(request, 'scipost/error.html', {'errormessage': errormessage})
 
     form = ConfirmationForm(request.POST or None)
     if form.is_valid():
         if form.cleaned_data['confirm'] == 'True':
+            # Update submission (current + any previous versions)
+            Submission.objects.filter(id=submission.id).update(
+                visible_public=False, visible_pool=False,
+                open_for_commenting=False, open_for_reporting=False,
+                status=STATUS_WITHDRAWN, latest_activity=timezone.now())
+            submission.get_other_versions().update(visible_public=False)
+            # Update all assignments
+            EditorialAssignment.objects.filter(submission=submission).need_response().update(
+                status=STATUS_DEPRECATED)
+            EditorialAssignment.objects.filter(submission=submission).accepted().update(
+                status=STATUS_COMPLETED)
+            # Deprecate any outstanding recommendation
+            EICRecommendation.objects.filter(submission=submission).active().update(
+                status=DEPRECATED)
+            # Inform EIC
+            mail_sender_eic = DirectMailUtil(
+                mail_code='eic/inform_eic_manuscript_withdrawn',
+                instance=submission)
+            mail_sender_eic.send()
+            # Confirm withdrawal to authors
+            mail_sender_authors = DirectMailUtil(
+                mail_code='authors/inform_authors_manuscript_withdrawn',
+                instance=submission)
+            mail_sender_authors.send()
+            # Email all referees (if outstanding), cancel all outstanding
+            for invitation in submission.referee_invitations.outstanding():
+                DirectMailUtil(
+                    mail_code='referees/inform_referee_manuscript_withdrawn',
+                    instance=invitation).send()
+            submission.referee_invitations.outstanding().update(cancelled=True)
+            # Add event
+            submission.add_general_event('The manuscript has been withdrawn by the authors.')
+            # All done
             messages.success(request, 'Your manuscript has been withdrawn.')
         else:
             messages.error(request, 'Withdrawal procedure aborted')
         return redirect(reverse('scipost:personal_page'))
     context = {'submission': submission, 'form': form}
-    return render(request, 'submissions/withdraw_manuscript.html')
+    return render(request, 'submissions/withdraw_manuscript.html', context)
 
 
 class SubmissionListView(PaginationMixin, ListView):
diff --git a/templates/email/authors/inform_authors_manuscript_withdrawn.html b/templates/email/authors/inform_authors_manuscript_withdrawn.html
new file mode 100644
index 000000000..cc6f29227
--- /dev/null
+++ b/templates/email/authors/inform_authors_manuscript_withdrawn.html
@@ -0,0 +1,20 @@
+<p>
+  Dear {{ submission.submitted_by.get_title_display }} {{ submission.submitted_by.user.last_name }},
+</p>
+<p>
+  We hereby acknowledge withdrawal of your recent SciPost submission,
+</p>
+<p>
+  {{ submission.title }}
+  <br/>
+  by {{ submission.author_list }}.
+</p>
+<p>
+  Editorial processing of your manuscript is hereby terminated, and the associated submission page has been removed from public view. You are now free to send your manuscript to an alternative journal.
+</p>
+<p>
+  Despite this outcome, we thank you very much for your contribution. If you have further questions or comments, please feel free to get in touch with our <a href="mailto:edadmin@scipost.org">editorial administration</a>.
+</p>
+<p>Sincerely,</p>
+<p>The SciPost Team</p>
+{% include 'email/_footer.html' %}
diff --git a/templates/email/authors/inform_authors_manuscript_withdrawn.json b/templates/email/authors/inform_authors_manuscript_withdrawn.json
new file mode 100644
index 000000000..f28043ed0
--- /dev/null
+++ b/templates/email/authors/inform_authors_manuscript_withdrawn.json
@@ -0,0 +1,8 @@
+{
+    "subject": "SciPost: manuscript withdrawn",
+    "to_address": "submitted_by.user.email",
+    "bcc_to": "edadmin@scipost.org",
+    "from_address_name": "SciPost Submissions",
+    "from_address": "submissions@scipost.org",
+    "context_object": "submission"
+}
diff --git a/templates/email/eic/inform_eic_manuscript_withdrawn.html b/templates/email/eic/inform_eic_manuscript_withdrawn.html
new file mode 100644
index 000000000..e0ed174be
--- /dev/null
+++ b/templates/email/eic/inform_eic_manuscript_withdrawn.html
@@ -0,0 +1,19 @@
+<p>Dear {{ submission.editor_in_charge.get_title_display }} {{ submission.editor_in_charge.user.last_name }},</p>
+
+<p>
+  For your information, the authors of Submission
+</p>
+<p>
+  {{ submission.title }}
+  <br/>
+  by {{ submission.author_list }}
+</p>
+<p>
+  have withdrawn their manuscript. There is no further action required from your part, and your editorial assignment is now marked as completed.
+</p>
+<p>
+    Many thanks,<br>
+    The SciPost Team.
+</p>
+
+{% include 'email/_footer.html' %}
diff --git a/templates/email/eic/inform_eic_manuscript_withdrawn.json b/templates/email/eic/inform_eic_manuscript_withdrawn.json
new file mode 100644
index 000000000..7f2e66ca8
--- /dev/null
+++ b/templates/email/eic/inform_eic_manuscript_withdrawn.json
@@ -0,0 +1,8 @@
+{
+    "subject": "SciPost: manuscript withdrawn",
+    "to_address": "editor_in_charge.user.email",
+    "bcc_to": "edadmin@scipost.org",
+    "from_address_name": "SciPost Editorial Admin",
+    "from_address": "submissions@scipost.org",
+    "context_object": "submission"
+}
diff --git a/templates/email/referees/inform_referee_manuscript_withdrawn.html b/templates/email/referees/inform_referee_manuscript_withdrawn.html
new file mode 100644
index 000000000..78b25a0f1
--- /dev/null
+++ b/templates/email/referees/inform_referee_manuscript_withdrawn.html
@@ -0,0 +1,20 @@
+<p>
+    Dear {{invitation.referee.get_title_display}} {{invitation.referee.user.last_name}},
+</p>
+<p>
+  This is a simple email to inform you that the authors of
+</p>
+<p>
+  {{invitation.submission.title}}
+  <br>
+  by {{invitation.submission.author_list}}
+</p>
+<p>
+  have withdrawn their manuscript. Your report is thus not needed anymore.
+</p>
+<p>
+  Sincerely,
+  <br>
+  The SciPost Team.
+</p>
+{% include 'email/_footer.html' %}
diff --git a/templates/email/referees/inform_referee_manuscript_withdrawn.json b/templates/email/referees/inform_referee_manuscript_withdrawn.json
new file mode 100644
index 000000000..4367c9e57
--- /dev/null
+++ b/templates/email/referees/inform_referee_manuscript_withdrawn.json
@@ -0,0 +1,8 @@
+{
+    "subject": "SciPost: manuscript withdrawn",
+    "to_address": "referee.user.email",
+    "bcc_to": "submission.editor_in_charge.user.email,edadmin@scipost.org",
+    "from_address_name": "SciPost Refereeing",
+    "from_address": "refereeing@scipost.org",
+    "context_object": "invitation"
+}
-- 
GitLab