Files
brewman/brewman/routers/management/rebase.py
T
tanshu 98edca5f60 Renamed "Salary Deduction" to "Employee Benefit"
Journal, Purchase and Purchase Return vouchers done!!

Changed the column type of "date" columns from "datetime" to better fit the data.
2020-05-21 13:11:47 +05:30

283 lines
9.1 KiB
Python

import datetime
import uuid
from decimal import Decimal
from sqlalchemy import func, and_, distinct
from sqlalchemy.orm import aliased, joinedload_all
from brewman.models.master import AccountBase, CostCentre, Account, Employee
from brewman.models.voucher import (
Journal,
Voucher,
VoucherType,
Batch,
Inventory,
EmployeeBenefit,
Fingerprint,
Attendance,
DbImage,
Incentive,
)
@router.post("/api/rebase/{date}") # "Rebase"
def rebase(request):
# request.dbsession.execute('SET statement_timeout TO 300000;') # 5 minutes
date = request.matchdict.get("date", None)
date = datetime.datetime.strptime(date, "%d-%b-%Y")
user_id = uuid.UUID(request.authenticated_userid)
voucher_l = opening_accounts(date, user_id, request.dbsession)
voucher_b = opening_batches(date, user_id, request.dbsession)
starred_vouchers = save_starred(date, request.dbsession)
request.dbsession.flush()
delete_data(date, starred_vouchers, request.dbsession)
request.dbsession.add(voucher_l)
for j in voucher_l.journals:
request.dbsession.add(j)
request.dbsession.add(voucher_b)
for j in voucher_b.journals:
request.dbsession.add(j)
for i in voucher_b.inventories:
request.dbsession.add(i)
request.dbsession.flush()
cleanup_lint(date, request.dbsession)
# request.dbsession.execute('RESET statement_timeout;')
transaction.commit()
return {}
def save_starred(date, dbsession):
accounts = [
i.id
for i in dbsession.query(AccountBase.id)
.filter(AccountBase.is_starred == True)
.all()
]
vouchers = []
query = (
dbsession.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)
dbsession.add(journal)
for other in others:
if voucher.type != VoucherType.by_name("Opening Accounts").id:
voucher.narration += "\nSuspense \u20B9{0:,.2f} is {1}".format(
other.amount, other.account.name
)
dbsession.delete(other)
voucher.type = VoucherType.by_name("Journal")
if len(voucher.narration) >= 1000:
voucher.narration = voucher.narration[:1000]
return vouchers
def opening_accounts(date, user_id, dbsession):
running_total = 0
sum_func = func.sum(Journal.signed_amount)
query = (
dbsession.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 - datetime.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, user_id, dbsession):
total = 0
sum_func = func.sum(Journal.debit * Inventory.quantity)
query = (
dbsession.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 - datetime.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, vouchers, dbsession):
sub_voucher = aliased(Voucher)
sub_query = (
dbsession.query(sub_voucher.id).filter(sub_voucher.date < date).subquery()
)
dbsession.execute(Inventory.__table__.delete(Inventory.voucher_id.in_(sub_query)))
dbsession.execute(
EmployeeBenefit.__table__.delete(EmployeeBenefit.voucher_id.in_(sub_query))
)
dbsession.execute(
Incentive.__table__.delete(Incentive.voucher_id.in_(sub_query))
)
dbsession.execute(
Journal.__table__.delete(
and_(Journal.voucher_id.in_(sub_query), ~Journal.voucher_id.in_(vouchers))
)
)
dbsession.execute(
DbImage.__table__.delete(
and_(
DbImage.resource_type == "voucher",
DbImage.resource_id.in_(sub_query),
~DbImage.resource_id.in_(vouchers),
)
)
)
dbsession.execute(
Voucher.__table__.delete(and_(Voucher.date < date, ~Voucher.id.in_(vouchers)))
)
def cleanup_lint(date, dbsession):
# Insert executes on the end so keep list of batches and journals
dbsession.execute(
Batch.__table__.delete(
~Batch.id.in_(dbsession.query(distinct(Inventory.batch_id)).subquery())
)
)
dbsession.execute(Fingerprint.__table__.delete(Fingerprint.date < date))
dbsession.execute(Attendance.__table__.delete(Attendance.date < date))
dbsession.execute(
Employee.__table__.delete(
and_(
~Employee.id.in_(
dbsession.query(distinct(Journal.account_id)).subquery()
),
~Employee.id.in_(
dbsession.query(distinct(Fingerprint.employee_id)).subquery()
),
~Employee.id.in_(
dbsession.query(distinct(Attendance.employee_id)).subquery()
),
Employee.id.in_(
dbsession.query(AccountBase.id)
.filter(AccountBase.is_fixture == False)
.filter(AccountBase.is_active == False)
.filter(AccountBase.is_starred == False)
.subquery()
),
Employee.leaving_date < date,
)
)
)
dbsession.execute(
AccountBase.__table__.delete(
and_(
~AccountBase.id.in_(dbsession.query(Employee.id).subquery()),
AccountBase.account_type
== Employee.__mapper_args__["polymorphic_identity"],
)
)
)
dbsession.execute(
Account.__table__.delete(
and_(
~Account.id.in_(
dbsession.query(distinct(Journal.account_id)).subquery()
),
Account.is_fixture == False,
Account.is_starred == False,
Account.account_type == Account.__mapper_args__["polymorphic_identity"],
)
)
)