Works:
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:
@ -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):
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
}
|
||||
)
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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]
|
||||
|
||||
Reference in New Issue
Block a user