Improvements for bank transfer importing (#1762)

Co-authored-by: Raphael Michel <michel@rami.io>
Co-authored-by: Raphael Michel <mail@raphaelmichel.de>
This commit is contained in:
Felix Rindt
2020-10-22 11:00:36 +02:00
committed by GitHub
parent 9e4dc344a4
commit a62c7939ae
26 changed files with 1204 additions and 139 deletions

View File

@@ -191,29 +191,33 @@ EXPECTED = [
[
{'amount': '-800.00',
'date': '2002-11-01',
'payer': 'MUELLER - 234567',
'payer': 'MUELLER',
'iban': '234567',
'reference': 'Miete November'},
{'amount': '3000.00',
'date': '2002-11-02',
'payer': 'MUELLER - 0847564700',
'payer': 'MUELLER',
'iban': '0847564700',
'reference': 'Gehalt Oktober Firma Mustermann GmbH'},
],
[
{'amount': '-400.62',
'date': '2012-02-02',
'payer': 'MARTHAMUELLER -',
'payer': 'MARTHAMUELLER',
'reference': 'RECHNUNGSNR. 1210815 KUNDENNR. 01234 22222222 DATUM 01.02.2012'},
{'amount': '-1210.00',
'date': '2012-02-03',
'reference': 'MIETE GOETHESTR. 12',
'payer': 'ABC IMMOBILIEN GMBH - 3333333333'},
'payer': 'ABC IMMOBILIEN GMBH',
'iban': '3333333333'},
{'amount': '30.00',
'date': '2012-02-03',
'payer': 'STEFAN SCHMIDT -',
'payer': 'STEFAN SCHMIDT',
'reference': 'RECHNUNG 20120188 STEFAN SCHMIDTKUNDENR. 4711,'},
{'amount': '89.97',
'date': '2012-02-03',
'payer': 'PETER PETERSEN - 5555555555',
'payer': 'PETER PETERSEN',
'iban': '5555555555',
'reference': 'RECHNUNG 20120165 PETER PETERSEN'}
],
[
@@ -228,12 +232,21 @@ EXPECTED = [
{'amount': '-50000.00', 'date': '2002-03-24', 'reference': ''}
],
[
{'amount': '12.00', 'date': '2017-08-23', 'payer': 'Peter Schneider - DE13495179316396679327', 'reference':
'Democon-Abcde (Peter Schneider ), Kategorie: Alles - E innahmen - Veranstaltungen Democon #1111'},
{'amount': '12.00', 'date': '2017-08-23', 'payer': 'Peter Schneider - DE13495179316396679327', 'reference':
'Democon-Abcde (Peter Schneider ), Kategorie: Alles - E innahmen - Veranstaltungen Democon #1111'},
{'amount': '12.00', 'date': '2017-08-24', 'payer': 'Peter Schneider - DE13495179316396679327', 'reference':
'Democon-Abcde (Peter Schneider ), Kategorie: Alles- E innahmen - Veranstaltungen Democon #1111'},
{'amount': '12.00',
'date': '2017-08-23',
'payer': 'Peter Schneider',
'iban': 'DE13495179316396679327',
'reference': 'Democon-Abcde (Peter Schneider ), Kategorie: Alles - E innahmen - Veranstaltungen Democon #1111'},
{'amount': '12.00',
'date': '2017-08-23',
'payer': 'Peter Schneider',
'iban': 'DE13495179316396679327',
'reference': 'Democon-Abcde (Peter Schneider ), Kategorie: Alles - E innahmen - Veranstaltungen Democon #1111'},
{'amount': '12.00',
'date': '2017-08-24',
'payer': 'Peter Schneider',
'iban': 'DE13495179316396679327',
'reference': 'Democon-Abcde (Peter Schneider ), Kategorie: Alles- E innahmen - Veranstaltungen Democon #1111'},
]
]

View File

@@ -0,0 +1,21 @@
from datetime import date
from pretix.plugins.banktransfer.tasks import parse_date
def test_date_formats():
dt = date(year=2020, month=7, day=1)
assert dt == parse_date("01.07.2020")
assert dt == parse_date("01.07.20")
assert dt == parse_date("1.7.2020")
assert dt == parse_date("1.7.20")
assert dt == parse_date("07/01/2020")
assert dt == parse_date("07/01/20")
assert dt == parse_date("7/1/2020")
assert dt == parse_date("7/1/20")
assert dt == parse_date("2020/07/01")
assert dt == parse_date("2020-07-01")
assert dt == parse_date("2020-7-1")

View File

@@ -0,0 +1,88 @@
import json
from datetime import timedelta
from decimal import Decimal
import pytest
from django.utils.timezone import now
from django_scopes import scope
from pretix.base.models import (
Event, Order, OrderPayment, OrderRefund, Organizer, Team, User,
)
@pytest.fixture
def env():
o = Organizer.objects.create(name='Dummy', slug='dummy')
event = Event.objects.create(
organizer=o, name='Dummy', slug='dummy',
date_from=now(), plugins='pretix.plugins.banktransfer,pretix.plugins.paypal'
)
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
t = Team.objects.create(organizer=event.organizer, can_view_orders=True, can_change_orders=True)
t.members.add(user)
t.limit_events.add(event)
order = Order.objects.create(
code='1Z3AS', event=event, email='admin@localhost',
status=Order.STATUS_PAID,
datetime=now(), expires=now() + timedelta(days=10),
total=23
)
payment = OrderPayment.objects.create(
order=order,
amount=Decimal("23"),
provider='banktransfer',
state=OrderPayment.PAYMENT_STATE_CONFIRMED,
info=json.dumps({
'payer': "Abc Def",
'iban': "DE27520521540534534466",
'bic': "HELADEF1MEG",
})
)
return event, user, payment
@pytest.mark.django_db
def test_perform_refund(client, env):
event, user, payment = env
client.login(email='dummy@dummy.dummy', password='dummy')
assert not OrderRefund.objects.exists()
url = "/control/event/dummy/dummy/orders/1Z3AS/refund"
r = client.post(url, {
f"refund-{payment.id}": "23.00",
"start-mode": "full",
"perform": True,
})
assert r.status_code == 302
with scope(organizer=event.organizer):
assert OrderRefund.objects.exists()
refund = OrderRefund.objects.first()
assert refund.payment == payment
assert refund.info_data == {
'payer': "Abc Def",
'iban': "DE27520521540534534466",
'bic': "HELADEF1MEG",
}
@pytest.mark.django_db
def test_cannot_perform_refund_with_invalid_iban(client, env):
event, user, payment = env
payment.info_data = {
'payer': "Abc Def",
'iban': "DE27520521540534534467", # invalid IBAN
'bic': "HELADEF1MEG",
}
payment.save()
assert not payment.payment_provider.payment_refund_supported(payment)
client.login(email='dummy@dummy.dummy', password='dummy')
url = "/control/event/dummy/dummy/orders/1Z3AS/refund"
r = client.post(url, {
f"refund-{payment.id}": "23.00",
"start-mode": "full",
"perform": True,
})
assert r.status_code == 200 # no successfull POST
with scope(organizer=event.organizer):
assert not OrderRefund.objects.exists()

View File

@@ -0,0 +1,135 @@
import json
from datetime import timedelta
from decimal import Decimal
import pytest
from django.utils.timezone import now
from pretix.base.models import Event, Order, OrderRefund, Organizer, Team, User
from pretix.plugins.banktransfer.models import RefundExport
from pretix.plugins.banktransfer.views import (
_row_key_func, _unite_transaction_rows,
)
@pytest.fixture
def env():
o = Organizer.objects.create(name='Dummy', slug='dummy')
event = Event.objects.create(
organizer=o, name='Dummy', slug='dummy',
date_from=now(), plugins='pretix.plugins.banktransfer,pretix.plugins.paypal'
)
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
t = Team.objects.create(organizer=event.organizer, can_view_orders=True, can_change_orders=True)
t.members.add(user)
t.limit_events.add(event)
order = Order.objects.create(
code='1Z3AS', event=event, email='admin@localhost',
status=Order.STATUS_PAID,
datetime=now(), expires=now() + timedelta(days=10),
total=23
)
refund = OrderRefund.objects.create(
order=order,
amount=Decimal("23"),
provider='banktransfer',
state=OrderRefund.REFUND_STATE_CREATED,
info=json.dumps({
'payer': "Abc Def",
'iban': "DE27520521540534534466",
'bic': "HELADEF1MEG",
})
)
return event, user, refund
url_prefixes = [
"/control/event/dummy/dummy/",
"/control/organizer/dummy/"
]
@pytest.mark.django_db
@pytest.mark.parametrize("url_prefix", url_prefixes)
def test_export_refunds_as_sepa_xml(client, env, url_prefix):
client.login(email='dummy@dummy.dummy', password='dummy')
r = client.post(f'{url_prefix}banktransfer/refunds/', {"unite_transactions": True}, follow=True)
assert b"SEPA" in r.content
r = client.get(f'{url_prefix}banktransfer/sepa-export/{RefundExport.objects.last().id}/')
assert r.status_code == 200
r = client.post(f'{url_prefix}banktransfer/sepa-export/{RefundExport.objects.last().id}/', {
"account_holder": "Fission Festival",
"iban": "DE71720690050653667120",
"bic": "GENODEF1AIL",
})
assert "DE27520521540534534466" in "".join(str(part) for part in r.streaming_content)
@pytest.mark.django_db
@pytest.mark.parametrize("url_prefix", url_prefixes)
def test_export_refunds(client, env, url_prefix):
client.login(email='dummy@dummy.dummy', password='dummy')
r = client.get(f'{url_prefix}banktransfer/refunds/')
assert r.status_code == 200
r = client.post(f'{url_prefix}banktransfer/refunds/', {"unite_transactions": True}, follow=True)
assert r.status_code == 200
refund = RefundExport.objects.last()
assert refund is not None
assert b"Download CSV" in r.content
r = client.get(f'{url_prefix}banktransfer/export/{refund.id}/')
assert r.status_code == 200
assert "DE27520521540534534466" in "".join(str(part) for part in r.streaming_content)
def test_unite_transaction_rows():
rows = sorted([
{
'payer': "Abc Def",
'iban': 'DE12345678901234567890',
'bic': 'HARKE9000',
'id': "ROLLA-R-1",
'amount': Decimal("42.23"),
},
{
'payer': "First Last",
'iban': 'DE111111111111111111111',
'bic': 'ikswez2020',
'id': "PARTY-R-1",
'amount': Decimal("6.50"),
}
], key=_row_key_func)
assert _unite_transaction_rows(rows) == rows
rows = sorted(rows + [
{
'payer': "Abc Def",
'iban': 'DE12345678901234567890',
'bic': 'HARKE9000',
'id': "ROLLA-R-1",
'amount': Decimal("7.77"),
},
{
'payer': "Another Last",
'iban': 'DE111111111111111111111',
'bic': 'ikswez2020',
'id': "PARTY-R-2",
'amount': Decimal("13.50"),
}
], key=_row_key_func)
assert _unite_transaction_rows(rows) == sorted([
{
'payer': "Abc Def",
'iban': 'DE12345678901234567890',
'bic': 'HARKE9000',
'id': "ROLLA-R-1",
'amount': Decimal("50.00"),
},
{
'payer': 'Another Last, First Last',
'iban': 'DE111111111111111111111',
'bic': 'ikswez2020',
'id': 'PARTY-R-1, PARTY-R-2',
'amount': Decimal('20.00'),
}], key=_row_key_func)