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

View File

@ -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 = (

View File

@ -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()
) )

View File

@ -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(

View File

@ -1,174 +1,139 @@
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))
if product_yield <= 0 or product_yield > 1:
raise ValidationError("Yield must be a decimal > 0 <= 1")
except (ValueError, InvalidOperation):
raise ValidationError("Yield must be a decimal > 0 <= 1")
product_group = json.get("productGroup", None)
if product_group is None:
raise ValidationError("please choose a product group")
product_group_id = uuid.UUID(product_group["id"])
try:
price = Decimal(json.get("price", 0))
if price < 0:
raise ValidationError("Price must be a decimal >= 0")
except (ValueError, InvalidOperation):
raise ValidationError("Price must be a decimal >= 0")
try:
sale_price = Decimal(json.get("salePrice", 0))
if price < 0:
raise ValidationError("Sale Price must be a decimal >= 0")
except (ValueError, InvalidOperation):
raise ValidationError("Price must be a decimal >= 0")
is_active = json.get("isActive", True)
is_purchased = json.get("isPurchased", True)
is_sold = json.get("isSold", True)
item = Product( item = Product(
0, name=data.name,
name, units=data.units,
units, fraction=data.fraction,
fraction, fraction_units=data.fraction_units,
fraction_units, product_yield=data.product_yield,
product_yield, product_group_id=data.product_group.id_,
product_group_id, account_id=Account.all_purchases(),
Account.all_purchases(), price=data.price,
price, sale_price=data.sale_price,
sale_price, is_active=data.is_active,
is_active, is_purchased=data.is_purchased,
is_purchased, is_sold=data.is_sold
is_sold, ).create(db)
).create(request.dbsession) db.commit()
transaction.commit() return product_info(item.id, db)
return product_info(item.id, request.dbsession) except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
@router.put("/{id}") # "Products" status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
def update(request): detail=str(e),
item = (
request.dbsession.query(Product)
.filter(Product.id == uuid.UUID(request.matchdict["id"]))
.first()
) )
except Exception:
db.rollback()
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=traceback.format_exc(),
)
@router.put("/{id_}", response_model=schemas.Product)
def update(
id_: uuid.UUID,
data: schemas.ProductIn,
db: Session = Depends(get_db),
user: User = Security(get_user, scopes=["products"]),
):
try:
item: Product = db.query(Product).filter(Product.id == id_).first()
if item.is_fixture: if item.is_fixture:
raise ValidationError( raise HTTPException(
"{0} is a fixture and cannot be edited or deleted.".format(item.full_name) status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"{item.name} is a fixture and cannot be edited or deleted.",
) )
item.name = request.json_body["name"].strip() item.name = data.name
item.units = request.json_body["units"].strip() item.units = data.units
try: item.fraction = data.fraction
item.fraction = Decimal(request.json_body["fraction"]) item.fraction_units = data.fraction_units
if item.fraction <= 0: item.product_yield = data.product_yield
raise ValidationError("Fraction must be a decimal > 0") item.product_group_id = data.product_group.id_
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() item.account_id = Account.all_purchases()
try: item.price = data.price
item.price = Decimal(request.json_body["price"]) item.sale_price = data.sale_price
if item.price < 0: item.is_active = data.is_active
raise ValidationError("Price must be a decimal >= 0") item.is_purchased = data.is_purchased
except (ValueError, InvalidOperation): item.is_sold = data.is_sold
raise ValidationError("Price must be a decimal >= 0") db.commit()
try: return product_info(item.id, db)
item.sale_price = Decimal(request.json_body["salePrice"]) except SQLAlchemyError as e:
if item.sale_price < 0: db.rollback()
raise ValidationError("Sale Price must be a decimal >= 0") raise HTTPException(
except (ValueError, InvalidOperation): status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
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"
def delete(request):
product = (
request.dbsession.query(Product)
.filter(Product.id == uuid.UUID(request.matchdict["id"]))
.first()
) )
can_delete, reason = product.can_delete(request.has_permission("Advanced Delete")) 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"
def show_id(request):
return product_info(uuid.UUID(request.matchdict.get("id", None)), request.dbsession)
@router.get("/new") # "Products"
def show_blank(request):
return product_info(None, request.dbsession)
@router.get("/", ) # "Authenticated"
def show_list(l: bool):
list_ = (
request.dbsession.query(Product)
.order_by(desc(Product.is_active))
.order_by(Product.product_group_id)
.order_by(Product.name)
.all()
) )
products = []
for item in list_:
products.append( @router.get("/") # "Products"
def show_blank(
db: Session = Depends(get_db), user: User = Security(get_user, scopes=["products"])
):
return product_info(None, db)
@router.get("/list")
def show_list(db: Session = Depends(get_db), user: User = Depends(get_user)):
return [
{ {
"id": item.id, "id": item.id,
"code": item.code, "code": item.code,
@ -185,27 +150,26 @@ def show_list(l: bool):
"productYield": item.product_yield, "productYield": item.product_yield,
"isFixture": item.is_fixture, "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()
return products ]
@router.get("/") # "Authenticated" @router.get("/query")
async def show_term(t: str): async def show_term(
term = request.GET.get("t", None) t: str = None,
term = term.strip() if term is not None and term.strip() != "" else None a: bool = None,
active = request.GET.get("a", None) c: int = None,
active = active if active is not None else None p: bool = None,
count = request.GET.get("c", None) e: bool = False,
count = None if count is None or count == "" else int(count) db: Session = Depends(get_db),
is_purchased = request.GET.get("p", None) current_user: User = Depends(get_user),
is_purchased = is_purchased if is_purchased is not None else None ):
extended = request.GET.get("e", False) count = c
extended = e
def add_list(query): list_ = []
local_results = [] for index, item in enumerate(Product.query(t, p, a, db)):
for index, item in enumerate(query): list_.append(
if extended: {
product = {
"id": item.id, "id": item.id,
"name": item.full_name, "name": item.full_name,
"price": item.price, "price": item.price,
@ -215,31 +179,25 @@ async def show_term(t: str):
"productYield": item.product_yield, "productYield": item.product_yield,
"isSold": item.is_sold, "isSold": item.is_sold,
"salePrice": item.sale_price, "salePrice": item.sale_price,
} if extended else {
"id": item.id, "name": item.full_name, "price": item.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: if count is not None and index == count - 1:
break break
return local_results return sorted(list_, key=lambda k: k["name"])
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): @router.get("/{id_}")
def show_id(
id_: uuid.UUID,
db: Session = Depends(get_db),
user: User = Security(get_user, scopes=["accounts"]),
):
return product_info(id_, db)
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)

View File

@ -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:
item = ProductGroup(name=data.name)
db.add(item)
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.put("/{id_}", response_model=schemas.ProductGroup)
def update(
id_: uuid.UUID,
data: schemas.ProductGroupIn,
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_fixture: if item.is_fixture:
raise ValidationError( raise HTTPException(
"{0} is a fixture and cannot be edited or deleted.".format(item.name) 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(),
) )
item.name = request.json_body["name"]
transaction.commit()
return product_group_info(item.id, request.dbsession)
@router.delete("/{id}") # "Product Groups" @router.delete("/{id_}")
def delete(request): def delete(
item = ( id_: uuid.UUID,
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:
item = db.query(ProductGroup).filter(ProductGroup.id == id_).first()
if item is None: if item is None:
response = Response("Product Group not Found") raise HTTPException(
response.status_int = 500 status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
return response detail="Product Group not found",
)
elif item.is_fixture: elif item.is_fixture:
raise ValidationError( raise HTTPException(
"{0} is a fixture and cannot be edited or deleted.".format(item.name) status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"{item.name} is a fixture and cannot be edited or deleted.",
) )
else: else:
response = Response("Product Group deletion not implemented") raise HTTPException(
response.status_int = 500 status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
return response detail="Product Group deletion not implemented",
)
except Exception:
@router.get("/{id}") # "Product Groups" db.rollback()
def show_id(request): raise HTTPException(
return product_group_info( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
uuid.UUID(request.matchdict.get("id", None)), request.dbsession detail=traceback.format_exc(),
) )
@router.get("/new") # "Product Groups" @router.get("/")
def show_blank(request): def show_blank(
return product_group_info(None, request.dbsession) db: Session = Depends(get_db),
user: User = Security(get_user, scopes=["product-groups"]),
):
return product_group_info(None, db)
@router.get("/") # "Authenticated" @router.get("/list", response_model=List[schemas.ProductGroup])
async def show_list(l: bool): async def show_list(db: Session = Depends(get_db), user: User = Depends(get_user)):
list_ = request.dbsession.query(ProductGroup).order_by(ProductGroup.name).all() return[
product_groups = []
for item in list_:
product_groups.append(
{"id": item.id, "name": item.name, "isFixture": item.is_fixture} {"id": item.id, "name": item.name, "isFixture": item.is_fixture}
) for item in db.query(ProductGroup).order_by(ProductGroup.name).all()
return product_groups ]
def product_group_info(id_, dbsession): @router.get("/{id_}", response_model=schemas.ProductGroup)
if id_ is None: def show_id(
return {"name": ''} id_: uuid.UUID,
else: db: Session = Depends(get_db),
product_group = ( user: User = Security(get_user, scopes=["product-groups"]),
dbsession.query(ProductGroup).filter(ProductGroup.id == id_).first() ):
) 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:
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,
} }

View File

@ -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'}