brewman/brewman/brewman/routers/rebase.py

287 lines
9.2 KiB
Python
Raw Normal View History

2013-09-30 10:50:43 +00:00
import uuid
2020-10-07 15:18:43 +00:00
from datetime import date, datetime, timedelta
from decimal import Decimal
from typing import List
2020-10-07 15:18:43 +00:00
from fastapi import APIRouter, Depends, Security
from sqlalchemy import and_, distinct, func
from sqlalchemy.orm import Session, aliased, joinedload_all
from ..core.security import get_current_active_user as get_user
from ..db.session import SessionLocal
2020-10-07 15:18:43 +00:00
from ..models import Batch, EmployeeBenefit, Inventory, Journal, Voucher, VoucherType
from ..models.master import Account, AccountBase, CostCentre, Employee
from ..models.voucher import Attendance, DbImage, Fingerprint, Incentive
from ..schemas.auth import UserToken
router = APIRouter()
# Dependency
def get_db() -> Session:
try:
db = SessionLocal()
yield db
finally:
db.close()
2013-09-30 10:50:43 +00:00
@router.post("/{date_}")
def rebase(
2020-10-07 15:18:43 +00:00
date_: str,
db: Session = Depends(get_db),
user: UserToken = Security(get_user, scopes=["rebase"]),
):
# request.dbsession.execute('SET statement_timeout TO 300000;') # 5 minutes
date_ = datetime.strptime(date_, "%d-%b-%Y")
voucher_l = opening_accounts(date_, user.id_, db)
voucher_b = opening_batches(date_, user.id_, db)
starred_vouchers = save_starred(date_, db)
db.flush()
delete_data(date_, starred_vouchers, db)
db.add(voucher_l)
2013-09-30 10:50:43 +00:00
for j in voucher_l.journals:
db.add(j)
db.flush()
db.add(voucher_b)
2013-09-30 10:50:43 +00:00
for j in voucher_b.journals:
db.add(j)
2013-09-30 10:50:43 +00:00
for i in voucher_b.inventories:
db.add(i)
db.flush()
cleanup_lint(date_, db)
# request.dbsession.execute('RESET statement_timeout;')
db.commit()
2013-09-30 10:50:43 +00:00
return {}
def save_starred(date_: date, db: Session):
2020-10-07 16:59:24 +00:00
accounts = [
i.id
for i in db.query(AccountBase.id).filter(AccountBase.is_starred == True).all()
]
vouchers = []
query = (
db.query(Voucher)
.options(joinedload_all(Voucher.journals, Journal.account, innerjoin=True))
.filter(Voucher.date < date_)
.filter(Voucher.journals.any(Journal.account_id.in_(accounts)))
.all()
)
for voucher in query:
vouchers.append(voucher.id)
2020-10-07 16:59:24 +00:00
others = [
journal
for journal in voucher.journals
if journal.account_id not in accounts
]
if len(others) == 0:
continue
amount = round(Decimal(sum(o.signed_amount for o in others)), 2)
if amount != 0:
journal = Journal(
amount=abs(amount),
debit=-1 if amount < 0 else 1,
account_id=AccountBase.suspense(),
cost_centre_id=CostCentre.cost_centre_overall(),
)
voucher.journals.append(journal)
db.add(journal)
for other in others:
if voucher.type != VoucherType.by_name("Opening Accounts").id:
2020-10-07 16:59:24 +00:00
voucher.narration += (
f"\nSuspense \u20B9{other.amount:,.2f} is {other.account.name}"
)
if other.employee_benefit:
db.delete(other.employee_benefit)
if other.incentive:
db.delete(other.incentive)
db.delete(other)
voucher.type = VoucherType.by_name("Journal")
if len(voucher.narration) >= 1000:
voucher.narration = voucher.narration[:1000]
return vouchers
def opening_accounts(date_: date, user_id: uuid.UUID, db: Session):
2013-09-30 10:50:43 +00:00
running_total = 0
sum_func = func.sum(Journal.signed_amount)
query = (
db.query(AccountBase, sum_func)
.join(Journal, Voucher.journals)
.join(AccountBase, Journal.account)
.filter(AccountBase.is_starred == False)
.filter(AccountBase.id != AccountBase.suspense())
.filter(Voucher.date < date_)
.filter(Voucher.type != VoucherType.by_name("Issue").id)
.having(sum_func != 0)
.group_by(AccountBase)
.all()
)
2013-09-30 10:50:43 +00:00
dt = date_ - timedelta(days=1)
voucher = Voucher(
date=dt,
narration="Opening Accounts",
user_id=user_id,
posted=True,
type_=VoucherType.by_name("Opening Accounts"),
)
for account, amount in query:
2013-09-30 10:50:43 +00:00
amount = round(Decimal(amount), 2)
if account.type_object.balance_sheet and amount != 0:
2013-09-30 10:50:43 +00:00
running_total += amount
journal = Journal(
amount=abs(amount),
debit=-1 if amount < 0 else 1,
account_id=account.id,
cost_centre_id=account.cost_centre_id,
)
2013-09-30 10:50:43 +00:00
voucher.journals.append(journal)
if running_total != 0:
journal = Journal(
amount=abs(amount),
debit=-1 if amount * -1 < 0 else 1,
account_id=AccountBase.suspense(),
cost_centre_id=CostCentre.cost_centre_overall(),
)
2013-09-30 10:50:43 +00:00
voucher.journals.append(journal)
return voucher
2013-09-30 10:50:43 +00:00
def opening_batches(date_: date, user_id: uuid.UUID, db: Session):
2013-09-30 10:50:43 +00:00
total = 0
sum_func = func.sum(Journal.debit * Inventory.quantity)
query = (
db.query(Batch, sum_func)
.join(Journal, Voucher.journals)
.join(Inventory, Voucher.inventories)
.join(Batch, Inventory.batch)
.filter(Voucher.date < date_)
.filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase())
.having(sum_func != 0)
.group_by(Batch)
.all()
)
2013-09-30 10:50:43 +00:00
dt = date_ - timedelta(days=1)
voucher = Voucher(
date=dt,
narration="Opening Batches",
user_id=user_id,
posted=True,
type_=VoucherType.by_name("Opening Batches"),
)
2013-09-30 10:50:43 +00:00
for batch, quantity in query:
quantity = round(Decimal(quantity), 2)
if quantity != 0:
total += quantity * batch.rate * (1 + batch.tax) * (1 - batch.discount)
inventory = Inventory(
product_id=batch.product_id,
batch=batch,
quantity=quantity,
rate=batch.rate,
tax=batch.tax,
discount=batch.discount,
)
2013-09-30 10:50:43 +00:00
voucher.inventories.append(inventory)
voucher.journals.append(
Journal(
amount=abs(total),
debit=-1,
account_id=AccountBase.all_purchases(),
cost_centre_id=CostCentre.cost_centre_overall(),
)
)
voucher.journals.append(
Journal(
amount=abs(total),
debit=1,
account_id=AccountBase.all_purchases(),
cost_centre_id=CostCentre.cost_centre_purchase(),
)
)
return voucher
2013-09-30 10:50:43 +00:00
def delete_data(date_: date, vouchers: List[Voucher], db: Session):
2013-09-30 10:50:43 +00:00
sub_voucher = aliased(Voucher)
2020-05-31 09:11:11 +00:00
sub_query = db.query(sub_voucher.id).filter(sub_voucher.date < date_).subquery()
db.execute(Inventory.__table__.delete(Inventory.voucher_id.in_(sub_query)))
2020-10-07 16:59:24 +00:00
db.execute(
EmployeeBenefit.__table__.delete(EmployeeBenefit.voucher_id.in_(sub_query))
)
2020-05-31 09:11:11 +00:00
db.execute(Incentive.__table__.delete(Incentive.voucher_id.in_(sub_query)))
2020-10-07 16:59:24 +00:00
db.execute(
Journal.__table__.delete(
and_(Journal.voucher_id.in_(sub_query), ~Journal.voucher_id.in_(vouchers))
)
)
db.execute(
DbImage.__table__.delete(
and_(
DbImage.resource_type == "voucher",
DbImage.resource_id.in_(sub_query),
~DbImage.resource_id.in_(vouchers),
)
)
)
2020-10-07 16:59:24 +00:00
db.execute(
Voucher.__table__.delete(and_(Voucher.date < date_, ~Voucher.id.in_(vouchers)))
)
def cleanup_lint(date_: date, db: Session):
# Insert executes on the end so keep list of batches and journals
2020-10-07 16:59:24 +00:00
db.execute(
Batch.__table__.delete(
~Batch.id.in_(db.query(distinct(Inventory.batch_id)).subquery())
)
)
db.execute(Fingerprint.__table__.delete(Fingerprint.date < date_))
db.execute(Attendance.__table__.delete(Attendance.date < date_))
db.execute(
Employee.__table__.delete(
and_(
2020-05-31 09:11:11 +00:00
~Employee.id.in_(db.query(distinct(Journal.account_id)).subquery()),
2020-10-07 16:59:24 +00:00
~Employee.id.in_(
db.query(distinct(Fingerprint.employee_id)).subquery()
),
2020-05-31 09:11:11 +00:00
~Employee.id.in_(db.query(distinct(Attendance.employee_id)).subquery()),
Employee.id.in_(
db.query(AccountBase.id)
.filter(AccountBase.is_fixture == False)
.filter(AccountBase.is_active == False)
.filter(AccountBase.is_starred == False)
.subquery()
),
Employee.leaving_date < date_,
)
)
)
db.execute(
AccountBase.__table__.delete(
and_(
~AccountBase.id.in_(db.query(Employee.id).subquery()),
2020-10-07 16:59:24 +00:00
AccountBase.account_type
== Employee.__mapper_args__["polymorphic_identity"],
)
)
)
db.execute(
Account.__table__.delete(
and_(
2020-05-31 09:11:11 +00:00
~Account.id.in_(db.query(distinct(Journal.account_id)).subquery()),
Account.is_fixture == False,
Account.is_starred == False,
Account.account_type == Account.__mapper_args__["polymorphic_identity"],
)
)
)