Added session support, but right now it is defaulting to 2 week long session

Reports working:
 Ledger
 Balance Sheet
 Profit & Loss
 Closing Stock
This commit is contained in:
tanshu 2020-05-12 02:57:48 +05:30
parent 6dbab6442f
commit 85d05392b8
8 changed files with 181 additions and 108 deletions

@ -1,5 +1,6 @@
import uvicorn import uvicorn
from fastapi import FastAPI from fastapi import FastAPI
from starlette.middleware.sessions import SessionMiddleware
from .routers import ( from .routers import (
account, account,
@ -17,15 +18,17 @@ from .routers import (
login, login,
) )
from .routers.auth import client, user, role from .routers.auth import client, user, role
from .routers.reports import ledger, balance_sheet, profit_loss, closing_stock
from .db.base_class import Base from .db.base_class import Base
from .config import Settings as settings from .config import Settings as settings
from .db.session import SessionLocal, engine from .db.session import engine
Base.metadata.create_all(bind=engine) Base.metadata.create_all(bind=engine)
app = FastAPI() app = FastAPI()
app.add_middleware(SessionMiddleware, secret_key="c982367648")
# app.include_router(brewman.routers, prefix="/api/db-image", tags=["db-image"]) # app.include_router(brewman.routers, prefix="/api/db-image", tags=["db-image"])
app.include_router(login.router, tags=["login"]) app.include_router(login.router, tags=["login"])
app.include_router(account.router, prefix="/api/accounts", tags=["accounts"]) app.include_router(account.router, prefix="/api/accounts", tags=["accounts"])
@ -57,6 +60,10 @@ app.include_router(recipe.router, prefix="/api/recipes", tags=["products"])
app.include_router(client.router, prefix="/api/clients", tags=["clients"]) app.include_router(client.router, prefix="/api/clients", tags=["clients"])
app.include_router(role.router, prefix="/api/roles", tags=["users"]) app.include_router(role.router, prefix="/api/roles", tags=["users"])
app.include_router(user.router, prefix="/api/users", tags=["users"]) app.include_router(user.router, prefix="/api/users", tags=["users"])
app.include_router(ledger.router, prefix="/api/ledger", tags=["reports"])
app.include_router(balance_sheet.router, prefix="/api/balance-sheet", tags=["reports"])
app.include_router(profit_loss.router, prefix="/api/profit-loss", tags=["reports"])
app.include_router(closing_stock.router, prefix="/api/closing-stock", tags=["reports"])
def init(): def init():

@ -1,8 +1,13 @@
import datetime import datetime
from fastapi import APIRouter, Depends, Security, Request
from sqlalchemy.orm import Session
from sqlalchemy.sql.expression import func, desc 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.master import AccountType, AccountBase
from brewman.models.voucher import Voucher, Journal, VoucherType from brewman.models.voucher import Voucher, Journal, VoucherType
from brewman.routers.reports.closing_stock import get_closing_stock from brewman.routers.reports.closing_stock import get_closing_stock
from brewman.routers.reports.profit_loss import get_accumulated_profit from brewman.routers.reports.profit_loss import get_accumulated_profit
@ -12,33 +17,47 @@ from brewman.routers.services.session import (
session_period_finish, session_period_finish,
) )
from fastapi import APIRouter
router = APIRouter() router = APIRouter()
@router.get("/api/balance-sheet") # "Balance Sheet" # Dependency
def report_blank(request): def get_db() -> Session:
return {"date": session_period_finish(request), "body": [], "footer": []} try:
db = SessionLocal()
yield db
finally:
db.close()
@router.get("/api/balance-sheet/{date}") # "Balance Sheet" @router.get("")
def report_data(request): def report_blank(
date = request.matchdict.get("date", None) request: Request,
body, footer = build_balance_sheet(date, request.dbsession) user: UserToken = Security(get_user, scopes=["balance-sheet"]),
session_period_set(session_period_start(request), date, request) ):
return {"date": session_period_finish(request.session), "body": [], "footer": []}
@router.get("/{date}")
def report_data(
date: str,
request: Request,
db: Session = Depends(get_db),
user: UserToken = Security(get_user, scopes=["balance-sheet"]),
):
body, footer = build_balance_sheet(date, db)
session_period_set(session_period_start(request.session), date, request.session)
return {"date": date, "body": body, "footer": footer} return {"date": date, "body": body, "footer": footer}
def build_balance_sheet(finish_date, dbsession): def build_balance_sheet(finish_date, db):
if not isinstance(finish_date, datetime.datetime): if not isinstance(finish_date, datetime.datetime):
finish_date = datetime.datetime.strptime(finish_date, "%d-%b-%Y") finish_date = datetime.datetime.strptime(finish_date, "%d-%b-%Y")
type_list = [i.id for i in AccountType.list() if i.balance_sheet == True] type_list = [i.id for i in AccountType.list() if i.balance_sheet == True]
report = [] report = []
groups = dict() groups = dict()
# Add Net Profit / Loss # Add Net Profit / Loss
closing_stock = get_closing_stock(finish_date, dbsession) closing_stock = get_closing_stock(finish_date, db)
net_profit = get_accumulated_profit(finish_date, dbsession) - closing_stock net_profit = get_accumulated_profit(finish_date, db) - closing_stock
total_amount = net_profit total_amount = net_profit
report.append( report.append(
{ {
@ -69,7 +88,7 @@ def build_balance_sheet(finish_date, dbsession):
amount_sum = func.sum(Journal.amount * Journal.debit) amount_sum = func.sum(Journal.amount * Journal.debit)
query = ( query = (
dbsession.query(AccountBase, amount_sum) db.query(AccountBase, amount_sum)
.join(Journal.voucher) .join(Journal.voucher)
.join(Journal.account) .join(Journal.account)
.filter(Voucher.date <= finish_date) .filter(Voucher.date <= finish_date)

@ -1,7 +1,12 @@
import datetime import datetime
from fastapi import APIRouter, Depends, Security, Request
from sqlalchemy.orm import Session
from sqlalchemy.sql.expression import func from sqlalchemy.sql.expression import func
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 Product, CostCentre from brewman.models.master import Product, CostCentre
from brewman.models.voucher import Voucher, Journal, Inventory from brewman.models.voucher import Voucher, Journal, Inventory
from brewman.routers.services.session import ( from brewman.routers.services.session import (
@ -10,31 +15,45 @@ from brewman.routers.services.session import (
session_period_finish, session_period_finish,
) )
from fastapi import APIRouter
router = APIRouter() router = APIRouter()
@router.get("/api/closing-stock") # "Closing Stock" # Dependency
def report_blank(request): def get_db() -> Session:
return {"date": session_period_finish(request), "body": []} try:
db = SessionLocal()
yield db
finally:
db.close()
@router.get("/api/closing-stock/{date}") # "Closing Stock" @router.get("") # "Closing Stock"
def report_data(request): def report_blank(
date = request.matchdict.get("date", None) request: Request,
session_period_set(session_period_start(request), date, request) user: UserToken = Security(get_user, scopes=["closing-stock"]),
return {"date": date, "body": build_report(date, request.dbsession)} ):
return {"date": session_period_finish(request.session), "body": []}
def build_report(date, dbsession): @router.get("/{date}")
def report_data(
date: str,
request: Request,
db: Session = Depends(get_db),
user: UserToken = Security(get_user, scopes=["closing-stock"]),
):
session_period_set(session_period_start(request.session), date, request.session)
return {"date": date, "body": build_report(date, db)}
def build_report(date, db):
date = datetime.datetime.strptime(date, "%d-%b-%Y") date = datetime.datetime.strptime(date, "%d-%b-%Y")
amount_sum = func.sum( amount_sum = func.sum(
Journal.debit * Inventory.quantity * Inventory.rate * (1 + Inventory.tax) Journal.debit * Inventory.quantity * Inventory.rate * (1 + Inventory.tax)
).label("amount") ).label("amount")
quantity_sum = func.sum(Journal.debit * Inventory.quantity).label("quantity") quantity_sum = func.sum(Journal.debit * Inventory.quantity).label("quantity")
query = ( query = (
dbsession.query(Product, quantity_sum, amount_sum) db.query(Product, quantity_sum, amount_sum)
.join(Product.inventories) .join(Product.inventories)
.join(Inventory.voucher) .join(Inventory.voucher)
.join(Voucher.journals) .join(Voucher.journals)
@ -59,9 +78,9 @@ def build_report(date, dbsession):
return body return body
def get_opening_stock(start_date, dbsession): def get_opening_stock(start_date, db):
opening_stock = ( opening_stock = (
dbsession.query( db.query(
func.sum( func.sum(
Inventory.quantity Inventory.quantity
* Inventory.rate * Inventory.rate
@ -79,9 +98,9 @@ def get_opening_stock(start_date, dbsession):
return 0 if opening_stock is None else opening_stock return 0 if opening_stock is None else opening_stock
def get_closing_stock(finish_date, dbsession): def get_closing_stock(finish_date, db):
closing_stock = ( closing_stock = (
dbsession.query( db.query(
func.sum( func.sum(
Inventory.quantity Inventory.quantity
* Inventory.rate * Inventory.rate

@ -1,9 +1,13 @@
import datetime import datetime
import uuid import uuid
from sqlalchemy.orm import joinedload_all from fastapi import APIRouter, Depends, Security, Request
from sqlalchemy.orm import joinedload_all, Session
from sqlalchemy.sql.expression import func from sqlalchemy.sql.expression import func
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 AccountBase from brewman.models.master import AccountBase
from brewman.models.voucher import Voucher, Journal, VoucherType from brewman.models.voucher import Voucher, Journal, VoucherType
from brewman.routers.services.session import ( from brewman.routers.services.session import (
@ -11,34 +15,47 @@ from brewman.routers.services.session import (
session_period_start, session_period_start,
session_period_finish, session_period_finish,
) )
from brewman.routers.services.voucher import get_edit_url
from fastapi import APIRouter
router = APIRouter() router = APIRouter()
@router.get("/api/ledger") # "Ledger" # Dependency
def show_blank(request): def get_db() -> Session:
try:
db = SessionLocal()
yield db
finally:
db.close()
@router.get("")
def show_blank(
request: Request,
user: UserToken = Security(get_user, scopes=["ledger"]),
):
return { return {
"startDate": session_period_start(request), "startDate": session_period_start(request.session),
"finishDate": session_period_finish(request), "finishDate": session_period_finish(request.session),
"account": None, "account": None,
"body": [], "body": [],
} }
@router.get("/api/ledger/{id}") # "Ledger" @router.get("/{id_}")
def show_data(request): def show_data(
account = ( id_: uuid.UUID,
request.dbsession.query(AccountBase) request: Request,
.filter(AccountBase.id == uuid.UUID(request.matchdict["id"])) s: str = None,
.first() f: str = None,
) db: Session = Depends(get_db),
start_date = request.GET.get("s", session_period_start(request)) user: UserToken = Security(get_user, scopes=["ledger"]),
finish_date = request.GET.get("f", session_period_finish(request)) ):
body = build_report(account.id, start_date, finish_date, request) account = db.query(AccountBase).filter(AccountBase.id == id_).first()
session_period_set(start_date, finish_date, request)
start_date = s if s is not None else session_period_start(request.session)
finish_date = f if f is not None else session_period_finish(request.session)
body = build_report(account.id, start_date, finish_date, db)
session_period_set(start_date, finish_date, request.session)
return { return {
"startDate": start_date, "startDate": start_date,
"finishDate": finish_date, "finishDate": finish_date,
@ -47,13 +64,13 @@ def show_data(request):
} }
def build_report(account_id, start_date, finish_date, request): def build_report(account_id, start_date, finish_date, db):
body = [] body = []
opening = opening_balance(account_id, start_date, request.dbsession) opening = opening_balance(account_id, start_date, db)
body.append(opening) body.append(opening)
query = ( query = (
request.dbsession.query(Voucher) db.query(Voucher)
.options(joinedload_all(Voucher.journals, Journal.account, innerjoin=True)) .options(joinedload_all(Voucher.journals, Journal.account, innerjoin=True))
.filter(Voucher.journals.any(Journal.account_id == account_id)) .filter(Voucher.journals.any(Journal.account_id == account_id))
.filter(Voucher.date >= datetime.datetime.strptime(start_date, "%d-%b-%Y")) .filter(Voucher.date >= datetime.datetime.strptime(start_date, "%d-%b-%Y"))
@ -87,7 +104,7 @@ def build_report(account_id, start_date, finish_date, request):
"id": voucher.id, "id": voucher.id,
"date": voucher.date.strftime("%d-%b-%Y"), "date": voucher.date.strftime("%d-%b-%Y"),
"name": name, "name": name,
"url": get_edit_url(voucher, request), "url": "", # get_edit_url(voucher, request),
"type": VoucherType.by_id(voucher.type).name, "type": VoucherType.by_id(voucher.type).name,
"narration": voucher.narration, "narration": voucher.narration,
"debit": debit, "debit": debit,
@ -98,9 +115,9 @@ def build_report(account_id, start_date, finish_date, request):
return body return body
def opening_balance(account_id, start_date, dbsession): def opening_balance(account_id, start_date, db):
opening = ( opening = (
dbsession.query(func.sum(Journal.amount * Journal.debit)) db.query(func.sum(Journal.amount * Journal.debit))
.join(Journal.voucher) .join(Journal.voucher)
.filter(Voucher.date < datetime.datetime.strptime(start_date, "%d-%b-%Y")) .filter(Voucher.date < datetime.datetime.strptime(start_date, "%d-%b-%Y"))
.filter(Voucher.type != VoucherType.by_name("Issue").id) .filter(Voucher.type != VoucherType.by_name("Issue").id)

@ -1,7 +1,13 @@
import datetime import datetime
from fastapi import APIRouter, Depends, Security, Request
from sqlalchemy.orm import Session
from sqlalchemy.sql.expression import func, desc 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.master import AccountType, AccountBase
from brewman.models.voucher import Voucher, Journal, VoucherType from brewman.models.voucher import Voucher, Journal, VoucherType
from brewman.routers.reports.closing_stock import get_opening_stock, get_closing_stock from brewman.routers.reports.closing_stock import get_opening_stock, get_closing_stock
@ -11,36 +17,50 @@ from brewman.routers.services.session import (
session_period_finish, session_period_finish,
) )
from fastapi import APIRouter
router = APIRouter() router = APIRouter()
@router.get("/api/profit-loss", permission="Profit & Loss") # Dependency
def report_blank(request): def get_db() -> Session:
try:
db = SessionLocal()
yield db
finally:
db.close()
@router.get("")
def report_blank(
request: Request,
user: UserToken = Security(get_user, scopes=["profit-&-loss"]),
):
return { return {
"startDate": session_period_start(request), "startDate": session_period_start(request.session),
"finishDate": session_period_finish(request), "finishDate": session_period_finish(request.session),
"body": [], "body": [],
"footer": {}, "footer": {},
} }
@router.get("/api/profit-loss", request_param=["s", "f"], permission="Profit & Loss") @router.get("/{start}/{finish}")
def report_data(request): def report_data(
start_date = request.GET["s"] start: str,
finish_date = request.GET["f"] finish: str,
body, footer = build_profit_loss(start_date, finish_date, request.dbsession) request: Request,
session_period_set(start_date, finish_date, request) db: Session = Depends(get_db),
user: UserToken = Security(get_user, scopes=["profit-&-loss"]),
):
body, footer = build_profit_loss(start, finish, db)
session_period_set(start, finish, request.session)
return { return {
"startDate": start_date, "startDate": start,
"finishDate": finish_date, "finishDate": finish,
"body": body, "body": body,
"footer": footer, "footer": footer,
} }
def build_profit_loss(start_date, finish_date, dbsession): def build_profit_loss(start_date, finish_date, db):
start_date = datetime.datetime.strptime(start_date, "%d-%b-%Y") start_date = datetime.datetime.strptime(start_date, "%d-%b-%Y")
finish_date = datetime.datetime.strptime(finish_date, "%d-%b-%Y") finish_date = datetime.datetime.strptime(finish_date, "%d-%b-%Y")
profit_type_list = [i.id for i in AccountType.list() if i.balance_sheet == False] profit_type_list = [i.id for i in AccountType.list() if i.balance_sheet == False]
@ -49,7 +69,7 @@ def build_profit_loss(start_date, finish_date, dbsession):
amount_sum = func.sum(Journal.amount * Journal.debit) amount_sum = func.sum(Journal.amount * Journal.debit)
query = ( query = (
dbsession.query(AccountBase, amount_sum) db.query(AccountBase, amount_sum)
.join(Journal.voucher) .join(Journal.voucher)
.join(Journal.account) .join(Journal.account)
.filter(Voucher.date >= start_date) .filter(Voucher.date >= start_date)
@ -63,8 +83,8 @@ def build_profit_loss(start_date, finish_date, dbsession):
) )
# Get opening / closing stock # Get opening / closing stock
opening_stock = get_opening_stock(start_date, dbsession) opening_stock = get_opening_stock(start_date, db)
closing_stock = get_closing_stock(finish_date, dbsession) closing_stock = get_closing_stock(finish_date, db)
total_amount = (opening_stock - closing_stock) * -1 total_amount = (opening_stock - closing_stock) * -1
report.append( report.append(
@ -117,11 +137,11 @@ def build_profit_loss(start_date, finish_date, dbsession):
return sorted(report, key=lambda d: d["order"]), footer return sorted(report, key=lambda d: d["order"]), footer
def get_accumulated_profit(finish_date, dbsession): def get_accumulated_profit(finish_date, db):
type_list = [i.id for i in AccountType.list() if i.balance_sheet is False] type_list = [i.id for i in AccountType.list() if i.balance_sheet is False]
accumulated_profit = ( accumulated_profit = (
dbsession.query(func.sum(Journal.amount * Journal.debit)) db.query(func.sum(Journal.amount * Journal.debit))
.join(Journal.voucher) .join(Journal.voucher)
.join(Journal.account) .join(Journal.account)
.filter(Voucher.date <= finish_date) .filter(Voucher.date <= finish_date)

@ -1,39 +1,34 @@
from datetime import date, timedelta from datetime import date, timedelta
def session_current_date(request): def session_current_date(session):
session = request.session if "date" not in session:
if "currentDate" not in session: session["date"] = date.today().strftime("%d-%b-%Y")
session["currentDate"] = date.today().strftime("%d-%b-%Y") return session["date"]
return session["currentDate"]
def session_current_date_set(request, date_): def session_current_date_set(session, date_):
session = request.session session["date"] = date_
session["currentDate"] = date_ return session["date"]
return session["currentDate"]
def session_period_start(request): def session_period_start(session):
session = request.session if "start" not in session:
if "periodStart" not in session: session["start"] = get_first_day(date.today()).strftime("%d-%b-%Y")
session["periodStart"] = get_first_day(date.today()).strftime("%d-%b-%Y") return session["start"]
return session["periodStart"]
def session_period_finish(request): def session_period_finish(session):
session = request.session if "finish" not in session:
if "periodFinish" not in session: session["finish"] = get_last_day(date.today()).strftime("%d-%b-%Y")
session["periodFinish"] = get_last_day(date.today()).strftime("%d-%b-%Y") return session["finish"]
return session["periodFinish"]
def session_period_set(start, finish, request): def session_period_set(start, finish, session):
session = request.session session["start"] = (
session["periodStart"] = (
start if isinstance(start, str) else start.strftime("%d-%b-%Y") start if isinstance(start, str) else start.strftime("%d-%b-%Y")
) )
session["periodFinish"] = ( session["finish"] = (
finish if isinstance(finish, str) else finish.strftime("%d-%b-%Y") finish if isinstance(finish, str) else finish.strftime("%d-%b-%Y")
) )

@ -21,14 +21,9 @@ export class ProfitLossService {
} }
list(startDate: string, finishDate): Observable<ProfitLoss> { list(startDate: string, finishDate): Observable<ProfitLoss> {
const options = {params: new HttpParams()}; startDate = startDate ? `/${startDate}` : '';
if (startDate !== null) { finishDate = finishDate ? `/${finishDate}` : '';
options.params = options.params.set('s', startDate); return <Observable<ProfitLoss>>this.http.get<ProfitLoss>(`${url}${startDate}${finishDate}`)
}
if (finishDate !== null) {
options.params = options.params.set('f', finishDate);
}
return <Observable<ProfitLoss>>this.http.get<ProfitLoss>(url, options)
.pipe( .pipe(
catchError(this.log.handleError(serviceName, 'list')) catchError(this.log.handleError(serviceName, 'list'))
); );

@ -8,3 +8,4 @@ psycopg2
python-multipart python-multipart
pyjwt pyjwt
alembic alembic
itsdangerous