import uuid from fastapi import APIRouter, Depends, HTTPException, Security, status from sqlalchemy import func from sqlalchemy.orm import Session from ..core.security import get_current_active_user as get_user from ..db.session import SessionLocal from ..models import Batch, Inventory, Journal, Voucher, VoucherType from ..models.master import AccountBase, CostCentre, Product from ..schemas.auth import UserToken from ..schemas.settings import ResetStock router = APIRouter() # Dependency def get_db() -> Session: try: db = SessionLocal() yield db finally: db.close() @router.post("/{id_}") def rebase( id_: uuid.UUID, item: ResetStock, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["reset-stock"]), ): product: Product = db.query(Product).filter(Product.id == id_).first() if item.reset_date > item.stock_date: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="Reset cannot be after the stock date", ) change = round(item.quantity, 2) - get_closing_stock( product, item.stock_date, db=db ) if change == 0: return {"No Change Needed"} final = get_closing_stock(product, db=db) if final + change < 0: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="Current Quantity will get negative. Cannot proceed", ) batch = get_last_batch(product, db) set_batches(batch, final + change, db) create_voucher(batch, change, item.reset_date, user.id_, db) db.commit() return {} def get_closing_stock(product, finish_date=None, db=None): query = ( db.query(func.sum(Inventory.quantity * Journal.debit)) .join(Voucher) .filter(Voucher.id == Inventory.voucher_id) .filter(Voucher.id == Journal.voucher_id) .filter(Inventory.product_id == product.id) .filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase()) ) if finish_date is not None: query = query.filter(Voucher.date <= finish_date) query = query.one() return 0 if query is None else query[0] def get_last_batch(product, db): batch = ( db.query(Batch) .filter(Batch.product_id == product.id) .order_by(Batch.name.desc()) .first() ) if batch is None: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="Details for the product exist. Just add a purchase entry", ) return batch def set_batches(batch, quantity, db): batch.quantity_remaining = quantity batches = ( db.query(Batch) .filter(Batch.id != batch.id) .filter(Batch.product_id == batch.product_id) ) for item in batches: item.quantity_remaining = 0 pass def create_voucher(batch, quantity, date_, user_id, db): voucher = Voucher( date=date_, narration="Product Reset", user_id=user_id, type_=VoucherType.by_name("Issue"), ) db.add(voucher) if quantity > 0: source = CostCentre.cost_centre_overall() destination = CostCentre.cost_centre_purchase() else: destination = CostCentre.cost_centre_overall() source = CostCentre.cost_centre_purchase() inventory = Inventory( product_id=batch.product.id, quantity=abs(quantity), rate=batch.rate, tax=batch.tax, discount=batch.discount, batch=batch, ) voucher.inventories.append(inventory) db.add(inventory) amount = round(inventory.amount, 2) source = Journal( debit=-1, account_id=AccountBase.all_purchases(), amount=amount, cost_centre_id=source, ) voucher.journals.append(source) db.add(source) destination = Journal( debit=1, account_id=AccountBase.all_purchases(), amount=amount, cost_centre_id=destination, ) voucher.journals.append(destination) db.add(destination)