gateway/tests/unit/features/trustee/test_accountingConnectorBexio_balances.py
2026-04-26 08:31:35 +02:00

114 lines
5.2 KiB
Python

# Copyright (c) 2026 Patrick Motsch
# All rights reserved.
"""Unit tests for the Bexio connector's getAccountBalances aggregation logic."""
from unittest.mock import patch
import pytest
from modules.features.trustee.accounting.connectors.accountingConnectorBexio import (
AccountingConnectorBexio,
_isIncomeStatementAccount,
)
class TestIsIncomeStatementAccount:
@pytest.mark.parametrize("accno,expected", [
("1020", False), ("2010", False), ("3000", True), ("9999", True), ("", False),
])
def test_classification(self, accno, expected):
assert _isIncomeStatementAccount(accno) == expected
class TestBexioGetAccountBalances:
@pytest.mark.asyncio
async def test_aggregatesBalanceSheetAccount_cumulativeAcrossMonths(self):
connector = AccountingConnectorBexio()
accounts = [{"id": 100, "account_no": "1020"}, {"id": 200, "account_no": "6000"}]
# Simulate a clean year for account 1020 (BS): +1000 in Jan, -300 in Feb, +500 in Dec
rawJournal = [
{"date": "2025-01-15", "amount": 1000.0, "debit_account_id": 100, "credit_account_id": 200},
{"date": "2025-02-10", "amount": 300.0, "debit_account_id": 200, "credit_account_id": 100},
{"date": "2025-12-20", "amount": 500.0, "debit_account_id": 100, "credit_account_id": 200},
]
async def _fakeAccounts(self, config):
return accounts
async def _fakeJournal(self, config, dateTo):
return rawJournal
with patch.object(AccountingConnectorBexio, "_loadRawAccounts", _fakeAccounts), \
patch.object(AccountingConnectorBexio, "_fetchAllJournalRows", _fakeJournal):
balances = await connector.getAccountBalances({"accessToken": "x", "apiBaseUrl": "http://x"}, years=[2025])
byPeriod = {(b.accountNumber, b.periodMonth): b for b in balances if b.periodYear == 2025}
# Account 1020 (BS) cumulative: Jan +1000, Feb +1000-300=700, Dec +700+500=1200
assert byPeriod[("1020", 1)].closingBalance == 1000.0
assert byPeriod[("1020", 2)].closingBalance == 700.0
assert byPeriod[("1020", 11)].closingBalance == 700.0
assert byPeriod[("1020", 12)].closingBalance == 1200.0
assert byPeriod[("1020", 0)].closingBalance == 1200.0 # annual
assert byPeriod[("1020", 0)].openingBalance == 0.0
assert byPeriod[("1020", 1)].openingBalance == 0.0
assert byPeriod[("1020", 2)].openingBalance == 1000.0 # = previous month's closing
@pytest.mark.asyncio
async def test_balanceSheetAccount_carriesPriorYearOpening(self):
connector = AccountingConnectorBexio()
accounts = [{"id": 100, "account_no": "1020"}, {"id": 200, "account_no": "6000"}]
rawJournal = [
{"date": "2024-06-01", "amount": 5000.0, "debit_account_id": 100, "credit_account_id": 200},
{"date": "2025-03-15", "amount": 1000.0, "debit_account_id": 100, "credit_account_id": 200},
]
async def _fakeAccounts(self, config):
return accounts
async def _fakeJournal(self, config, dateTo):
return rawJournal
with patch.object(AccountingConnectorBexio, "_loadRawAccounts", _fakeAccounts), \
patch.object(AccountingConnectorBexio, "_fetchAllJournalRows", _fakeJournal):
balances = await connector.getAccountBalances({"accessToken": "x", "apiBaseUrl": "http://x"}, years=[2025])
byPeriod = {(b.accountNumber, b.periodMonth): b for b in balances if b.periodYear == 2025}
# 2025 opening for 1020 = 5000 (carried over from 2024)
assert byPeriod[("1020", 1)].openingBalance == 5000.0
assert byPeriod[("1020", 0)].openingBalance == 5000.0
assert byPeriod[("1020", 12)].closingBalance == 6000.0
assert byPeriod[("1020", 0)].closingBalance == 6000.0
@pytest.mark.asyncio
async def test_incomeStatementAccount_resetsToZeroEachYear(self):
connector = AccountingConnectorBexio()
accounts = [{"id": 200, "account_no": "6000"}, {"id": 300, "account_no": "1020"}]
rawJournal = [
{"date": "2024-12-31", "amount": 99999.99, "debit_account_id": 200, "credit_account_id": 300},
{"date": "2025-06-15", "amount": 250.0, "debit_account_id": 200, "credit_account_id": 300},
]
async def _fakeAccounts(self, config):
return accounts
async def _fakeJournal(self, config, dateTo):
return rawJournal
with patch.object(AccountingConnectorBexio, "_loadRawAccounts", _fakeAccounts), \
patch.object(AccountingConnectorBexio, "_fetchAllJournalRows", _fakeJournal):
balances = await connector.getAccountBalances({"accessToken": "x", "apiBaseUrl": "http://x"}, years=[2025])
byPeriod = {(b.accountNumber, b.periodMonth): b for b in balances if b.periodYear == 2025}
# ER account 6000: prior year had 99999.99 movement; 2025 opening MUST be 0
assert byPeriod[("6000", 1)].openingBalance == 0.0
assert byPeriod[("6000", 0)].openingBalance == 0.0
assert byPeriod[("6000", 6)].closingBalance == 250.0
assert byPeriod[("6000", 12)].closingBalance == 250.0
assert byPeriod[("6000", 0)].closingBalance == 250.0