Balance sheet
 Ledger
 Cash Flow

along with urls
Balance sheet schema does not enforce multiple_of for amounts as multiple_of borks on random figures
This commit is contained in:
tanshu
2020-05-14 11:26:28 +05:30
parent 708a60baf7
commit a4b9fb7408
15 changed files with 120 additions and 138 deletions

View File

@ -268,7 +268,7 @@ class AccountBase(Base):
__mapper_args__ = {"polymorphic_on": account_type}
journals = relationship("Journal", backref="account")
journals = relationship("Journal", back_populates="account")
@property
def __name__(self):

View File

@ -80,12 +80,7 @@ class Voucher(Base):
"User", primaryjoin="User.id==Voucher.poster_id", cascade=None
)
journals = relationship(
"Journal",
backref="voucher",
cascade="delete, delete-orphan",
cascade_backrefs=False,
)
journals = relationship("Journal", back_populates="voucher", cascade="delete, delete-orphan", cascade_backrefs=False,)
inventories = relationship(
"Inventory",
backref="voucher",
@ -167,6 +162,9 @@ class Journal(Base):
account_id = Column("account_id", GUID(), ForeignKey("accounts.id"), nullable=False)
cost_centre_id = Column("cost_centre_id", GUID(), ForeignKey("cost_centres.id"), nullable=False)
voucher = relationship("Voucher", back_populates="journals")
account = relationship("AccountBase", back_populates="journals")
@hybrid_property
def signed_amount(self):
return self.debit * self.amount

View File

@ -1,4 +1,4 @@
import datetime
from datetime import datetime, date
from fastapi import APIRouter, Depends, Security, Request
from sqlalchemy.orm import Session
@ -11,6 +11,7 @@ from brewman.models.master import AccountType, AccountBase
from brewman.models.voucher import Voucher, Journal, VoucherType
from brewman.routers.reports.closing_stock import get_closing_stock
from brewman.routers.reports.profit_loss import get_accumulated_profit
import brewman.schemas.reports as schemas
from ...core.session import (
set_period,
get_start_date,
@ -29,60 +30,58 @@ def get_db() -> Session:
db.close()
@router.get("")
@router.get("", response_model=schemas.BalanceSheet)
def report_blank(
request: Request,
user: UserToken = Security(get_user, scopes=["balance-sheet"]),
):
return {"date": get_finish_date(request.session), "body": [], "footer": []}
return {"date": get_finish_date(request.session), "body": [], "footer": None}
@router.get("/{date}")
@router.get("/{date_}", response_model=schemas.BalanceSheet)
def report_data(
date: str,
date_: str,
request: Request,
db: Session = Depends(get_db),
user: UserToken = Security(get_user, scopes=["balance-sheet"]),
):
body, footer = build_balance_sheet(date, db)
set_period(get_start_date(request.session), date, request.session)
return {"date": date, "body": body, "footer": footer}
body, footer = build_balance_sheet(datetime.strptime(date_, "%d-%b-%Y"), db)
set_period(get_start_date(request.session), date_, request.session)
return {"date": date_, "body": body, "footer": footer}
def build_balance_sheet(finish_date, db):
if not isinstance(finish_date, datetime.datetime):
finish_date = datetime.datetime.strptime(finish_date, "%d-%b-%Y")
type_list = [i.id for i in AccountType.list() if i.balance_sheet == True]
def build_balance_sheet(date_: date, db: Session):
type_list = [i.id for i in AccountType.list() if i.balance_sheet]
report = []
groups = dict()
# Add Net Profit / Loss
closing_stock = get_closing_stock(finish_date, db)
net_profit = get_accumulated_profit(finish_date, db) - closing_stock
closing_stock = round(get_closing_stock(date_, db), 2)
net_profit = round(get_accumulated_profit(date_, db), 2) - closing_stock
total_amount = net_profit
report.append(
{
"name": "Net Loss" if net_profit >= 0 else "Net Profit",
"subAmount": net_profit,
"order": 79,
"subAmount": round(net_profit, 2),
"order": 79000,
}
)
capital_group = AccountType.by_id(5)
groups[capital_group.id] = {
"group": capital_group.name,
"amount": total_amount,
"amount": round(total_amount, 2),
"order": capital_group.order,
}
total_amount += closing_stock
report.append(
{"name": "Closing Stock", "subAmount": closing_stock, "order": 20.001}
{"name": "Closing Stock", "subAmount": round(closing_stock, 2), "order": 20001}
)
asset_group = AccountType.by_id(4)
groups[asset_group.id] = {
"group": asset_group.name,
"amount": closing_stock,
"amount": round(closing_stock, 2),
"order": asset_group.order,
}
@ -91,7 +90,7 @@ def build_balance_sheet(finish_date, db):
db.query(AccountBase, amount_sum)
.join(Journal.voucher)
.join(Journal.account)
.filter(Voucher.date <= finish_date)
.filter(Voucher.date <= date_)
.filter(Voucher.type != VoucherType.by_name("Issue").id)
.filter(AccountBase.type.in_(type_list))
.group_by(AccountBase)
@ -101,27 +100,25 @@ def build_balance_sheet(finish_date, db):
)
counter = 0
sss = 0
for account, amount in query:
# Add Items
account_type = AccountType.by_id(account.type)
sss += amount
total_amount += amount
if amount != 0:
counter += 0.001
counter += 1
report.append(
{
"name": account.name,
"subAmount": amount,
"subAmount": round(amount, 2),
"order": account_type.order + counter,
}
)
if account_type.id in groups:
groups[account_type.id]["amount"] += amount
groups[account_type.id]["amount"] = round(groups[account_type.id]["amount"] + amount, 2)
else:
groups[account_type.id] = {
"group": account_type.name,
"amount": amount,
"amount": round(amount, 2),
"order": account_type.order,
}
@ -129,5 +126,5 @@ def build_balance_sheet(finish_date, db):
for item in groups.values():
report.append(item)
footer = {"name": "Total", "amount": total_amount, "order": 100}
footer = {"name": "Total", "amount": round(total_amount, 2), "order": 100000}
return sorted(report, key=lambda d: d["order"]), footer

View File

@ -10,6 +10,7 @@ from ...core.security import get_current_active_user as get_user
from ...db.session import SessionLocal
from brewman.models.master import AccountBase, AccountType
from brewman.models.voucher import Voucher, Journal, VoucherType
import brewman.schemas.reports as schemas
from ...core.session import (
set_period,
get_start_date,
@ -28,7 +29,7 @@ def get_db() -> Session:
db.close()
@router.get("")
@router.get("", response_model=schemas.CashFlow)
def report_blank(
request: Request,
user: UserToken = Security(get_user, scopes=["cash-flow"]),
@ -36,8 +37,8 @@ def report_blank(
return {
"startDate": get_start_date(request.session),
"finishDate": get_finish_date(request.session),
"body": [],
"footer": {},
"body": {"operating": [], "investing": [], "financing": [], "details": []},
"footer": None,
}
@ -112,7 +113,7 @@ def build_report(start_date, finish_date, db):
cf[lt.cash_flow_classification.lower()].append(
{
"name": lt.name,
"url": "", # request.route_url("cash_flow_id", id=str(lt.id), _query={"startDate": start_date, "finishDate": finish_date},),
"url": ['/', 'cash-flow', str(lt.id)],
"amount": amount * -1,
}
)
@ -186,7 +187,7 @@ def build_report_id(account_type, start_date, finish_date, db):
details.append(
{
"name": account.name,
"url": "", # request.route_url("ledger_id", id=account.id, _query={"startDate": start_date, "finishDate": finish_date},),
"url": ['/', 'ledger', str(account.id)],
"amount": amount * -1,
}
)

View File

@ -104,6 +104,7 @@ def build_report(account_id, start_date, finish_date, db):
"id": voucher.id,
"date": voucher.date.strftime("%d-%b-%Y"),
"name": name,
"url": ['/', VoucherType.by_id(voucher.type).name.replace(" ", "-").lower(), str(voucher.id)],
"type": VoucherType.by_id(voucher.type).name,
"narration": voucher.narration,
"debit": debit,
@ -135,6 +136,7 @@ def opening_balance(account_id, start_date, db):
"id": None,
"name": "Opening Balance",
"type": "Opening Balance",
"url": [],
"narration": "",
"debit": debit,
"credit": credit,

View File

@ -61,7 +61,6 @@ def build_report(db: Session):
"date": voucher.date.strftime("%d-%b-%Y"),
"voucherType": VoucherType.by_id(voucher.type).name,
"narration": voucher.narration,
"isPosted": voucher.posted,
"debitName": name_debit,
"debitAmount": debit,
"creditName": name_credit,

View File

@ -16,7 +16,7 @@ class LedgerItem(BaseModel):
id_: Optional[uuid.UUID]
date_: date
name: str
url: str
url: List[str]
type_: str
narration: str
debit: Decimal = Field(multiple_of=0.01)
@ -33,6 +33,9 @@ class LedgerItem(BaseModel):
class Config:
anystr_strip_whitespace = True
alias_generator = to_camel
json_encoders = {
date: lambda v: v.strftime("%d-%b-%Y")
}
class Ledger(BaseModel):
@ -63,100 +66,84 @@ class Ledger(BaseModel):
).date()
class ClientIn(BaseModel):
name: str
enabled: bool
otp: Optional[int]
class Client(ClientIn):
id_: uuid.UUID
code: int
creation_date: datetime
class LoginHistory(BaseModel):
id_: uuid.UUID
user_id: uuid.UUID
client_id: uuid.UUID
date: datetime
class BalanceSheetItem(BaseModel):
name: Optional[str]
group: Optional[str]
amount: Optional[Decimal]
sub_amount: Optional[Decimal]
order: int
class Config:
fields = {"id_": "id"}
anystr_strip_whitespace = True
alias_generator = to_camel
class PermissionItem(BaseModel):
id_: uuid.UUID
name: str
enabled: bool
class BalanceSheet(BaseModel):
date_: date
body: List[BalanceSheetItem]
footer: Optional[BalanceSheetItem]
class Config:
fields = {"id_": "id"}
class RoleIn(BaseModel):
name: str
permissions: List[PermissionItem]
class Config:
fields = {"id_": "id"}
anystr_strip_whitespace = True
alias_generator = to_camel
json_encoders = {
date: lambda v: v.strftime("%d-%b-%Y")
}
@validator("date_", pre=True)
def parse_date(cls, value):
return datetime.strptime(
value,
"%d-%b-%Y"
).date()
class Role(RoleIn):
id_: uuid.UUID
class RoleList(BaseModel):
id_: uuid.UUID
class CashFlowItem(BaseModel):
name: str
permissions: List[str]
url: Optional[List[str]]
amount: Decimal = Field(multiple_of=0.01)
class Config:
fields = {"id_": "id"}
anystr_strip_whitespace = True
class RoleItem(BaseModel):
id_: uuid.UUID
name: str
enabled: bool
class Config:
fields = {"id_": "id"}
class UserIn(BaseModel):
name: str
password: str
locked_out: bool
roles: List[RoleItem]
class Config:
fields = {"id_": "id"}
anystr_strip_whitespace = True
alias_generator = to_camel
class User(UserIn):
id_: uuid.UUID
class UserList(BaseModel):
id_: uuid.UUID
name: str
roles: List[str]
class CashFlowBody(BaseModel):
operating: List[CashFlowItem]
investing: List[CashFlowItem]
financing: List[CashFlowItem]
details: List[CashFlowItem]
class Config:
fields = {"id_": "id"}
anystr_strip_whitespace = True
alias_generator = to_camel
class CashFlow(BaseModel):
start_date: date
finish_date: date
body: CashFlowBody
footer: Optional[List[CashFlowItem]]
class Config:
anystr_strip_whitespace = True
alias_generator = to_camel
json_encoders = {
date: lambda v: v.strftime("%d-%b-%Y")
}
@validator("start_date", pre=True)
def parse_start_date(cls, value):
return datetime.strptime(
value,
"%d-%b-%Y"
).date()
@validator("finish_date", pre=True)
def parse_finish_date(cls, value):
return datetime.strptime(
value,
"%d-%b-%Y"
).date()
class UserToken(BaseModel):
id_: uuid.UUID
name: str
locked_out: bool = None
password: str
permissions: List[str]