94 lines
3.8 KiB
Python
94 lines
3.8 KiB
Python
# Copyright (c) 2026 Patrick Motsch
|
|
# All rights reserved.
|
|
"""Unit tests for the Abacus connector's getAccountBalances aggregation logic."""
|
|
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
|
|
from modules.features.trustee.accounting.connectors.accountingConnectorAbacus import (
|
|
AccountingConnectorAbacus,
|
|
_isIncomeStatementAccount,
|
|
)
|
|
|
|
|
|
class TestIsIncomeStatementAccount:
|
|
@pytest.mark.parametrize("accno,expected", [
|
|
("1020", False), ("2010", False), ("3000", True), ("8500", True),
|
|
])
|
|
def test_classification(self, accno, expected):
|
|
assert _isIncomeStatementAccount(accno) == expected
|
|
|
|
|
|
class TestAbacusGetAccountBalances:
|
|
@pytest.mark.asyncio
|
|
async def test_aggregatesFromGeneralJournalEntries(self):
|
|
connector = AccountingConnectorAbacus()
|
|
|
|
rawEntries = [
|
|
{
|
|
"Id": "e1", "JournalDate": "2025-01-15T00:00:00",
|
|
"Lines": [
|
|
{"AccountId": "1020", "DebitAmount": 1000.0, "CreditAmount": 0.0},
|
|
{"AccountId": "6000", "DebitAmount": 0.0, "CreditAmount": 1000.0},
|
|
],
|
|
},
|
|
{
|
|
"Id": "e2", "JournalDate": "2025-12-20T00:00:00",
|
|
"Lines": [
|
|
{"AccountId": "1020", "DebitAmount": 500.0, "CreditAmount": 0.0},
|
|
{"AccountId": "6000", "DebitAmount": 0.0, "CreditAmount": 500.0},
|
|
],
|
|
},
|
|
]
|
|
|
|
async def _fakeAuth(self, config):
|
|
return {"Authorization": "Bearer X"}
|
|
|
|
async def _fakeFetch(self, config, headers, dateTo):
|
|
return rawEntries
|
|
|
|
with patch.object(AccountingConnectorAbacus, "_buildAuthHeaders", _fakeAuth), \
|
|
patch.object(AccountingConnectorAbacus, "_fetchAllJournalEntries", _fakeFetch):
|
|
balances = await connector.getAccountBalances({"apiBaseUrl": "http://x", "clientName": "y"}, years=[2025])
|
|
|
|
byPeriod = {(b.accountNumber, b.periodYear, b.periodMonth): b for b in balances}
|
|
|
|
assert byPeriod[("1020", 2025, 1)].closingBalance == 1000.0
|
|
assert byPeriod[("1020", 2025, 12)].closingBalance == 1500.0
|
|
assert byPeriod[("1020", 2025, 0)].closingBalance == 1500.0
|
|
# 6000 is income statement (3xxx-9xxx) but credit-side -- closing = -1500 (net debit-credit)
|
|
assert byPeriod[("6000", 2025, 0)].closingBalance == -1500.0
|
|
# ER account January opening must be 0 (no prior-year carry)
|
|
assert byPeriod[("6000", 2025, 1)].openingBalance == 0.0
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_balanceSheetCarryOverAcrossYears(self):
|
|
connector = AccountingConnectorAbacus()
|
|
|
|
rawEntries = [
|
|
{
|
|
"Id": "e1", "JournalDate": "2024-06-30T00:00:00",
|
|
"Lines": [
|
|
{"AccountId": "1020", "DebitAmount": 7000.0, "CreditAmount": 0.0},
|
|
{"AccountId": "9999", "DebitAmount": 0.0, "CreditAmount": 7000.0},
|
|
],
|
|
},
|
|
]
|
|
|
|
async def _fakeAuth(self, config):
|
|
return {"Authorization": "Bearer X"}
|
|
|
|
async def _fakeFetch(self, config, headers, dateTo):
|
|
return rawEntries
|
|
|
|
with patch.object(AccountingConnectorAbacus, "_buildAuthHeaders", _fakeAuth), \
|
|
patch.object(AccountingConnectorAbacus, "_fetchAllJournalEntries", _fakeFetch):
|
|
balances = await connector.getAccountBalances({"apiBaseUrl": "http://x", "clientName": "y"}, years=[2025])
|
|
|
|
byPeriod = {(b.accountNumber, b.periodYear, b.periodMonth): b for b in balances}
|
|
|
|
# 1020 (BS) opens 2025 with 7000 from prior year, no movements in 2025 -> closes at 7000
|
|
assert byPeriod[("1020", 2025, 1)].openingBalance == 7000.0
|
|
assert byPeriod[("1020", 2025, 0)].openingBalance == 7000.0
|
|
assert byPeriod[("1020", 2025, 0)].closingBalance == 7000.0
|