summary history files

web/penny/resources/reports/profitloss.py
from flask import current_app as app, g
from penny import models
from penny.common.util import merge_dicts


class ReportsProfitLoss:
    def __init__(self, **kwargs):
        self.entity = kwargs.get("entity")
        self.bankaccount = kwargs.get("bankaccount")
        self.title = "Profit Loss"
        self.start_date = kwargs.get("start_date")
        self.end_date = kwargs.get("end_date")
        self.order_by = kwargs.get("order_by", "account")

    def generate(self):

        txs = None

        self.transactions = ProfitLossTransactions()

        app.logger.info(
            "Generating report; bankaccount={0.bankaccount}, "
            "entity={0.entity}, order_by={0.order_by}, "
            "start_date={0.start_date}, end_date={0.end_date}".format(self)
        )

        if self.entity:
            txs = (
                models.db.session.query(models.Transaction)
                .join(
                    models.Account, models.Transaction.account_id == models.Account.id
                )
                .join(models.Entity, models.Account.entity_id == models.Entity.id)
                .filter(
                    models.Account.entity == self.entity,
                    models.Transaction.is_deleted == 0,
                    models.Transaction.user == g.user,
                )
            )
        elif self.bankaccount:
            txs = (
                models.db.session.query(models.Transaction)
                .join(
                    models.Account, models.Transaction.account_id == models.Account.id
                )
                .join(models.Entity, models.Account.entity_id == models.Entity.id)
                .filter(
                    models.Transaction.bankaccount == self.bankaccount,
                    models.Transaction.is_deleted == 0,
                )
            )

        # If not transactions are found, provide empty report.
        if not txs:
            return {}

        # If order_by is invalid, provide empty report.
        if self.order_by not in ["account", "entity", "bankaccount", "amount"]:
            return {}

        if self.start_date:
            txs = txs.filter(models.Transaction.date >= self.start_date)

        if self.end_date:
            txs = txs.filter(models.Transaction.date <= self.end_date)

        txs = txs.all()

        income_account = (
            models.db.session.query(models.AccountType)
            .filter(
                models.AccountType.name == "Revenue", models.AccountType.parent == None
            )
            .one()
        )  # noqa[E711]

        expense_account = (
            models.db.session.query(models.AccountType)
            .filter(
                models.AccountType.name == "Expenses", models.AccountType.parent == None
            )
            .one()
        )  # noqa[E711]

        for tx in txs:
            amount = tx.credit + tx.debit
            account = tx.account
            bankaccount = tx.bankaccount
            accounttype = account.accounttype
            entity = account.entity

            account_info = {"account_name": account.name, "amount": amount}
            bankaccount_info = {
                "bankaccount_id": bankaccount.id,
                "bankaccount_bank": bankaccount.bank,
                "bankaccount_number": bankaccount.number,
            }
            entity_info = {"entity_id": entity.id, "entity_name": entity.name}

            if accounttype.parent == income_account:
                if account.id not in self.transactions.income:
                    self.transactions.income[account.id] = merge_dicts(
                        account_info, bankaccount_info, entity_info
                    )
                else:
                    self.transactions.income[account.id]["amount"] += amount
                self.transactions.income_total_amount += amount
            elif accounttype.parent == expense_account:
                if account.id not in self.transactions.expenses:
                    self.transactions.expenses[account.id] = merge_dicts(
                        account_info, bankaccount_info, entity_info
                    )
                else:
                    self.transactions.expenses[account.id]["amount"] += amount
                self.transactions.expenses_total_amount += amount
        return {
            "name": self.title,
            "start_date": self.start_date,
            "end_date": self.end_date,
            "transactions": self.transactions.__dict__,
        }


class ProfitLossTransactions:
    def __init__(self):
        self.income = {}
        self.income_total_amount = 0
        self.expenses = {}
        self.expenses_total_amount = 0