diff --git a/back/boxtribute_server/business_logic/mobile_distribution/crud.py b/back/boxtribute_server/business_logic/mobile_distribution/crud.py index cee78288fc..40f663da2c 100644 --- a/back/boxtribute_server/business_logic/mobile_distribution/crud.py +++ b/back/boxtribute_server/business_logic/mobile_distribution/crud.py @@ -21,6 +21,7 @@ from ...models.definitions.product import Product from ...models.definitions.size import Size from ...models.definitions.size_range import SizeRange +from ...models.definitions.size_range_size import SizeRangeSize from ...models.definitions.unboxed_items_collection import UnboxedItemsCollection from ...models.utils import utcnow from .exceptions import ( @@ -150,6 +151,7 @@ def set_products_for_packing_list( for product_id in product_ids_to_add: sizes = ( Size.select(Size.id) + .join(SizeRangeSize) .join(SizeRange) .join(Product) .where(Product.id == product_id) diff --git a/back/boxtribute_server/business_logic/warehouse/box/crud.py b/back/boxtribute_server/business_logic/warehouse/box/crud.py index b20033e84a..894923ca7e 100644 --- a/back/boxtribute_server/business_logic/warehouse/box/crud.py +++ b/back/boxtribute_server/business_logic/warehouse/box/crud.py @@ -45,6 +45,7 @@ from ....models.definitions.product import Product from ....models.definitions.qr_code import QrCode from ....models.definitions.size import Size +from ....models.definitions.size_range_size import SizeRangeSize from ....models.definitions.tags_relation import TagsRelation from ....models.definitions.unit import Unit from ....models.utils import ( @@ -693,18 +694,21 @@ def create_boxes(*, user_id, data): sanitized_data, all_tag_ids = sanitize_input(data, new_tag_ids) # Build look-ups for products and their sizes - all_sizes = ( - Product.select(Product.id, Product.size_range, Size.id, Size.label) - .left_outer_join(Size, on=(Product.size_range == Size.size_range)) - .where(Product.id << product_ids) + product_rows = list( + Product.select(Product.id, Product.size_range).where(Product.id << product_ids) ) - sizes_for_product = defaultdict(dict) - products = {} - for row in all_sizes: - products[row.id] = row - size = getattr(row, "size", None) - if size is not None: - sizes_for_product[row.id][size.label.lower()] = size.id + products = {p.id: p for p in product_rows} + size_range_ids = {p.size_range_id for p in product_rows if p.size_range_id} + sizes_for_size_range = defaultdict(dict) + for srs in ( + SizeRangeSize.select(SizeRangeSize.size_range, Size.id, Size.label) + .join(Size) + .where(SizeRangeSize.size_range << size_range_ids) + ): + sizes_for_size_range[srs.size_range_id][srs.size.label.lower()] = srs.size_id + sizes_for_product = { + p.id: sizes_for_size_range.get(p.size_range_id, {}) for p in product_rows + } # Prepare units look-up units = {u.symbol: u for u in Unit.select()} diff --git a/back/boxtribute_server/cron/data_faking.py b/back/boxtribute_server/cron/data_faking.py index d894fc2da0..4870124bf2 100644 --- a/back/boxtribute_server/cron/data_faking.py +++ b/back/boxtribute_server/cron/data_faking.py @@ -62,6 +62,8 @@ from ..models.definitions.product import Product from ..models.definitions.qr_code import QrCode from ..models.definitions.size import Size +from ..models.definitions.size_range import SizeRange +from ..models.definitions.size_range_size import SizeRangeSize from ..models.definitions.standard_product import StandardProduct from ..models.definitions.tag import Tag from ..models.definitions.transfer_agreement import TransferAgreement @@ -750,9 +752,11 @@ def _generate_boxes(self): Product.category, fn.GROUP_CONCAT(Size.id).python_value(convert_ids).alias("size_ids"), ) + .join(SizeRangeSize) + .join(SizeRange) .join( Product, - on=(Product.size_range == Size.size_range), + on=(Product.size_range == SizeRange.id), ) .group_by(Product.category) .namedtuples() diff --git a/back/boxtribute_server/graph_ql/loaders.py b/back/boxtribute_server/graph_ql/loaders.py index 2073014c38..9211706028 100644 --- a/back/boxtribute_server/graph_ql/loaders.py +++ b/back/boxtribute_server/graph_ql/loaders.py @@ -24,6 +24,7 @@ from ..models.definitions.shipment_detail import ShipmentDetail from ..models.definitions.size import Size from ..models.definitions.size_range import SizeRange +from ..models.definitions.size_range_size import SizeRangeSize from ..models.definitions.standard_product import StandardProduct from ..models.definitions.tag import Tag from ..models.definitions.tags_relation import TagsRelation @@ -606,8 +607,8 @@ async def batch_load_fn(self, keys): authorize(permission="size:read") # Mapping of size range ID to list of sizes sizes = defaultdict(list) - for size in Size.select(): - sizes[size.size_range_id].append(size) + for srs in SizeRangeSize.select(SizeRangeSize, Size).join(Size): + sizes[srs.size_range_id].append(srs.size) # Keys are in fact size range IDs. Return empty list if size range has no sizes return [sizes.get(i, []) for i in keys] diff --git a/back/boxtribute_server/models/__init__.py b/back/boxtribute_server/models/__init__.py index a5cbd4b269..7278af757d 100644 --- a/back/boxtribute_server/models/__init__.py +++ b/back/boxtribute_server/models/__init__.py @@ -25,6 +25,7 @@ from .definitions.shipment_detail import ShipmentDetail from .definitions.size import Size from .definitions.size_range import SizeRange +from .definitions.size_range_size import SizeRangeSize from .definitions.standard_product import StandardProduct from .definitions.tag import Tag from .definitions.tags_relation import TagsRelation @@ -71,6 +72,7 @@ ShipmentDetail, Size, SizeRange, + SizeRangeSize, StandardProduct, Tag, TagsRelation, diff --git a/back/boxtribute_server/models/definitions/size.py b/back/boxtribute_server/models/definitions/size.py index a7fd4554c9..370a950fc1 100644 --- a/back/boxtribute_server/models/definitions/size.py +++ b/back/boxtribute_server/models/definitions/size.py @@ -1,8 +1,7 @@ -from peewee import CharField, DateTimeField, IntegerField +from peewee import CharField, DateTimeField from ..fields import UIntForeignKeyField from . import Model -from .size_range import SizeRange from .user import User @@ -26,15 +25,6 @@ class Size(Model): on_delete="SET NULL", on_update="CASCADE", ) - seq = IntegerField(null=True) - size_range = UIntForeignKeyField( - column_name="sizegroup_id", - field="id", - model=SizeRange, - null=True, - on_update="CASCADE", - object_id_name="size_range_id", - ) class Meta: table_name = "sizes" diff --git a/back/boxtribute_server/models/definitions/size_range_size.py b/back/boxtribute_server/models/definitions/size_range_size.py new file mode 100644 index 0000000000..4500139f46 --- /dev/null +++ b/back/boxtribute_server/models/definitions/size_range_size.py @@ -0,0 +1,29 @@ +from peewee import CompositeKey + +from ..fields import UIntForeignKeyField +from . import Model +from .size import Size +from .size_range import SizeRange + + +class SizeRangeSize(Model): + size = UIntForeignKeyField( + column_name="size_id", + field="id", + model=Size, + object_id_name="size_id", + on_delete="CASCADE", + on_update="CASCADE", + ) + size_range = UIntForeignKeyField( + column_name="sizegroup_id", + field="id", + model=SizeRange, + object_id_name="size_range_id", + on_delete="CASCADE", + on_update="CASCADE", + ) + + class Meta: + table_name = "sizes_sizegroup" + primary_key = CompositeKey("size", "size_range") diff --git a/back/test/data/__init__.py b/back/test/data/__init__.py index 0e45c73777..d6c3bb21b6 100644 --- a/back/test/data/__init__.py +++ b/back/test/data/__init__.py @@ -257,6 +257,7 @@ "product", "size", "unit", + "size_range_size", "box", "beneficiary", "transfer_agreement", diff --git a/back/test/data/size.py b/back/test/data/size.py index d8090600da..deb1b2fe3c 100644 --- a/back/test/data/size.py +++ b/back/test/data/size.py @@ -1,19 +1,17 @@ import pytest from boxtribute_server.models.definitions.size import Size -from .size_range import data as size_range_data - def default_size_data(): - return {"id": 1, "label": "small", "size_range": size_range_data()[0]["id"]} + return {"id": 1, "label": "small"} def another_size_data(): - return {"id": 2, "label": "medium", "size_range": size_range_data()[0]["id"]} + return {"id": 2, "label": "medium"} def mixed_size_data(): - return {"id": 3, "label": "Mixed", "size_range": size_range_data()[0]["id"]} + return {"id": 3, "label": "Mixed"} @pytest.fixture diff --git a/back/test/data/size_range_size.py b/back/test/data/size_range_size.py new file mode 100644 index 0000000000..4e10228a16 --- /dev/null +++ b/back/test/data/size_range_size.py @@ -0,0 +1,17 @@ +from boxtribute_server.models.definitions.size_range_size import SizeRangeSize + +from .size import another_size_data, default_size_data, mixed_size_data +from .size_range import data as size_range_data + + +def data(): + size_range_id = size_range_data()[0]["id"] + return [ + {"size": default_size_data()["id"], "size_range": size_range_id}, + {"size": another_size_data()["id"], "size_range": size_range_id}, + {"size": mixed_size_data()["id"], "size_range": size_range_id}, + ] + + +def create(): + SizeRangeSize.insert_many(data()).execute()