From dba60fdab8ce40c6449d50f274d19026a5a2e8dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Gr=C3=B6ger?= Date: Sun, 14 Nov 2021 19:35:11 +0100 Subject: [PATCH] [pricelist] serverside pagination and filtering for pricelist --- flaschengeist/plugins/pricelist/__init__.py | 40 ++++++++++ flaschengeist/plugins/pricelist/models.py | 16 +++- .../plugins/pricelist/pricelist_controller.py | 80 +++++++++++++++++-- 3 files changed, 127 insertions(+), 9 deletions(-) diff --git a/flaschengeist/plugins/pricelist/__init__.py b/flaschengeist/plugins/pricelist/__init__.py index 5ad57af..68693e8 100644 --- a/flaschengeist/plugins/pricelist/__init__.py +++ b/flaschengeist/plugins/pricelist/__init__.py @@ -242,11 +242,51 @@ def get_drinks(identifier=None): ingredient=ingredient, receipt=receipt, ) + mop = drinks.copy() logger.debug(f"GET drink {drinks}, {count}") # return jsonify({"drinks": drinks, "count": count}) return jsonify({"drinks": drinks, "count": count}) +@PriceListPlugin.blueprint.route("/list", methods=["GET"]) +def get_pricelist(): + """Get Priclist + Route: ``/pricelist/list`` | Method: ``GET`` + + Returns: + JSON encoded list of DrinkPrices or HTTP-KeyError + """ + public = True + try: + extract_session() + public = False + except Unauthorized: + public = True + + limit = request.args.get("limit") + offset = request.args.get("offset") + search_name = request.args.get("search_name") + search_key = request.args.get("search_key") + ingredient = request.args.get("ingredient", type=bool) + receipt = request.args.get("receipt", type=bool) + try: + if limit is not None: + limit = int(limit) + if offset is not None: + offset = int(offset) + if ingredient is not None: + ingredient = bool(ingredient) + if receipt is not None: + receipt = bool(receipt) + except ValueError: + raise BadRequest + pricelist, count = pricelist_controller.get_pricelist( + public=public, limit=limit, offset=offset, search_name=search_name, search_key=search_key + ) + logger.debug(f"GET pricelist {pricelist}, {count}") + return jsonify({"pricelist": pricelist, "count": count}) + + @PriceListPlugin.blueprint.route("/drinks/search/", methods=["GET"]) def search_drinks(name): """Search Drink diff --git a/flaschengeist/plugins/pricelist/models.py b/flaschengeist/plugins/pricelist/models.py index f6d68f9..43cf792 100644 --- a/flaschengeist/plugins/pricelist/models.py +++ b/flaschengeist/plugins/pricelist/models.py @@ -48,7 +48,8 @@ class DrinkPrice(db.Model, ModelSerializeMixin): id: int = db.Column("id", db.Integer, primary_key=True) price: float = db.Column(db.Numeric(precision=5, scale=2, asdecimal=False)) volume_id_ = db.Column("volume_id", db.Integer, db.ForeignKey("drink_price_volume.id")) - volume = db.relationship("DrinkPriceVolume", back_populates="prices") + volume: "DrinkPriceVolume" = None + _volume: "DrinkPriceVolume" = db.relationship("DrinkPriceVolume", back_populates="_prices", join_depth=1) public: bool = db.Column(db.Boolean, default=True) description: Optional[str] = db.Column(db.String(30)) @@ -121,11 +122,15 @@ class DrinkPriceVolume(db.Model, ModelSerializeMixin): __tablename__ = "drink_price_volume" id: int = db.Column("id", db.Integer, primary_key=True) drink_id = db.Column(db.Integer, db.ForeignKey("drink.id")) + drink: "Drink" = None + _drink: "Drink" = db.relationship("Drink", back_populates="_volumes") volume: float = db.Column(db.Numeric(precision=5, scale=2, asdecimal=False)) min_prices: list[MinPrices] = [] # ingredients: list[Ingredient] = [] - - prices: list[DrinkPrice] = db.relationship(DrinkPrice, back_populates="volume", cascade="all,delete,delete-orphan") + prices: list[DrinkPrice] = [] + _prices: list[DrinkPrice] = db.relationship( + DrinkPrice, back_populates="_volume", cascade="all,delete,delete-orphan" + ) ingredients: list[Ingredient] = db.relationship("Ingredient", foreign_keys=Ingredient.volume_id) def __repr__(self): @@ -153,7 +158,10 @@ class Drink(db.Model, ModelSerializeMixin): tags: Optional[list[Tag]] = db.relationship("Tag", secondary=drink_tag_association, cascade="save-update, merge") type: Optional[DrinkType] = db.relationship("DrinkType", foreign_keys=[_type_id]) - volumes: list[DrinkPriceVolume] = db.relationship(DrinkPriceVolume) + volumes: list[DrinkPriceVolume] = [] + _volumes: list[DrinkPriceVolume] = db.relationship( + DrinkPriceVolume, back_populates="_drink", cascade="all,delete,delete-orphan" + ) def __repr__(self): return f"Drink({self.id},{self.name},{self.volumes})" diff --git a/flaschengeist/plugins/pricelist/pricelist_controller.py b/flaschengeist/plugins/pricelist/pricelist_controller.py index 3a441f3..1c5ac35 100644 --- a/flaschengeist/plugins/pricelist/pricelist_controller.py +++ b/flaschengeist/plugins/pricelist/pricelist_controller.py @@ -142,9 +142,9 @@ def get_drinks( if ingredient: query = query.filter(Drink.cost_per_volume >= 0) if receipt: - query = query.filter(Drink.volumes.any(DrinkPriceVolume.ingredients != None)) + query = query.filter(Drink._volumes.any(DrinkPriceVolume.ingredients != None)) if public: - query = query.filter(Drink.volumes.any(DrinkPriceVolume.prices.any(DrinkPrice.public))) + query = query.filter(Drink._volumes.any(DrinkPriceVolume._prices.any(DrinkPrice.public))) if search_name: if search_key == "name": query = query.filter(Drink.name.contains(search_name)) @@ -168,9 +168,72 @@ def get_drinks( if offset is not None: query = query.offset(offset) drinks = query.all() + for drink in drinks: + for volume in drink._volumes: + volume.prices = volume._prices + drink.volumes = drink._volumes + return drinks, count +def get_pricelist(public=False, limit=None, offset=None, search_name=None, search_key=None): + count = None + query = DrinkPrice.query + if public: + query.filter(DrinkPrice.public) + if search_name: + if search_key == "name": + query = query.filter(DrinkPrice._volume.has(DrinkPriceVolume._drink.has(Drink.name.contains(search_name)))) + if search_key == "type": + query = query.filter( + DrinkPrice._volume.has( + DrinkPriceVolume._drink.has(Drink.type.has(DrinkType.name.contains(search_name))) + ) + ) + if search_key == "tags": + query = query.filter( + DrinkPrice._volume.has(DrinkPriceVolume._drink.has(Drink.tags.any(Tag.name.conaitns(search_name)))) + ) + if search_key == "volume": + query = query.filter(DrinkPrice._volume.has(DrinkPriceVolume.volume == float(search_name))) + if search_key == "price": + query = query.filter(DrinkPrice.price == float(search_name)) + if search_key == "description": + query = query.filter(DrinkPrice.description.contains(search_name)) + else: + try: + search_name = float(search_name) + query = query.filter( + (DrinkPrice._volume.has(DrinkPriceVolume.volume == float(search_name))) + | (DrinkPrice.price == float(search_name)) + ) + except: + query = query.filter( + (DrinkPrice._volume.has(DrinkPriceVolume._drink.has(Drink.name.contains(search_name)))) + | ( + DrinkPrice._volume.has( + DrinkPriceVolume._drink.has(Drink.type.has(DrinkType.name.contains(search_name))) + ) + ) + | ( + DrinkPrice._volume.has( + DrinkPriceVolume._drink.has(Drink.tags.any(Tag.name.conaitns(search_name))) + ) + ) + | (DrinkPrice.description.contains(search_name)) + ) + if limit is not None: + count = query.count() + query = query.limit(limit) + if offset is not None: + query = query.offset(offset) + prices = query.all() + for price in prices: + price._volume.drink = price._volume._drink + price.volume = price._volume + return prices, count + + def get_drink(identifier, public=False): drink = None if isinstance(identifier, int): @@ -183,6 +246,9 @@ def get_drink(identifier, public=False): raise NotFound if public: return _create_public_drink(drink) + for volume in drink._volumes: + volume.prices = volume._prices + drink.volumes = drink._volumes return drink @@ -219,11 +285,15 @@ def update_drink(identifier, data): if drink_type: drink.type = drink_type if volumes is not None and session.user_.has_permission(EDIT_VOLUME): - drink.volumes = [] - drink.volumes = set_volumes(volumes) + drink._volumes = [] + drink._volumes = set_volumes(volumes) if len(tags) > 0: drink.tags = tags db.session.commit() + for volume in drink._volumes: + volume.prices = volume._prices + drink.volumes = drink._volumes + return drink except (NotFound, KeyError): raise BadRequest @@ -291,7 +361,7 @@ def set_prices(prices, volume): for _price in prices: price = set_price(_price) _prices.append(price) - volume.prices = _prices + volume._prices = _prices def set_ingredients(ingredients, volume):