brewman/brewman/brewman/routers/reset_stock.py

148 lines
4.0 KiB
Python

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)