diff --git a/flaschengeist/plugins/pricelist/__init__.py b/flaschengeist/plugins/pricelist/__init__.py deleted file mode 100644 index c644ca0..0000000 --- a/flaschengeist/plugins/pricelist/__init__.py +++ /dev/null @@ -1,753 +0,0 @@ -"""Pricelist plugin""" -from flask import Blueprint, jsonify, request -from werkzeug.exceptions import BadRequest, Forbidden, NotFound, Unauthorized - -from flaschengeist import logger -from flaschengeist.controller import userController -from flaschengeist.controller.imageController import send_image, send_thumbnail -from flaschengeist.plugins import Plugin -from flaschengeist.utils.decorators import login_required, extract_session -from flaschengeist.utils.HTTP import no_content - -from . import models -from . import pricelist_controller, permissions - - -class PriceListPlugin(Plugin): - models = models - blueprint = Blueprint("pricelist", __name__, url_prefix="/pricelist") - - def install(self): - self.install_permissions(permissions.permissions) - - def load(self): - config = {"discount": 0} - config.update(config) - - -@PriceListPlugin.blueprint.route("/drink-types", methods=["GET"]) -@PriceListPlugin.blueprint.route("/drink-types/", methods=["GET"]) -def get_drink_types(identifier=None): - """Get DrinkType(s) - - Route: ``/pricelist/drink-types`` | Method: ``GET`` - Route: ``/pricelist/drink-types/`` | Method: ``GET`` - - Args: - identifier: If querying a spicific DrinkType - - Returns: - JSON encoded (list of) DrinkType(s) or HTTP-error - """ - if identifier is None: - result = pricelist_controller.get_drink_types() - else: - result = pricelist_controller.get_drink_type(identifier) - return jsonify(result) - - -@PriceListPlugin.blueprint.route("/drink-types", methods=["POST"]) -@login_required(permission=permissions.CREATE_TYPE) -def new_drink_type(current_session): - """Create new DrinkType - - Route ``/pricelist/drink-types`` | Method: ``POST`` - - POST-data: ``{name: string}`` - - Args: - current_session: Session sent with Authorization Header - - Returns: - JSON encoded DrinkType or HTTP-error - """ - data = request.get_json() - if "name" not in data: - raise BadRequest - drink_type = pricelist_controller.create_drink_type(data["name"]) - return jsonify(drink_type) - - -@PriceListPlugin.blueprint.route("/drink-types/", methods=["PUT"]) -@login_required(permission=permissions.EDIT_TYPE) -def update_drink_type(identifier, current_session): - """Modify DrinkType - - Route ``/pricelist/drink-types/`` | METHOD ``PUT`` - - POST-data: ``{name: string}`` - - Args: - identifier: Identifier of DrinkType - current_session: Session sent with Authorization Header - - Returns: - JSON encoded DrinkType or HTTP-error - """ - data = request.get_json() - if "name" not in data: - raise BadRequest - drink_type = pricelist_controller.rename_drink_type(identifier, data["name"]) - return jsonify(drink_type) - - -@PriceListPlugin.blueprint.route("/drink-types/", methods=["DELETE"]) -@login_required(permission=permissions.DELETE_TYPE) -def delete_drink_type(identifier, current_session): - """Delete DrinkType - - Route: ``/pricelist/drink-types/`` | Method: ``DELETE`` - - Args: - identifier: Identifier of DrinkType - current_session: Session sent with Authorization Header - - Returns: - HTTP-NoContent or HTTP-error - """ - pricelist_controller.delete_drink_type(identifier) - return no_content() - - -@PriceListPlugin.blueprint.route("/tags", methods=["GET"]) -@PriceListPlugin.blueprint.route("/tags/", methods=["GET"]) -def get_tags(identifier=None): - """Get Tag(s) - - Route: ``/pricelist/tags`` | Method: ``GET`` - Route: ``/pricelist/tags/`` | Method: ``GET`` - - Args: - identifier: Identifier of Tag - - Returns: - JSON encoded (list of) Tag(s) or HTTP-error - """ - if identifier: - result = pricelist_controller.get_tag(identifier) - else: - result = pricelist_controller.get_tags() - return jsonify(result) - - -@PriceListPlugin.blueprint.route("/tags", methods=["POST"]) -@login_required(permission=permissions.CREATE_TAG) -def new_tag(current_session): - """Create Tag - - Route: ``/pricelist/tags`` | Method: ``POST`` - - POST-data: ``{name: string, color: string}`` - - Args: - current_session: Session sent with Authorization Header - - Returns: - JSON encoded Tag or HTTP-error - """ - data = request.get_json() - drink_type = pricelist_controller.create_tag(data) - return jsonify(drink_type) - - -@PriceListPlugin.blueprint.route("/tags/", methods=["PUT"]) -@login_required(permission=permissions.EDIT_TAG) -def update_tag(identifier, current_session): - """Modify Tag - - Route: ``/pricelist/tags/`` | Methods: ``PUT`` - - POST-data: ``{name: string, color: string}`` - - Args: - identifier: Identifier of Tag - current_session: Session sent with Authorization Header - - Returns: - JSON encoded Tag or HTTP-error - """ - data = request.get_json() - tag = pricelist_controller.update_tag(identifier, data) - return jsonify(tag) - - -@PriceListPlugin.blueprint.route("/tags/", methods=["DELETE"]) -@login_required(permission=permissions.DELETE_TAG) -def delete_tag(identifier, current_session): - """Delete Tag - - Route: ``/pricelist/tags/`` | Methods: ``DELETE`` - - Args: - identifier: Identifier of Tag - current_session: Session sent with Authorization Header - - Returns: - HTTP-NoContent or HTTP-error - """ - pricelist_controller.delete_tag(identifier) - return no_content() - - -@PriceListPlugin.blueprint.route("/drinks", methods=["GET"]) -@PriceListPlugin.blueprint.route("/drinks/", methods=["GET"]) -def get_drinks(identifier=None): - """Get Drink(s) - - Route: ``/pricelist/drinks`` | Method: ``GET`` - Route: ``/pricelist/drinks/`` | Method: ``GET`` - - Args: - identifier: Identifier of Drink - - Returns: - JSON encoded (list of) Drink(s) or HTTP-error - """ - public = True - try: - extract_session() - public = False - except Unauthorized: - public = True - - if identifier: - result = pricelist_controller.get_drink(identifier, public=public) - return jsonify(result) - else: - 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 - drinks, count = pricelist_controller.get_drinks( - public=public, - limit=limit, - offset=offset, - search_name=search_name, - search_key=search_key, - 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) - descending = request.args.get("descending", type=bool) - sortBy = request.args.get("sortBy") - 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) - if descending is not None: - descending = bool(descending) - except ValueError: - raise BadRequest - pricelist, count = pricelist_controller.get_pricelist( - public=public, - limit=limit, - offset=offset, - search_name=search_name, - search_key=search_key, - descending=descending, - sortBy=sortBy, - ) - 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 - - Route: ``/pricelist/drinks/search/`` | Method: ``GET`` - - Args: - name: Name to search - - Returns: - JSON encoded list of Drinks or HTTP-error - """ - public = True - try: - extract_session() - public = False - except Unauthorized: - public = True - return jsonify(pricelist_controller.get_drinks(name, public=public)) - - -@PriceListPlugin.blueprint.route("/drinks", methods=["POST"]) -@login_required(permission=permissions.CREATE) -def create_drink(current_session): - """Create Drink - - Route: ``/pricelist/drinks`` | Method: ``POST`` - - POST-data : - ``{ - article_id?: string - cost_per_package?: float, - cost_per_volume?: float, - name: string, - package_size?: number, - receipt?: list[string], - tags?: list[Tag], - type: DrinkType, - uuid?: string, - volume?: float, - volumes?: list[ - { - ingredients?: list[{ - id: int - drink_ingredient?: { - ingredient_id: int, - volume: float - }, - extra_ingredient?: { - id: number, - } - }], - prices?: list[ - { - price: float - public: boolean - } - ], - volume: float - } - ] - }`` - - Args: - current_session: Session sent with Authorization Header - - Returns: - JSON encoded Drink or HTTP-error - """ - data = request.get_json() - return jsonify(pricelist_controller.set_drink(data)) - - -@PriceListPlugin.blueprint.route("/drinks/", methods=["PUT"]) -@login_required(permission=permissions.EDIT) -def update_drink(identifier, current_session): - """Modify Drink - - Route: ``/pricelist/drinks/`` | Method: ``PUT`` - - POST-data : - ``{ - article_id?: string - cost_per_package?: float, - cost_per_volume?: float, - name: string, - package_size?: number, - receipt?: list[string], - tags?: list[Tag], - type: DrinkType, - uuid?: string, - volume?: float, - volumes?: list[ - { - ingredients?: list[{ - id: int - drink_ingredient?: { - ingredient_id: int, - volume: float - }, - extra_ingredient?: { - id: number, - } - }], - prices?: list[ - { - price: float - public: boolean - } - ], - volume: float - } - ] - }`` - - Args: - identifier: Identifier of Drink - current_session: Session sent with Authorization Header - - Returns: - JSON encoded Drink or HTTP-error - """ - data = request.get_json() - logger.debug(f"update drink {data}") - return jsonify(pricelist_controller.update_drink(identifier, data)) - - -@PriceListPlugin.blueprint.route("/drinks/", methods=["DELETE"]) -@login_required(permission=permissions.DELETE) -def delete_drink(identifier, current_session): - """Delete Drink - - Route: ``/pricelist/drinks/`` | Method: ``DELETE`` - - Args: - identifier: Identifier of Drink - current_session: Session sent with Authorization Header - - Returns: - HTTP-NoContent or HTTP-error - """ - pricelist_controller.delete_drink(identifier) - return no_content() - - -@PriceListPlugin.blueprint.route("/prices/", methods=["DELETE"]) -@login_required(permission=permissions.DELETE_PRICE) -def delete_price(identifier, current_session): - """Delete Price - - Route: ``/pricelist/prices/`` | Methods: ``DELETE`` - - Args: - identifier: Identiefer of Price - current_session: Session sent with Authorization Header - - Returns: - HTTP-NoContent or HTTP-error - """ - pricelist_controller.delete_price(identifier) - return no_content() - - -@PriceListPlugin.blueprint.route("/volumes/", methods=["DELETE"]) -@login_required(permission=permissions.DELETE_VOLUME) -def delete_volume(identifier, current_session): - """Delete DrinkPriceVolume - - Route: ``/pricelist/volumes/`` | Method: ``DELETE`` - - Args: - identifier: Identifier of DrinkPriceVolume - current_session: Session sent with Authorization Header - - Returns: - HTTP-NoContent or HTTP-error - """ - pricelist_controller.delete_volume(identifier) - return no_content() - - -@PriceListPlugin.blueprint.route("/ingredients/extraIngredients", methods=["GET"]) -@login_required() -def get_extra_ingredients(current_session): - """Get ExtraIngredients - - Route: ``/pricelist/ingredients/extraIngredients`` | Method: ``GET`` - - Args: - current_session: Session sent with Authorization Header - - Returns: - JSON encoded list of ExtraIngredients or HTTP-error - """ - return jsonify(pricelist_controller.get_extra_ingredients()) - - -@PriceListPlugin.blueprint.route("/ingredients/", methods=["DELETE"]) -@login_required(permission=permissions.DELETE_INGREDIENTS_DRINK) -def delete_ingredient(identifier, current_session): - """Delete Ingredient - - Route: ``/pricelist/ingredients/`` | Method: ``DELETE`` - - Args: - identifier: Identifier of Ingredient - current_session: Session sent with Authorization Header - - Returns: - HTTP-NoContent or HTTP-error - """ - pricelist_controller.delete_ingredient(identifier) - return no_content() - - -@PriceListPlugin.blueprint.route("/ingredients/extraIngredients", methods=["POST"]) -@login_required(permission=permissions.EDIT_INGREDIENTS) -def set_extra_ingredient(current_session): - """Create ExtraIngredient - - Route: ``/pricelist/ingredients/extraIngredients`` | Method: ``POST`` - - POST-data: ``{ name: string, price: float }`` - - Args: - current_session: Session sent with Authorization Header - - Returns: - JSON encoded ExtraIngredient or HTTP-error - """ - data = request.get_json() - return jsonify(pricelist_controller.set_extra_ingredient(data)) - - -@PriceListPlugin.blueprint.route("/ingredients/extraIngredients/", methods=["PUT"]) -@login_required(permission=permissions.EDIT_INGREDIENTS) -def update_extra_ingredient(identifier, current_session): - """Modify ExtraIngredient - - Route: ``/pricelist/ingredients/extraIngredients`` | Method: ``PUT`` - - POST-data: ``{ name: string, price: float }`` - - Args: - identifier: Identifier of ExtraIngredient - current_session: Session sent with Authorization Header - - Returns: - JSON encoded ExtraIngredient or HTTP-error - """ - data = request.get_json() - return jsonify(pricelist_controller.update_extra_ingredient(identifier, data)) - - -@PriceListPlugin.blueprint.route("/ingredients/extraIngredients/", methods=["DELETE"]) -@login_required(permission=permissions.DELETE_INGREDIENTS) -def delete_extra_ingredient(identifier, current_session): - """Delete ExtraIngredient - - Route: ``/pricelist/ingredients/extraIngredients`` | Method: ``DELETE`` - - Args: - identifier: Identifier of ExtraIngredient - current_session: Session sent with Authorization Header - - Returns: - HTTP-NoContent or HTTP-error - """ - pricelist_controller.delete_extra_ingredient(identifier) - return no_content() - - -@PriceListPlugin.blueprint.route("/settings/min_prices", methods=["GET"]) -@login_required() -def get_pricelist_settings_min_prices(current_session): - """Get MinPrices - - Route: ``/pricelist/settings/min_prices`` | Method: ``GET`` - - Args: - current_session: Session sent with Authorization Header - - Returns: - JSON encoded list of MinPrices - """ - # TODO: Handle if no prices are set! - try: - min_prices = PriceListPlugin.plugin.get_setting("min_prices") - except KeyError: - min_prices = [] - return jsonify(min_prices) - - -@PriceListPlugin.blueprint.route("/settings/min_prices", methods=["POST"]) -@login_required(permission=permissions.EDIT_MIN_PRICES) -def post_pricelist_settings_min_prices(current_session): - """Create MinPrices - - Route: ``/pricelist/settings/min_prices`` | Method: ``POST`` - - POST-data: ``list[int]`` - - Args: - current_session: Session sent with Authorization Header - - Returns: - HTTP-NoContent or HTTP-error - """ - data = request.get_json() - if not isinstance(data, list) or not all(isinstance(n, int) for n in data): - raise BadRequest - data.sort() - PriceListPlugin.plugin.set_setting("min_prices", data) - return no_content() - - -@PriceListPlugin.blueprint.route("/users//pricecalc_columns", methods=["GET", "PUT"]) -@login_required() -def get_columns(userid, current_session): - """Get pricecalc_columns of an user - - Route: ``/users//pricelist/pricecac_columns`` | Method: ``GET`` or ``PUT`` - POST-data: On ``PUT`` json encoded array of floats - - Args: - userid: Userid identifying the user - current_session: Session sent with Authorization Header - - Returns: - GET: JSON object containing the shortcuts as float array or HTTP error - PUT: HTTP-created or HTTP error - """ - if userid != current_session.user_.userid: - raise Forbidden - - user = userController.get_user(userid) - if request.method == "GET": - return jsonify(user.get_attribute("pricecalc_columns", [])) - else: - data = request.get_json() - if not isinstance(data, list) or not all(isinstance(n, str) for n in data): - raise BadRequest - data.sort(reverse=True) - user.set_attribute("pricecalc_columns", data) - userController.persist() - return no_content() - - -@PriceListPlugin.blueprint.route("/users//pricecalc_columns_order", methods=["GET", "PUT"]) -@login_required() -def get_columns_order(userid, current_session): - """Get pricecalc_columns_order of an user - - Route: ``/users//pricelist/pricecac_columns_order`` | Method: ``GET`` or ``PUT`` - POST-data: On ``PUT`` json encoded array of floats - - Args: - userid: Userid identifying the user - current_session: Session sent with Authorization Header - - Returns: - GET: JSON object containing the shortcuts as object array or HTTP error - PUT: HTTP-created or HTTP error - """ - if userid != current_session.user_.userid: - raise Forbidden - - user = userController.get_user(userid) - if request.method == "GET": - return jsonify(user.get_attribute("pricecalc_columns_order", [])) - else: - data = request.get_json() - if not isinstance(data, list) or not all(isinstance(n, str) for mop in data for n in mop.values()): - raise BadRequest - user.set_attribute("pricecalc_columns_order", data) - userController.persist() - return no_content() - - -@PriceListPlugin.blueprint.route("/users//pricelist", methods=["GET", "PUT"]) -@login_required() -def get_priclist_setting(userid, current_session): - """Get pricelistsetting of an user - - Route: ``/pricelist/user//pricelist`` | Method: ``GET`` or ``PUT`` - - POST-data: on ``PUT`` ``{value: boolean}`` - - Args: - userid: Userid identifying the user - current_session: Session sent wth Authorization Header - - Returns: - GET: JSON object containing the value as boolean or HTTP-error - PUT: HTTP-NoContent or HTTP-error - """ - - if userid != current_session.user_.userid: - raise Forbidden - - user = userController.get_user(userid) - if request.method == "GET": - return jsonify(user.get_attribute("pricelist_view", {"value": False})) - else: - data = request.get_json() - if not isinstance(data, dict) or not "value" in data or not isinstance(data["value"], bool): - raise BadRequest - user.set_attribute("pricelist_view", data) - userController.persist() - return no_content() - - -@PriceListPlugin.blueprint.route("/drinks//picture", methods=["POST", "DELETE"]) -@login_required(permission=permissions.EDIT) -def set_picture(identifier, current_session): - """Get, Create, Delete Drink Picture - - Route: ``/pricelist//picture`` | Method: ``GET,POST,DELETE`` - - POST-data: (if remaining) ``Form-Data: mime: 'image/*'`` - - Args: - identifier: Identifier of Drink - current_session: Session sent with Authorization - - Returns: - Picture or HTTP-error - """ - if request.method == "DELETE": - pricelist_controller.delete_drink_picture(identifier) - return no_content() - - file = request.files.get("file") - if file: - return jsonify(pricelist_controller.save_drink_picture(identifier, file)) - else: - raise BadRequest - - -@PriceListPlugin.blueprint.route("/drinks//picture", methods=["GET"]) -# @headers({"Cache-Control": "private, must-revalidate"}) -def _get_picture(identifier): - """Get Picture - - Args: - identifier: Identifier of Drink - - Returns: - Picture or HTTP-error - """ - drink = pricelist_controller.get_drink(identifier) - if drink.has_image: - if request.args.get("thumbnail"): - return send_thumbnail(image=drink.image_) - return send_image(image=drink.image_) - raise NotFound diff --git a/flaschengeist/plugins/pricelist/migrations/58ab9b6a8839_pricelist_initial.py b/flaschengeist/plugins/pricelist/migrations/58ab9b6a8839_pricelist_initial.py deleted file mode 100644 index 3a6c5ad..0000000 --- a/flaschengeist/plugins/pricelist/migrations/58ab9b6a8839_pricelist_initial.py +++ /dev/null @@ -1,141 +0,0 @@ -"""pricelist: initial - -Revision ID: 58ab9b6a8839 -Revises: -Create Date: 2022-02-23 14:45:30.563647 - -""" -from alembic import op -import sqlalchemy as sa -import flaschengeist - - -# revision identifiers, used by Alembic. -revision = "58ab9b6a8839" -down_revision = None -branch_labels = ("pricelist",) -depends_on = "flaschengeist" - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.create_table( - "drink_extra_ingredient", - sa.Column("id", flaschengeist.models.Serial(), nullable=False), - sa.Column("name", sa.String(length=30), nullable=False), - sa.Column("price", sa.Numeric(precision=5, scale=2, asdecimal=False), nullable=True), - sa.PrimaryKeyConstraint("id", name=op.f("pk_drink_extra_ingredient")), - sa.UniqueConstraint("name", name=op.f("uq_drink_extra_ingredient_name")), - ) - op.create_table( - "drink_tag", - sa.Column("id", flaschengeist.models.Serial(), nullable=False), - sa.Column("name", sa.String(length=30), nullable=False), - sa.Column("color", sa.String(length=7), nullable=False), - sa.PrimaryKeyConstraint("id", name=op.f("pk_drink_tag")), - sa.UniqueConstraint("name", name=op.f("uq_drink_tag_name")), - ) - op.create_table( - "drink_type", - sa.Column("id", flaschengeist.models.Serial(), nullable=False), - sa.Column("name", sa.String(length=30), nullable=False), - sa.PrimaryKeyConstraint("id", name=op.f("pk_drink_type")), - sa.UniqueConstraint("name", name=op.f("uq_drink_type_name")), - ) - op.create_table( - "drink", - sa.Column("id", flaschengeist.models.Serial(), nullable=False), - sa.Column("article_id", sa.String(length=64), nullable=True), - sa.Column("package_size", sa.Integer(), nullable=True), - sa.Column("name", sa.String(length=60), nullable=False), - sa.Column("volume", sa.Numeric(precision=5, scale=2, asdecimal=False), nullable=True), - sa.Column("cost_per_volume", sa.Numeric(precision=5, scale=3, asdecimal=False), nullable=True), - sa.Column("cost_per_package", sa.Numeric(precision=5, scale=3, asdecimal=False), nullable=True), - sa.Column("receipt", sa.PickleType(), nullable=True), - sa.Column("type_id", flaschengeist.models.Serial(), nullable=True), - sa.Column("image_id", flaschengeist.models.Serial(), nullable=True), - sa.ForeignKeyConstraint(["image_id"], ["image.id"], name=op.f("fk_drink_image_id_image")), - sa.ForeignKeyConstraint(["type_id"], ["drink_type.id"], name=op.f("fk_drink_type_id_drink_type")), - sa.PrimaryKeyConstraint("id", name=op.f("pk_drink")), - ) - op.create_table( - "drink_ingredient", - sa.Column("id", flaschengeist.models.Serial(), nullable=False), - sa.Column("volume", sa.Numeric(precision=5, scale=2, asdecimal=False), nullable=False), - sa.Column("ingredient_id", flaschengeist.models.Serial(), nullable=True), - sa.ForeignKeyConstraint(["ingredient_id"], ["drink.id"], name=op.f("fk_drink_ingredient_ingredient_id_drink")), - sa.PrimaryKeyConstraint("id", name=op.f("pk_drink_ingredient")), - ) - op.create_table( - "drink_price_volume", - sa.Column("id", flaschengeist.models.Serial(), nullable=False), - sa.Column("drink_id", flaschengeist.models.Serial(), nullable=True), - sa.Column("volume", sa.Numeric(precision=5, scale=2, asdecimal=False), nullable=True), - sa.ForeignKeyConstraint(["drink_id"], ["drink.id"], name=op.f("fk_drink_price_volume_drink_id_drink")), - sa.PrimaryKeyConstraint("id", name=op.f("pk_drink_price_volume")), - ) - op.create_table( - "drink_x_tag", - sa.Column("drink_id", flaschengeist.models.Serial(), nullable=True), - sa.Column("tag_id", flaschengeist.models.Serial(), nullable=True), - sa.ForeignKeyConstraint(["drink_id"], ["drink.id"], name=op.f("fk_drink_x_tag_drink_id_drink")), - sa.ForeignKeyConstraint(["tag_id"], ["drink_tag.id"], name=op.f("fk_drink_x_tag_tag_id_drink_tag")), - ) - op.create_table( - "drink_x_type", - sa.Column("drink_id", flaschengeist.models.Serial(), nullable=True), - sa.Column("type_id", flaschengeist.models.Serial(), nullable=True), - sa.ForeignKeyConstraint(["drink_id"], ["drink.id"], name=op.f("fk_drink_x_type_drink_id_drink")), - sa.ForeignKeyConstraint(["type_id"], ["drink_type.id"], name=op.f("fk_drink_x_type_type_id_drink_type")), - ) - op.create_table( - "drink_ingredient_association", - sa.Column("id", flaschengeist.models.Serial(), nullable=False), - sa.Column("volume_id", flaschengeist.models.Serial(), nullable=True), - sa.Column("_drink_ingredient_id", flaschengeist.models.Serial(), nullable=True), - sa.Column("_extra_ingredient_id", flaschengeist.models.Serial(), nullable=True), - sa.ForeignKeyConstraint( - ["_drink_ingredient_id"], - ["drink_ingredient.id"], - name=op.f("fk_drink_ingredient_association__drink_ingredient_id_drink_ingredient"), - ), - sa.ForeignKeyConstraint( - ["_extra_ingredient_id"], - ["drink_extra_ingredient.id"], - name=op.f("fk_drink_ingredient_association__extra_ingredient_id_drink_extra_ingredient"), - ), - sa.ForeignKeyConstraint( - ["volume_id"], - ["drink_price_volume.id"], - name=op.f("fk_drink_ingredient_association_volume_id_drink_price_volume"), - ), - sa.PrimaryKeyConstraint("id", name=op.f("pk_drink_ingredient_association")), - ) - op.create_table( - "drink_price", - sa.Column("id", flaschengeist.models.Serial(), nullable=False), - sa.Column("price", sa.Numeric(precision=5, scale=2, asdecimal=False), nullable=True), - sa.Column("volume_id", flaschengeist.models.Serial(), nullable=True), - sa.Column("public", sa.Boolean(), nullable=True), - sa.Column("description", sa.String(length=30), nullable=True), - sa.ForeignKeyConstraint( - ["volume_id"], ["drink_price_volume.id"], name=op.f("fk_drink_price_volume_id_drink_price_volume") - ), - sa.PrimaryKeyConstraint("id", name=op.f("pk_drink_price")), - ) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_table("drink_price") - op.drop_table("drink_ingredient_association") - op.drop_table("drink_x_type") - op.drop_table("drink_x_tag") - op.drop_table("drink_price_volume") - op.drop_table("drink_ingredient") - op.drop_table("drink") - op.drop_table("drink_type") - op.drop_table("drink_tag") - op.drop_table("drink_extra_ingredient") - # ### end Alembic commands ### diff --git a/flaschengeist/plugins/pricelist/models.py b/flaschengeist/plugins/pricelist/models.py deleted file mode 100644 index 1a5335d..0000000 --- a/flaschengeist/plugins/pricelist/models.py +++ /dev/null @@ -1,180 +0,0 @@ -from __future__ import annotations # TODO: Remove if python requirement is >= 3.12 (? PEP 563 is defered) - -from typing import Optional - -from flaschengeist.database import db -from flaschengeist.database.types import ModelSerializeMixin, Serial -from flaschengeist.models import Image - - -drink_tag_association = db.Table( - "drink_x_tag", - db.Column("drink_id", Serial, db.ForeignKey("drink.id")), - db.Column("tag_id", Serial, db.ForeignKey("drink_tag.id")), -) - -drink_type_association = db.Table( - "drink_x_type", - db.Column("drink_id", Serial, db.ForeignKey("drink.id")), - db.Column("type_id", Serial, db.ForeignKey("drink_type.id")), -) - - -class Tag(db.Model, ModelSerializeMixin): - """ - Tag - """ - - __tablename__ = "drink_tag" - id: int = db.Column("id", Serial, primary_key=True) - name: str = db.Column(db.String(30), nullable=False, unique=True) - color: str = db.Column(db.String(7), nullable=False) - - -class DrinkType(db.Model, ModelSerializeMixin): - """ - DrinkType - """ - - __tablename__ = "drink_type" - id: int = db.Column("id", Serial, primary_key=True) - name: str = db.Column(db.String(30), nullable=False, unique=True) - - -class DrinkPrice(db.Model, ModelSerializeMixin): - """ - PriceFromVolume - """ - - __tablename__ = "drink_price" - id: int = db.Column("id", Serial, primary_key=True) - price: float = db.Column(db.Numeric(precision=5, scale=2, asdecimal=False)) - volume_id_ = db.Column("volume_id", Serial, db.ForeignKey("drink_price_volume.id")) - 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)) - - def __repr__(self): - return f"DrinkPric({self.id},{self.price},{self.public},{self.description})" - - -class ExtraIngredient(db.Model, ModelSerializeMixin): - """ - ExtraIngredient - """ - - __tablename__ = "drink_extra_ingredient" - id: int = db.Column("id", Serial, 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" - id: int = db.Column("id", Serial, primary_key=True) - volume: float = db.Column(db.Numeric(precision=5, scale=2, asdecimal=False), nullable=False) - ingredient_id: int = db.Column(Serial, db.ForeignKey("drink.id")) - cost_per_volume: float - name: str - _drink_ingredient: Drink = db.relationship("Drink") - - @property - def cost_per_volume(self): - return self._drink_ingredient.cost_per_volume if self._drink_ingredient else None - - @property - def name(self): - return self._drink_ingredient.name if self._drink_ingredient else None - - -class Ingredient(db.Model, ModelSerializeMixin): - """ - Ingredient Associationtable - """ - - __tablename__ = "drink_ingredient_association" - id: int = db.Column("id", Serial, primary_key=True) - volume_id = db.Column(Serial, db.ForeignKey("drink_price_volume.id")) - drink_ingredient: Optional[DrinkIngredient] = db.relationship(DrinkIngredient, cascade="all,delete") - extra_ingredient: Optional[ExtraIngredient] = db.relationship(ExtraIngredient) - - _drink_ingredient_id = db.Column(Serial, db.ForeignKey("drink_ingredient.id")) - _extra_ingredient_id = db.Column(Serial, db.ForeignKey("drink_extra_ingredient.id")) - - -class MinPrices(ModelSerializeMixin): - """ - MinPrices - """ - - percentage: float - price: float - - -class DrinkPriceVolume(db.Model, ModelSerializeMixin): - """ - Drink Volumes and Prices - """ - - __tablename__ = "drink_price_volume" - id: int = db.Column("id", Serial, primary_key=True) - drink_id = db.Column(Serial, 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] = [] - _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, - cascade="all,delete,delete-orphan", - ) - - def __repr__(self): - return f"DrinkPriceVolume({self.id},{self.drink_id},{self.volume},{self.prices})" - - -class Drink(db.Model, ModelSerializeMixin): - """ - DrinkPrice - """ - - __tablename__ = "drink" - id: int = db.Column("id", Serial, 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) - volume: Optional[float] = db.Column(db.Numeric(precision=5, scale=2, asdecimal=False)) - cost_per_volume: Optional[float] = db.Column(db.Numeric(precision=5, scale=3, asdecimal=False)) - cost_per_package: Optional[float] = db.Column(db.Numeric(precision=5, scale=3, asdecimal=False)) - has_image: bool = False - - receipt: Optional[list[str]] = db.Column(db.PickleType(protocol=4)) - - _type_id = db.Column("type_id", Serial, db.ForeignKey("drink_type.id")) - _image_id = db.Column("image_id", Serial, db.ForeignKey("image.id")) - - image_: Image = db.relationship("Image", cascade="all, delete", foreign_keys=[_image_id]) - - 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] = [] - _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})" - - @property - def has_image(self): - return self.image_ is not None diff --git a/flaschengeist/plugins/pricelist/permissions.py b/flaschengeist/plugins/pricelist/permissions.py deleted file mode 100644 index a94b62b..0000000 --- a/flaschengeist/plugins/pricelist/permissions.py +++ /dev/null @@ -1,37 +0,0 @@ -CREATE = "drink_create" -"""Can create drinks""" - -EDIT = "drink_edit" -"""Can edit drinks""" - -DELETE = "drink_delete" -"""Can delete drinks""" - -CREATE_TAG = "drink_tag_create" -"""Can create and edit Tags""" - -EDIT_PRICE = "edit_price" -DELETE_PRICE = "delete_price" - -EDIT_VOLUME = "edit_volume" -DELETE_VOLUME = "delete_volume" - -EDIT_INGREDIENTS_DRINK = "edit_ingredients_drink" -DELETE_INGREDIENTS_DRINK = "delete_ingredients_drink" - -EDIT_INGREDIENTS = "edit_ingredients" -DELETE_INGREDIENTS = "delete_ingredients" - -EDIT_TAG = "drink_tag_edit" - -DELETE_TAG = "drink_tag_delete" - -CREATE_TYPE = "drink_type_create" - -EDIT_TYPE = "drink_type_edit" - -DELETE_TYPE = "drink_type_delete" - -EDIT_MIN_PRICES = "edit_min_prices" - -permissions = [value for key, value in globals().items() if not key.startswith("_")] diff --git a/flaschengeist/plugins/pricelist/pricelist_controller.py b/flaschengeist/plugins/pricelist/pricelist_controller.py deleted file mode 100644 index 872b412..0000000 --- a/flaschengeist/plugins/pricelist/pricelist_controller.py +++ /dev/null @@ -1,540 +0,0 @@ -from werkzeug.exceptions import BadRequest, NotFound -from sqlalchemy.exc import IntegrityError - -from flaschengeist import logger -from flaschengeist.database import db -from flaschengeist.utils.decorators import extract_session - -from .models import ( - Drink, - DrinkPrice, - Ingredient, - Tag, - DrinkType, - DrinkPriceVolume, - DrinkIngredient, - ExtraIngredient, -) -from .permissions import EDIT_VOLUME, EDIT_PRICE, EDIT_INGREDIENTS_DRINK - -import flaschengeist.controller.imageController as image_controller - - -def update(): - db.session.commit() - - -def get_tags(): - return Tag.query.all() - - -def get_tag(identifier): - if isinstance(identifier, int): - ret = Tag.query.get(identifier) - elif isinstance(identifier, str): - ret = Tag.query.filter(Tag.name == identifier).one_or_none() - else: - logger.debug("Invalid identifier type for Tag") - raise BadRequest - if ret is None: - raise NotFound - return ret - - -def create_tag(data): - try: - if "id" in data: - data.pop("id") - allowed_keys = Tag().serialize().keys() - values = {key: value for key, value in data.items() if key in allowed_keys} - tag = Tag(**values) - db.session.add(tag) - update() - return tag - except IntegrityError: - raise BadRequest("Name already exists") - - -def update_tag(identifier, data): - tag = get_tag(identifier) - allowed_keys = Tag().serialize().keys() - values = {key: value for key, value in data.items() if key in allowed_keys} - for key, value in values.items(): - setattr(tag, key, value) - try: - update() - except IntegrityError: - raise BadRequest("Name already exists") - - -def delete_tag(identifier): - tag = get_tag(identifier) - db.session.delete(tag) - try: - update() - except IntegrityError: - raise BadRequest("Tag still in use") - - -def get_drink_types(): - return DrinkType.query.all() - - -def get_drink_type(identifier): - if isinstance(identifier, int): - ret = DrinkType.query.get(identifier) - elif isinstance(identifier, str): - ret = DrinkType.query.filter(Tag.name == identifier).one_or_none() - else: - logger.debug("Invalid identifier type for DrinkType") - raise BadRequest - if ret is None: - raise NotFound - return ret - - -def create_drink_type(name): - try: - drink_type = DrinkType(name=name) - db.session.add(drink_type) - update() - return drink_type - except IntegrityError: - raise BadRequest("Name already exists") - - -def rename_drink_type(identifier, new_name): - drink_type = get_drink_type(identifier) - drink_type.name = new_name - try: - update() - except IntegrityError: - raise BadRequest("Name already exists") - return drink_type - - -def delete_drink_type(identifier): - drink_type = get_drink_type(identifier) - db.session.delete(drink_type) - try: - update() - except IntegrityError: - raise BadRequest("DrinkType still in use") - - -def _create_public_drink(drink): - _volumes = [] - for volume in drink.volumes: - _prices = [] - for price in volume.prices: - price: DrinkPrice - if price.public: - _prices.append(price) - volume.prices = _prices - if len(volume.prices) > 0: - _volumes.append(volume) - drink.volumes = _volumes - if len(drink.volumes) > 0: - return drink - return None - - -def get_drinks( - name=None, - public=False, - limit=None, - offset=None, - search_name=None, - search_key=None, - ingredient=False, - receipt=None, -): - count = None - if name: - query = Drink.query.filter(Drink.name.contains(name)) - else: - query = Drink.query - if ingredient: - query = query.filter(Drink.cost_per_volume >= 0) - if receipt: - query = query.filter(Drink._volumes.any(DrinkPriceVolume.ingredients != None)) - if 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)) - elif search_key == "article_id": - query = query.filter(Drink.article_id.contains(search_name)) - elif search_key == "drink_type": - query = query.filter(Drink.type.has(DrinkType.name.contains(search_name))) - elif search_key == "tags": - query = query.filter(Drink.tags.any(Tag.name.contains(search_name))) - else: - query = query.filter( - (Drink.name.contains(search_name)) - | (Drink.article_id.contains(search_name)) - | (Drink.type.has(DrinkType.name.contains(search_name))) - | (Drink.tags.any(Tag.name.contains(search_name))) - ) - query = query.order_by(Drink.name.asc()) - - if limit is not None: - count = query.count() - query = query.limit(limit) - 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, - sortBy=None, - descending=False, -): - count = None - query = DrinkPrice.query - if public: - query = 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.contains(search_name))) - ) - ) - | (DrinkPrice.description.contains(search_name)) - ) - if sortBy == "type": - query = ( - query.join(DrinkPrice._volume) - .join(DrinkPriceVolume._drink) - .join(Drink.type) - .order_by(DrinkType.name.desc() if descending else DrinkType.name.asc()) - ) - elif sortBy == "volume": - query = query.join(DrinkPrice._volume).order_by( - DrinkPriceVolume.volume.desc() if descending else DrinkPriceVolume.volume.asc() - ) - elif sortBy == "price": - query = query.order_by(DrinkPrice.price.desc() if descending else DrinkPrice.price.asc()) - else: - query = ( - query.join(DrinkPrice._volume) - .join(DrinkPriceVolume._drink) - .order_by(Drink.name.desc() if descending else Drink.name.asc()) - ) - 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): - drink = Drink.query.get(identifier) - elif isinstance(identifier, str): - drink = Drink.query.filter(Tag.name == identifier).one_or_none() - else: - raise BadRequest("Invalid identifier type for Drink") - if drink is None: - raise NotFound - if public: - return _create_public_drink(drink) - for volume in drink._volumes: - volume.prices = volume._prices - drink.volumes = drink._volumes - return drink - - -def set_drink(data): - return update_drink(-1, data) - - -def update_drink(identifier, data): - try: - session = extract_session() - if "id" in data: - data.pop("id") - volumes = data.pop("volumes") if "volumes" in data else None - tags = [] - if "tags" in data: - _tags = data.pop("tags") - if isinstance(_tags, list): - for _tag in _tags: - if isinstance(_tag, dict) and "id" in _tag: - tags.append(get_tag(_tag["id"])) - drink_type = data.pop("type") - if isinstance(drink_type, dict) and "id" in drink_type: - drink_type = drink_type["id"] - drink_type = get_drink_type(drink_type) - if identifier == -1: - drink = Drink() - db.session.add(drink) - else: - drink = get_drink(identifier) - for key, value in data.items(): - if hasattr(drink, key) and key != "has_image": - setattr(drink, key, value if value != "" else None) - - 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) - 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 - - -def set_volumes(volumes): - retVal = [] - if not isinstance(volumes, list): - raise BadRequest - for volume in volumes: - retVal.append(set_volume(volume)) - return retVal - - -def delete_drink(identifier): - drink = get_drink(identifier) - db.session.delete(drink) - db.session.commit() - - -def get_volume(identifier): - return DrinkPriceVolume.query.get(identifier) - - -def get_volumes(drink_id=None): - if drink_id: - return DrinkPriceVolume.query.filter(DrinkPriceVolume.drink_id == drink_id).all() - return DrinkPriceVolume.query.all() - - -def set_volume(data): - session = extract_session() - allowed_keys = DrinkPriceVolume().serialize().keys() - values = {key: value for key, value in data.items() if key in allowed_keys} - prices = None - ingredients = None - if "prices" in values: - prices = values.pop("prices") - if "ingredients" in values: - ingredients = values.pop("ingredients") - values.pop("id", None) - volume = DrinkPriceVolume(**values) - db.session.add(volume) - - if prices and session.user_.has_permission(EDIT_PRICE): - set_prices(prices, volume) - if ingredients and session.user_.has_permission(EDIT_INGREDIENTS_DRINK): - set_ingredients(ingredients, volume) - return volume - - -def set_prices(prices, volume): - if isinstance(prices, list): - _prices = [] - for _price in prices: - price = set_price(_price) - _prices.append(price) - volume._prices = _prices - - -def set_ingredients(ingredients, volume): - if isinstance(ingredients, list): - _ingredietns = [] - for _ingredient in ingredients: - ingredient = set_ingredient(_ingredient) - _ingredietns.append(ingredient) - volume.ingredients = _ingredietns - - -def delete_volume(identifier): - volume = get_volume(identifier) - db.session.delete(volume) - db.session.commit() - - -def get_price(identifier): - if isinstance(identifier, int): - return DrinkPrice.query.get(identifier) - raise NotFound - - -def get_prices(volume_id=None): - if volume_id: - return DrinkPrice.query.filter(DrinkPrice.volume_id_ == volume_id).all() - return DrinkPrice.query.all() - - -def set_price(data): - allowed_keys = list(DrinkPrice().serialize().keys()) - allowed_keys.append("description") - logger.debug(f"allowed_key {allowed_keys}") - values = {key: value for key, value in data.items() if key in allowed_keys} - values.pop("id", -1) - price = DrinkPrice(**values) - db.session.add(price) - - return price - - -def delete_price(identifier): - price = get_price(identifier) - db.session.delete(price) - db.session.commit() - - -def set_drink_ingredient(data): - allowed_keys = DrinkIngredient().serialize().keys() - values = {key: value for key, value in data.items() if key in allowed_keys} - if "cost_per_volume" in values: - values.pop("cost_per_volume") - if "name" in values: - values.pop("name") - values.pop("id", -1) - drink_ingredient = DrinkIngredient(**values) - db.session.add(drink_ingredient) - return drink_ingredient - - -def get_ingredient(identifier): - return Ingredient.query.get(identifier) - - -def set_ingredient(data): - drink_ingredient_value = None - extra_ingredient_value = None - if "drink_ingredient" in data: - drink_ingredient_value = data.pop("drink_ingredient") - if "extra_ingredient" in data: - extra_ingredient_value = data.pop("extra_ingredient") - data.pop("id", -1) - ingredient = Ingredient(**data) - db.session.add(ingredient) - if drink_ingredient_value: - ingredient.drink_ingredient = set_drink_ingredient(drink_ingredient_value) - if extra_ingredient_value: - if "id" in extra_ingredient_value: - ingredient.extra_ingredient = get_extra_ingredient(extra_ingredient_value.get("id")) - return ingredient - - -def delete_ingredient(identifier): - ingredient = get_ingredient(identifier) - if ingredient.drink_ingredient: - db.session.delete(ingredient.drink_ingredient) - db.session.delete(ingredient) - db.session.commit() - - -def get_extra_ingredients(): - return ExtraIngredient.query.all() - - -def get_extra_ingredient(identifier): - return ExtraIngredient.query.get(identifier) - - -def set_extra_ingredient(data): - allowed_keys = ExtraIngredient().serialize().keys() - if "id" in data: - data.pop("id") - values = {key: value for key, value in data.items() if key in allowed_keys} - extra_ingredient = ExtraIngredient(**values) - db.session.add(extra_ingredient) - db.session.commit() - return extra_ingredient - - -def update_extra_ingredient(identifier, data): - allowed_keys = ExtraIngredient().serialize().keys() - if "id" in data: - data.pop("id") - values = {key: value for key, value in data.items() if key in allowed_keys} - extra_ingredient = get_extra_ingredient(identifier) - if extra_ingredient: - for key, value in values.items(): - setattr(extra_ingredient, key, value) - db.session.commit() - return extra_ingredient - - -def delete_extra_ingredient(identifier): - extra_ingredient = get_extra_ingredient(identifier) - db.session.delete(extra_ingredient) - db.session.commit() - - -def save_drink_picture(identifier, file): - drink = delete_drink_picture(identifier) - drink.image_ = image_controller.upload_image(file) - db.session.commit() - return drink - - -def delete_drink_picture(identifier): - drink = get_drink(identifier) - if drink.image_: - db.session.delete(drink.image_) - drink.image_ = None - db.session.commit() - return drink diff --git a/setup.cfg b/setup.cfg index c911aea..7c51e91 100644 --- a/setup.cfg +++ b/setup.cfg @@ -65,7 +65,6 @@ flaschengeist.plugins = roles = flaschengeist.plugins.roles:RolesPlugin balance = flaschengeist.plugins.balance:BalancePlugin mail = flaschengeist.plugins.message_mail:MailMessagePlugin - pricelist = flaschengeist.plugins.pricelist:PriceListPlugin scheduler = flaschengeist.plugins.scheduler:SchedulerPlugin [bdist_wheel]