2013-09-30 10:50:43 +00:00
|
|
|
import uuid
|
2020-10-07 15:18:43 +00:00
|
|
|
|
|
|
|
from datetime import date, datetime, timedelta
|
2018-07-07 11:01:44 +00:00
|
|
|
from decimal import Decimal
|
2020-05-22 04:40:45 +00:00
|
|
|
from typing import List
|
2014-06-09 07:38:36 +00:00
|
|
|
|
2021-09-06 15:06:36 +00:00
|
|
|
from fastapi import APIRouter, Security
|
|
|
|
from sqlalchemy import and_, delete, distinct, func, select
|
|
|
|
from sqlalchemy.orm import Session, aliased
|
2020-10-07 15:18:43 +00:00
|
|
|
|
2020-05-22 04:40:45 +00:00
|
|
|
from ..core.security import get_current_active_user as get_user
|
2021-09-06 15:06:36 +00:00
|
|
|
from ..db.session import SessionFuture
|
2021-01-25 07:14:17 +00:00
|
|
|
from ..models.account import Account
|
|
|
|
from ..models.account_base import AccountBase
|
|
|
|
from ..models.attendance import Attendance
|
|
|
|
from ..models.batch import Batch
|
|
|
|
from ..models.cost_centre import CostCentre
|
|
|
|
from ..models.db_image import DbImage
|
|
|
|
from ..models.employee import Employee
|
2021-11-07 13:00:14 +00:00
|
|
|
from ..models.employee_benefit import EmployeeBenefit
|
2021-01-25 07:14:17 +00:00
|
|
|
from ..models.fingerprint import Fingerprint
|
|
|
|
from ..models.incentive import Incentive
|
|
|
|
from ..models.inventory import Inventory
|
|
|
|
from ..models.journal import Journal
|
|
|
|
from ..models.voucher import Voucher
|
|
|
|
from ..models.voucher_type import VoucherType
|
2020-12-04 07:32:13 +00:00
|
|
|
from ..schemas.user import UserToken
|
2020-10-07 15:18:43 +00:00
|
|
|
|
2020-05-22 04:40:45 +00:00
|
|
|
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
|
|
|
2021-11-14 06:32:22 +00:00
|
|
|
@router.post("/{date_}", response_model=None)
|
2020-05-22 04:40:45 +00:00
|
|
|
def rebase(
|
2020-10-07 15:18:43 +00:00
|
|
|
date_: str,
|
|
|
|
user: UserToken = Security(get_user, scopes=["rebase"]),
|
2021-11-14 06:32:22 +00:00
|
|
|
) -> None:
|
2021-09-06 15:06:36 +00:00
|
|
|
with SessionFuture() as db:
|
2021-11-14 06:32:22 +00:00
|
|
|
date_obj = datetime.strptime(date_, "%d-%b-%Y")
|
|
|
|
voucher_l = opening_accounts(date_obj, user.id_, db)
|
|
|
|
voucher_b = opening_batches(date_obj, user.id_, db)
|
|
|
|
starred_vouchers = save_starred(date_obj, db)
|
2021-09-06 15:06:36 +00:00
|
|
|
db.flush()
|
2021-11-14 06:32:22 +00:00
|
|
|
delete_data(date_obj, starred_vouchers, db)
|
2021-09-06 15:06:36 +00:00
|
|
|
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()
|
2021-11-14 06:32:22 +00:00
|
|
|
cleanup_lint(date_obj, db)
|
2021-09-06 15:06:36 +00:00
|
|
|
# request.dbsession.execute('RESET statement_timeout;')
|
|
|
|
db.commit()
|
2013-09-30 10:50:43 +00:00
|
|
|
|
|
|
|
|
2021-11-14 06:32:22 +00:00
|
|
|
def save_starred(date_: date, db: Session) -> List[Voucher]:
|
2021-09-06 15:06:36 +00:00
|
|
|
accounts = [
|
|
|
|
i.id for i in db.execute(select(AccountBase.id).where(AccountBase.is_starred == True)).all() # noqa: E712
|
|
|
|
]
|
2018-07-07 11:01:44 +00:00
|
|
|
vouchers = []
|
2019-04-06 04:13:12 +00:00
|
|
|
query = (
|
2021-09-06 15:06:36 +00:00
|
|
|
db.execute(
|
|
|
|
select(Voucher)
|
|
|
|
.join(Voucher.journals)
|
|
|
|
.join(Journal.account)
|
|
|
|
.where(Voucher.date < date_, Voucher.journals.any(Journal.account_id.in_(accounts)))
|
|
|
|
)
|
|
|
|
.unique()
|
|
|
|
.scalars()
|
2019-04-06 04:13:12 +00:00
|
|
|
.all()
|
|
|
|
)
|
2018-07-07 11:01:44 +00:00
|
|
|
|
|
|
|
for voucher in query:
|
|
|
|
vouchers.append(voucher.id)
|
2020-11-02 17:48:56 +00:00
|
|
|
others = [journal for journal in voucher.journals if journal.account_id not in accounts]
|
2018-07-07 11:01:44 +00:00
|
|
|
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(),
|
2019-04-06 04:13:12 +00:00
|
|
|
cost_centre_id=CostCentre.cost_centre_overall(),
|
2018-07-07 11:01:44 +00:00
|
|
|
)
|
|
|
|
voucher.journals.append(journal)
|
2020-05-22 04:40:45 +00:00
|
|
|
db.add(journal)
|
2018-07-07 11:01:44 +00:00
|
|
|
|
|
|
|
for other in others:
|
2021-10-31 13:11:06 +00:00
|
|
|
if voucher.voucher_type != VoucherType.OPENING_ACCOUNTS:
|
2020-11-02 17:48:56 +00:00
|
|
|
voucher.narration += f"\nSuspense \u20B9{other.amount:,.2f} is {other.account.name}"
|
2020-06-01 15:10:52 +00:00
|
|
|
if other.employee_benefit:
|
|
|
|
db.delete(other.employee_benefit)
|
|
|
|
if other.incentive:
|
|
|
|
db.delete(other.incentive)
|
2020-05-22 04:40:45 +00:00
|
|
|
db.delete(other)
|
2021-10-31 13:11:06 +00:00
|
|
|
voucher.voucher_type = VoucherType.JOURNAL
|
2018-07-07 11:01:44 +00:00
|
|
|
if len(voucher.narration) >= 1000:
|
|
|
|
voucher.narration = voucher.narration[:1000]
|
|
|
|
return vouchers
|
|
|
|
|
|
|
|
|
2021-11-14 06:32:22 +00:00
|
|
|
def opening_accounts(date_: date, user_id: uuid.UUID, db: Session) -> Voucher:
|
2013-09-30 10:50:43 +00:00
|
|
|
running_total = 0
|
|
|
|
sum_func = func.sum(Journal.signed_amount)
|
2021-09-06 15:06:36 +00:00
|
|
|
query = db.execute(
|
|
|
|
select(AccountBase, sum_func)
|
2019-04-06 04:13:12 +00:00
|
|
|
.join(Journal, Voucher.journals)
|
|
|
|
.join(AccountBase, Journal.account)
|
2021-09-06 15:06:36 +00:00
|
|
|
.where(
|
|
|
|
AccountBase.is_starred == False, # noqa: E712
|
|
|
|
AccountBase.id != AccountBase.suspense(),
|
|
|
|
Voucher.date < date_,
|
2021-10-31 13:11:06 +00:00
|
|
|
Voucher.voucher_type != VoucherType.ISSUE,
|
2021-09-06 15:06:36 +00:00
|
|
|
)
|
2019-04-06 04:13:12 +00:00
|
|
|
.having(sum_func != 0)
|
|
|
|
.group_by(AccountBase)
|
2021-09-06 15:06:36 +00:00
|
|
|
).all()
|
2013-09-30 10:50:43 +00:00
|
|
|
|
2020-05-22 04:40:45 +00:00
|
|
|
dt = date_ - timedelta(days=1)
|
2018-07-07 11:01:44 +00:00
|
|
|
voucher = Voucher(
|
|
|
|
date=dt,
|
2019-04-06 04:13:12 +00:00
|
|
|
narration="Opening Accounts",
|
|
|
|
user_id=user_id,
|
|
|
|
posted=True,
|
2021-10-31 13:11:06 +00:00
|
|
|
voucher_type=VoucherType.OPENING_ACCOUNTS,
|
2018-07-07 11:01:44 +00:00
|
|
|
)
|
|
|
|
for account, amount in query:
|
2013-09-30 10:50:43 +00:00
|
|
|
amount = round(Decimal(amount), 2)
|
2021-10-31 13:11:06 +00:00
|
|
|
if account.type_.balance_sheet and amount != 0:
|
2013-09-30 10:50:43 +00:00
|
|
|
running_total += amount
|
2019-04-06 04:13:12 +00:00
|
|
|
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:
|
2019-04-06 04:13:12 +00:00
|
|
|
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)
|
2018-11-26 03:24:39 +00:00
|
|
|
return voucher
|
2013-09-30 10:50:43 +00:00
|
|
|
|
|
|
|
|
2021-11-14 06:32:22 +00:00
|
|
|
def opening_batches(date_: date, user_id: uuid.UUID, db: Session) -> Voucher:
|
2021-11-21 06:48:26 +00:00
|
|
|
total = Decimal(0)
|
2013-09-30 10:50:43 +00:00
|
|
|
sum_func = func.sum(Journal.debit * Inventory.quantity)
|
2021-09-06 15:06:36 +00:00
|
|
|
query = db.execute(
|
|
|
|
select(Batch, sum_func)
|
2021-09-27 04:01:58 +00:00
|
|
|
.join(Batch.inventories)
|
|
|
|
.join(Inventory.voucher)
|
|
|
|
.join(Voucher.journals)
|
2021-09-06 15:06:36 +00:00
|
|
|
.where(Voucher.date < date_, Journal.cost_centre_id == CostCentre.cost_centre_purchase())
|
2019-04-06 04:13:12 +00:00
|
|
|
.having(sum_func != 0)
|
|
|
|
.group_by(Batch)
|
2021-09-06 15:06:36 +00:00
|
|
|
).all()
|
2013-09-30 10:50:43 +00:00
|
|
|
|
2020-05-22 04:40:45 +00:00
|
|
|
dt = date_ - timedelta(days=1)
|
2018-07-07 11:01:44 +00:00
|
|
|
voucher = Voucher(
|
|
|
|
date=dt,
|
2019-04-06 04:13:12 +00:00
|
|
|
narration="Opening Batches",
|
2018-07-07 11:01:44 +00:00
|
|
|
user_id=user_id,
|
|
|
|
posted=True,
|
2021-10-31 13:11:06 +00:00
|
|
|
voucher_type=VoucherType.OPENING_BATCHES,
|
2018-07-07 11:01:44 +00:00
|
|
|
)
|
|
|
|
|
2021-11-21 06:48:26 +00:00
|
|
|
quantity: Decimal
|
2013-09-30 10:50:43 +00:00
|
|
|
for batch, quantity in query:
|
2021-11-21 06:48:26 +00:00
|
|
|
quantity = round(quantity, 2)
|
2013-09-30 10:50:43 +00:00
|
|
|
if quantity != 0:
|
|
|
|
total += quantity * batch.rate * (1 + batch.tax) * (1 - batch.discount)
|
2019-04-06 04:13:12 +00:00
|
|
|
inventory = Inventory(
|
|
|
|
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)
|
2019-04-06 04:13:12 +00:00
|
|
|
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(),
|
|
|
|
)
|
|
|
|
)
|
2018-11-26 03:24:39 +00:00
|
|
|
return voucher
|
2013-09-30 10:50:43 +00:00
|
|
|
|
|
|
|
|
2021-11-14 06:32:22 +00:00
|
|
|
def delete_data(date_: date, vouchers: List[Voucher], db: Session) -> None:
|
2013-09-30 10:50:43 +00:00
|
|
|
sub_voucher = aliased(Voucher)
|
2021-09-06 15:06:36 +00:00
|
|
|
sub_query = select(sub_voucher.id).where(sub_voucher.date < date_).subquery()
|
2019-04-06 04:13:12 +00:00
|
|
|
|
2020-05-22 04:40:45 +00:00
|
|
|
db.execute(
|
2022-05-09 18:26:51 +00:00
|
|
|
delete(Inventory).where(Inventory.voucher_id.in_(sub_query)).execution_options(synchronize_session=False)
|
|
|
|
)
|
|
|
|
db.execute(
|
|
|
|
delete(EmployeeBenefit)
|
|
|
|
.where(EmployeeBenefit.voucher_id.in_(sub_query))
|
|
|
|
.execution_options(synchronize_session=False)
|
|
|
|
)
|
|
|
|
db.execute(
|
|
|
|
delete(Incentive).where(Incentive.voucher_id.in_(sub_query)).execution_options(synchronize_session=False)
|
|
|
|
)
|
|
|
|
db.execute(
|
|
|
|
delete(Journal)
|
|
|
|
.where(and_(Journal.voucher_id.in_(sub_query), ~Journal.voucher_id.in_(vouchers)))
|
|
|
|
.execution_options(synchronize_session=False)
|
|
|
|
)
|
|
|
|
db.execute(
|
|
|
|
delete(DbImage)
|
|
|
|
.where(
|
2018-07-07 11:01:44 +00:00
|
|
|
and_(
|
2019-04-06 04:13:12 +00:00
|
|
|
DbImage.resource_type == "voucher",
|
|
|
|
DbImage.resource_id.in_(sub_query),
|
|
|
|
~DbImage.resource_id.in_(vouchers),
|
2018-07-07 11:01:44 +00:00
|
|
|
)
|
|
|
|
)
|
2022-05-09 18:26:51 +00:00
|
|
|
.execution_options(synchronize_session=False)
|
|
|
|
)
|
|
|
|
db.execute(
|
|
|
|
delete(Voucher)
|
|
|
|
.where(Voucher.date < date_, ~Voucher.id.in_(vouchers))
|
|
|
|
.execution_options(synchronize_session=False)
|
2016-12-24 11:41:01 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2021-11-14 06:32:22 +00:00
|
|
|
def cleanup_lint(date_: date, db: Session) -> None:
|
2014-06-09 07:38:36 +00:00
|
|
|
# Insert executes on the end so keep list of batches and journals
|
2020-05-22 04:40:45 +00:00
|
|
|
db.execute(
|
2022-05-09 18:26:51 +00:00
|
|
|
delete(Batch)
|
|
|
|
.where(~Batch.id.in_(select(distinct(Inventory.batch_id)).subquery()))
|
|
|
|
.execution_options(synchronize_session=False)
|
|
|
|
)
|
|
|
|
db.execute(delete(Fingerprint).where(Fingerprint.date < date_).execution_options(synchronize_session=False))
|
|
|
|
db.execute(delete(Attendance).where(Attendance.date < date_).execution_options(synchronize_session=False))
|
|
|
|
db.execute(
|
|
|
|
delete(Employee)
|
|
|
|
.where(
|
2016-12-24 11:41:01 +00:00
|
|
|
and_(
|
2021-09-06 15:06:36 +00:00
|
|
|
~Employee.id.in_(select(distinct(Journal.account_id)).subquery()),
|
|
|
|
~Employee.id.in_(select(distinct(Fingerprint.employee_id)).subquery()),
|
|
|
|
~Employee.id.in_(select(distinct(Attendance.employee_id)).subquery()),
|
2016-12-24 11:41:01 +00:00
|
|
|
Employee.id.in_(
|
2021-09-06 15:06:36 +00:00
|
|
|
select(AccountBase.id)
|
|
|
|
.where(
|
|
|
|
AccountBase.is_fixture == False, # noqa: E712
|
|
|
|
AccountBase.is_active == False, # noqa: E712
|
|
|
|
AccountBase.is_starred == False, # noqa: E712
|
|
|
|
)
|
2019-04-06 04:13:12 +00:00
|
|
|
.subquery()
|
|
|
|
),
|
2020-05-22 04:40:45 +00:00
|
|
|
Employee.leaving_date < date_,
|
2016-12-24 11:41:01 +00:00
|
|
|
)
|
2014-06-09 07:38:36 +00:00
|
|
|
)
|
2022-05-09 18:26:51 +00:00
|
|
|
.execution_options(synchronize_session=False)
|
2016-12-24 11:41:01 +00:00
|
|
|
)
|
2020-05-22 04:40:45 +00:00
|
|
|
db.execute(
|
2022-05-09 18:26:51 +00:00
|
|
|
delete(AccountBase)
|
|
|
|
.where(
|
2016-12-24 11:41:01 +00:00
|
|
|
and_(
|
2021-09-06 15:06:36 +00:00
|
|
|
~AccountBase.id.in_(select(Employee.id).subquery()),
|
2020-11-02 17:48:56 +00:00
|
|
|
AccountBase.account_type == Employee.__mapper_args__["polymorphic_identity"],
|
2016-12-24 11:41:01 +00:00
|
|
|
)
|
2014-06-09 07:38:36 +00:00
|
|
|
)
|
2022-05-09 18:26:51 +00:00
|
|
|
.execution_options(synchronize_session=False)
|
2016-12-24 11:41:01 +00:00
|
|
|
)
|
2020-05-22 04:40:45 +00:00
|
|
|
db.execute(
|
2022-05-09 18:26:51 +00:00
|
|
|
delete(Account)
|
|
|
|
.where(
|
2016-12-24 11:41:01 +00:00
|
|
|
and_(
|
2021-09-06 15:06:36 +00:00
|
|
|
~Account.id.in_(select(distinct(Journal.account_id)).subquery()),
|
2020-11-02 17:48:56 +00:00
|
|
|
Account.is_fixture == False, # noqa: E712
|
2022-05-09 18:26:51 +00:00
|
|
|
Account.is_starred == False, # noqa: E712
|
2019-04-06 04:13:12 +00:00
|
|
|
Account.account_type == Account.__mapper_args__["polymorphic_identity"],
|
2016-12-24 11:41:01 +00:00
|
|
|
)
|
2014-06-09 07:38:36 +00:00
|
|
|
)
|
2022-05-09 18:26:51 +00:00
|
|
|
.execution_options(synchronize_session=False)
|
2016-12-24 11:41:01 +00:00
|
|
|
)
|