[pricelist] break api, new model

This commit is contained in:
Tim Gröger 2021-03-15 19:56:51 +01:00
parent 919a31bede
commit df1610557f
3 changed files with 140 additions and 106 deletions

View File

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

View File

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

View File

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