"""Ledger model tests.""" from datetime import datetime, timedelta from decimal import Decimal import pytest from ledger.models.ledger_account import LedgerAccount from ledger.schemas.ledger_account import LedgerAccountListSchema, LedgerAccountSchema from tests.conftest import mock_account from tests.utils.factories import ( LedgerAccountFactory, LedgerContractAdvanceAppliedFactory, ) def test_create_ledger_account(mock_event_fixtures): """Create a ledger account.""" LedgerAccount.create( account_id=1, abacus_event_id=1, contract_id=1, currency_code='USD', currency_amount=5050.50, previous_balance=10000, current_balance=-2020.20, note='credit ledger item', ) ledgers = LedgerAccount.query.all() assert len(ledgers) == 1 ledger_entry = ledgers[0] assert ledger_entry.account_id == 1 assert ledger_entry.abacus_event_id == 1 assert ledger_entry.contract_id == 1 assert ledger_entry.currency_code == 'USD' assert ledger_entry.currency_amount == Decimal('5050.50') assert ledger_entry.previous_balance == Decimal('10000') assert ledger_entry.current_balance == Decimal('-2020.20') assert ledger_entry.note == 'credit ledger item' def test_get_by_account_id(mock_event_fixtures): """Test getting ledger entries by account_id ordered by most recent.""" yesterday = datetime.now() - timedelta(days=1) entry_1 = LedgerAccountFactory.create(account_id=1, created_at=yesterday) LedgerAccountFactory.create(account_id=50) account_ledgers = LedgerAccount.get_by_account_id(1).all() assert account_ledgers[0] == entry_1 def test_get_ledger_account_balance(mock_event_fixtures): """Test to get account's most recent current balance.""" account_id = 2 mock_account(account_id) LedgerAccountFactory.create( account_id=account_id, abacus_event_id=1, currency_code='EUR', currency_amount=10000.0, previous_balance=0, current_balance=78.0, note='credit ledger item', ) entry_2 = LedgerAccountFactory.create( account_id=account_id, abacus_event_id=2, currency_code='USD', currency_amount=67614.28, previous_balance=0, current_balance=67614.28, note='credit ledger item', ) account_ledgers = LedgerAccount.get_ledger_account_balance(account_id).all() assert account_ledgers[0].ledger_account_id == entry_2.ledger_account_id assert account_ledgers[0].current_balance == entry_2.current_balance def test_get_ledger_account_balances(mock_event_fixtures): """Test get ledger_account current balances by account_ids.""" account_id = 2 mock_account(account_id) LedgerAccountFactory.create( account_id=account_id, abacus_event_id=1, currency_code='EUR', currency_amount=10000.0, previous_balance=0, current_balance=78.0, note='credit ledger item', ) entry_2 = LedgerAccountFactory.create( account_id=account_id, abacus_event_id=2, currency_code='USD', currency_amount=67614.28, previous_balance=0, current_balance=67614.28, note='credit ledger item', ) entry_3 = LedgerAccountFactory.create( account_id=1, abacus_event_id=2, currency_code='USD', currency_amount=67614.28, previous_balance=0, current_balance=67614.28, note='credit ledger item', ) LedgerAccountFactory.create( account_id=50, abacus_event_id=2, currency_code='USD', currency_amount=67614.28, previous_balance=0, current_balance=67614.28, note='credit ledger item', ) account_ledgers = LedgerAccount.get_ledger_account_balances( [account_id, entry_3.account_id] ).all() assert len(account_ledgers) == 2 assert account_ledgers[0].ledger_account_id == entry_2.ledger_account_id assert account_ledgers[0].current_balance == entry_2.current_balance assert account_ledgers[0].ledger_account_id == entry_2.ledger_account_id assert account_ledgers[0].current_balance == entry_2.current_balance def test_get_ledger_account_info(mock_event_fixtures): """Test getting ledger information by account_id ordered by most recent.""" LedgerAccountFactory.create( account_id=1, abacus_event_id=24, currency_code='USD', currency_amount=-1000.0, previous_balance=5000.00, current_balance=4000.00, note='mechanical deduction (debit)', contract_id=1, ) LedgerAccountFactory.create( account_id=1, abacus_event_id=1, currency_code='USD', currency_amount=-100.0, previous_balance=0, current_balance=-100.0, note='take reserves (debit)', ) # commit royalties event tied to accounting period LedgerAccountFactory.create( account_id=1, abacus_event_id=2, currency_code='USD', currency_amount=5000.0, previous_balance=-100.00, current_balance=4900.00, note='close accounting period (credit)', contract_id=2, ) # commit royalties event tied to accounting run LedgerAccountFactory.create( account_id=1, abacus_event_id=9, currency_code='USD', currency_amount=500.0, previous_balance=-100.00, current_balance=400.00, note='commit accounting run (credit)', contract_id=1, ) LedgerAccountFactory.create( account_id=1, abacus_event_id=3, currency_code='USD', currency_amount=25.00, previous_balance=4900.00, current_balance=4925.00, note='release reserves (credit)', ) LedgerAccountFactory.create( account_id=1, abacus_event_id=5, currency_code='USD', currency_amount=-502.37, previous_balance=4925.00, current_balance=4422.63, note='adjustments applied (debit)', contract_id=1, ) LedgerAccountFactory.create( account_id=1, abacus_event_id=6, currency_code='USD', currency_amount=-4422.63, previous_balance=4422.63, current_balance=0.00, note='payment accepted (debit)', contract_id=1, ) LedgerAccountFactory.create( account_id=1, abacus_event_id=8, currency_code='USD', currency_amount=4422.63, previous_balance=0.00, current_balance=4422.63, note='payoneer canceled this payment so sad', contract_id=1, ) account_ledgers, total_count = LedgerAccount.get_ledger_account_info(1) assert total_count == 8 data = LedgerAccountListSchema().dump(account_ledgers, many=True) assert data[0]['ending_balance'] == '4422.63' assert data[0]['opening_balance'] == '0.00' assert data[0]['currency_code'] == 'USD' assert data[0]['transaction_type'] == 'payment_returned' assert data[0]['contract_id'] == 1 assert data[1]['ending_balance'] == '0.00' assert data[1]['opening_balance'] == '4422.63' assert data[1]['currency_code'] == 'USD' assert data[1]['transaction_type'] == 'send_payments' assert data[1]['contract_id'] == 1 assert data[2]['ending_balance'] == '4422.63' assert data[2]['amount'] == '-502.37' assert data[2]['opening_balance'] == '4925.00' assert data[2]['currency_code'] == 'USD' assert data[2]['transaction_type'] == 'apply_pending_adjustments' assert data[2]['contract_id'] == 1 # commit royalties event tied to accounting run assert data[4]['ending_balance'] == '400.00' assert data[4]['amount'] == '500.00' assert data[4]['opening_balance'] == '-100.00' assert data[4]['currency_code'] == 'USD' assert data[4]['transaction_type'] == 'commit_royalties' assert data[4]['contract_id'] == 1 # commit royalties event tied to accounting period assert data[5]['ending_balance'] == '4900.00' assert data[5]['amount'] == '5000.00' assert data[5]['opening_balance'] == '-100.00' assert data[5]['currency_code'] == 'USD' assert data[5]['transaction_type'] == 'commit_royalties' assert data[5]['contract_id'] == 2 assert data[7]['ending_balance'] == '4000.00' assert data[7]['amount'] == '-1000.00' assert data[7]['opening_balance'] == '5000.00' assert data[7]['currency_code'] == 'USD' assert data[7]['transaction_type'] == 'commit_mechanicals' assert data[7]['contract_id'] == 1 def test_get_ledger_account_info_for_contract_advance(mock_event_fixtures): """Test getting ledger information for contract_advance by account_id.""" LedgerContractAdvanceAppliedFactory.create() LedgerAccountFactory.create( account_id=1, abacus_event_id=7, currency_code='USD', currency_amount=-150.00, previous_balance=0, current_balance=-150.00, note='Advance payment (debit)', contract_id=1, ) account_ledgers, _ = LedgerAccount.get_ledger_account_info(1) data = LedgerAccountListSchema().dump(account_ledgers, many=True) assert data[0]['currency_code'] == 'USD' assert data[0]['transaction_type'] == 'confirm_advance_payment' assert data[0]['contract_id'] == 1 def test_get_ledger_account_info_for_royalty_reversal(mock_event_fixtures): """Test getting ledger information for apply_royalty_reversal by account_id.""" LedgerContractAdvanceAppliedFactory.create() LedgerAccountFactory.create( account_id=1, abacus_event_id=10, currency_code='USD', currency_amount=-210.00, previous_balance=0, current_balance=-210.00, note='Royalty Reverse', contract_id=1, ) account_ledgers, _ = LedgerAccount.get_ledger_account_info(1) data = LedgerAccountListSchema().dump(account_ledgers, many=True) assert data[0]['currency_code'] == 'USD' assert data[0]['transaction_type'] == 'apply_royalty_reversal' assert data[0]['contract_id'] == 1 def test_get_ledger_account_info_for_royalty_correction(mock_event_fixtures): """Test getting ledger information for apply_royalty_correction by account_id.""" LedgerContractAdvanceAppliedFactory.create() LedgerAccountFactory.create( account_id=1, abacus_event_id=12, currency_code='USD', currency_amount=210.00, previous_balance=0, current_balance=210.00, note='Royalty Correction', contract_id=1, ) account_ledgers, _ = LedgerAccount.get_ledger_account_info(1) data = LedgerAccountListSchema().dump(account_ledgers, many=True) assert data[0]['currency_code'] == 'USD' assert data[0]['transaction_type'] == 'apply_royalty_correction' assert data[0]['contract_id'] == 1 def test_get_ledger_account_info_for_vat_summary(mock_event_fixtures): """Test getting ledger information for commit_vat_summary event.""" account_id = 1 LedgerAccountFactory.create( account_id=account_id, abacus_event_id=16, currency_code='USD', currency_amount=10.00, previous_balance=1000.00, current_balance=1010.00, contract_id=1, ) account_ledgers, _ = LedgerAccount.get_ledger_account_info(account_id) data = LedgerAccountListSchema().dump(account_ledgers, many=True) assert data[0]['currency_code'] == 'USD' assert data[0]['transaction_type'] == 'commit_vat_summary' assert data[0]['account_id'] == account_id def test_get_ledger_account_info_for_returned_contract_advance_payment( mock_event_fixtures, ): """Test getting ledger information for 'return_advance_payment' event.""" ledger_contract_advance_applied = LedgerContractAdvanceAppliedFactory.create() LedgerAccountFactory.create(abacus_event_id=17) account_ledgers, _ = LedgerAccount.get_ledger_account_info(1) assert account_ledgers[0].account_id == ledger_contract_advance_applied.account_id assert account_ledgers[0].contract_id == ledger_contract_advance_applied.contract_id assert ( account_ledgers[0].currency_code == ledger_contract_advance_applied.advance_payee_currency_code ) assert account_ledgers[0].transaction_type == 'return_advance_payment' def test_get_ledger_account_info_for_payment_group_events(mock_event_fixtures): """Test getting ledger information for the "payment group" events.""" account_id = 1 LedgerAccountFactory.create( account_id=account_id, abacus_event_id=18, currency_code='USD', currency_amount=10.00, previous_balance=1000.00, current_balance=1010.00, note='Commit batch payment', ) LedgerAccountFactory.create( account_id=account_id, abacus_event_id=19, currency_code='USD', currency_amount=10.00, previous_balance=1010.00, current_balance=1020.00, note='Commit vat summary', ) LedgerAccountFactory.create( account_id=account_id, abacus_event_id=20, currency_code='USD', currency_amount=10.00, previous_balance=1020.00, current_balance=1030.00, note='Commit withholding tax', ) LedgerAccountFactory.create( account_id=account_id, abacus_event_id=21, currency_code='USD', currency_amount=-10.00, previous_balance=1030.00, current_balance=1020.00, note='Return batch payment', ) LedgerAccountFactory.create( account_id=account_id, abacus_event_id=22, currency_code='USD', currency_amount=-10.00, previous_balance=1020.00, current_balance=1010.00, note='Return vat summary', ) LedgerAccountFactory.create( account_id=account_id, abacus_event_id=23, currency_code='USD', currency_amount=-10.00, previous_balance=1010.00, current_balance=1000.00, note='Return withholding tax', ) account_ledgers, _ = LedgerAccount.get_ledger_account_info(account_id) data = LedgerAccountListSchema().dump(account_ledgers, many=True) assert data[0]['account_id'] == account_id assert data[0]['transaction_type'] == 'return_withholding_tax' assert data[0]['currency_code'] == 'USD' assert data[0]['amount'] == '-10.00' assert data[0]['opening_balance'] == '1010.00' assert data[0]['ending_balance'] == '1000.00' assert data[1]['account_id'] == account_id assert data[1]['transaction_type'] == 'return_vat_summary' assert data[1]['currency_code'] == 'USD' assert data[1]['amount'] == '-10.00' assert data[1]['opening_balance'] == '1020.00' assert data[1]['ending_balance'] == '1010.00' assert data[2]['account_id'] == account_id assert data[2]['transaction_type'] == 'return_batch_payment' assert data[2]['currency_code'] == 'USD' assert data[2]['amount'] == '-10.00' assert data[2]['opening_balance'] == '1030.00' assert data[2]['ending_balance'] == '1020.00' assert data[3]['account_id'] == account_id assert data[3]['transaction_type'] == 'commit_withholding_tax' assert data[3]['currency_code'] == 'USD' assert data[3]['amount'] == '10.00' assert data[3]['opening_balance'] == '1020.00' assert data[3]['ending_balance'] == '1030.00' assert data[4]['account_id'] == account_id assert data[4]['transaction_type'] == 'commit_vat_summary' assert data[4]['currency_code'] == 'USD' assert data[4]['amount'] == '10.00' assert data[4]['opening_balance'] == '1010.00' assert data[4]['ending_balance'] == '1020.00' assert data[5]['account_id'] == account_id assert data[5]['transaction_type'] == 'commit_batch_payment' assert data[5]['currency_code'] == 'USD' assert data[5]['amount'] == '10.00' assert data[5]['opening_balance'] == '1000.00' assert data[5]['ending_balance'] == '1010.00' def test_get_by_custom_filters(mock_event_fixtures): """Test getting ledger information with filtering.""" created_at = datetime.now() # mock_event_fixtures already creates account #1 for ind in range(2, 12): mock_account(ind) LedgerAccountFactory.create( account_id=ind, current_balance=5, created_at=created_at + timedelta(minutes=1), ) # we've got 10 rows for 10 distinct accounts assert len(LedgerAccount.query.all()) == 10 # filter by account_ids data = LedgerAccount.get_by_custom_filters(account_ids=[2, 3, 4, 5, 6]).all() assert len(data) == 5 account_ids = sorted([item.account_id for item in data]) assert account_ids == [2, 3, 4, 5, 6] assert all([item.current_balance == 5 for item in data]) # filter by current_balance amount < 3 for ind in (13, 14): mock_account(ind) LedgerAccountFactory.create( account_id=ind, current_balance=2, created_at=datetime.now() + timedelta(minutes=4), ) assert len(LedgerAccount.query.all()) == 12 data = LedgerAccount.get_by_custom_filters(balance_max=3 - 0.0001).all() assert len(data) == 2 account_ids = sorted([item.account_id for item in data]) assert account_ids == [13, 14] assert all([item.current_balance == 2 for item in data]) # filter by current_balance == 0 mock_account(15) LedgerAccountFactory.create( account_id=15, current_balance=0, created_at=datetime.now() + timedelta(minutes=5), ) data = LedgerAccount.get_by_custom_filters(balance_max=0, balance_min=0).all() assert len(data) == 1 assert data[0].account_id == 15 assert data[0].current_balance == 0 @pytest.mark.skip(reason='method to be deprecated (dczinsky)') def test_get_accounts_by_acc_period_id(mock_event_fixtures): """Test to get ledger accounts by accounting period id.""" LedgerAccountFactory.create( account_id=1, contract_id=1, abacus_event_id=2, currency_code='EUR', currency_amount=10000.0, previous_balance=0, current_balance=78.0, note='credit ledger item', ) LedgerAccountFactory.create( account_id=1, contract_id=2, abacus_event_id=2, currency_code='USD', currency_amount=67614.28, previous_balance=0, current_balance=67614.28, note='credit ledger item', ) LedgerAccountFactory.create( account_id=1, contract_id=3, abacus_event_id=2, currency_code='USD', currency_amount=100, previous_balance=67614.28, current_balance=67714.28, note='credit ledger item', ) account_ledgers = LedgerAccount.get_accounts_by_acc_period_id(2, 0, 1) ledger_account_count = LedgerAccount.get_total_accounts_count_by_acc_period_id(1) assert len(account_ledgers) == 2 assert ledger_account_count == 3 data = LedgerAccountSchema().dump(account_ledgers, many=True) assert data[0]['abacus_event_id'] == 4 assert data[1]['abacus_event_id'] == 4