brewman/brewman/brewman/models/account_base.py

141 lines
4.9 KiB
Python

import uuid
from typing import TYPE_CHECKING, List, Optional, Tuple
from sqlalchemy import Boolean, Column, ForeignKey, Integer, Unicode, func, select
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, Session, relationship
from ..schemas.account import AccountLink
from .account_type import AccountType
from .meta import Base
if TYPE_CHECKING:
# if the target of the relationship is in another module
# that cannot normally be imported at runtime
from .cost_centre import CostCentre
from .journal import Journal
from .product import Product
from .rate_contract import RateContract
class AccountBase(Base):
__tablename__ = "accounts"
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
code: int = Column("code", Integer, nullable=False)
name: str = Column("name", Unicode(255), unique=True, nullable=False)
type_id: int = Column("type", Integer, ForeignKey("account_types.id"), nullable=False)
account_type: str = Column("account_type", Unicode(50), nullable=False)
is_starred: bool = Column("is_starred", Boolean, nullable=False)
is_active: bool = Column("is_active", Boolean, nullable=False)
is_reconcilable: bool = Column("is_reconcilable", Boolean, nullable=False)
cost_centre_id: uuid.UUID = Column(
"cost_centre_id",
UUID(as_uuid=True),
ForeignKey("cost_centres.id"),
nullable=False,
)
is_fixture: bool = Column("is_fixture", Boolean, nullable=False)
__mapper_args__ = {"polymorphic_on": account_type}
type_: AccountType = relationship("AccountType")
journals: List["Journal"] = relationship("Journal", back_populates="account")
cost_centre: Mapped["CostCentre"] = relationship("CostCentre", back_populates="accounts")
products: List["Product"] = relationship("Product", back_populates="account")
rate_contracts: List["RateContract"] = relationship("RateContract", back_populates="vendor")
@property
def __name__(self) -> str:
return self.name
def __init__(
self,
code: int,
name: str,
type_id: int,
is_starred: bool,
is_active: bool,
is_reconcilable: bool,
cost_centre_id: uuid.UUID,
id_: Optional[uuid.UUID] = None,
is_fixture: bool = False,
) -> None:
self.code = code
self.name = name
self.type_id = type_id
self.is_starred = is_starred
self.is_active = is_active
self.is_reconcilable = is_reconcilable
self.cost_centre_id = cost_centre_id
if id_ is not None:
self.id = id_
self.is_fixture = is_fixture
def create(self, db: Session) -> "AccountBase":
self.code = db.execute(
select(func.coalesce(func.max(AccountBase.code), 0) + 1).where(AccountBase.type_id == self.type_id)
).scalar_one()
db.add(self)
return self
def can_delete(self, advanced_delete: bool) -> Tuple[bool, str]:
if self.is_fixture:
return False, f"{self.name} is a fixture and cannot be edited or deleted."
if self.is_active:
return False, "Account is active"
if len(self.journals) > 0 and not advanced_delete:
return False, "Account has journal entries"
return True, ""
@classmethod
def get_code(cls, type_: int, db: Session) -> int:
code: int = db.execute(
select(func.coalesce(func.max(AccountBase.code), 0) + 1).where(AccountBase.type_id == type_)
).scalar_one()
return code
@classmethod
def all_purchases(cls) -> uuid.UUID:
return uuid.UUID("240dd899-c413-854c-a7eb-67a29d154490")
@classmethod
def cash_in_hand(cls) -> AccountLink:
return AccountLink(id=uuid.UUID("ed2341bb-80b8-9649-90db-f9aaca183bb3"), name="Cash in Hand")
@classmethod
def local_purchase(cls) -> AccountLink:
return AccountLink(id=uuid.UUID("d2b75912-505f-2548-9093-466dfff6a0f9"), name="Local Purchase")
@classmethod
def salary(cls) -> AccountLink:
return AccountLink(id=uuid.UUID("5c2b54d0-c174-004d-a0d5-92cdaadcefa7"), name="Staff Salary")
@classmethod
def salary_id(cls) -> uuid.UUID:
return uuid.UUID("5c2b54d0-c174-004d-a0d5-92cdaadcefa7")
@classmethod
def incentive(cls) -> AccountLink:
return AccountLink(id=uuid.UUID("b7eff754-e8ba-e047-ab06-9132c15c7640"), name="Incentives")
@classmethod
def incentive_id(cls) -> uuid.UUID:
return uuid.UUID("b7eff754-e8ba-e047-ab06-9132c15c7640")
@classmethod
def esi_pf_expense(cls) -> uuid.UUID:
return uuid.UUID("d2a1a286-e900-764b-a1a5-9f4b00dbb940")
@classmethod
def esi_pf_payable(cls) -> uuid.UUID:
return uuid.UUID("42277912-cc18-854b-b134-9f4b00dba419")
@classmethod
def suspense(cls) -> uuid.UUID:
return uuid.UUID("3854e317-6f3b-5142-ab26-9c44d4cddd08")