Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
thalia
concrexit
Commits
129d4eb1
Verified
Commit
129d4eb1
authored
Apr 28, 2019
by
Sébastiaan Versteeg
Browse files
Add user in front of default auth urls & add last_used
parent
8b06298d
Changes
16
Hide whitespace changes
Inline
Side-by-side
docs/payments.management.commands.rst
0 → 100644
View file @
129d4eb1
payments.management.commands package
====================================
.. automodule:: payments.management.commands
:members:
:undoc-members:
:show-inheritance:
Submodules
----------
payments.management.commands.revokeoldmandates module
-----------------------------------------------------
.. automodule:: payments.management.commands.revokeoldmandates
:members:
:undoc-members:
:show-inheritance:
docs/payments.management.rst
0 → 100644
View file @
129d4eb1
payments.management package
===========================
.. automodule:: payments.management
:members:
:undoc-members:
:show-inheritance:
Subpackages
-----------
.. toctree::
payments.management.commands
docs/payments.rst
View file @
129d4eb1
...
...
@@ -6,6 +6,13 @@ payments package
:undoc-members:
:show-inheritance:
Subpackages
-----------
.. toctree::
payments.management
Submodules
----------
...
...
website/payments/admin.py
View file @
129d4eb1
...
...
@@ -222,14 +222,16 @@ class ValidAccountFilter(admin.SimpleListFilter):
class
BankAccountAdmin
(
admin
.
ModelAdmin
):
"""Manage bank accounts"""
list_display
=
(
'iban'
,
'
initials
'
,
'last_
name
'
,
'owner_link'
,
'valid_from'
,
'valid_until'
)
list_display
=
(
'iban'
,
'
owner_link
'
,
'last_
used
'
,
'valid_from'
,
'valid_until'
)
list_filter
=
(
ValidAccountFilter
,)
fields
=
(
'created_at'
,
'owner'
,
'iban'
,
'bic'
,
'initials'
,
'last_name'
,
'mandate_no'
,
'valid_from'
,
'valid_until'
,
'signature'
)
fields
=
(
'created_at'
,
'last_used'
,
'owner'
,
'iban'
,
'bic'
,
'initials'
,
'last_name'
,
'mandate_no'
,
'valid_from'
,
'valid_until'
,
'signature'
)
readonly_fields
=
(
'created_at'
,)
search_fields
=
(
'owner__username'
,
'owner__first_name'
,
'owner__last_name'
,
'iban'
)
actions
=
[
'set_last_used'
]
form
=
BankAccountAdminForm
def
owner_link
(
self
,
obj
:
BankAccount
)
->
str
:
...
...
@@ -242,6 +244,18 @@ class BankAccountAdmin(admin.ModelAdmin):
owner_link
.
admin_order_field
=
'owner'
owner_link
.
short_description
=
_
(
'owner'
)
def
set_last_used
(
self
,
request
:
HttpRequest
,
queryset
:
QuerySet
)
->
None
:
"""Set the last used date of selected accounts"""
if
request
.
user
.
has_perm
(
'payments.change_bankaccount'
):
updated
=
services
.
update_last_used
(
queryset
)
_show_message
(
self
,
request
,
updated
,
message
=
_
(
"Successfully updated %(count)d %(items)s."
),
error
=
_
(
'The selected account(s) could not be updated.'
)
)
set_last_used
.
short_description
=
_
(
'Update the last used date'
)
def
export_csv
(
self
,
request
:
HttpRequest
,
queryset
:
QuerySet
)
->
HttpResponse
:
response
=
HttpResponse
(
content_type
=
'text/csv'
)
...
...
website/payments/management/__init__.py
0 → 100644
View file @
129d4eb1
website/payments/management/commands/__init__.py
0 → 100644
View file @
129d4eb1
website/payments/management/commands/revokeoldmandates.py
0 → 100644
View file @
129d4eb1
from
django.core.management.base
import
BaseCommand
from
payments
import
services
class
Command
(
BaseCommand
):
def
handle
(
self
,
*
args
,
**
options
):
services
.
revoke_old_mandates
()
website/payments/migrations/0004_bankaccount.py
View file @
129d4eb1
# Generated by Django 2.2 on 2019-04-27 19:41
from
django.db
import
migrations
,
models
import
django.db.models.deletion
import
uuid
import
django.utils.timezone
import
localflavor.generic.models
import
uuid
from
django.db
import
migrations
,
models
class
Migration
(
migrations
.
Migration
):
...
...
@@ -20,6 +20,7 @@ class Migration(migrations.Migration):
fields
=
[
(
'id'
,
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
editable
=
False
,
primary_key
=
True
,
serialize
=
False
)),
(
'created_at'
,
models
.
DateTimeField
(
default
=
django
.
utils
.
timezone
.
now
,
verbose_name
=
'created at'
)),
(
'last_used'
,
models
.
DateField
(
blank
=
True
,
null
=
True
,
verbose_name
=
'last used'
)),
(
'initials'
,
models
.
CharField
(
max_length
=
20
,
verbose_name
=
'initials'
)),
(
'last_name'
,
models
.
CharField
(
max_length
=
255
,
verbose_name
=
'last name'
)),
(
'iban'
,
localflavor
.
generic
.
models
.
IBANField
(
include_countries
=
(
'AT'
,
'BE'
,
'BG'
,
'CH'
,
'CY'
,
'CZ'
,
'DE'
,
'DK'
,
'EE'
,
'ES'
,
'FI'
,
'FR'
,
'GB'
,
'GI'
,
'GR'
,
'HR'
,
'HU'
,
'IE'
,
'IS'
,
'IT'
,
'LI'
,
'LT'
,
'LU'
,
'LV'
,
'MC'
,
'MT'
,
'NL'
,
'NO'
,
'PL'
,
'PT'
,
'RO'
,
'SE'
,
'SI'
,
'SK'
,
'SM'
),
max_length
=
34
,
use_nordea_extensions
=
False
,
verbose_name
=
'IBAN'
)),
...
...
website/payments/models.py
View file @
129d4eb1
...
...
@@ -107,6 +107,12 @@ class BankAccount(models.Model):
created_at
=
models
.
DateTimeField
(
_
(
'created at'
),
default
=
timezone
.
now
)
last_used
=
models
.
DateField
(
verbose_name
=
_
(
'last used'
),
blank
=
True
,
null
=
True
,
)
owner
=
models
.
ForeignKey
(
to
=
'members.Member'
,
verbose_name
=
_
(
'owner'
),
...
...
website/payments/services.py
View file @
129d4eb1
"""The services defined by the payments package"""
from
django.db.models
import
QuerySet
import
datetime
from
django.db.models
import
QuerySet
,
Q
from
django.utils
import
timezone
from
members.models
import
Member
from
.models
import
Payment
from
.models
import
Payment
,
BankAccount
def
process_payment
(
queryset
:
QuerySet
,
processed_by
:
Member
,
...
...
@@ -32,3 +35,33 @@ def process_payment(queryset: QuerySet, processed_by: Member,
data
.
append
(
payment
)
return
data
def
update_last_used
(
queryset
:
QuerySet
,
date
:
datetime
.
date
=
None
)
->
int
:
"""
Update the last used field of a BankAccount queryset
:param queryset: Queryset of BankAccounts
:param date: date to set last_used to
:return: number of affected rows
"""
if
not
date
:
date
=
timezone
.
now
().
date
()
result
=
(
queryset
.
filter
((
Q
(
valid_from__gte
=
timezone
.
now
())
&
Q
(
valid_until__lt
=
timezone
.
now
()))
|
Q
(
valid_until
=
None
))
.
update
(
last_used
=
date
))
return
result
def
revoke_old_mandates
()
->
int
:
"""
Revokes all mandates that have not been used for 36 months or more
:return: number of affected rows
"""
return
BankAccount
.
objects
.
filter
(
last_used__lte
=
(
timezone
.
now
()
-
timezone
.
timedelta
(
days
=
36
*
30
))
).
update
(
valid_until
=
timezone
.
now
().
date
())
website/payments/tests/api/__init__.py
0 → 100644
View file @
129d4eb1
website/payments/tests/api/test_fields.py
0 → 100644
View file @
129d4eb1
from
unittest
import
mock
from
django.test
import
TestCase
from
freezegun
import
freeze_time
from
payments.api.fields
import
PaymentTypeField
from
payments.models
import
Payment
@
freeze_time
(
'2019-01-01'
)
class
PaymentTypeFieldTest
(
TestCase
):
"""
Test for the payment type field
"""
fixtures
=
[
'members.json'
]
@
mock
.
patch
(
'rest_framework.serializers.ChoiceField.get_attribute'
)
def
test_get_attribute
(
self
,
mock_super
):
field
=
PaymentTypeField
(
choices
=
Payment
.
PAYMENT_TYPE
)
obj
=
Payment
()
obj
.
payment
=
False
self
.
assertEqual
(
field
.
get_attribute
(
obj
),
Payment
.
NONE
)
obj
.
payment
=
True
field
.
get_attribute
(
obj
)
mock_super
.
assert_called
()
website/payments/tests/test_admin.py
View file @
129d4eb1
from
unittest
import
mock
from
unittest.mock
import
Mock
from
unittest.mock
import
Mock
,
MagicMock
from
django.contrib
import
messages
from
django.contrib.admin
import
AdminSite
...
...
@@ -40,6 +40,7 @@ class PaymentAdminTest(TestCase):
@
classmethod
def
setUpTestData
(
cls
)
->
None
:
cls
.
user
=
Member
.
objects
.
create
(
pk
=
1
,
username
=
'test1'
,
first_name
=
'Test1'
,
last_name
=
'Example'
,
...
...
@@ -300,7 +301,7 @@ class PaymentAdminTest(TestCase):
self
.
assertEqual
(
urls
[
0
].
name
,
'payments_payment_process'
)
@
freeze_time
(
'2019-01-01'
)
def
test_export_csv
(
self
):
def
test_export_csv
(
self
)
->
None
:
"""
Test that the CSV export of payments is correct
"""
...
...
@@ -324,13 +325,14 @@ class PaymentAdminTest(TestCase):
response
=
self
.
admin
.
export_csv
(
HttpRequest
(),
Payment
.
objects
.
all
())
self
.
assertEqual
(
b
'Created,Processed,Amount,Type,Processor,Payer id,Payer name,'
b
'Notes
\r\n
2019-01-01 00:00:00+00:00,2019-01-01 00:00:00+00:00,'
b
'7.50,Card payment,Test1 Example,1,Test1 Example,
\r\n
2019-01-01 '
b
'00:00:00+00:00,2019-01-01 00:00:00+00:00,17.50,Cash payment,'
b
'Test1 Example,1,Test1 Example,
\r\n
2019-01-01 00:00:00+00:00,,'
b
'9.00,No payment,-,-,-,This is a test
\r\n
'
,
response
.
content
f
'Created,Processed,Amount,Type,Processor,Payer id,Payer name,'
f
'Notes
\r\n
2019-01-01 00:00:00+00:00,2019-01-01 00:00:00+00:00,'
f
'7.50,Card payment,Test1 Example,
{
self
.
user
.
pk
}
,Test1 Example,'
f
'
\r\n
2019-01-01 00:00:00+00:00,2019-01-01 00:00:00+00:00,17.50,'
f
'Cash payment,Test1 Example,
{
self
.
user
.
pk
}
,Test1 Example,'
f
'
\r\n
2019-01-01 00:00:00+00:00,,9.00,No payment,-,-,-,This is a '
f
'test
\r\n
'
,
response
.
content
.
decode
(
'utf-8'
)
)
...
...
@@ -377,7 +379,7 @@ class ValidAccountFilterTest(TestCase):
self
.
site
=
AdminSite
()
self
.
admin
=
admin
.
BankAccountAdmin
(
BankAccount
,
admin_site
=
self
.
site
)
def
test_lookups
(
self
):
def
test_lookups
(
self
)
->
None
:
"""
Tests that the right options are implemented for lookups
"""
...
...
@@ -394,7 +396,7 @@ class ValidAccountFilterTest(TestCase):
(
'none'
,
'None'
),
),
account_filter
.
lookups
(
None
,
None
))
def
test_queryset
(
self
):
def
test_queryset
(
self
)
->
None
:
"""
Tests that the right results are returned
"""
...
...
@@ -445,12 +447,14 @@ class BankAccountAdminTest(TestCase):
last_name
=
'Example'
,
email
=
'test1@example.org'
,
is_staff
=
True
,
is_superuser
=
True
)
Profile
.
objects
.
create
(
user
=
cls
.
user
)
def
setUp
(
self
)
->
None
:
self
.
site
=
AdminSite
()
self
.
admin
=
admin
.
BankAccountAdmin
(
BankAccount
,
admin_site
=
self
.
site
)
self
.
rf
=
RequestFactory
()
def
test_owner_link
(
self
)
->
None
:
"""
...
...
@@ -476,7 +480,7 @@ class BankAccountAdminTest(TestCase):
self
.
assertEqual
(
self
.
admin
.
owner_link
(
bank_account2
),
''
)
def
test_export_csv
(
self
):
def
test_export_csv
(
self
)
->
None
:
"""
Test that the CSV export of accounts is correct
"""
...
...
@@ -527,3 +531,53 @@ class BankAccountAdminTest(TestCase):
b
'DE12500105170648489890,NBBEBEBB,2019-01-01,2019-01-06,sig
\r\n
'
,
response
.
content
)
@
mock
.
patch
(
'django.contrib.admin.ModelAdmin.message_user'
)
@
mock
.
patch
(
'payments.services.update_last_used'
)
def
test_set_last_used
(
self
,
update_last_used
,
message_user
)
->
None
:
"""
Tests that the last used value is updated
"""
update_last_used
.
return_value
=
1
request_noperms
=
self
.
rf
.
post
(
'/'
,
{
'action'
:
'set_last_used'
,
'index'
:
1
,
'_selected_action'
:
[
'bla'
]
}
)
request_noperms
.
user
=
MagicMock
()
request_noperms
.
user
.
has_perm
=
lambda
_
:
False
request_hasperms
=
self
.
rf
.
post
(
'/'
,
{
'action'
:
'set_last_used'
,
'index'
:
1
,
'_selected_action'
:
[
'bla'
]
}
)
request_hasperms
.
user
=
MagicMock
()
request_hasperms
.
user
.
has_perm
=
lambda
_
:
True
update_last_used
.
reset_mock
()
message_user
.
reset_mock
()
queryset_mock
=
MagicMock
()
self
.
admin
.
set_last_used
(
request_noperms
,
queryset_mock
)
update_last_used
.
assert_not_called
()
self
.
admin
.
set_last_used
(
request_hasperms
,
queryset_mock
)
update_last_used
.
assert_called_once_with
(
queryset_mock
)
message_user
.
assert_called_once_with
(
request_hasperms
,
_
(
'Successfully updated %(count)d %(items)s.'
)
%
{
"count"
:
1
,
"items"
:
model_ngettext
(
BankAccount
(),
1
)
},
messages
.
SUCCESS
)
website/payments/tests/test_commands.py
0 → 100644
View file @
129d4eb1
from
unittest
import
mock
from
django.test
import
TestCase
from
freezegun
import
freeze_time
from
payments.management.commands.revokeoldmandates
import
Command
@
freeze_time
(
'2019-01-01'
)
class
RevokeOldMandatesCommandTest
(
TestCase
):
"""
Test for the management command
"""
fixtures
=
[
'members.json'
]
@
mock
.
patch
(
'payments.services.revoke_old_mandates'
)
def
test_handle
(
self
,
revoke_old_mandates
):
command
=
Command
()
command
.
handle
()
revoke_old_mandates
.
assert_called
()
website/payments/tests/test_services.py
0 → 100644
View file @
129d4eb1
from
django.test
import
TestCase
from
django.utils
import
timezone
from
freezegun
import
freeze_time
from
members.models
import
Member
from
payments
import
services
from
payments.models
import
BankAccount
@
freeze_time
(
'2019-01-01'
)
class
ServicesTest
(
TestCase
):
"""
Test for the services
"""
fixtures
=
[
'members.json'
]
@
classmethod
def
setUpTestData
(
cls
):
cls
.
member
=
Member
.
objects
.
filter
(
last_name
=
"Wiggers"
).
first
()
def
test_update_last_used
(
self
):
BankAccount
.
objects
.
create
(
owner
=
self
.
member
,
initials
=
'J'
,
last_name
=
'Test'
,
iban
=
'NL91ABNA0417164300'
,
mandate_no
=
'11-1'
,
valid_from
=
timezone
.
now
().
date
()
-
timezone
.
timedelta
(
days
=
2000
),
valid_until
=
timezone
.
now
().
date
()
-
timezone
.
timedelta
(
days
=
1500
),
signature
=
'base64,png'
)
BankAccount
.
objects
.
create
(
owner
=
self
.
member
,
initials
=
'J'
,
last_name
=
'Test'
,
iban
=
'NL91ABNA0417164300'
,
mandate_no
=
'11-2'
,
valid_from
=
timezone
.
now
().
date
()
-
timezone
.
timedelta
(
days
=
5
),
last_used
=
timezone
.
now
().
date
()
-
timezone
.
timedelta
(
days
=
5
),
signature
=
'base64,png'
)
self
.
assertEqual
(
services
.
update_last_used
(
BankAccount
.
objects
),
1
)
self
.
assertEqual
(
BankAccount
.
objects
.
filter
(
mandate_no
=
'11-2'
).
first
().
last_used
,
timezone
.
now
().
date
()
)
self
.
assertEqual
(
services
.
update_last_used
(
BankAccount
.
objects
,
timezone
.
datetime
(
year
=
2018
,
month
=
12
,
day
=
12
)
),
1
)
self
.
assertEqual
(
BankAccount
.
objects
.
filter
(
mandate_no
=
'11-2'
).
first
().
last_used
,
timezone
.
datetime
(
year
=
2018
,
month
=
12
,
day
=
12
).
date
()
)
def
test_revoke_old_mandates
(
self
):
BankAccount
.
objects
.
create
(
owner
=
self
.
member
,
initials
=
'J'
,
last_name
=
'Test1'
,
iban
=
'NL91ABNA0417164300'
,
mandate_no
=
'11-1'
,
valid_from
=
timezone
.
now
().
date
()
-
timezone
.
timedelta
(
days
=
2000
),
last_used
=
timezone
.
now
().
date
()
-
timezone
.
timedelta
(
days
=
2000
),
signature
=
'base64,png'
)
BankAccount
.
objects
.
create
(
owner
=
self
.
member
,
initials
=
'J'
,
last_name
=
'Test2'
,
iban
=
'NL91ABNA0417164300'
,
mandate_no
=
'11-2'
,
valid_from
=
timezone
.
now
().
date
()
-
timezone
.
timedelta
(
days
=
5
),
last_used
=
timezone
.
now
().
date
()
-
timezone
.
timedelta
(
days
=
5
),
signature
=
'base64,png'
)
self
.
assertEqual
(
BankAccount
.
objects
.
filter
(
valid_until
=
None
).
count
(),
2
)
services
.
revoke_old_mandates
()
self
.
assertEqual
(
BankAccount
.
objects
.
filter
(
valid_until
=
None
).
count
(),
1
)
website/thaliawebsite/urls.py
View file @
129d4eb1
...
...
@@ -112,7 +112,7 @@ urlpatterns = [ # pylint: disable=invalid-name
# Default login helpers
url
(
r
'^login/$'
,
LoginView
.
as_view
(),
{
'authentication_form'
:
AuthenticationForm
},
name
=
'login'
),
url
(
r
'^'
,
include
(
'django.contrib.auth.urls'
)),
url
(
r
'^
user/
'
,
include
(
'django.contrib.auth.urls'
)),
url
(
r
'^i18n/'
,
include
(
'django.conf.urls.i18n'
)),
# Sitemap
url
(
r
'^sitemap\.xml$'
,
sitemap
,
{
'sitemaps'
:
THALIA_SITEMAP
},
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment