From a35161dc4b008efffc2d9737af224aa451acd539 Mon Sep 17 00:00:00 2001
From: "J.-S. Caux" <J.S.Caux@uva.nl>
Date: Wed, 16 Oct 2019 05:20:23 +0200
Subject: [PATCH] Add AlternativeRecommendation for use during voting

---
 submissions/forms.py                          | 18 +++++--
 .../0070_alternativerecommendation.py         | 26 ++++++++++
 submissions/models.py                         |  8 ++++
 .../recommendation_author_content.html        |  2 +-
 .../submissions/pool/recommendation.html      | 48 ++++++++++++++++++-
 submissions/views.py                          | 17 +++++--
 6 files changed, 109 insertions(+), 10 deletions(-)
 create mode 100644 submissions/migrations/0070_alternativerecommendation.py

diff --git a/submissions/forms.py b/submissions/forms.py
index 349145ee2..f1cab22f3 100644
--- a/submissions/forms.py
+++ b/submissions/forms.py
@@ -18,8 +18,10 @@ from .constants import (
     REPORT_REFUSAL_CHOICES, STATUS_REJECTED, STATUS_INCOMING, REPORT_POST_EDREC, REPORT_NORMAL,
     STATUS_DRAFT, STATUS_UNVETTED, REPORT_ACTION_ACCEPT, REPORT_ACTION_REFUSE, STATUS_UNASSIGNED,
     EXPLICIT_REGEX_MANUSCRIPT_CONSTRAINTS, SUBMISSION_STATUS, PUT_TO_VOTING, CYCLE_UNDETERMINED,
-    SUBMISSION_CYCLE_CHOICES, REPORT_PUBLISH_1, REPORT_PUBLISH_2, REPORT_PUBLISH_3, STATUS_VETTED,
-    REPORT_MINOR_REV, REPORT_MAJOR_REV, REPORT_REJECT, DECISION_FIXED, DEPRECATED, STATUS_COMPLETED,
+    SUBMISSION_CYCLE_CHOICES,
+    REPORT_PUBLISH_1, REPORT_PUBLISH_2, REPORT_PUBLISH_3,
+    REPORT_MINOR_REV, REPORT_MAJOR_REV, REPORT_REJECT, REPORT_REC,
+    STATUS_VETTED, DECISION_FIXED, DEPRECATED, STATUS_COMPLETED,
     STATUS_EIC_ASSIGNED, CYCLE_DEFAULT, CYCLE_DIRECT_REC, STATUS_PREASSIGNED, STATUS_REPLACED,
     STATUS_FAILED_PRESCREENING, STATUS_DEPRECATED, STATUS_ACCEPTED, STATUS_DECLINED, STATUS_WITHDRAWN)
 from . import exceptions, helpers
@@ -1250,7 +1252,7 @@ class EICRecommendationForm(forms.ModelForm):
                 }
 
         super().__init__(*args, **kwargs)
-        self.fields['for_journal'].queryset = Journal.objects.filter(
+        self.fields['for_journal'].queryset = Journal.objects.active().filter(
             Q(discipline=self.submission.discipline) | Q(name='SciPost Selections'))
         self.load_assignment()
 
@@ -1328,10 +1330,18 @@ class RecommendationVoteForm(forms.Form):
     vote = forms.ChoiceField(
         widget=forms.RadioSelect, choices=[
             ('agree', 'Agree'), ('disagree', 'Disagree'), ('abstain', 'Abstain')])
+    alternative_for_journal = forms.ModelChoiceField(
+        label='Alternative recommendation: for which Journal?',
+        widget=forms.Select,
+        queryset=Journal.objects.active()
+    )
+    alternative_recommendation = forms.ChoiceField(
+        label='Which action do you recommend?',
+        widget=forms.Select, choices=REPORT_REC)
     remark = forms.CharField(widget=forms.Textarea(attrs={
         'rows': 3,
         'cols': 30,
-        'placeholder': 'Your remark (optional)'
+        'placeholder': 'Any further remark you want to add? (optional)'
     }), label='', required=False)
 
 
diff --git a/submissions/migrations/0070_alternativerecommendation.py b/submissions/migrations/0070_alternativerecommendation.py
new file mode 100644
index 000000000..f75270cdd
--- /dev/null
+++ b/submissions/migrations/0070_alternativerecommendation.py
@@ -0,0 +1,26 @@
+# Generated by Django 2.1.8 on 2019-10-15 15:43
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('scipost', '0033_auto_20191005_1142'),
+        ('journals', '0084_journal_minimal_nr_of_reports'),
+        ('submissions', '0069_auto_20191014_2201'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='AlternativeRecommendation',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('recommendation', models.SmallIntegerField(choices=[(None, '-'), (1, 'Publish (surpasses expectations and criteria for this Journal; among top 10%)'), (2, 'Publish (easily meets expectations and criteria for this Journal; among top 50%)'), (3, 'Publish (meets expectations and criteria for this Journal)'), (-1, 'Ask for minor revision'), (-2, 'Ask for major revision'), (-3, 'Reject')])),
+                ('eicrec', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='submissions.EICRecommendation')),
+                ('fellow', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='scipost.Contributor')),
+                ('for_journal', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='journals.Journal')),
+            ],
+        ),
+    ]
diff --git a/submissions/models.py b/submissions/models.py
index a91173438..e7b191250 100644
--- a/submissions/models.py
+++ b/submissions/models.py
@@ -1026,6 +1026,14 @@ class EICRecommendation(SubmissionRelatedObjectMixin, models.Model):
         return _str
 
 
+class AlternativeRecommendation(models.Model):
+    """Alternative recommendation from voting Fellow who disagrees with EICRec."""
+    eicrec = models.ForeignKey('submissions.EICRecommendation', on_delete=models.CASCADE)
+    fellow = models.ForeignKey('scipost.Contributor', on_delete=models.CASCADE)
+    for_journal = models.ForeignKey('journals.Journal', on_delete=models.CASCADE)
+    recommendation = models.SmallIntegerField(choices=REPORT_REC)
+
+
 class iThenticateReport(TimeStampedModel):
     """iThenticate report registration.
 
diff --git a/submissions/templates/partials/submissions/recommendation_author_content.html b/submissions/templates/partials/submissions/recommendation_author_content.html
index 62d00929d..56dd822c2 100644
--- a/submissions/templates/partials/submissions/recommendation_author_content.html
+++ b/submissions/templates/partials/submissions/recommendation_author_content.html
@@ -35,7 +35,7 @@
     {% block recommendation_before_recommendation %}{% endblock %}
 
     <h3 class="pb-0">Recommendation</h3>
-    <p class="pl-md-3 mb-0"><em>For Journal {{ recommendation.for_journal }}:</em>&emsp;<strong>{{ recommendation.get_recommendation_display }}</strong></p>
+    <p class="pl-md-3 mb-0">For Journal <em>{{ recommendation.for_journal }}:</em> <strong>{{ recommendation.get_recommendation_display }}</strong></p>
   </div>
 
   {% if not recommendation.active %}
diff --git a/submissions/templates/submissions/pool/recommendation.html b/submissions/templates/submissions/pool/recommendation.html
index 6d038c280..ed13a66bc 100644
--- a/submissions/templates/submissions/pool/recommendation.html
+++ b/submissions/templates/submissions/pool/recommendation.html
@@ -13,7 +13,7 @@
 {% block content %}
   <h1 class="highlight">Editorial Recommendation to vote on</h1>
 
-
+  <h2>Concerning Submission:</h2>
   {% include 'partials/submissions/submission_li.html' with submission=recommendation.submission %}
 
   <a class="d-inline-block mb-3" href="{{ recommendation.submission.get_absolute_url }}" target="_blank">View Reports and Submission details</a>
@@ -57,6 +57,14 @@
 		{% endfor %}
               </li>
             </ul>
+	    {% if old_rec.alternativerecommendation_set.all|length > 0 %}
+	      <h3>Alternative recommendations offered during voting by Fellows who disagreed:</h3>
+	      <ul>
+		{% for altrec in old_rec.alternativerecommendation_set.all %}
+		  <li>{{ altrec.fellow }}: for Journal <em>{{ altrec.for_journal }}</em>: <strong>{{ altrec.get_recommendation_display }}</strong></li>
+		{% endfor %}
+	      </ul>
+	    {% endif %}
             <h3 class="card-title">Remarks:</h3>
             <ul>
               {% for rem in old_rec.remarks.all %}
@@ -106,6 +114,15 @@
         </li>
       </ul>
 
+      {% if recommendation.alternativerecommendation_set.all|length > 0 %}
+	<h3>Alternative recommendations offered during voting by Fellows who disagreed:</h3>
+	<ul>
+	  {% for altrec in recommendation.alternativerecommendation_set.all %}
+	    <li>{{ altrec.fellow }}: for Journal <em>{{ altrec.for_journal }}</em>: <strong>{{ altrec.get_recommendation_display }}</strong></li>
+	  {% endfor %}
+	</ul>
+      {% endif %}
+
       <h3 class="card-title">Remarks:</h3>
       <ul>
         {% for rem in recommendation.remarks.all %}
@@ -114,6 +131,7 @@
           <li><em>No remarks</em></li>
         {% endfor %}
       </ul>
+
     </div>
 
     {% if perms.scipost.can_fix_College_decision %}
@@ -142,10 +160,36 @@
       <p>You had previously voted <span class="text-danger">{{ previous_vote }}</span>; you can use the form below to change your vote and/or add a remark:</p>
     {% endif %}
     <form action="{% url 'submissions:vote_on_rec' rec_id=recommendation.id %}" method="post">
+      <p id="disagree_instructions" class="text-danger"><strong>If you vote disagree, please provide an alternative recommendation below</strong></p>
       {% csrf_token %}
-      {{ voting_form|bootstrap:'0,12' }}
+      {{ voting_form|bootstrap }}
       <input type="submit" name="submit" value="Cast your vote" class="btn btn-primary" id="submit-id-submit">
     </form>
   {% endif %}
 
 {% endblock %}
+
+{% block footer_script %}
+  <script nonce="{{ request.csp_nonce }}">
+   $(document).ready(function(){
+       $("#disagree_instructions").hide()
+       $("#id_alternative_for_journal").parents('.form-group').hide()
+       $("#id_alternative_recommendation").parents('.form-group').hide()
+       $('input[name=vote]').on('change', function(){
+	   var selection = $('input[name=vote]:checked').val();
+	   switch(selection){
+	       case "disagree":
+		   $("#disagree_instructions").show()
+		   $("#id_alternative_for_journal").parents('.form-group').show()
+		   $("#id_alternative_recommendation").parents('.form-group').show()
+		   break;
+	       default:
+		   $("#disagree_instructions").hide()
+		   $("#id_alternative_for_journal").parents('.form-group').hide()
+		   $("#id_alternative_recommendation").parents('.form-group').hide()
+		   break;
+	   }
+       }).trigger('change');
+   });
+  </script>
+{% endblock %}
diff --git a/submissions/views.py b/submissions/views.py
index f4b7c5fea..8217b5950 100644
--- a/submissions/views.py
+++ b/submissions/views.py
@@ -29,7 +29,8 @@ from .constants import (
     DEPRECATED)
 from .helpers import check_verified_author, check_unverified_author
 from .models import (
-    Submission, EICRecommendation, EditorialAssignment, RefereeInvitation, Report, SubmissionEvent)
+    Submission, EICRecommendation, AlternativeRecommendation,
+    EditorialAssignment, RefereeInvitation, Report, SubmissionEvent)
 from .mixins import SubmissionAdminViewMixin
 from .forms import (
     SubmissionIdentifierForm, SubmissionForm, SubmissionSearchForm, RecommendationVoteForm,
@@ -1729,9 +1730,19 @@ def vote_on_rec(request, rec_id):
                 recommendation.voted_against.add(request.user.contributor)
             except IntegrityError:
                 messages.warning(request, 'You have already voted against this Recommendation.')
-                #return redirect(reverse('submissions:pool'))
-                pass
             recommendation.voted_abstain.remove(request.user.contributor)
+            # Create an alternative recommendation, if given
+            if (form.cleaned_data['alternative_for_journal'] and
+                form.cleaned_data['alternative_recommendation']):
+                # Delete previous alternative recs before creating new one
+                AlternativeRecommendation.objects.filter(
+                    eicrec=recommendation, fellow=request.user.contributor).delete()
+                altrec = AlternativeRecommendation(
+                        eicrec=recommendation,
+                        fellow=request.user.contributor,
+                        for_journal=form.cleaned_data['alternative_for_journal'],
+                        recommendation=form.cleaned_data['alternative_recommendation'])
+                altrec.save()
         elif form.cleaned_data['vote'] == 'abstain':
             recommendation.voted_for.remove(request.user.contributor)
             recommendation.voted_against.remove(request.user.contributor)
-- 
GitLab