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"], ) ) )