# The Mia! Accounting Project. # Author: imacat@mail.imacat.idv.tw (imacat), 2023/4/7 # Copyright (c) 2023 imacat. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """The unapplied original line item utilities. """ import sqlalchemy as sa from accounting import db from accounting.models import Account, JournalEntryLineItem from accounting.utils.cast import be from accounting.utils.offset_alias import offset_alias def get_accounts_with_unapplied() -> list[Account]: """Returns the accounts with unapplied original line items. :return: The accounts with unapplied original line items. """ offset: sa.Alias = offset_alias() net_balance: sa.Label \ = (JournalEntryLineItem.amount + sa.func.sum(sa.case( (be(offset.c.is_debit == JournalEntryLineItem.is_debit), offset.c.amount), else_=-offset.c.amount))).label("net_balance") select_unapplied: sa.Select \ = sa.select(JournalEntryLineItem.id)\ .join(Account)\ .join(offset, be(JournalEntryLineItem.id == offset.c.original_line_item_id), isouter=True)\ .filter(Account.is_need_offset, sa.or_(sa.and_(Account.base_code.startswith("2"), sa.not_(JournalEntryLineItem.is_debit)), sa.and_(Account.base_code.startswith("1"), JournalEntryLineItem.is_debit)))\ .group_by(JournalEntryLineItem.id)\ .having(sa.or_(sa.func.count(offset.c.id) == 0, net_balance != 0)) count_func: sa.Label \ = sa.func.count(JournalEntryLineItem.id).label("count") select: sa.Select = sa.select(Account.id, count_func)\ .join(JournalEntryLineItem, isouter=True)\ .filter(JournalEntryLineItem.id.in_(select_unapplied))\ .group_by(Account.id)\ .having(count_func > 0) counts: dict[int, int] \ = {x.id: x.count for x in db.session.execute(select)} accounts: list[Account] = Account.query.filter(Account.id.in_(counts))\ .order_by(Account.base_code, Account.no).all() for account in accounts: account.count = counts[account.id] return accounts