287 lines
9.2 KiB
Python
287 lines
9.2 KiB
Python
import uuid
|
|
|
|
from datetime import date, datetime, timedelta
|
|
from decimal import Decimal
|
|
from typing import List
|
|
|
|
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
|
|
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()
|
|
|
|
|
|
@router.post("/{date_}")
|
|
def rebase(
|
|
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)
|
|
for j in voucher_l.journals:
|
|
db.add(j)
|
|
db.flush()
|
|
db.add(voucher_b)
|
|
for j in voucher_b.journals:
|
|
db.add(j)
|
|
for i in voucher_b.inventories:
|
|
db.add(i)
|
|
db.flush()
|
|
cleanup_lint(date_, db)
|
|
# request.dbsession.execute('RESET statement_timeout;')
|
|
db.commit()
|
|
return {}
|
|
|
|
|
|
def save_starred(date_: date, db: Session):
|
|
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)
|
|
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:
|
|
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):
|
|
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()
|
|
)
|
|
|
|
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:
|
|
amount = round(Decimal(amount), 2)
|
|
if account.type_object.balance_sheet and amount != 0:
|
|
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,
|
|
)
|
|
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(),
|
|
)
|
|
voucher.journals.append(journal)
|
|
return voucher
|
|
|
|
|
|
def opening_batches(date_: date, user_id: uuid.UUID, db: Session):
|
|
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()
|
|
)
|
|
|
|
dt = date_ - timedelta(days=1)
|
|
voucher = Voucher(
|
|
date=dt,
|
|
narration="Opening Batches",
|
|
user_id=user_id,
|
|
posted=True,
|
|
type_=VoucherType.by_name("Opening Batches"),
|
|
)
|
|
|
|
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,
|
|
)
|
|
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
|
|
|
|
|
|
def delete_data(date_: date, vouchers: List[Voucher], db: Session):
|
|
sub_voucher = aliased(Voucher)
|
|
sub_query = db.query(sub_voucher.id).filter(sub_voucher.date < date_).subquery()
|
|
|
|
db.execute(Inventory.__table__.delete(Inventory.voucher_id.in_(sub_query)))
|
|
db.execute(
|
|
EmployeeBenefit.__table__.delete(EmployeeBenefit.voucher_id.in_(sub_query))
|
|
)
|
|
db.execute(Incentive.__table__.delete(Incentive.voucher_id.in_(sub_query)))
|
|
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),
|
|
)
|
|
)
|
|
)
|
|
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
|
|
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_(
|
|
~Employee.id.in_(db.query(distinct(Journal.account_id)).subquery()),
|
|
~Employee.id.in_(
|
|
db.query(distinct(Fingerprint.employee_id)).subquery()
|
|
),
|
|
~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()),
|
|
AccountBase.account_type
|
|
== Employee.__mapper_args__["polymorphic_identity"],
|
|
)
|
|
)
|
|
)
|
|
db.execute(
|
|
Account.__table__.delete(
|
|
and_(
|
|
~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"],
|
|
)
|
|
)
|
|
)
|