[pricelist] break api, new model
This commit is contained in:
parent
919a31bede
commit
df1610557f
|
@ -124,4 +124,32 @@ def create_drink(current_session):
|
||||||
item in data for item in ["name", "ingredients"]
|
item in data for item in ["name", "ingredients"]
|
||||||
):
|
):
|
||||||
raise BadRequest("No correct Keys to create drink")
|
raise BadRequest("No correct Keys to create drink")
|
||||||
return jsonify(pricelist_controller.create_drink(data))
|
return "jsonify(pricelist_controller.create_drink(data))"
|
||||||
|
|
||||||
|
|
||||||
|
@pricelist_bp.route("/prices", methods=["GET"])
|
||||||
|
@pricelist_bp.route("/prices/<int:identifier>", methods=["GET"])
|
||||||
|
def get_prices(identifier=None):
|
||||||
|
if identifier:
|
||||||
|
result = pricelist_controller.get_price(identifier)
|
||||||
|
else:
|
||||||
|
result = pricelist_controller.get_prices()
|
||||||
|
return jsonify(result)
|
||||||
|
|
||||||
|
|
||||||
|
@pricelist_bp.route("/prices/volumes/<int:identifier>", methods=["POST"])
|
||||||
|
def create_price(identifier):
|
||||||
|
data = request.get_json()
|
||||||
|
return jsonify(pricelist_controller.set_price(identifier, data))
|
||||||
|
|
||||||
|
|
||||||
|
@pricelist_bp.route("/prices/<int:identifier>", methods=["PUT"])
|
||||||
|
def modify_price(identifier):
|
||||||
|
data = request.get_json()
|
||||||
|
return jsonify(pricelist_controller.update_price(identifier, data))
|
||||||
|
|
||||||
|
|
||||||
|
@pricelist_bp.route("/prices/<int:identifier>", methods=["DELETE"])
|
||||||
|
def delete_price(identifier):
|
||||||
|
pricelist_controller.delete_price(identifier)
|
||||||
|
return NO_CONTENT
|
||||||
|
|
|
@ -43,28 +43,78 @@ class DrinkPrice(db.Model, ModelSerializeMixin):
|
||||||
|
|
||||||
__tablename__ = "drink_price"
|
__tablename__ = "drink_price"
|
||||||
id: int = db.Column("id", db.Integer, primary_key=True)
|
id: int = db.Column("id", db.Integer, primary_key=True)
|
||||||
volume: float = db.Column(db.Numeric(precision=5, scale=2, asdecimal=False), nullable=False)
|
|
||||||
price: float = db.Column(db.Numeric(precision=5, scale=2, asdecimal=False))
|
price: float = db.Column(db.Numeric(precision=5, scale=2, asdecimal=False))
|
||||||
drink_id = db.Column("drink_id", db.Integer, db.ForeignKey("drink.id"))
|
volume_id_ = db.Column("volume_id", db.Integer, db.ForeignKey("drink_price_volume.id"))
|
||||||
drink = db.relationship("Drink", back_populates="prices")
|
volume = db.relationship("DrinkPriceVolume", back_populates="prices")
|
||||||
no_auto: bool = db.Column(db.Boolean, default=False)
|
|
||||||
public: bool = db.Column(db.Boolean, default=True)
|
public: bool = db.Column(db.Boolean, default=True)
|
||||||
description: Optional[str] = db.Column(db.String(30))
|
description: Optional[str] = db.Column(db.String(30))
|
||||||
round_step: float = db.Column(db.Numeric(precision=3, scale=2, asdecimal=False), nullable=False, default=0.5)
|
|
||||||
|
|
||||||
|
|
||||||
class Ingredient(db.Model, ModelSerializeMixin):
|
class ExtraIngredient(db.Model, ModelSerializeMixin):
|
||||||
"""
|
"""
|
||||||
Drink Build
|
ExtraIngredient
|
||||||
|
"""
|
||||||
|
|
||||||
|
__tablename__ = "extra_ingredient"
|
||||||
|
id: int = db.Column("id", db.Integer, primary_key=True)
|
||||||
|
name: str = db.Column(db.String(30), unique=True, nullable=False)
|
||||||
|
price: float = db.Column(db.Numeric(precision=5, scale=2, asdecimal=False))
|
||||||
|
|
||||||
|
|
||||||
|
class DrinkIngredient(db.Model, ModelSerializeMixin):
|
||||||
|
"""
|
||||||
|
Drink Ingredient
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__tablename__ = "drink_ingredient"
|
__tablename__ = "drink_ingredient"
|
||||||
id: int = db.Column("id", db.Integer, primary_key=True)
|
id: int = db.Column("id", db.Integer, primary_key=True)
|
||||||
volume: float = db.Column(db.Numeric(precision=5, scale=2, asdecimal=False), nullable=False)
|
volume: float = db.Column(db.Numeric(precision=5, scale=2, asdecimal=False), nullable=False)
|
||||||
drink_parent_id: int = db.Column("drink_parent_id", db.Integer, db.ForeignKey("drink.id"))
|
|
||||||
drink_parent = db.relationship("Drink", foreign_keys=drink_parent_id)
|
|
||||||
drink_ingredient_id: int = db.Column("drink_ingredient_id", db.Integer, db.ForeignKey("drink.id"))
|
drink_ingredient_id: int = db.Column("drink_ingredient_id", db.Integer, db.ForeignKey("drink.id"))
|
||||||
drink_ingredient: "Drink" = db.relationship("Drink", foreign_keys=drink_ingredient_id)
|
drink_ingredient: "Drink" = db.relationship("Drink")
|
||||||
|
price: float = 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def price(self):
|
||||||
|
return self.drink_ingredient.cost_price_pro_volume * self.volume
|
||||||
|
|
||||||
|
|
||||||
|
class Ingredient(db.Model, ModelSerializeMixin):
|
||||||
|
"""
|
||||||
|
Ingredient Associationtable
|
||||||
|
"""
|
||||||
|
|
||||||
|
__tablename__ = "ingredient_association"
|
||||||
|
id: int = db.Column("id", db.Integer, primary_key=True)
|
||||||
|
volume_id: int = db.Column(db.Integer, db.ForeignKey("drink_price_volume.id"))
|
||||||
|
drink_ingredient_id = db.Column(db.Integer, db.ForeignKey("drink_ingredient.id"))
|
||||||
|
drink_ingredient: DrinkIngredient = db.relationship(DrinkIngredient)
|
||||||
|
extra_ingredient_id = db.Column(db.Integer, db.ForeignKey("extra_ingredient.id"))
|
||||||
|
extra_ingredient: ExtraIngredient = db.relationship(ExtraIngredient)
|
||||||
|
|
||||||
|
|
||||||
|
class DrinkPriceVolume(db.Model, ModelSerializeMixin):
|
||||||
|
"""
|
||||||
|
Drink Volumes and Prices
|
||||||
|
"""
|
||||||
|
|
||||||
|
__tablename__ = "drink_price_volume"
|
||||||
|
id: int = db.Column("id", db.Integer, primary_key=True)
|
||||||
|
volume: float = db.Column(db.Numeric(precision=5, scale=2, asdecimal=False))
|
||||||
|
prices: [DrinkPrice] = db.relationship(DrinkPrice, back_populates="volume", cascade="all,delete,delete-orphan")
|
||||||
|
ingredients: [DrinkIngredient or ExtraIngredient] = []
|
||||||
|
_ingredients: [Ingredient] = db.relationship("Ingredient", foreign_keys=Ingredient.volume_id)
|
||||||
|
|
||||||
|
drink_id = db.Column(db.Integer, db.ForeignKey("drink.id"), nullable=False)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ingredients(self):
|
||||||
|
retVal = []
|
||||||
|
for ingredient in self._ingredients:
|
||||||
|
if ingredient.drink_ingredient_id != None:
|
||||||
|
retVal.append(ingredient.drink_ingredient)
|
||||||
|
if ingredient.extra_ingredient_id != None:
|
||||||
|
retVal.append(ingredient.extra_ingredient)
|
||||||
|
return retVal
|
||||||
|
|
||||||
|
|
||||||
class Drink(db.Model, ModelSerializeMixin):
|
class Drink(db.Model, ModelSerializeMixin):
|
||||||
|
@ -74,17 +124,15 @@ class Drink(db.Model, ModelSerializeMixin):
|
||||||
|
|
||||||
__tablename__ = "drink"
|
__tablename__ = "drink"
|
||||||
id: int = db.Column("id", db.Integer, primary_key=True)
|
id: int = db.Column("id", db.Integer, primary_key=True)
|
||||||
|
article_id: Optional[str] = db.Column(db.String(64))
|
||||||
|
package_size: Optional[int] = db.Column(db.Integer)
|
||||||
name: str = db.Column(db.String(60), nullable=False)
|
name: str = db.Column(db.String(60), nullable=False)
|
||||||
volume: float = db.Column(db.Numeric(precision=5, scale=2, asdecimal=False))
|
volume: Optional[float] = db.Column(db.Numeric(precision=5, scale=2, asdecimal=False))
|
||||||
cost_price: float = db.Column(db.Numeric(precision=5, scale=2, asdecimal=False))
|
cost_price_pro_volume: Optional[float] = db.Column(db.Numeric(precision=5, scale=3, asdecimal=False))
|
||||||
discount: float = db.Column(db.Numeric(precision=3, scale=2, asdecimal=False), nullable=False)
|
cost_price_package_netto: Optional[float] = db.Column(db.Numeric(precision=5, scale=3, asdecimal=False))
|
||||||
extra_charge: Optional[float] = db.Column(db.Numeric(precision=3, scale=2, asdecimal=False), default=0)
|
|
||||||
prices: [DrinkPrice] = db.relationship(
|
|
||||||
"DrinkPrice", back_populates="drink", cascade="all,delete,delete-orphan", order_by=[DrinkPrice.volume]
|
|
||||||
)
|
|
||||||
ingredients: [Ingredient] = db.relationship(
|
|
||||||
"Ingredient", back_populates="drink_parent", foreign_keys=Ingredient.drink_parent_id
|
|
||||||
)
|
|
||||||
tags: [Optional[Tag]] = db.relationship("Tag", secondary=drink_tag_association, cascade="save-update, merge")
|
tags: [Optional[Tag]] = db.relationship("Tag", secondary=drink_tag_association, cascade="save-update, merge")
|
||||||
type_id_ = db.Column("type_id", db.Integer, db.ForeignKey("drink_type.id"))
|
type_id_ = db.Column("type_id", db.Integer, db.ForeignKey("drink_type.id"))
|
||||||
type = db.relationship("DrinkType")
|
type: DrinkType = db.relationship("DrinkType")
|
||||||
|
|
||||||
|
volumes: [DrinkPriceVolume] = db.relationship(DrinkPriceVolume)
|
||||||
|
|
|
@ -3,7 +3,7 @@ from sqlalchemy.exc import IntegrityError
|
||||||
|
|
||||||
from flaschengeist import logger
|
from flaschengeist import logger
|
||||||
from flaschengeist.database import db
|
from flaschengeist.database import db
|
||||||
from .models import Drink, DrinkPrice, Ingredient, Tag, DrinkType
|
from .models import Drink, DrinkPrice, Ingredient, Tag, DrinkType, DrinkPriceVolume, DrinkIngredient, ExtraIngredient
|
||||||
|
|
||||||
from math import ceil
|
from math import ceil
|
||||||
|
|
||||||
|
@ -103,56 +103,6 @@ def delete_drink_type(identifier):
|
||||||
raise BadRequest("DrinkType still in use")
|
raise BadRequest("DrinkType still in use")
|
||||||
|
|
||||||
|
|
||||||
def round_price(price, round_step):
|
|
||||||
return round(ceil(float(price) / round_step) * round_step * 100) / 100
|
|
||||||
|
|
||||||
|
|
||||||
def calc_prices(drink, prices):
|
|
||||||
retVal = []
|
|
||||||
if len(drink.ingredients) > 0:
|
|
||||||
return calc_price_by_ingredients(drink, prices)
|
|
||||||
allowed_keys = DrinkPrice().serialize().keys()
|
|
||||||
for price in prices:
|
|
||||||
values = {key: value for key, value in price.items() if key in allowed_keys}
|
|
||||||
if values.get("no_auto"):
|
|
||||||
retVal.append(DrinkPrice(**values))
|
|
||||||
else:
|
|
||||||
volume = float(values.pop("volume"))
|
|
||||||
if "price" in values:
|
|
||||||
values.pop("price")
|
|
||||||
_price = float(drink.cost_price) / float(drink.volume) * volume
|
|
||||||
_price += _price * float(drink.discount)
|
|
||||||
if drink.extra_charge:
|
|
||||||
_price += float(drink.extra_charge)
|
|
||||||
_price = round_price(_price, float(price.get("round_step")))
|
|
||||||
retVal.append(DrinkPrice(volume=volume, price=_price, **values))
|
|
||||||
return retVal
|
|
||||||
|
|
||||||
|
|
||||||
def calc_price_by_ingredients(drink, prices):
|
|
||||||
allowed_keys = DrinkPrice().serialize().keys()
|
|
||||||
retVal = []
|
|
||||||
for price in prices:
|
|
||||||
values = {key: value for key, value in price.items() if key in allowed_keys}
|
|
||||||
if values.get("no_auto"):
|
|
||||||
retVal.append(DrinkPrice(**values))
|
|
||||||
else:
|
|
||||||
volume = float(values.pop("volume"))
|
|
||||||
if "price" in values:
|
|
||||||
values.pop("price")
|
|
||||||
_price = 0
|
|
||||||
for ingredient in drink.ingredients:
|
|
||||||
_price = (
|
|
||||||
float(ingredient.drink_ingredient.cost_price)
|
|
||||||
/ float(ingredient.drink_ingredient.volume)
|
|
||||||
* float(ingredient.volume)
|
|
||||||
)
|
|
||||||
_price += _price * float(drink.discount) + float(drink.extra_charge)
|
|
||||||
_price = round_price(_price, price.get("round_step"))
|
|
||||||
retVal.append(DrinkPrice(volume=volume, price=_price, **values))
|
|
||||||
return retVal
|
|
||||||
|
|
||||||
|
|
||||||
def get_drinks(name=None):
|
def get_drinks(name=None):
|
||||||
if name:
|
if name:
|
||||||
return Drink.query.filter(Drink.name.contains(name)).all()
|
return Drink.query.filter(Drink.name.contains(name)).all()
|
||||||
|
@ -161,49 +111,57 @@ def get_drinks(name=None):
|
||||||
|
|
||||||
def get_drink(identifier):
|
def get_drink(identifier):
|
||||||
if isinstance(identifier, int):
|
if isinstance(identifier, int):
|
||||||
retVal = Drink.query.get(identifier)
|
return Drink.query.get(identifier)
|
||||||
elif isinstance(identifier, str):
|
elif isinstance(identifier, str):
|
||||||
retVal = Drink.query.filter(Tag.name == identifier).one_or_none()
|
return Drink.query.filter(Tag.name == identifier).one_or_none()
|
||||||
else:
|
else:
|
||||||
logger.debug("Invalid identifier type for Drink")
|
logger.debug("Invalid identifier type for Drink")
|
||||||
raise BadRequest
|
raise BadRequest
|
||||||
if not retVal:
|
raise NotFound
|
||||||
raise NotFound
|
|
||||||
return retVal
|
|
||||||
|
|
||||||
|
|
||||||
def add_prices(drink, prices):
|
def get_volume(identifier):
|
||||||
for price in prices:
|
return DrinkPriceVolume.query.get(identifier)
|
||||||
drink.prices.append(price)
|
|
||||||
|
|
||||||
|
|
||||||
def add_ingredients(drink, ingredients):
|
def get_price(identifier):
|
||||||
for identifier, volume in ingredients:
|
if isinstance(identifier, int):
|
||||||
ingredient = Ingredient(volume=volume, drink_ingredient=get_drink(identifier))
|
return DrinkPrice.query.get(identifier)
|
||||||
drink.ingredients.append(ingredient)
|
raise NotFound
|
||||||
|
|
||||||
|
|
||||||
def create_drink(data):
|
def get_prices(volume_id=None):
|
||||||
allowed_keys = Drink().serialize().keys()
|
if volume_id:
|
||||||
|
return DrinkPrice.query.filter(DrinkPrice.volume_id_ == volume_id).all()
|
||||||
|
return DrinkPrice.query.all()
|
||||||
|
|
||||||
|
|
||||||
|
def set_price(identifier, data):
|
||||||
|
allowed_keys = DrinkPrice().serialize().keys()
|
||||||
values = {key: value for key, value in data.items() if key in allowed_keys}
|
values = {key: value for key, value in data.items() if key in allowed_keys}
|
||||||
prices = values.pop("prices", [])
|
price = DrinkPrice(**values)
|
||||||
ingredients = values.pop("ingredients", [])
|
volume = get_volume(identifier)
|
||||||
if "id" in values:
|
if not volume:
|
||||||
values.pop("id")
|
raise BadRequest
|
||||||
|
volume.prices.append(price)
|
||||||
drink = Drink(**values)
|
db.session.add(price)
|
||||||
add_ingredients(drink, ingredients)
|
db.session.commit()
|
||||||
drink.prices = calc_prices(drink, prices)
|
return price
|
||||||
db.session.add(drink)
|
|
||||||
update()
|
|
||||||
return drink
|
|
||||||
|
|
||||||
|
|
||||||
def delete_drink(identifier):
|
def update_price(identifier, data):
|
||||||
drink = get_drink(identifier)
|
allowed_keys = DrinkPrice().serialize().keys()
|
||||||
for price in drink.prices:
|
if "id" in data:
|
||||||
db.session.delete(price)
|
data.pop("id")
|
||||||
for ingredient in drink.ingredients:
|
values = {key: value for key, value in data.items() if key in allowed_keys}
|
||||||
db.session.delete(ingredient)
|
price = get_price(identifier)
|
||||||
db.session.delete(drink)
|
for key, value in values:
|
||||||
update()
|
setattr(price, key, value)
|
||||||
|
db.session.commit()
|
||||||
|
return price
|
||||||
|
|
||||||
|
|
||||||
|
def delete_price(identifier):
|
||||||
|
price = get_price(identifier)
|
||||||
|
db.session.delete(price)
|
||||||
|
db.session.commit()
|
||||||
|
|
Loading…
Reference in New Issue