brewman/brewman/brewman/routers/product.py

277 lines
8.5 KiB
Python
Raw Normal View History

import uuid
2020-10-07 15:18:43 +00:00
2020-05-10 10:35:39 +00:00
from typing import Optional
2020-10-07 15:18:43 +00:00
import brewman.schemas.master as schemas
from fastapi import APIRouter, Depends, HTTPException, Security, status
from sqlalchemy import desc
2020-05-10 10:35:39 +00:00
from sqlalchemy.exc import SQLAlchemyError
2020-10-07 15:18:43 +00:00
from sqlalchemy.orm import Session, joinedload_all
from ..core.security import get_current_active_user as get_user
2020-05-10 10:35:39 +00:00
from ..db.session import SessionLocal
2020-10-07 15:18:43 +00:00
from ..models.master import Account, Product
from ..models.voucher import Batch, Inventory, Voucher, VoucherType
from ..schemas.auth import UserToken
router = APIRouter()
2020-05-10 10:35:39 +00:00
# Dependency
def get_db():
try:
2020-05-10 10:35:39 +00:00
db = SessionLocal()
yield db
finally:
db.close()
@router.post("", response_model=schemas.Product)
2020-05-10 10:35:39 +00:00
def save(
2020-10-07 15:18:43 +00:00
data: schemas.ProductIn,
db: Session = Depends(get_db),
user: UserToken = Security(get_user, scopes=["products"]),
2020-05-10 10:35:39 +00:00
):
try:
2020-05-10 10:35:39 +00:00
item = Product(
name=data.name,
units=data.units,
fraction=round(data.fraction, 5),
2020-05-10 10:35:39 +00:00
fraction_units=data.fraction_units,
product_yield=round(data.product_yield, 5),
2020-05-10 10:35:39 +00:00
product_group_id=data.product_group.id_,
account_id=Account.all_purchases(),
price=round(data.price, 2),
sale_price=round(data.sale_price, 2),
2020-05-10 10:35:39 +00:00
is_active=data.is_active,
is_purchased=data.is_purchased,
is_sold=data.is_sold,
2020-05-10 10:35:39 +00:00
).create(db)
db.commit()
return product_info(item.id, db)
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
2020-10-07 15:18:43 +00:00
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=str(e),
2020-05-10 10:35:39 +00:00
)
except Exception:
db.rollback()
raise
2020-05-10 10:35:39 +00:00
@router.put("/{id_}", response_model=schemas.Product)
def update(
id_: uuid.UUID,
data: schemas.ProductIn,
db: Session = Depends(get_db),
user: UserToken = Security(get_user, scopes=["products"]),
2020-05-10 10:35:39 +00:00
):
try:
2020-05-10 10:35:39 +00:00
item: Product = db.query(Product).filter(Product.id == id_).first()
if item.is_fixture:
raise HTTPException(
2020-10-07 15:18:43 +00:00
status_code=status.HTTP_423_LOCKED,
detail=f"{item.name} is a fixture and cannot be edited or deleted.",
2020-05-10 10:35:39 +00:00
)
item.name = data.name
item.units = data.units
item.fraction = round(data.fraction, 5)
2020-05-10 10:35:39 +00:00
item.fraction_units = data.fraction_units
item.product_yield = round(data.product_yield, 5)
2020-05-10 10:35:39 +00:00
item.product_group_id = data.product_group.id_
item.account_id = Account.all_purchases()
item.price = round(data.price, 2)
item.sale_price = round(data.sale_price, 2)
2020-05-10 10:35:39 +00:00
item.is_active = data.is_active
item.is_purchased = data.is_purchased
item.is_sold = data.is_sold
db.commit()
return product_info(item.id, db)
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
2020-10-07 15:18:43 +00:00
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=str(e),
2020-05-10 10:35:39 +00:00
)
except Exception:
db.rollback()
raise
2020-05-10 10:35:39 +00:00
@router.delete("/{id_}")
def delete(
2020-10-07 15:18:43 +00:00
id_: uuid.UUID,
db: Session = Depends(get_db),
user: UserToken = Security(get_user, scopes=["products"]),
2020-05-10 10:35:39 +00:00
):
item: Product = db.query(Product).filter(Product.id == id_).first()
can_delete, reason = item.can_delete("advanced-delete" in user.permissions)
if can_delete:
delete_with_data(item, db)
2020-05-10 10:35:39 +00:00
db.commit()
return product_info(None, db)
else:
2020-05-10 10:35:39 +00:00
db.abort()
raise HTTPException(
2020-10-07 15:18:43 +00:00
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Cannot delete account because {reason}",
2020-05-10 10:35:39 +00:00
)
@router.get("")
2020-05-10 10:35:39 +00:00
def show_blank(
2020-10-07 15:18:43 +00:00
db: Session = Depends(get_db),
user: UserToken = Security(get_user, scopes=["products"]),
2020-05-10 10:35:39 +00:00
):
return product_info(None, db)
@router.get("/list")
def show_list(db: Session = Depends(get_db), user: UserToken = Depends(get_user)):
2020-05-10 10:35:39 +00:00
return [
{
"id": item.id,
"code": item.code,
"name": item.name,
"units": item.units,
"costPrice": item.price,
"salePrice": item.sale_price,
"productGroup": item.product_group.name,
"isActive": item.is_active,
"fraction": item.fraction,
"fractionUnits": item.fraction_units,
"isPurchased": item.is_purchased,
"isSold": item.is_sold,
"productYield": item.product_yield,
"isFixture": item.is_fixture,
}
for item in db.query(Product)
.order_by(desc(Product.is_active))
.order_by(Product.product_group_id)
.order_by(Product.name)
.all()
2020-05-10 10:35:39 +00:00
]
@router.get("/query")
async def show_term(
q: str = None,
2020-05-10 10:35:39 +00:00
a: bool = None,
c: int = None,
p: bool = None,
e: bool = False,
db: Session = Depends(get_db),
current_user: UserToken = Depends(get_user),
2020-05-10 10:35:39 +00:00
):
count = c
extended = e
list_ = []
for index, item in enumerate(Product.query(q, p, a, db)):
2020-05-10 10:35:39 +00:00
list_.append(
{
"id": item.id,
2020-05-10 10:35:39 +00:00
"name": item.full_name,
"price": item.price,
"units": item.units,
"fraction": item.fraction,
"fractionUnits": item.fraction_units,
"productYield": item.product_yield,
2020-05-10 10:35:39 +00:00
"isSold": item.is_sold,
"salePrice": item.sale_price,
}
if extended
else {"id": item.id, "name": item.full_name, "price": item.price}
)
2020-05-10 10:35:39 +00:00
if count is not None and index == count - 1:
break
return sorted(list_, key=lambda k: k["name"])
2020-05-10 10:35:39 +00:00
@router.get("/{id_}")
def show_id(
2020-10-07 15:18:43 +00:00
id_: uuid.UUID,
db: Session = Depends(get_db),
user: UserToken = Security(get_user, scopes=["accounts"]),
2020-05-10 10:35:39 +00:00
):
return product_info(id_, db)
2020-05-10 10:35:39 +00:00
def product_info(id_: Optional[uuid.UUID], db: Session):
if id_ is None:
product = {
"code": "(Auto)",
"productGroup": {},
"isActive": True,
"isPurchased": True,
"isSold": False,
}
else:
2020-05-10 10:35:39 +00:00
product = db.query(Product).filter(Product.id == id_).first()
product = {
"id": product.id,
"code": product.code,
"name": product.name,
"units": product.units,
"fraction": product.fraction,
"fractionUnits": product.fraction_units,
"productYield": product.product_yield,
"price": product.price,
"salePrice": product.sale_price,
"isActive": product.is_active,
"isFixture": product.is_fixture,
"isPurchased": product.is_purchased,
"isSold": product.is_sold,
"productGroup": {"id": product.product_group_id},
"account": {"id": product.account_id},
}
return product
2020-05-10 10:35:39 +00:00
def delete_with_data(product: Product, db: Session):
2020-10-07 16:59:24 +00:00
suspense_product = (
db.query(Product).filter(Product.id == Product.suspense()).first()
)
suspense_batch = db.query(Batch).filter(Batch.id == Batch.suspense()).first()
query = (
2020-05-10 10:35:39 +00:00
db.query(Voucher)
.options(joinedload_all(Voucher.inventories, Inventory.product, innerjoin=True))
.filter(Voucher.inventories.any(Inventory.product_id == product.id))
.all()
)
for voucher in query:
others, sus_inv, prod_inv = False, None, None
for inventory in voucher.inventories:
if inventory.product_id == product.id:
prod_inv = inventory
elif inventory.product_id == Product.suspense():
sus_inv = inventory
else:
others = True
if not others and voucher.type == VoucherType.by_id("Issue"):
2020-05-10 10:35:39 +00:00
db.delete(voucher)
else:
if sus_inv is None:
prod_inv.product = suspense_product
prod_inv.quantity = prod_inv.amount
prod_inv.rate = 1
prod_inv.tax = 0
prod_inv.discount = 0
prod_inv.batch = suspense_batch
2020-10-07 16:59:24 +00:00
voucher.narration += (
f"\nSuspense \u20B9{prod_inv.amount:,.2f} is {product.name}"
)
else:
sus_inv.quantity += prod_inv.amount
2020-05-10 10:35:39 +00:00
db.delete(prod_inv)
2020-10-07 16:59:24 +00:00
voucher.narration += (
f"\nDeleted \u20B9{prod_inv.amount:,.2f} of {product.name}"
)
for batch in product.batches:
2020-05-10 10:35:39 +00:00
db.delete(batch)
db.delete(product)