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