Source code for pyluca.aging

import json
import re
from datetime import datetime
from typing import NamedTuple, List, Optional, Tuple
from pyluca.account_config import BalanceType
from pyluca.journal import JournalEntry
from pyluca.amount_counter import AmountCounter


[docs]class AccountAge(NamedTuple): date: datetime counter: AmountCounter meta: Optional[dict]
[docs]class AccountAging: def __init__(self, account: str, ages: List[AccountAge], excess_amount: float, last_sl_no: int): self.account = account self.ages = ages self.excess_amount = excess_amount self.last_sl_no = last_sl_no
def __pay_counters(ages: List[AccountAge], amount: float, date: datetime) -> float: if len(ages) == 0: return amount if amount == 0: return 0 rem_amount, cur_idx = amount, 0 while rem_amount > 0 and cur_idx < len(ages): _, rem_amount = ages[cur_idx].counter.pay(rem_amount, date) if ages[cur_idx].counter.is_paid(): cur_idx += 1 else: break return rem_amount
[docs]def get_account_aging( config: dict, entries: List[JournalEntry], account: str, as_of: datetime, previous_aging: AccountAging = None ) -> AccountAging: def should_entry_applied(e: JournalEntry) -> bool: return e.date <= as_of and e.account == account \ and (previous_aging is None or e.sl_no > previous_aging.last_sl_no) aging = previous_aging if aging is None: aging = AccountAging(account, [], 0, -1) if aging.account != account: raise ValueError('Invalid previous aging! account not matching') account_type = config['accounts'][account]['type'] for entry in entries: if not should_entry_applied(entry): continue account_balance_type = config['account_types'][account_type]['balance_type'] positive_amount = entry.cr_amount if account_balance_type == BalanceType.CREDIT.value else entry.dr_amount negative_amount = entry.dr_amount if account_balance_type == BalanceType.CREDIT.value else entry.cr_amount if positive_amount > 0: meta = re.match('.*##(.*)##.*', entry.narration) aging.ages.append( AccountAge( entry.date, AmountCounter(positive_amount), json.loads(meta.group(1)) if meta else None ) ) aging.excess_amount = __pay_counters(aging.ages, aging.excess_amount + negative_amount, entry.date) aging.last_sl_no = entry.sl_no return aging