From 85e8413525e0d43711c1daff468257138fd132af Mon Sep 17 00:00:00 2001
From: Chris Lawton <31627284+chris-lawton@users.noreply.github.com>
Date: Fri, 13 Sep 2019 16:09:21 +0100
Subject: [PATCH] add styles for checkboxes used to remove items (#1470)

* add styles for checkboxes used to remove items
* Make sure that we can add and remove receipts from the PRs
---
 opentech/apply/projects/forms.py              | 67 ++++++++++++-------
 opentech/apply/projects/models.py             |  3 +-
 opentech/apply/projects/tests/factories.py    |  1 +
 opentech/apply/projects/tests/test_views.py   | 46 +++++++++++--
 opentech/static_src/src/images/cross.svg      |  3 +
 .../src/sass/apply/components/_form.scss      | 37 ++++++++++
 .../src/sass/apply/components/_grid.scss      |  4 ++
 7 files changed, 127 insertions(+), 34 deletions(-)
 create mode 100644 opentech/static_src/src/images/cross.svg

diff --git a/opentech/apply/projects/forms.py b/opentech/apply/projects/forms.py
index e967bf915..31d75f369 100644
--- a/opentech/apply/projects/forms.py
+++ b/opentech/apply/projects/forms.py
@@ -1,5 +1,4 @@
 import functools
-import os
 
 from django import forms
 from django.contrib.auth import get_user_model
@@ -138,31 +137,6 @@ class CreateApprovalForm(forms.ModelForm):
         return by
 
 
-class EditPaymentRequestForm(forms.ModelForm):
-    receipt_list = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple(attrs={'checked': 'checked'}))
-
-    name = 'edit_payment_request_form'
-
-    class Meta:
-        fields = ['invoice', 'requested_value', 'date_from', 'date_to', 'receipt_list', 'comment']
-        model = PaymentRequest
-        widgets = {
-            'date_from': forms.DateInput,
-            'date_to': forms.DateInput,
-        }
-
-    def __init__(self, user=None, instance=None, *args, **kwargs):
-        super().__init__(*args, instance=instance, **kwargs)
-
-        self.instance = instance
-
-        self.fields['receipt_list'].choices = [
-            (r.pk, os.path.basename(r.file.url))
-            for r in instance.receipts.all()
-        ]
-        self.fields['requested_value'].label = 'Value'
-
-
 class ProjectEditForm(forms.ModelForm):
     contact_address = AddressField()
 
@@ -260,6 +234,47 @@ class RequestPaymentForm(forms.ModelForm):
         return request
 
 
+class EditPaymentRequestForm(forms.ModelForm):
+    receipt_list = forms.ModelMultipleChoiceField(
+        widget=forms.CheckboxSelectMultiple(attrs={'class': 'delete'}),
+        queryset=PaymentReceipt.objects.all(),
+        required=False,
+        label='Receipts'
+    )
+    receipts = MultiFileField(label='', required=False)
+
+    class Meta:
+        fields = ['invoice', 'requested_value', 'date_from', 'date_to', 'receipt_list', 'receipts', 'comment']
+        model = PaymentRequest
+        widgets = {
+            'date_from': forms.DateInput,
+            'date_to': forms.DateInput,
+        }
+
+    def __init__(self, user=None, instance=None, *args, **kwargs):
+        super().__init__(*args, instance=instance, **kwargs)
+
+        self.fields['receipt_list'].queryset = instance.receipts.all()
+
+        self.fields['requested_value'].label = 'Value'
+
+    @transaction.atomic
+    def save(self, *args, **kwargs):
+        request = super().save(*args, **kwargs)
+
+        removed_receipts = self.cleaned_data['receipt_list']
+
+        removed_receipts.delete()
+
+        to_add = self.cleaned_data['receipts']
+        if to_add:
+            PaymentReceipt.objects.bulk_create(
+                PaymentReceipt(payment_request=request, file=receipt)
+                for receipt in to_add
+            )
+        return request
+
+
 class SelectDocumentForm(forms.ModelForm):
     document = forms.ChoiceField()
 
diff --git a/opentech/apply/projects/models.py b/opentech/apply/projects/models.py
index 9fbce3f67..2fc4a9bf1 100644
--- a/opentech/apply/projects/models.py
+++ b/opentech/apply/projects/models.py
@@ -2,6 +2,7 @@ import collections
 import decimal
 import json
 import logging
+import os
 
 
 from django.conf import settings
@@ -131,7 +132,7 @@ class PaymentReceipt(models.Model):
     file = models.FileField(upload_to=receipt_path, storage=PrivateStorage())
 
     def __str__(self):
-        return f'Receipt for {self.payment_request}'
+        return os.path.basename(self.file.name)
 
 
 SUBMITTED = 'submitted'
diff --git a/opentech/apply/projects/tests/factories.py b/opentech/apply/projects/tests/factories.py
index 084f7e65d..23a535ed8 100644
--- a/opentech/apply/projects/tests/factories.py
+++ b/opentech/apply/projects/tests/factories.py
@@ -119,6 +119,7 @@ class PacketFileFactory(factory.DjangoModelFactory):
 class PaymentRequestFactory(factory.DjangoModelFactory):
     project = factory.SubFactory(ProjectFactory)
     by = factory.SubFactory(UserFactory)
+    requested_value = factory.Faker('pydecimal', min_value=1, max_value=10000000, right_digits=2)
 
     date_from = factory.Faker('date_time').generate({'tzinfo': pytz.utc})
     date_to = factory.Faker('date_time').generate({'tzinfo': pytz.utc})
diff --git a/opentech/apply/projects/tests/test_views.py b/opentech/apply/projects/tests/test_views.py
index 010bf3a72..cf9e5b4ae 100644
--- a/opentech/apply/projects/tests/test_views.py
+++ b/opentech/apply/projects/tests/test_views.py
@@ -925,23 +925,37 @@ class TestApplicantEditPaymentRequestView(BaseViewTestCase):
     def get_kwargs(self, instance):
         return {'pk': instance.pk}
 
-    def test_editing_payment_request_fires_messaging(self):
+    def test_editing_payment_remove_receipt(self):
+        payment_request = PaymentRequestFactory(project__user=self.user)
+        receipt = PaymentReceiptFactory(payment_request=payment_request)
+
+        response = self.post_page(payment_request, {
+            'requested_value': payment_request.requested_value,
+            'date_from': '2018-08-15',
+            'date_to': '2019-08-15',
+            'comment': 'test comment',
+            'invoice': None,
+            'receipt_list': [receipt.pk],
+        })
+
+        self.assertEqual(response.status_code, 200)
+
+        self.assertFalse(payment_request.receipts.exists())
+
+    def test_editing_payment_keeps_receipts(self):
         project = ProjectFactory(user=self.user)
         payment_request = PaymentRequestFactory(project=project)
         receipt = PaymentReceiptFactory(payment_request=payment_request)
 
         requested_value = payment_request.requested_value
 
-        invoice = BytesIO(b'somebinarydata')
-        invoice.name = 'invoice.pdf'
-
         response = self.post_page(payment_request, {
             'requested_value': requested_value + 1,
             'date_from': '2018-08-15',
             'date_to': '2019-08-15',
             'comment': 'test comment',
-            'invoice': invoice,
-            'receipt_list': [receipt.pk],
+            'invoice': None,
+            'receipt_list': [],
         })
 
         self.assertEqual(response.status_code, 200)
@@ -952,6 +966,7 @@ class TestApplicantEditPaymentRequestView(BaseViewTestCase):
         self.assertEqual(project.payment_requests.first().pk, payment_request.pk)
 
         self.assertEqual(requested_value + Decimal("1"), payment_request.requested_value)
+        self.assertEqual(payment_request.receipts.first().file, receipt.file)
 
 
 class TestStaffEditPaymentRequestView(BaseViewTestCase):
@@ -962,7 +977,24 @@ class TestStaffEditPaymentRequestView(BaseViewTestCase):
     def get_kwargs(self, instance):
         return {'pk': instance.pk}
 
-    def test_editing_payment_request_fires_messaging(self):
+    def test_editing_payment_remove_receipt(self):
+        payment_request = PaymentRequestFactory()
+        receipt = PaymentReceiptFactory(payment_request=payment_request)
+
+        response = self.post_page(payment_request, {
+            'requested_value': payment_request.requested_value,
+            'date_from': '2018-08-15',
+            'date_to': '2019-08-15',
+            'comment': 'test comment',
+            'invoice': None,
+            'receipt_list': [receipt.pk],
+        })
+
+        self.assertEqual(response.status_code, 200)
+
+        self.assertFalse(payment_request.receipts.exists())
+
+    def test_editing_payment_keeps_receipts(self):
         project = ProjectFactory()
         payment_request = PaymentRequestFactory(project=project)
         receipt = PaymentReceiptFactory(payment_request=payment_request)
diff --git a/opentech/static_src/src/images/cross.svg b/opentech/static_src/src/images/cross.svg
new file mode 100644
index 000000000..b818cbe1e
--- /dev/null
+++ b/opentech/static_src/src/images/cross.svg
@@ -0,0 +1,3 @@
+<svg viewBox="0 0 21.9 21.9" xmlns="http://www.w3.org/2000/svg">
+    <path fill="#f05e54" d="M14.1 11.3c-.2-.2-.2-.5 0-.7l7.5-7.5c.2-.2.3-.5.3-.7s-.1-.5-.3-.7L20.2.3c-.2-.2-.5-.3-.7-.3-.3 0-.5.1-.7.3l-7.5 7.5c-.2.2-.5.2-.7 0L3.1.3C2.9.1 2.6 0 2.4 0s-.5.1-.7.3L.3 1.7c-.2.2-.3.5-.3.7s.1.5.3.7l7.5 7.5c.2.2.2.5 0 .7L.3 18.8c-.2.2-.3.5-.3.7s.1.5.3.7l1.4 1.4c.2.2.5.3.7.3s.5-.1.7-.3l7.5-7.5c.2-.2.5-.2.7 0l7.5 7.5c.2.2.5.3.7.3s.5-.1.7-.3l1.4-1.4c.2-.2.3-.5.3-.7s-.1-.5-.3-.7l-7.5-7.5z"/>
+</svg>
diff --git a/opentech/static_src/src/sass/apply/components/_form.scss b/opentech/static_src/src/sass/apply/components/_form.scss
index fb85976fa..a88244c8e 100644
--- a/opentech/static_src/src/sass/apply/components/_form.scss
+++ b/opentech/static_src/src/sass/apply/components/_form.scss
@@ -408,6 +408,43 @@
             background-size: 12px;
             border: 1px solid $color--dark-blue;
         }
+
+        &.delete {
+            + label {
+                padding-left: 0;
+
+                &::before {
+                    display: none;
+                }
+
+                &::after {
+                    content: '';
+                    background: url('./../../images/cross.svg') left no-repeat;
+                    margin-left: 10px;
+                    width: 14px;
+                    height: 13px;
+                    display: inline-block;
+                }
+            }
+
+            &:checked + label {
+                text-decoration: line-through;
+                color: $color--black-60;
+
+                &::after {
+                    content: '(will be removed on save) - undo';
+                    background: none;
+                    color: $color--light-blue;
+                    font-size: 14px;
+                    position: absolute;
+                    font-weight: $weight--bold;
+                    width: auto;
+                    height: auto;
+                }
+            }
+
+
+        }
     }
 
     .errorlist {
diff --git a/opentech/static_src/src/sass/apply/components/_grid.scss b/opentech/static_src/src/sass/apply/components/_grid.scss
index 23e966a90..06903cce6 100644
--- a/opentech/static_src/src/sass/apply/components/_grid.scss
+++ b/opentech/static_src/src/sass/apply/components/_grid.scss
@@ -53,6 +53,10 @@
                 grid-template-columns: 1fr 1fr;
             }
 
+            &.delete {
+                grid-template-columns: 1fr;
+            }
+
             .form--comments & {
                 margin: 20px 0 0;
                 grid-gap: 10px; // sass-lint:disable-line no-misspelled-properties
-- 
GitLab