Files
brewman/brewman/routers/reports/profit_loss.py
T
2020-05-31 14:41:11 +05:30

144 lines
4.4 KiB
Python

from datetime import datetime, date
from fastapi import APIRouter, Depends, Security, Request
from sqlalchemy.orm import Session
from sqlalchemy.sql.expression import func, desc
from ...schemas.auth import UserToken
from ...core.security import get_current_active_user as get_user
from ...db.session import SessionLocal
from brewman.models.master import AccountType, AccountBase
from brewman.models.voucher import Voucher, Journal, VoucherType
from brewman.routers.reports.closing_stock import get_opening_stock, get_closing_stock
import brewman.schemas.reports as schemas
from ...core.session import (
set_period,
get_start_date,
get_finish_date,
)
router = APIRouter()
# Dependency
def get_db() -> Session:
try:
db = SessionLocal()
yield db
finally:
db.close()
@router.get("", response_model=schemas.ProfitLoss)
def report_blank(
request: Request, user: UserToken = Security(get_user, scopes=["profit-&-loss"]),
):
return {
"startDate": get_start_date(request.session),
"finishDate": get_finish_date(request.session),
"body": [],
"footer": None,
}
@router.get("/{start}/{finish}", response_model=schemas.ProfitLoss)
def report_data(
start: str,
finish: str,
request: Request,
db: Session = Depends(get_db),
user: UserToken = Security(get_user, scopes=["profit-&-loss"]),
):
body, footer = build_profit_loss(datetime.strptime(start, "%d-%b-%Y"), datetime.strptime(finish, "%d-%b-%Y"), db)
set_period(start, finish, request.session)
return {
"startDate": start,
"finishDate": finish,
"body": body,
"footer": footer,
}
def build_profit_loss(start_date: date, finish_date: date, db: Session):
profit_type_list = [i.id for i in AccountType.list() if i.balance_sheet == False]
report = []
groups = {}
amount_sum = func.sum(Journal.amount * Journal.debit)
query = (
db.query(AccountBase, amount_sum)
.join(Journal.voucher)
.join(Journal.account)
.filter(Voucher.date >= start_date)
.filter(Voucher.date <= finish_date)
.filter(Voucher.type != VoucherType.by_name("Issue").id)
.filter(AccountBase.type.in_(profit_type_list))
.group_by(AccountBase)
.order_by(AccountBase.type)
.order_by(desc(func.abs(amount_sum)))
.all()
)
# Get opening / closing stock
opening_stock = get_opening_stock(start_date, db)
closing_stock = get_closing_stock(finish_date, db)
total_amount = (opening_stock - closing_stock) * -1
report.append({"name": "Opening Stock", "amount": opening_stock * -1, "order": 200001})
report.append({"name": "Closing Stock", "amount": closing_stock, "order": 290000})
purchase_group = AccountType.by_id(2)
groups[purchase_group.id] = {
"group": purchase_group.name,
"total": total_amount,
"order": purchase_group.order,
}
counter = 0
for account, amount in query:
# Add Items
amount *= -1
account_type = AccountType.by_id(account.type)
total_amount += amount
if amount != 0:
counter += 10
report.append(
{"name": account.name, "amount": amount, "order": account_type.order + counter,}
)
if account_type.id in groups:
groups[account_type.id]["total"] += amount
else:
groups[account_type.id] = {
"group": account_type.name,
"total": amount,
"order": account_type.order,
}
# Add Subtotals
for item in groups.values():
report.append(item)
# Add Net
footer = {
"group": "Net Profit" if total_amount > 0 else "Net Loss",
"total": total_amount,
"order": 1000000,
}
return sorted(report, key=lambda d: d["order"]), footer
def get_accumulated_profit(finish_date, db):
type_list = [i.id for i in AccountType.list() if i.balance_sheet is False]
accumulated_profit = (
db.query(func.sum(Journal.amount * Journal.debit))
.join(Journal.voucher)
.join(Journal.account)
.filter(Voucher.date <= finish_date)
.filter(Voucher.type != VoucherType.by_name("Issue").id)
.filter(AccountBase.type.in_(type_list))
.scalar()
)
return 0 if accumulated_profit is None else accumulated_profit