230 lines
8 KiB
Python
230 lines
8 KiB
Python
"""Tests for data mapping functions (mappings.py)."""
|
|
|
|
from unittest.mock import Mock, patch
|
|
|
|
import pytest
|
|
from cteward_ng.mappings import (
|
|
none_mapper,
|
|
contract_mapper,
|
|
contractlist_mapper,
|
|
debit_mapper,
|
|
debitlist_mapper,
|
|
contributions_mapper,
|
|
member_mapper,
|
|
memo_mapper,
|
|
memberlist_mapper,
|
|
memberlist_to_ldapcsv_mapper,
|
|
withdrawal_mapper,
|
|
withdrawallist_mapper,
|
|
)
|
|
|
|
|
|
# ── helpers ───────────────────────────────────────────────────────
|
|
|
|
def _ctx(data=None, config_base='', path='/test/', flags=None):
|
|
req = Mock()
|
|
req.path = path
|
|
return {
|
|
'data': data or [],
|
|
'config': {'base': config_base},
|
|
'request': req,
|
|
'flags': flags or [],
|
|
}
|
|
|
|
|
|
# ── none_mapper ─────────────────────────────────────────────────
|
|
|
|
class TestNoneMapper:
|
|
def test_identity(self):
|
|
ctx = _ctx(data=[{'x': 1}])
|
|
result = none_mapper(ctx)
|
|
assert result['data'] == [{'x': 1}]
|
|
|
|
|
|
# ── contract mappers ─────────────────────────────────────────────
|
|
|
|
class TestContractMapper:
|
|
def test_single_contract(self):
|
|
ctx = _ctx(data=[{
|
|
'VertragNr': '42',
|
|
'ArtName': 'Ehrenmitglied',
|
|
'Sollstellung': 'monatlich',
|
|
'Betrag': 15.0,
|
|
'VertragBegin': '2020-01-01T00:00:00Z',
|
|
'VerwZw1': 'Mahnung',
|
|
'VerwZw2': '',
|
|
}], config_base='https://api.example.com/')
|
|
contract_mapper(ctx)
|
|
assert ctx['data']['Vertragsnummer'] == 42
|
|
assert ctx['data']['Vertragsart'] == 'Ehrenmitglied'
|
|
assert 'Mahnung' in ctx['data']['Verwendungszweck']
|
|
|
|
def test_empty_data(self):
|
|
ctx = _ctx(data=[])
|
|
contract_mapper(ctx)
|
|
assert ctx['data'] == {}
|
|
|
|
|
|
class TestContractlistMapper:
|
|
def test_list(self):
|
|
ctx = _ctx(data=[{
|
|
'VertragNr': '1', 'ArtName': 'A', 'Sollstellung': 'x',
|
|
'Betrag': 10, 'VertragBegin': '2020-01-01T00:00:00Z',
|
|
}], config_base='https://api.example.com/')
|
|
contractlist_mapper(ctx)
|
|
assert ctx['data']['count'] == 1
|
|
assert ctx['data']['next'] is None
|
|
|
|
|
|
# ── debit mappers ───────────────────────────────────────────────
|
|
|
|
class TestDebitMapper:
|
|
def test_single_debit(self):
|
|
ctx = _ctx(data=[{
|
|
'VertragNr': '1', 'ArtName': 'Soll', 'Jahr': 2023,
|
|
'Monat': 6, 'Datum': '2023-06-01T00:00:00Z',
|
|
'Betrag': 25, 'Bezahlt': 25, 'Offen': 0, 'GUID': 'abc',
|
|
}], config_base='https://api.example.com/', path='/debit/')
|
|
debit_mapper(ctx)
|
|
assert ctx['data']['Vertragsnummer'] == 1
|
|
assert ctx['data']['Betrag'] == 25
|
|
|
|
def test_zeroed_fields(self):
|
|
ctx = _ctx(data=[{
|
|
'VertragNr': '1', 'ArtName': 'Soll', 'Jahr': 2023,
|
|
'Monat': 6, 'Datum': '2023-06-01T00:00:00Z',
|
|
'Betrag': None, 'Bezahlt': None, 'Offen': None,
|
|
}])
|
|
debit_mapper(ctx)
|
|
assert ctx['data']['Betrag'] == 0
|
|
|
|
|
|
# ── contributions mapper ───────────────────────────────────────
|
|
|
|
class TestContributionsMapper:
|
|
def test_aggregation(self):
|
|
ctx = _ctx(data=[{
|
|
'VertragNr': '1', 'ArtName': 'Ehren', 'Jahr': 2023,
|
|
'Betrag': 100, 'Bezahlt': 80, 'Offen': 20,
|
|
}, {
|
|
'VertragNr': '1', 'ArtName': 'Ehren', 'Jahr': 2024,
|
|
'Betrag': 120, 'Bezahlt': 60, 'Offen': 60,
|
|
}], config_base='https://api.example.com/')
|
|
contributions_mapper(ctx)
|
|
assert ctx['data']['total']['billed'] == 220
|
|
assert ctx['data']['total']['paid'] == 140
|
|
assert len(ctx['data']['contracts']) == 1
|
|
assert '2023' in ctx['data']['years']
|
|
assert '2024' in ctx['data']['years']
|
|
|
|
|
|
# ── member mappers ─────────────────────────────────────────────
|
|
|
|
class TestMemberMapper:
|
|
def test_full_member(self):
|
|
ctx = _ctx(data=[{
|
|
'Eintritt': '2020-01-15T00:00:00Z',
|
|
'Kontaktwoher': 'Alice, Bob',
|
|
'Vorname': 'Max',
|
|
'Nachname': 'Mustermann',
|
|
'Kurzname': 'maxm',
|
|
'Kennung3': 'crew',
|
|
'AdrNr': 42,
|
|
'MITGLNR': '1001',
|
|
'Zahlungsart': 'L',
|
|
'Betreuung': 'MÄNNLICH',
|
|
}], config_base='https://api.example.com/',
|
|
path='/member/maxm/', flags=['_board_'])
|
|
member_mapper(ctx)
|
|
d = ctx['data']
|
|
assert d['Vorname'] == 'Max'
|
|
assert d['Email'] == 'maxm@c-base.org'
|
|
assert d['Zahlungsart'] == 'Lastschrift'
|
|
assert d['Geschlecht'] == 'M'
|
|
assert d['Mitgliedsnummer'] == 1001
|
|
assert 'memo' in d # board-only
|
|
|
|
def test_no_board_no_memo(self):
|
|
ctx = _ctx(data=[{
|
|
'Eintritt': '2020-01-01T00:00:00Z',
|
|
'Kontaktwoher': '', 'Kurzname': 'x',
|
|
'Kennung3': 'crew',
|
|
}], flags=[])
|
|
member_mapper(ctx)
|
|
assert 'memo' not in ctx['data']
|
|
|
|
|
|
class TestMemberlistMapper:
|
|
def test_list(self):
|
|
ctx = _ctx(data=[{
|
|
'Kurzname': 'alice', 'AdrNr': 1, 'Kennung3': 'crew',
|
|
'Eintritt': '2020-01-01T00:00:00Z', 'Kontaktwoher': '',
|
|
'Vorname': 'A', 'Nachname': 'B',
|
|
}])
|
|
memberlist_mapper(ctx)
|
|
assert ctx['data']['count'] == 1
|
|
assert ctx['data']['results'][0]['Crewname'] == 'alice'
|
|
|
|
def test_x_prefix_no_url(self):
|
|
ctx = _ctx(data=[{
|
|
'Kurzname': 'Xdisabled', 'AdrNr': 2, 'Kennung3': 'crew',
|
|
'Eintritt': '', 'Kontaktwoher': '',
|
|
}])
|
|
memberlist_mapper(ctx)
|
|
assert 'url' not in ctx['data']['results'][0]
|
|
|
|
|
|
class TestMemberListToLdapCsv:
|
|
def test_csv_shape(self):
|
|
ctx = _ctx(data=[{
|
|
'Kurzname': 'alice', 'Nachname': 'A', 'Vorname': 'B',
|
|
'Kennung3': 'crew', 'Eintritt': '2020-01-01T00:00:00Z',
|
|
'Telefon3': 'alice@mail.org', 'Kontaktwoher': 'Bob',
|
|
}])
|
|
memberlist_to_ldapcsv_mapper(ctx)
|
|
assert len(ctx['data']) == 1
|
|
row = ctx['data'][0]
|
|
assert 'externe E-Mail' in row
|
|
|
|
|
|
# ── memo mapper ────────────────────────────────────────────────
|
|
|
|
class TestMemoMapper:
|
|
def test_basic(self):
|
|
ctx = _ctx(data=[{
|
|
'Eintritt': '2020-01-01T00:00:00Z',
|
|
'Memotext': '{\\rtf plain text}',
|
|
'Benutzer': 'admin',
|
|
}])
|
|
memo_mapper(ctx)
|
|
assert ctx['data']['Editor'] == 'admin'
|
|
|
|
def test_no_data(self):
|
|
ctx = _ctx(data=[])
|
|
memo_mapper(ctx)
|
|
assert ctx['data'] == {}
|
|
|
|
|
|
# ── withdrawal mappers ───────────────────────────────────────
|
|
|
|
class TestWithdrawalMapper:
|
|
def test_single(self):
|
|
ctx = _ctx(data=[{
|
|
'VertragNr': '5', 'Adr_BLZ': '1234', 'Adr_Konto': '5678',
|
|
'IBAN': '', 'BIC': '', 'MandatsNr': 'MAND1',
|
|
'Betrag_EU': 50, 'Jahr': 2023, 'Zeitraum': 3,
|
|
'ErstDatum': '2023-03-15T00:00:00Z',
|
|
}], config_base='https://api.example.com/', path='/withdrawal/')
|
|
withdrawal_mapper(ctx)
|
|
assert ctx['data']['Vertragsnummer'] == 5
|
|
assert ctx['data']['BLZ'] == '1234'
|
|
|
|
def test_list(self):
|
|
ctx = _ctx(data=[{
|
|
'VertragNr': '1', 'Adr_BLZ': '', 'Adr_Konto': '',
|
|
'IBAN': '', 'BIC': '', 'MandatsNr': '',
|
|
'Betrag_EU': 0, 'Jahr': 2023, 'Zeitraum': 1,
|
|
'ErstDatum': '',
|
|
}])
|
|
withdrawallist_mapper(ctx)
|
|
assert ctx['data']['count'] == 1
|