Added type hints to the accounting application.

This commit is contained in:
2020-08-13 07:25:35 +08:00
parent 9cb6f25ee5
commit d4e7458117
8 changed files with 302 additions and 287 deletions

View File

@ -18,6 +18,9 @@
"""The data models of the accounting application.
"""
import datetime
from typing import Dict, List, Optional
from dirtyfields import DirtyFieldsMixin
from django.conf import settings
from django.db import models, transaction
@ -83,51 +86,44 @@ class Account(DirtyFieldsMixin, models.Model):
db_table = "accounting_accounts"
@property
def title(self):
def title(self) -> str:
"""The title in the current language."""
return get_multi_lingual_attr(self, "title")
@title.setter
def title(self, value):
def title(self, value: str) -> None:
set_multi_lingual_attr(self, "title", value)
@property
def option_data(self):
def option_data(self) -> Dict[str, str]:
"""The data as an option."""
return {
"code": self.code,
"title": self.title,
}
@property
def is_parent_and_in_use(self):
"""Whether this is a parent account and is in use.
Returns:
bool: True if this is a parent account and is in use, or false
otherwise
"""
def is_parent_and_in_use(self) -> bool:
"""Whether this is a parent account and is in use."""
if self._is_parent_and_in_use is None:
self._is_parent_and_in_use = self.child_set.count() > 0\
and self.record_set.count() > 0
return self._is_parent_and_in_use
@is_parent_and_in_use.setter
def is_parent_and_in_use(self, value):
def is_parent_and_in_use(self, value: bool) -> None:
self._is_parent_and_in_use = value
@property
def is_in_use(self):
"""Whether this account is in use.
Returns:
bool: True if this account is in use, or false otherwise.
"""
def is_in_use(self) -> bool:
"""Whether this account is in use."""
if self._is_in_use is None:
self._is_in_use = self.child_set.count() > 0\
or self.record_set.count() > 0
return self._is_in_use
@is_in_use.setter
def is_in_use(self, value):
def is_in_use(self, value: bool) -> None:
self._is_in_use = value
@ -157,7 +153,7 @@ class Transaction(DirtyFieldsMixin, models.Model):
transaction."""
return self.date.__str__() + " #" + self.ord.__str__()
def get_absolute_url(self):
def get_absolute_url(self) -> str:
"""Returns the URL to view this transaction."""
if self.is_cash_expense:
return reverse(
@ -169,13 +165,13 @@ class Transaction(DirtyFieldsMixin, models.Model):
return reverse(
"accounting:transactions.detail", args=("transfer", self))
def is_dirty(self, check_relationship=False, check_m2m=None):
def is_dirty(self, check_relationship=False, check_m2m=None) -> bool:
"""Returns whether the data of this transaction is changed and need
to be saved into the database.
Returns:
bool: True if the data of this transaction is changed and need
to be saved into the database, or False otherwise.
True if the data of this transaction is changed and need to be
saved into the database, or False otherwise.
"""
if super().is_dirty(check_relationship=check_relationship,
check_m2m=check_m2m):
@ -189,8 +185,9 @@ class Transaction(DirtyFieldsMixin, models.Model):
return True
return False
def save(self, current_user=None, old_date=None, force_insert=False,
force_update=False, using=None, update_fields=None):
def save(self, current_user=None, old_date: datetime.date = None,
force_insert=False, force_update=False, using=None,
update_fields=None):
# When the date is changed, the orders of the transactions in the same
# day need to be reordered
txn_to_sort = []
@ -262,7 +259,7 @@ class Transaction(DirtyFieldsMixin, models.Model):
"""The records of the transaction.
Returns:
list[Record]: The records.
List[Record]: The records.
"""
if self._records is None:
self._records = list(self.record_set.all())
@ -278,22 +275,18 @@ class Transaction(DirtyFieldsMixin, models.Model):
"""The debit records of this transaction.
Returns:
list[Record]: The records.
List[Record]: The records.
"""
return [x for x in self.records if not x.is_credit]
def debit_total(self):
def debit_total(self) -> int:
"""The total amount of the debit records."""
return sum([x.amount for x in self.debit_records
if isinstance(x.amount, int)])
@property
def debit_summaries(self):
"""The summaries of the debit records.
Returns:
list[str]: The summaries of the debit records.
"""
def debit_summaries(self) -> List[str]:
"""The summaries of the debit records."""
return [x.account.title if x.summary is None else x.summary
for x in self.debit_records]
@ -302,36 +295,28 @@ class Transaction(DirtyFieldsMixin, models.Model):
"""The credit records of this transaction.
Returns:
list[Record]: The records.
List[Record]: The records.
"""
return [x for x in self.records if x.is_credit]
def credit_total(self):
def credit_total(self) -> int:
"""The total amount of the credit records."""
return sum([x.amount for x in self.credit_records
if isinstance(x.amount, int)])
@property
def credit_summaries(self):
"""The summaries of the credit records.
Returns:
list[str]: The summaries of the credit records.
"""
def credit_summaries(self) -> List[str]:
"""The summaries of the credit records."""
return [x.account.title if x.summary is None else x.summary
for x in self.credit_records]
@property
def amount(self):
"""The amount of this transaction.
Returns:
int: The amount of this transaction.
"""
def amount(self) -> int:
"""The amount of this transaction."""
return self.debit_total()
@property
def is_balanced(self):
def is_balanced(self) -> bool:
"""Whether the sum of the amounts of the debit records is the
same as the sum of the amounts of the credit records. """
if self._is_balanced is None:
@ -341,16 +326,16 @@ class Transaction(DirtyFieldsMixin, models.Model):
return self._is_balanced
@is_balanced.setter
def is_balanced(self, value):
def is_balanced(self, value: bool) -> None:
self._is_balanced = value
def has_many_same_day(self):
def has_many_same_day(self) -> bool:
"""whether there are more than one transactions at this day,
so that the user can sort their orders. """
return Transaction.objects.filter(date=self.date).count() > 1
@property
def has_order_hole(self):
def has_order_hole(self) -> bool:
"""Whether the order of the transactions on this day is not
1, 2, 3, 4, 5..., and should be reordered. """
if self._has_order_hole is None:
@ -369,11 +354,11 @@ class Transaction(DirtyFieldsMixin, models.Model):
return self._has_order_hole
@has_order_hole.setter
def has_order_hole(self, value):
def has_order_hole(self, value: bool) -> None:
self._has_order_hole = value
@property
def is_cash_income(self):
def is_cash_income(self) -> bool:
"""Whether this transaction is a cash income transaction."""
debit_records = self.debit_records
return (len(debit_records) == 1
@ -381,7 +366,7 @@ class Transaction(DirtyFieldsMixin, models.Model):
and debit_records[0].summary is None)
@property
def is_cash_expense(self):
def is_cash_expense(self) -> bool:
"""Whether this transaction is a cash expense transaction."""
credit_records = self.credit_records
return (len(credit_records) == 1
@ -389,7 +374,7 @@ class Transaction(DirtyFieldsMixin, models.Model):
and credit_records[0].summary is None)
@property
def type(self):
def type(self) -> str:
"""The transaction type."""
if self.is_cash_expense:
return "expense"
@ -444,40 +429,40 @@ class Record(DirtyFieldsMixin, models.Model):
db_table = "accounting_records"
@property
def debit_amount(self):
def debit_amount(self) -> Optional[int]:
"""The debit amount of this accounting record."""
if self._debit_amount is None:
self._debit_amount = self.amount if not self.is_credit else None
return self._debit_amount
@debit_amount.setter
def debit_amount(self, value):
def debit_amount(self, value: Optional[int]) -> None:
self._debit_amount = value
@property
def credit_amount(self):
def credit_amount(self) -> Optional[int]:
"""The credit amount of this accounting record."""
if self._credit_amount is None:
self._credit_amount = self.amount if self.is_credit else None
return self._credit_amount
@credit_amount.setter
def credit_amount(self, value):
def credit_amount(self, value: Optional[int]):
self._credit_amount = value
@property
def is_balanced(self):
def is_balanced(self) -> bool:
"""Whether the transaction of this record is balanced. """
if self._is_balanced is None:
self._is_balanced = self.transaction.is_balanced
return self._is_balanced
@is_balanced.setter
def is_balanced(self, value):
def is_balanced(self, value: bool) -> None:
self._is_balanced = value
@property
def has_order_hole(self):
def has_order_hole(self) -> bool:
"""Whether the order of the transactions on this day is not
1, 2, 3, 4, 5..., and should be reordered. """
if self._has_order_hole is None:
@ -485,5 +470,5 @@ class Record(DirtyFieldsMixin, models.Model):
return self._has_order_hole
@has_order_hole.setter
def has_order_hole(self, value):
def has_order_hole(self, value: bool) -> None:
self._has_order_hole = value