Done: Product Group

Done: Product
This commit is contained in:
tanshu 2020-05-10 16:05:39 +05:30
parent aae48faf91
commit 9383cf84d4
6 changed files with 394 additions and 331 deletions

@ -111,6 +111,18 @@ class Product(Base):
return False, "Product has entries" return False, "Product has entries"
return True, "" return True, ""
@classmethod
def query(cls, term, is_purchased=None, active=None, db=None):
query_ = db.query(Product)
if active is not None:
query_ = query_.filter(Product.is_active == active)
if is_purchased is not None:
query_ = query_.filter(Product.is_purchased == is_purchased)
if term is not None:
for item in term.split():
if item.strip() != "":
query_ = query_.filter(Product.name.ilike("%" + item + "%"))
@classmethod @classmethod
def suspense(cls): def suspense(cls):
return uuid.UUID("aa79a643-9ddc-4790-ac7f-a41f9efb4c15") return uuid.UUID("aa79a643-9ddc-4790-ac7f-a41f9efb4c15")
@ -303,20 +315,20 @@ class AccountBase(Base):
self.is_fixture = is_fixture self.is_fixture = is_fixture
@classmethod @classmethod
def list(cls, type, name, reconcilable=None, active=None, dbsession=None): def query(cls, q, type_, reconcilable=None, active=None, db=None):
query = dbsession.query(cls) query_ = db.query(cls)
if type is not None: if type_ is not None:
if not isinstance(type, int): if not isinstance(type_, int):
type = int(type) type_ = int(type_)
query = query.filter(cls.type == type) query_ = query_.filter(cls.type == type_)
if reconcilable is not None: if reconcilable is not None:
query = query.filter(cls.is_reconcilable == reconcilable) query_ = query_.filter(cls.is_reconcilable == reconcilable)
if active is not None: if active is not None:
query = query.filter(cls.is_active == active) query_ = query_.filter(cls.is_active == active)
if name is not None: if q is not None:
for item in name.split(): for item in q.split():
query = query.filter(cls.name.ilike("%" + item + "%")) query_ = query_.filter(cls.name.ilike("%" + item + "%"))
return query.order_by(cls.name) return query_.order_by(cls.name)
def create(self, dbsession): def create(self, dbsession):
code = ( code = (

@ -151,7 +151,7 @@ async def show_term(
count = c count = c
list_ = [] list_ = []
for index, item in enumerate(AccountBase.list(t, q, r, a, db)): for index, item in enumerate(AccountBase.query(q, t, r, a, db)):
list_.append({"id": item.id, "name": item.name}) list_.append({"id": item.id, "name": item.name})
if count is not None and index == count - 1: if count is not None and index == count - 1:
break break
@ -195,7 +195,7 @@ def balance(id_: uuid.UUID, date, db: Session):
return 0 if bal is None else bal return 0 if bal is None else bal
def account_info(id_, db): def account_info(id_: uuid.UUID, db: Session):
if id_ is None: if id_ is None:
account = { account = {
"code": "(Auto)", "code": "(Auto)",
@ -224,7 +224,7 @@ def account_info(id_, db):
return account return account
def delete_with_data(account, db): def delete_with_data(account: Account, db: Session):
suspense_account = ( suspense_account = (
db.query(Account).filter(Account.id == Account.suspense()).first() db.query(Account).filter(Account.id == Account.suspense()).first()
) )

@ -1,6 +1,7 @@
import traceback import traceback
import uuid import uuid
from typing import List, Optional from typing import List, Optional
from fastapi import APIRouter, HTTPException, status, Depends, Security from fastapi import APIRouter, HTTPException, status, Depends, Security
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
@ -28,10 +29,16 @@ def save(
user: User = Security(get_user, scopes=["cost-centres"]), user: User = Security(get_user, scopes=["cost-centres"]),
): ):
try: try:
item = CostCentre(data.name) item = CostCentre(name=data.name)
db.add(item) db.add(item)
db.commit() db.commit()
return cost_centre_info(item, db) return cost_centre_info(item, db)
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=str(e),
)
except Exception: except Exception:
db.rollback() db.rollback()
raise HTTPException( raise HTTPException(

@ -1,245 +1,203 @@
import traceback
import uuid import uuid
from decimal import Decimal, InvalidOperation from typing import Optional
from fastapi import APIRouter, HTTPException, status, Depends, Security
from sqlalchemy import desc from sqlalchemy import desc
from sqlalchemy.orm import joinedload_all from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import joinedload_all, Session
from brewman.models.master import Product, Account import brewman.schemas.master as schemas
from brewman.models.validation_exception import ValidationError from ..core.security import User, get_current_active_user as get_user
from brewman.models.voucher import Voucher, Batch, Inventory, VoucherType from ..db.session import SessionLocal
from ..models.master import Product, Account
from fastapi import APIRouter from ..models.voucher import Voucher, Batch, Inventory, VoucherType
router = APIRouter() router = APIRouter()
@router.post("/new") # "Products" # Dependency
def save(request): def get_db():
json = request.json_body
name = json.get("name", "").strip()
if name == "":
raise ValidationError("Name cannot be blank")
units = json.get("units", "").strip()
try: try:
fraction = Decimal(json.get("fraction", 0)) db = SessionLocal()
if fraction <= 0: yield db
raise ValidationError("Fraction must be a decimal > 0") finally:
except (ValueError, InvalidOperation): db.close()
raise ValidationError("Fraction must be a decimal > 0")
fraction_units = json.get("fractionUnits", "").strip()
@router.post("/", response_model=schemas.Product)
def save(
data: schemas.ProductIn,
db: Session = Depends(get_db),
user: User = Security(get_user, scopes=["products"]),
):
try: try:
product_yield = Decimal(json.get("productYield", 1)) item = Product(
if product_yield <= 0 or product_yield > 1: name=data.name,
raise ValidationError("Yield must be a decimal > 0 <= 1") units=data.units,
except (ValueError, InvalidOperation): fraction=data.fraction,
raise ValidationError("Yield must be a decimal > 0 <= 1") fraction_units=data.fraction_units,
product_yield=data.product_yield,
product_group = json.get("productGroup", None) product_group_id=data.product_group.id_,
if product_group is None: account_id=Account.all_purchases(),
raise ValidationError("please choose a product group") price=data.price,
product_group_id = uuid.UUID(product_group["id"]) sale_price=data.sale_price,
try: is_active=data.is_active,
price = Decimal(json.get("price", 0)) is_purchased=data.is_purchased,
if price < 0: is_sold=data.is_sold
raise ValidationError("Price must be a decimal >= 0") ).create(db)
except (ValueError, InvalidOperation): db.commit()
raise ValidationError("Price must be a decimal >= 0") return product_info(item.id, db)
try: except SQLAlchemyError as e:
sale_price = Decimal(json.get("salePrice", 0)) db.rollback()
if price < 0: raise HTTPException(
raise ValidationError("Sale Price must be a decimal >= 0") status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
except (ValueError, InvalidOperation): detail=str(e),
raise ValidationError("Price must be a decimal >= 0") )
is_active = json.get("isActive", True) except Exception:
is_purchased = json.get("isPurchased", True) db.rollback()
is_sold = json.get("isSold", True) raise HTTPException(
item = Product( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
0, detail=traceback.format_exc(),
name,
units,
fraction,
fraction_units,
product_yield,
product_group_id,
Account.all_purchases(),
price,
sale_price,
is_active,
is_purchased,
is_sold,
).create(request.dbsession)
transaction.commit()
return product_info(item.id, request.dbsession)
@router.put("/{id}") # "Products"
def update(request):
item = (
request.dbsession.query(Product)
.filter(Product.id == uuid.UUID(request.matchdict["id"]))
.first()
)
if item.is_fixture:
raise ValidationError(
"{0} is a fixture and cannot be edited or deleted.".format(item.full_name)
) )
item.name = request.json_body["name"].strip()
item.units = request.json_body["units"].strip()
try:
item.fraction = Decimal(request.json_body["fraction"])
if item.fraction <= 0:
raise ValidationError("Fraction must be a decimal > 0")
except (ValueError, InvalidOperation):
raise ValidationError("Fraction must be a decimal > 0")
item.fraction_units = request.json_body["fractionUnits"]
try:
item.product_yield = Decimal(request.json_body["productYield"])
if item.product_yield <= 0 or item.product_yield > 1:
raise ValidationError("Yield must be a decimal > 0 <= 1")
except (ValueError, InvalidOperation):
raise ValidationError("Yield must be a decimal > 0 <= 1")
item.product_group_id = uuid.UUID(request.json_body["productGroup"]["id"])
item.account_id = Account.all_purchases()
try:
item.price = Decimal(request.json_body["price"])
if item.price < 0:
raise ValidationError("Price must be a decimal >= 0")
except (ValueError, InvalidOperation):
raise ValidationError("Price must be a decimal >= 0")
try:
item.sale_price = Decimal(request.json_body["salePrice"])
if item.sale_price < 0:
raise ValidationError("Sale Price must be a decimal >= 0")
except (ValueError, InvalidOperation):
raise ValidationError("Sale Price must be a decimal >= 0")
item.is_active = request.json_body["isActive"]
item.is_fixture = request.json_body["isFixture"]
item.is_purchased = request.json_body["isPurchased"]
item.is_sold = request.json_body["isSold"]
transaction.commit()
return product_info(item.id, request.dbsession)
@router.delete("/{id}") # "Products" @router.put("/{id_}", response_model=schemas.Product)
def delete(request): def update(
product = ( id_: uuid.UUID,
request.dbsession.query(Product) data: schemas.ProductIn,
.filter(Product.id == uuid.UUID(request.matchdict["id"])) db: Session = Depends(get_db),
.first() user: User = Security(get_user, scopes=["products"]),
) ):
can_delete, reason = product.can_delete(request.has_permission("Advanced Delete")) try:
item: Product = db.query(Product).filter(Product.id == id_).first()
if item.is_fixture:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"{item.name} is a fixture and cannot be edited or deleted.",
)
item.name = data.name
item.units = data.units
item.fraction = data.fraction
item.fraction_units = data.fraction_units
item.product_yield = data.product_yield
item.product_group_id = data.product_group.id_
item.account_id = Account.all_purchases()
item.price = data.price
item.sale_price = data.sale_price
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(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
)
except Exception:
db.rollback()
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=traceback.format_exc(),
)
@router.delete("/{id_}")
def delete(
id_: uuid.UUID,
db: Session = Depends(get_db),
user: User = Security(get_user, scopes=["products"]),
):
product: Product = db.query(Product).filter(Product.id == id_).first()
can_delete, reason = product.can_delete("Advanced Delete" in user.permissions)
if can_delete: if can_delete:
delete_with_data(product, request) delete_with_data(product, db)
transaction.commit() db.commit()
return product_info(None, request.dbsession) return product_info(None, db)
else: else:
transaction.abort() db.abort()
response = Response("Cannot delete product because {0}".format(reason)) raise HTTPException(
response.status_int = 500 status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
return response detail=f"Cannot delete account because {reason}",
)
@router.get("/{id}") # "Products" @router.get("/") # "Products"
def show_id(request): def show_blank(
return product_info(uuid.UUID(request.matchdict.get("id", None)), request.dbsession) db: Session = Depends(get_db), user: User = Security(get_user, scopes=["products"])
):
return product_info(None, db)
@router.get("/new") # "Products" @router.get("/list")
def show_blank(request): def show_list(db: Session = Depends(get_db), user: User = Depends(get_user)):
return product_info(None, request.dbsession) 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()
]
@router.get("/", ) # "Authenticated" @router.get("/query")
def show_list(l: bool): async def show_term(
list_ = ( t: str = None,
request.dbsession.query(Product) a: bool = None,
.order_by(desc(Product.is_active)) c: int = None,
.order_by(Product.product_group_id) p: bool = None,
.order_by(Product.name) e: bool = False,
.all() db: Session = Depends(get_db),
) current_user: User = Depends(get_user),
products = [] ):
for item in list_: count = c
products.append( extended = e
list_ = []
for index, item in enumerate(Product.query(t, p, a, db)):
list_.append(
{ {
"id": item.id, "id": item.id,
"code": item.code, "name": item.full_name,
"name": item.name, "price": item.price,
"units": item.units, "units": item.units,
"costPrice": item.price,
"salePrice": item.sale_price,
"productGroup": item.product_group.name,
"isActive": item.is_active,
"fraction": item.fraction, "fraction": item.fraction,
"fractionUnits": item.fraction_units, "fractionUnits": item.fraction_units,
"isPurchased": item.is_purchased,
"isSold": item.is_sold,
"productYield": item.product_yield, "productYield": item.product_yield,
"isFixture": item.is_fixture, "isSold": item.is_sold,
"salePrice": item.sale_price,
} if extended else {
"id": item.id, "name": item.full_name, "price": item.price
} }
) )
return products if count is not None and index == count - 1:
break
return sorted(list_, key=lambda k: k["name"])
@router.get("/") # "Authenticated" @router.get("/{id_}")
async def show_term(t: str): def show_id(
term = request.GET.get("t", None) id_: uuid.UUID,
term = term.strip() if term is not None and term.strip() != "" else None db: Session = Depends(get_db),
active = request.GET.get("a", None) user: User = Security(get_user, scopes=["accounts"]),
active = active if active is not None else None ):
count = request.GET.get("c", None) return product_info(id_, db)
count = None if count is None or count == "" else int(count)
is_purchased = request.GET.get("p", None)
is_purchased = is_purchased if is_purchased is not None else None
extended = request.GET.get("e", False)
def add_list(query):
local_results = []
for index, item in enumerate(query):
if extended:
product = {
"id": item.id,
"name": item.full_name,
"price": item.price,
"units": item.units,
"fraction": item.fraction,
"fractionUnits": item.fraction_units,
"productYield": item.product_yield,
"isSold": item.is_sold,
"salePrice": item.sale_price,
}
else:
product = {"id": item.id, "name": item.full_name, "price": item.price}
local_results.append(product)
if count is not None and index == count - 1:
break
return local_results
result_list = []
query = request.dbsession.query(Product)
if active is not None:
query = query.filter(Product.is_active == active)
if is_purchased is not None:
query = query.filter(Product.is_purchased == is_purchased)
if term is not None:
for item in term.split():
if item.strip() != "":
query = query.filter(Product.name.ilike("%" + item + "%"))
result_list += add_list(query)
return sorted(result_list, key=lambda k: k["name"])
def product_info(id_, dbsession): def product_info(id_: Optional[uuid.UUID], db: Session):
if id_ is None: if id_ is None:
product = { product = {
"code": "(Auto)", "code": "(Auto)",
@ -249,7 +207,7 @@ def product_info(id_, dbsession):
"isSold": False, "isSold": False,
} }
else: else:
product = dbsession.query(Product).filter(Product.id == id_).first() product = db.query(Product).filter(Product.id == id_).first()
product = { product = {
"id": product.id, "id": product.id,
"code": product.code, "code": product.code,
@ -270,17 +228,17 @@ def product_info(id_, dbsession):
return product return product
def delete_with_data(product, request): def delete_with_data(product: Product, db: Session):
suspense_product = ( suspense_product = (
request.dbsession.query(Product) db.query(Product)
.filter(Product.id == Product.suspense()) .filter(Product.id == Product.suspense())
.first() .first()
) )
suspense_batch = ( suspense_batch = (
request.dbsession.query(Batch).filter(Batch.id == Batch.suspense()).first() db.query(Batch).filter(Batch.id == Batch.suspense()).first()
) )
query = ( query = (
request.dbsession.query(Voucher) db.query(Voucher)
.options(joinedload_all(Voucher.inventories, Inventory.product, innerjoin=True)) .options(joinedload_all(Voucher.inventories, Inventory.product, innerjoin=True))
.filter(Voucher.inventories.any(Inventory.product_id == product.id)) .filter(Voucher.inventories.any(Inventory.product_id == product.id))
.all() .all()
@ -296,7 +254,7 @@ def delete_with_data(product, request):
else: else:
others = True others = True
if not others and voucher.type == VoucherType.by_id("Issue"): if not others and voucher.type == VoucherType.by_id("Issue"):
request.dbsession.delete(voucher) db.delete(voucher)
else: else:
if sus_inv is None: if sus_inv is None:
prod_inv.product = suspense_product prod_inv.product = suspense_product
@ -305,15 +263,11 @@ def delete_with_data(product, request):
prod_inv.tax = 0 prod_inv.tax = 0
prod_inv.discount = 0 prod_inv.discount = 0
prod_inv.batch = suspense_batch prod_inv.batch = suspense_batch
voucher.narration += "\nSuspense \u20B9{0:,.2f} is {1}".format( voucher.narration += f"\nSuspense \u20B9{prod_inv.amount:,.2f} is {product.name}"
prod_inv.amount, product.name
)
else: else:
sus_inv.quantity += prod_inv.amount sus_inv.quantity += prod_inv.amount
request.dbsession.delete(prod_inv) db.delete(prod_inv)
voucher.narration += "\nDeleted \u20B9{0:,.2f} of {1}".format( voucher.narration += f"\nDeleted \u20B9{prod_inv.amount:,.2f} of {product.name}"
prod_inv.amount, product.name
)
for batch in product.batches: for batch in product.batches:
request.dbsession.delete(batch) db.delete(batch)
request.dbsession.delete(product) db.delete(product)

@ -1,90 +1,150 @@
import traceback
import uuid import uuid
from typing import List, Optional
from fastapi import APIRouter, HTTPException, status, Depends, Security
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
import brewman.schemas.master as schemas
from ..core.security import User, get_current_active_user as get_user
from ..db.session import SessionLocal
from brewman.models.master import ProductGroup from brewman.models.master import ProductGroup
from brewman.models.validation_exception import ValidationError
from fastapi import APIRouter
router = APIRouter() router = APIRouter()
@router.post("/new") # "Product Groups" # Dependency
def save(request): def get_db():
item = ProductGroup(request.json_body["name"]) try:
request.dbsession.add(item) db = SessionLocal()
transaction.commit() yield db
return product_group_info(item.id, request.dbsession) finally:
db.close()
@router.put("/{id}") # "Product Groups" @router.post("/", response_model=schemas.ProductGroup)
def update(request): def save(
item = ( data: schemas.ProductGroupIn,
request.dbsession.query(ProductGroup) db: Session = Depends(get_db),
.filter(ProductGroup.id == uuid.UUID(request.matchdict["id"])) user: User = Security(get_user, scopes=["product-groups"]),
.first() ):
) try:
if item.is_fixture: item = ProductGroup(name=data.name)
raise ValidationError( db.add(item)
"{0} is a fixture and cannot be edited or deleted.".format(item.name) db.commit()
return product_group_info(item, db)
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=str(e),
)
except Exception:
db.rollback()
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=traceback.format_exc(),
) )
item.name = request.json_body["name"]
transaction.commit()
return product_group_info(item.id, request.dbsession)
@router.delete("/{id}") # "Product Groups" @router.put("/{id_}", response_model=schemas.ProductGroup)
def delete(request): def update(
item = ( id_: uuid.UUID,
request.dbsession.query(ProductGroup) data: schemas.ProductGroupIn,
.filter(ProductGroup.id == uuid.UUID(request.matchdict["id"])) db: Session = Depends(get_db),
.first() user: User = Security(get_user, scopes=["product-groups"]),
) ):
try:
item = db.query(ProductGroup).filter(ProductGroup.id == id_).first()
if item.is_fixture:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"{item.name} is a fixture and cannot be edited or deleted.",
)
item.name = data.name
db.commit()
return product_group_info(item, db)
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=str(e),
)
except Exception:
db.rollback()
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=traceback.format_exc(),
)
@router.delete("/{id_}")
def delete(
id_: uuid.UUID,
db: Session = Depends(get_db),
user: User = Security(get_user, scopes=["product-groups"]),
):
try:
item = db.query(ProductGroup).filter(ProductGroup.id == id_).first()
if item is None:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Product Group not found",
)
elif item.is_fixture:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"{item.name} is a fixture and cannot be edited or deleted.",
)
else:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Product Group deletion not implemented",
)
except Exception:
db.rollback()
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=traceback.format_exc(),
)
@router.get("/")
def show_blank(
db: Session = Depends(get_db),
user: User = Security(get_user, scopes=["product-groups"]),
):
return product_group_info(None, db)
@router.get("/list", response_model=List[schemas.ProductGroup])
async def show_list(db: Session = Depends(get_db), user: User = Depends(get_user)):
return[
{"id": item.id, "name": item.name, "isFixture": item.is_fixture}
for item in db.query(ProductGroup).order_by(ProductGroup.name).all()
]
@router.get("/{id_}", response_model=schemas.ProductGroup)
def show_id(
id_: uuid.UUID,
db: Session = Depends(get_db),
user: User = Security(get_user, scopes=["product-groups"]),
):
item = db.query(ProductGroup).filter(ProductGroup.id == id_).first()
return product_group_info(item, db)
def product_group_info(item: Optional[ProductGroup], db):
if item is None: if item is None:
response = Response("Product Group not Found")
response.status_int = 500
return response
elif item.is_fixture:
raise ValidationError(
"{0} is a fixture and cannot be edited or deleted.".format(item.name)
)
else:
response = Response("Product Group deletion not implemented")
response.status_int = 500
return response
@router.get("/{id}") # "Product Groups"
def show_id(request):
return product_group_info(
uuid.UUID(request.matchdict.get("id", None)), request.dbsession
)
@router.get("/new") # "Product Groups"
def show_blank(request):
return product_group_info(None, request.dbsession)
@router.get("/") # "Authenticated"
async def show_list(l: bool):
list_ = request.dbsession.query(ProductGroup).order_by(ProductGroup.name).all()
product_groups = []
for item in list_:
product_groups.append(
{"id": item.id, "name": item.name, "isFixture": item.is_fixture}
)
return product_groups
def product_group_info(id_, dbsession):
if id_ is None:
return {"name": ''}
else:
product_group = (
dbsession.query(ProductGroup).filter(ProductGroup.id == id_).first()
)
return { return {
"id": product_group.id, "name": "",
"name": product_group.name, "isFixture": False,
"isFixture": product_group.is_fixture, }
else:
return {
"id": item.id,
"name": item.name,
"isFixture": item.is_fixture,
} }

@ -11,23 +11,59 @@ def to_camel(string: str) -> str:
return ''.join([first] + [word.capitalize() for word in others]) return ''.join([first] + [word.capitalize() for word in others])
class Product(BaseModel): class AccountLink(BaseModel):
id_: uuid.UUID = Field(...)
class Config:
fields = {'id_': 'id'}
class ProductGroupIn(BaseModel):
name: str = Field(..., min_length=1)
class ProductGroup(ProductGroupIn):
id_: uuid.UUID id_: uuid.UUID
code: int
name: str
units: str
fraction: Decimal
fraction_units: str
product_yield: Decimal
product_group_id: uuid.UUID
account_id: uuid.UUID
price: Decimal
sale_price: Decimal
is_active: bool
is_fixture: bool is_fixture: bool
class Config:
fields = {'id_': 'id'}
anystr_strip_whitespace = True
alias_generator = to_camel
class ProductGroupLink(BaseModel):
id_: uuid.UUID = Field(...)
class Config:
fields = {'id_': 'id'}
class ProductIn(BaseModel):
name: str = Field(..., min_length=1)
units: str
fraction: Decimal = Field(ge=0, multiple_of=0.00001, default=0)
fraction_units: str
product_yield: Decimal = Field(ge=0, le=1, multiple_of=0.00001, default=1)
product_group: ProductGroupLink = Field(...)
account_id: AccountLink = Field(...)
price: Decimal = Field(ge=0, multiple_of=0.01, default=0)
sale_price: Decimal = Field(ge=0, multiple_of=0.01, default=0)
is_active: bool
is_purchased: bool is_purchased: bool
is_sold: bool is_sold: bool
class Config:
fields = {'id_': 'id'}
anystr_strip_whitespace = True
alias_generator = to_camel
class Product(ProductIn):
id_: uuid.UUID
code: int
is_fixture: bool
class Recipe(BaseModel): class Recipe(BaseModel):
id_: uuid.UUID id_: uuid.UUID
@ -53,14 +89,8 @@ class RecipeItem(BaseModel):
price: int price: int
class ProductGroup(BaseModel):
id_: uuid.UUID
name: str
is_fixture: bool
class CostCentreLink(BaseModel): class CostCentreLink(BaseModel):
id_: uuid.UUID id_: uuid.UUID = Field(...)
class Config: class Config:
fields = {'id_': 'id'} fields = {'id_': 'id'}