Changed the unmatched offsets from a module to a report, and to show both the unapplied original line items and the unmatched offsets instead of only the unmatched offsets, and added the accumulated balance, in order for ease of use. Removed the match information from the unapplied original line item report. Added the currency and period filters to both the unapplied original line item report and unmatched offset reports.
This commit is contained in:
@ -23,18 +23,19 @@ from decimal import Decimal
|
||||
from flask import render_template, Response
|
||||
|
||||
from accounting.locale import gettext
|
||||
from accounting.models import Account, JournalEntryLineItem
|
||||
from accounting.models import Currency, Account, JournalEntryLineItem
|
||||
from accounting.report.period import Period, PeriodChooser
|
||||
from accounting.report.utils.base_page_params import BasePageParams
|
||||
from accounting.report.utils.base_report import BaseReport
|
||||
from accounting.report.utils.csv_export import BaseCSVRow, csv_download
|
||||
from accounting.report.utils.csv_export import BaseCSVRow, csv_download, \
|
||||
period_spec
|
||||
from accounting.report.utils.offset_matcher import OffsetMatcher
|
||||
from accounting.report.utils.option_link import OptionLink
|
||||
from accounting.report.utils.report_chooser import ReportChooser
|
||||
from accounting.report.utils.report_type import ReportType
|
||||
from accounting.report.utils.unapplied import get_accounts_with_unapplied
|
||||
from accounting.report.utils.urls import unapplied_url
|
||||
from accounting.utils.offset_matcher import OffsetMatcher
|
||||
from accounting.utils.pagination import Pagination
|
||||
from accounting.utils.permission import can_edit
|
||||
|
||||
|
||||
class CSVRow(BaseCSVRow):
|
||||
@ -75,25 +76,32 @@ class CSVRow(BaseCSVRow):
|
||||
class PageParams(BasePageParams):
|
||||
"""The HTML page parameters."""
|
||||
|
||||
def __init__(self, account: Account,
|
||||
is_mark_matches: bool,
|
||||
def __init__(self, currency: Currency,
|
||||
account: Account,
|
||||
period: Period,
|
||||
pagination: Pagination[JournalEntryLineItem],
|
||||
line_items: list[JournalEntryLineItem]):
|
||||
"""Constructs the HTML page parameters.
|
||||
|
||||
:param currency: The currency.
|
||||
:param account: The account.
|
||||
:param is_mark_matches: Whether to mark the matched offsets.
|
||||
:param period: The period.
|
||||
:param pagination: The pagination.
|
||||
:param line_items: The line items.
|
||||
"""
|
||||
self.currency: Currency = currency
|
||||
"""The currency."""
|
||||
self.account: Account = account
|
||||
"""The account."""
|
||||
self.period: Period = period
|
||||
"""The period."""
|
||||
self.pagination: Pagination[JournalEntryLineItem] = pagination
|
||||
"""The pagination."""
|
||||
self.line_items: list[JournalEntryLineItem] = line_items
|
||||
"""The line items."""
|
||||
self.is_mark_matches: bool = is_mark_matches
|
||||
"""Whether to mark the matched offsets."""
|
||||
self.period_chooser: PeriodChooser = PeriodChooser(
|
||||
lambda x: unapplied_url(currency, account, x))
|
||||
"""The period chooser."""
|
||||
|
||||
@property
|
||||
def has_data(self) -> bool:
|
||||
@ -109,8 +117,18 @@ class PageParams(BasePageParams):
|
||||
|
||||
:return: The report chooser.
|
||||
"""
|
||||
return ReportChooser(ReportType.UNAPPLIED,
|
||||
account=self.account)
|
||||
return ReportChooser(ReportType.UNAPPLIED, currency=self.currency,
|
||||
account=self.account, period=self.period)
|
||||
|
||||
@property
|
||||
def currency_options(self) -> list[OptionLink]:
|
||||
"""Returns the currency options.
|
||||
|
||||
:return: The currency options.
|
||||
"""
|
||||
return self._get_currency_options(
|
||||
lambda x: unapplied_url(x, self.account, self.period),
|
||||
self.currency)
|
||||
|
||||
@property
|
||||
def account_options(self) -> list[OptionLink]:
|
||||
@ -118,13 +136,15 @@ class PageParams(BasePageParams):
|
||||
|
||||
:return: The account options.
|
||||
"""
|
||||
options: list[OptionLink] = [OptionLink(gettext("Accounts"),
|
||||
unapplied_url(None),
|
||||
False)]
|
||||
options.extend([OptionLink(str(x),
|
||||
unapplied_url(x),
|
||||
x.id == self.account.id)
|
||||
for x in get_accounts_with_unapplied()])
|
||||
options: list[OptionLink] \
|
||||
= [OptionLink(gettext("Accounts"),
|
||||
unapplied_url(self.currency, None, self.period),
|
||||
False)]
|
||||
options.extend(
|
||||
[OptionLink(str(x),
|
||||
unapplied_url(self.currency, x, self.period),
|
||||
x.id == self.account.id)
|
||||
for x in get_accounts_with_unapplied(self.currency, self.period)])
|
||||
return options
|
||||
|
||||
|
||||
@ -146,27 +166,33 @@ def get_csv_rows(line_items: list[JournalEntryLineItem]) -> list[CSVRow]:
|
||||
class UnappliedOriginalLineItems(BaseReport):
|
||||
"""The unapplied original line items."""
|
||||
|
||||
def __init__(self, account: Account):
|
||||
def __init__(self, currency: Currency, account: Account, period: Period):
|
||||
"""Constructs the unapplied original line items.
|
||||
|
||||
:param currency: The currency.
|
||||
:param account: The account.
|
||||
:param period: The period.
|
||||
"""
|
||||
self.__currency: Currency = currency
|
||||
"""The currency."""
|
||||
self.__account: Account = account
|
||||
"""The account."""
|
||||
offset_matcher: OffsetMatcher = OffsetMatcher(self.__account)
|
||||
self.__period: Period = period
|
||||
"""The period."""
|
||||
offset_matcher: OffsetMatcher \
|
||||
= OffsetMatcher(self.__currency, self.__account, self.__period)
|
||||
self.__line_items: list[JournalEntryLineItem] \
|
||||
= offset_matcher.unapplied
|
||||
"""The line items."""
|
||||
self.__is_mark_matches: bool \
|
||||
= can_edit() and len(offset_matcher.unmatched_offsets) > 0
|
||||
"""Whether to mark the matched offsets."""
|
||||
|
||||
def csv(self) -> Response:
|
||||
"""Returns the report as CSV for download.
|
||||
|
||||
:return: The response of the report for download.
|
||||
"""
|
||||
filename: str = f"unapplied-{self.__account.code}.csv"
|
||||
filename: str = "unapplied-{currency}-{account}-{period}.csv"\
|
||||
.format(currency=self.__currency.code, account=self.__account.code,
|
||||
period=period_spec(self.__period))
|
||||
return csv_download(filename, get_csv_rows(self.__line_items))
|
||||
|
||||
def html(self) -> str:
|
||||
@ -177,8 +203,9 @@ class UnappliedOriginalLineItems(BaseReport):
|
||||
pagination: Pagination[JournalEntryLineItem] \
|
||||
= Pagination[JournalEntryLineItem](self.__line_items,
|
||||
is_reversed=True)
|
||||
params: PageParams = PageParams(account=self.__account,
|
||||
is_mark_matches=self.__is_mark_matches,
|
||||
params: PageParams = PageParams(currency=self.__currency,
|
||||
account=self.__account,
|
||||
period=self.__period,
|
||||
pagination=pagination,
|
||||
line_items=pagination.list)
|
||||
return render_template("accounting/report/unapplied.html",
|
||||
|
@ -23,7 +23,8 @@ from decimal import Decimal
|
||||
from flask import render_template, Response
|
||||
|
||||
from accounting.locale import gettext
|
||||
from accounting.models import Account
|
||||
from accounting.models import Currency, Account
|
||||
from accounting.report.period import Period, PeriodChooser
|
||||
from accounting.report.utils.base_page_params import BasePageParams
|
||||
from accounting.report.utils.base_report import BaseReport
|
||||
from accounting.report.utils.csv_export import BaseCSVRow, csv_download
|
||||
@ -60,13 +61,24 @@ class CSVRow(BaseCSVRow):
|
||||
class PageParams(BasePageParams):
|
||||
"""The HTML page parameters."""
|
||||
|
||||
def __init__(self, accounts: list[Account]):
|
||||
def __init__(self, currency: Currency,
|
||||
period: Period,
|
||||
accounts: list[Account]):
|
||||
"""Constructs the HTML page parameters.
|
||||
|
||||
:param currency: The currency.
|
||||
:param period: The period.
|
||||
:param accounts: The accounts.
|
||||
"""
|
||||
self.currency: Currency = currency
|
||||
"""The currency."""
|
||||
self.period: Period = period
|
||||
"""The period."""
|
||||
self.accounts: list[Account] = accounts
|
||||
"""The accounts."""
|
||||
self.period_chooser: PeriodChooser = PeriodChooser(
|
||||
lambda x: unapplied_url(currency, None, x))
|
||||
"""The period chooser."""
|
||||
|
||||
@property
|
||||
def has_data(self) -> bool:
|
||||
@ -82,7 +94,18 @@ class PageParams(BasePageParams):
|
||||
|
||||
:return: The report chooser.
|
||||
"""
|
||||
return ReportChooser(ReportType.UNAPPLIED)
|
||||
return ReportChooser(ReportType.UNAPPLIED, currency=self.currency,
|
||||
account=None, period=self.period)
|
||||
|
||||
@property
|
||||
def currency_options(self) -> list[OptionLink]:
|
||||
"""Returns the currency options.
|
||||
|
||||
:return: The currency options.
|
||||
"""
|
||||
return self._get_currency_options(
|
||||
lambda x: unapplied_url(x, None, self.period),
|
||||
self.currency)
|
||||
|
||||
@property
|
||||
def account_options(self) -> list[OptionLink]:
|
||||
@ -90,13 +113,15 @@ class PageParams(BasePageParams):
|
||||
|
||||
:return: The account options.
|
||||
"""
|
||||
options: list[OptionLink] = [OptionLink(gettext("Accounts"),
|
||||
unapplied_url(None),
|
||||
True)]
|
||||
options.extend([OptionLink(str(x),
|
||||
unapplied_url(x),
|
||||
False)
|
||||
for x in self.accounts])
|
||||
options: list[OptionLink] \
|
||||
= [OptionLink(gettext("Accounts"),
|
||||
unapplied_url(self.currency, None, self.period),
|
||||
True)]
|
||||
options.extend(
|
||||
[OptionLink(str(x),
|
||||
unapplied_url(self.currency, x, self.period),
|
||||
False)
|
||||
for x in self.accounts])
|
||||
return options
|
||||
|
||||
|
||||
@ -115,9 +140,18 @@ def get_csv_rows(accounts: list[Account]) -> list[CSVRow]:
|
||||
class AccountsWithUnappliedOriginalLineItems(BaseReport):
|
||||
"""The accounts with unapplied original line items."""
|
||||
|
||||
def __init__(self):
|
||||
"""Constructs the outstanding balances."""
|
||||
self.__accounts: list[Account] = get_accounts_with_unapplied()
|
||||
def __init__(self, currency: Currency, period: Period):
|
||||
"""Constructs the outstanding balances.
|
||||
|
||||
:param currency: The currency.
|
||||
:param period: The period.
|
||||
"""
|
||||
self.__currency: Currency = currency
|
||||
"""The currency."""
|
||||
self.__period: Period = period
|
||||
"""The period."""
|
||||
self.__accounts: list[Account] \
|
||||
= get_accounts_with_unapplied(currency, period)
|
||||
"""The accounts."""
|
||||
|
||||
def csv(self) -> Response:
|
||||
@ -134,4 +168,6 @@ class AccountsWithUnappliedOriginalLineItems(BaseReport):
|
||||
:return: The report as HTML.
|
||||
"""
|
||||
return render_template("accounting/report/unapplied-accounts.html",
|
||||
report=PageParams(accounts=self.__accounts))
|
||||
report=PageParams(currency=self.__currency,
|
||||
period=self.__period,
|
||||
accounts=self.__accounts))
|
||||
|
230
src/accounting/report/reports/unmatched.py
Normal file
230
src/accounting/report/reports/unmatched.py
Normal file
@ -0,0 +1,230 @@
|
||||
# The Mia! Accounting Project.
|
||||
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/4/17
|
||||
|
||||
# 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 unmatched offsets.
|
||||
|
||||
"""
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
|
||||
from flask import render_template, Response
|
||||
from flask_babel import LazyString
|
||||
|
||||
from accounting.locale import gettext
|
||||
from accounting.models import Currency, Account, JournalEntryLineItem
|
||||
from accounting.report.period import Period, PeriodChooser
|
||||
from accounting.report.utils.base_page_params import BasePageParams
|
||||
from accounting.report.utils.base_report import BaseReport
|
||||
from accounting.report.utils.csv_export import BaseCSVRow, csv_download, \
|
||||
period_spec
|
||||
from accounting.report.utils.option_link import OptionLink
|
||||
from accounting.report.utils.report_chooser import ReportChooser
|
||||
from accounting.report.utils.report_type import ReportType
|
||||
from accounting.report.utils.unmatched import get_accounts_with_unmatched
|
||||
from accounting.report.utils.urls import unmatched_url
|
||||
from accounting.report.utils.offset_matcher import OffsetMatcher, OffsetPair
|
||||
from accounting.utils.pagination import Pagination
|
||||
|
||||
|
||||
class CSVRow(BaseCSVRow):
|
||||
"""A row in the CSV."""
|
||||
|
||||
def __init__(self, journal_entry_date: str | date, currency: str,
|
||||
description: str | None, debit: str | Decimal,
|
||||
credit: str | Decimal, balance: str | Decimal):
|
||||
"""Constructs a row in the CSV.
|
||||
|
||||
:param journal_entry_date: The journal entry date.
|
||||
:param currency: The currency.
|
||||
:param description: The description.
|
||||
:param debit: The debit amount.
|
||||
:param credit: The credit amount.
|
||||
:param balance: The balance.
|
||||
"""
|
||||
self.date: str | date = journal_entry_date
|
||||
"""The date."""
|
||||
self.currency: str = currency
|
||||
"""The currency."""
|
||||
self.description: str | None = description
|
||||
"""The description."""
|
||||
self.debit: str | Decimal | None = debit
|
||||
"""The debit amount."""
|
||||
self.credit: str | Decimal | None = credit
|
||||
"""The credit amount."""
|
||||
self.balance: str | Decimal = balance
|
||||
"""The balance."""
|
||||
|
||||
@property
|
||||
def values(self) -> list[str | date | Decimal | None]:
|
||||
"""Returns the values of the row.
|
||||
|
||||
:return: The values of the row.
|
||||
"""
|
||||
return [self.date, self.currency, self.description, self.debit,
|
||||
self.credit, self.balance]
|
||||
|
||||
|
||||
class PageParams(BasePageParams):
|
||||
"""The HTML page parameters."""
|
||||
|
||||
def __init__(self, currency: Currency,
|
||||
account: Account,
|
||||
period: Period,
|
||||
match_status: str | LazyString,
|
||||
matched_pairs: list[OffsetPair],
|
||||
pagination: Pagination[JournalEntryLineItem],
|
||||
line_items: list[JournalEntryLineItem]):
|
||||
"""Constructs the HTML page parameters.
|
||||
|
||||
:param currency: The currency.
|
||||
:param account: The account.
|
||||
:param period: The period.
|
||||
:param match_status: The match status message.
|
||||
:param matched_pairs: A list of matched pairs.
|
||||
:param pagination: The pagination.
|
||||
:param line_items: The line items.
|
||||
"""
|
||||
self.currency: Currency = currency
|
||||
"""The currency."""
|
||||
self.account: Account = account
|
||||
"""The account."""
|
||||
self.period: Period = period
|
||||
"""The period."""
|
||||
self.match_status: str | LazyString = match_status
|
||||
"""The match status message."""
|
||||
self.matched_pairs: list[OffsetPair] = matched_pairs
|
||||
"""A list of matched pairs."""
|
||||
self.pagination: Pagination[JournalEntryLineItem] = pagination
|
||||
"""The pagination."""
|
||||
self.line_items: list[JournalEntryLineItem] = line_items
|
||||
"""The line items."""
|
||||
self.period_chooser: PeriodChooser = PeriodChooser(
|
||||
lambda x: unmatched_url(currency, account, x))
|
||||
"""The period chooser."""
|
||||
|
||||
@property
|
||||
def has_data(self) -> bool:
|
||||
"""Returns whether there is any data on the page.
|
||||
|
||||
:return: True if there is any data, or False otherwise.
|
||||
"""
|
||||
return len(self.line_items) > 0
|
||||
|
||||
@property
|
||||
def report_chooser(self) -> ReportChooser:
|
||||
"""Returns the report chooser.
|
||||
|
||||
:return: The report chooser.
|
||||
"""
|
||||
return ReportChooser(ReportType.UNMATCHED, currency=self.currency,
|
||||
account=self.account)
|
||||
|
||||
@property
|
||||
def currency_options(self) -> list[OptionLink]:
|
||||
"""Returns the currency options.
|
||||
|
||||
:return: The currency options.
|
||||
"""
|
||||
return self._get_currency_options(
|
||||
lambda x: unmatched_url(x, self.account, self.period),
|
||||
self.currency)
|
||||
|
||||
@property
|
||||
def account_options(self) -> list[OptionLink]:
|
||||
"""Returns the account options.
|
||||
|
||||
:return: The account options.
|
||||
"""
|
||||
options: list[OptionLink] \
|
||||
= [OptionLink(gettext("Accounts"),
|
||||
unmatched_url(self.currency, None, self.period),
|
||||
False)]
|
||||
options.extend(
|
||||
[OptionLink(str(x),
|
||||
unmatched_url(self.currency, x, self.period),
|
||||
x.id == self.account.id)
|
||||
for x in get_accounts_with_unmatched(self.currency, self.period)])
|
||||
return options
|
||||
|
||||
|
||||
def get_csv_rows(line_items: list[JournalEntryLineItem]) -> list[CSVRow]:
|
||||
"""Composes and returns the CSV rows from the line items.
|
||||
|
||||
:param line_items: The line items.
|
||||
:return: The CSV rows.
|
||||
"""
|
||||
rows: list[CSVRow] = [CSVRow(gettext("Date"), gettext("Currency"),
|
||||
gettext("Description"), gettext("Debit"),
|
||||
gettext("Credit"), gettext("Balance"))]
|
||||
rows.extend([CSVRow(x.journal_entry.date, x.currency.code,
|
||||
x.description, x.debit, x.credit, x.balance)
|
||||
for x in line_items])
|
||||
return rows
|
||||
|
||||
|
||||
class UnmatchedOffsets(BaseReport):
|
||||
"""The unmatched offsets."""
|
||||
|
||||
def __init__(self, currency: Currency, account: Account, period: Period):
|
||||
"""Constructs the unmatched offsets.
|
||||
|
||||
:param currency: The currency.
|
||||
:param account: The account.
|
||||
:param period: The period.
|
||||
"""
|
||||
self.__currency: Currency = currency
|
||||
"""The currency."""
|
||||
self.__account: Account = account
|
||||
"""The account."""
|
||||
self.__period: Period = period
|
||||
"""The period."""
|
||||
offset_matcher: OffsetMatcher \
|
||||
= OffsetMatcher(self.__currency, self.__account, self.__period)
|
||||
self.__line_items: list[JournalEntryLineItem] \
|
||||
= offset_matcher.line_items
|
||||
"""The line items."""
|
||||
self.__match_status: str | LazyString = offset_matcher.status
|
||||
"""The match status message."""
|
||||
self.__matched_pairs: list[OffsetPair] = offset_matcher.matched_pairs
|
||||
"""A list of matched pairs."""
|
||||
|
||||
def csv(self) -> Response:
|
||||
"""Returns the report as CSV for download.
|
||||
|
||||
:return: The response of the report for download.
|
||||
"""
|
||||
filename: str = "unmatched-{currency}-{account}-{period}.csv"\
|
||||
.format(currency=self.__currency.code, account=self.__account.code,
|
||||
period=period_spec(self.__period))
|
||||
return csv_download(filename, get_csv_rows(self.__line_items))
|
||||
|
||||
def html(self) -> str:
|
||||
"""Composes and returns the report as HTML.
|
||||
|
||||
:return: The report as HTML.
|
||||
"""
|
||||
pagination: Pagination[JournalEntryLineItem] \
|
||||
= Pagination[JournalEntryLineItem](self.__line_items,
|
||||
is_reversed=True)
|
||||
params: PageParams = PageParams(currency=self.__currency,
|
||||
account=self.__account,
|
||||
period=self.__period,
|
||||
match_status=self.__match_status,
|
||||
matched_pairs=self.__matched_pairs,
|
||||
pagination=pagination,
|
||||
line_items=pagination.list)
|
||||
return render_template("accounting/report/unmatched.html",
|
||||
report=params)
|
173
src/accounting/report/reports/unmatched_accounts.py
Normal file
173
src/accounting/report/reports/unmatched_accounts.py
Normal file
@ -0,0 +1,173 @@
|
||||
# The Mia! Accounting Project.
|
||||
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/4/17
|
||||
|
||||
# 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 accounts with unmatched offsets.
|
||||
|
||||
"""
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
|
||||
from flask import render_template, Response
|
||||
|
||||
from accounting.locale import gettext
|
||||
from accounting.models import Currency, Account
|
||||
from accounting.report.period import Period, PeriodChooser
|
||||
from accounting.report.utils.base_page_params import BasePageParams
|
||||
from accounting.report.utils.base_report import BaseReport
|
||||
from accounting.report.utils.csv_export import BaseCSVRow, csv_download
|
||||
from accounting.report.utils.option_link import OptionLink
|
||||
from accounting.report.utils.report_chooser import ReportChooser
|
||||
from accounting.report.utils.report_type import ReportType
|
||||
from accounting.report.utils.unmatched import get_accounts_with_unmatched
|
||||
from accounting.report.utils.urls import unmatched_url
|
||||
|
||||
|
||||
class CSVRow(BaseCSVRow):
|
||||
"""A row in the CSV."""
|
||||
|
||||
def __init__(self, account: str, count: int | str):
|
||||
"""Constructs a row in the CSV.
|
||||
|
||||
:param account: The account.
|
||||
:param count: The number of unapplied original line items.
|
||||
"""
|
||||
self.account: str = account
|
||||
"""The currency."""
|
||||
self.count: int | str = count
|
||||
"""The number of unapplied original line items."""
|
||||
|
||||
@property
|
||||
def values(self) -> list[str | date | Decimal | None]:
|
||||
"""Returns the values of the row.
|
||||
|
||||
:return: The values of the row.
|
||||
"""
|
||||
return [self.account, self.count]
|
||||
|
||||
|
||||
class PageParams(BasePageParams):
|
||||
"""The HTML page parameters."""
|
||||
|
||||
def __init__(self, currency: Currency,
|
||||
period: Period,
|
||||
accounts: list[Account]):
|
||||
"""Constructs the HTML page parameters.
|
||||
|
||||
:param currency: The currency.
|
||||
:param period: The period.
|
||||
:param accounts: The accounts.
|
||||
"""
|
||||
self.currency: Currency = currency
|
||||
"""The currency."""
|
||||
self.period: Period = period
|
||||
"""The period."""
|
||||
self.accounts: list[Account] = accounts
|
||||
"""The accounts."""
|
||||
self.period_chooser: PeriodChooser = PeriodChooser(
|
||||
lambda x: unmatched_url(currency, None, x))
|
||||
"""The period chooser."""
|
||||
|
||||
@property
|
||||
def has_data(self) -> bool:
|
||||
"""Returns whether there is any data on the page.
|
||||
|
||||
:return: True if there is any data, or False otherwise.
|
||||
"""
|
||||
return len(self.accounts) > 0
|
||||
|
||||
@property
|
||||
def report_chooser(self) -> ReportChooser:
|
||||
"""Returns the report chooser.
|
||||
|
||||
:return: The report chooser.
|
||||
"""
|
||||
return ReportChooser(ReportType.UNMATCHED, currency=self.currency,
|
||||
account=None, period=self.period)
|
||||
|
||||
@property
|
||||
def currency_options(self) -> list[OptionLink]:
|
||||
"""Returns the currency options.
|
||||
|
||||
:return: The currency options.
|
||||
"""
|
||||
return self._get_currency_options(
|
||||
lambda x: unmatched_url(x, None, self.period),
|
||||
self.currency)
|
||||
|
||||
@property
|
||||
def account_options(self) -> list[OptionLink]:
|
||||
"""Returns the account options.
|
||||
|
||||
:return: The account options.
|
||||
"""
|
||||
options: list[OptionLink] \
|
||||
= [OptionLink(gettext("Accounts"),
|
||||
unmatched_url(self.currency, None, self.period),
|
||||
True)]
|
||||
options.extend(
|
||||
[OptionLink(str(x),
|
||||
unmatched_url(self.currency, x, self.period),
|
||||
False)
|
||||
for x in self.accounts])
|
||||
return options
|
||||
|
||||
|
||||
def get_csv_rows(accounts: list[Account]) -> list[CSVRow]:
|
||||
"""Composes and returns the CSV rows from the line items.
|
||||
|
||||
:param accounts: The accounts.
|
||||
:return: The CSV rows.
|
||||
"""
|
||||
rows: list[CSVRow] = [CSVRow(gettext("Account"), gettext("Count"))]
|
||||
rows.extend([CSVRow(str(x).title(), x.count)
|
||||
for x in accounts])
|
||||
return rows
|
||||
|
||||
|
||||
class AccountsWithUnmatchedOffsets(BaseReport):
|
||||
"""The accounts with unmatched offsets."""
|
||||
|
||||
def __init__(self, currency: Currency, period: Period):
|
||||
"""Constructs the outstanding balances.
|
||||
|
||||
:param currency: The currency.
|
||||
:param period: The period.
|
||||
"""
|
||||
self.__currency: Currency = currency
|
||||
"""The currency."""
|
||||
self.__period: Period = period
|
||||
"""The period."""
|
||||
self.__accounts: list[Account] \
|
||||
= get_accounts_with_unmatched(currency, period)
|
||||
"""The accounts."""
|
||||
|
||||
def csv(self) -> Response:
|
||||
"""Returns the report as CSV for download.
|
||||
|
||||
:return: The response of the report for download.
|
||||
"""
|
||||
filename: str = f"unapplied-accounts.csv"
|
||||
return csv_download(filename, get_csv_rows(self.__accounts))
|
||||
|
||||
def html(self) -> str:
|
||||
"""Composes and returns the report as HTML.
|
||||
|
||||
:return: The report as HTML.
|
||||
"""
|
||||
return render_template("accounting/report/unmatched-accounts.html",
|
||||
report=PageParams(currency=self.__currency,
|
||||
period=self.__period,
|
||||
accounts=self.__accounts))
|
Reference in New Issue
Block a user