diff --git a/src/purchase/forms.py b/src/purchase/forms.py index ff013aa..d73be8a 100644 --- a/src/purchase/forms.py +++ b/src/purchase/forms.py @@ -51,13 +51,19 @@ class BasketForm(forms.ModelForm): def save(self, commit=True): instance: Basket = super().save(commit=True) name: str + products = {product.id: product for product in Product.objects.all()} for name, value in self.cleaned_data.items(): if name.startswith(PREFIX): product_id = int(name.removeprefix(PREFIX)) + product = products[product_id] if value > 0: instance.items.update_or_create( - product_id=product_id, defaults={"quantity": value} + product=product, + defaults={ + "quantity": value, + "unit_price_cents": product.unit_price_cents, + }, ) if value == 0: - instance.items.filter(product_id=product_id).delete() + instance.items.filter(product=product).delete() return instance diff --git a/src/purchase/management/commands/generate_dummy_baskets.py b/src/purchase/management/commands/generate_dummy_baskets.py index a12d146..bad5540 100644 --- a/src/purchase/management/commands/generate_dummy_baskets.py +++ b/src/purchase/management/commands/generate_dummy_baskets.py @@ -41,7 +41,10 @@ class Command(BaseCommand): product = random.choice(products) items.append( BasketItem( - product=product, basket=basket, quantity=random.randint(1, 3) + product=product, + basket=basket, + quantity=random.randint(1, 3), + unit_price_cents=product.unit_price_cents, ) ) BasketItem.objects.bulk_create(items) diff --git a/src/purchase/migrations/0006_basketitem_unit_price_cents.py b/src/purchase/migrations/0006_basketitem_unit_price_cents.py new file mode 100644 index 0000000..08110aa --- /dev/null +++ b/src/purchase/migrations/0006_basketitem_unit_price_cents.py @@ -0,0 +1,35 @@ +# Generated by Django 4.0.4 on 2022-04-27 18:30 + +from django.db import migrations, models + + +def forwards(apps, schema_editor): + BasketItem = apps.get_model("purchase", "BasketItem") + items = ( + BasketItem.objects.using(schema_editor.connection.alias) + .all() + .select_related("product") + ) + for item in items: + item.unit_price_cents = item.product.unit_price_cents + BasketItem.objects.bulk_update(items, ["unit_price_cents"]) + + +class Migration(migrations.Migration): + + dependencies = [ + ("purchase", "0005_alter_basket_options_alter_basketitem_options_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="basketitem", + name="unit_price_cents", + field=models.PositiveIntegerField( + help_text="product's unit price in cents at the time of purchase", + null=True, + verbose_name="unit price (cents)", + ), + ), + migrations.RunPython(forwards, migrations.RunPython.noop), + ] diff --git a/src/purchase/migrations/0007_alter_basketitem_unit_price_cents.py b/src/purchase/migrations/0007_alter_basketitem_unit_price_cents.py new file mode 100644 index 0000000..b30f326 --- /dev/null +++ b/src/purchase/migrations/0007_alter_basketitem_unit_price_cents.py @@ -0,0 +1,21 @@ +# Generated by Django 4.0.4 on 2022-04-27 18:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("purchase", "0006_basketitem_unit_price_cents"), + ] + + operations = [ + migrations.AlterField( + model_name="basketitem", + name="unit_price_cents", + field=models.PositiveIntegerField( + help_text="product's unit price in cents at the time of purchase", + verbose_name="unit price (cents)", + ), + ), + ] diff --git a/src/purchase/models.py b/src/purchase/models.py index c8f6e46..dd4e8fa 100644 --- a/src/purchase/models.py +++ b/src/purchase/models.py @@ -23,7 +23,7 @@ class PaymentMethodQuerySet(models.QuerySet): turnover=Coalesce( Sum( F("baskets__items__quantity") - * F("baskets__items__product__unit_price_cents") + * F("baskets__items__unit_price_cents") ), 0, ) @@ -65,7 +65,8 @@ class ProductQuerySet(models.QuerySet): def with_turnover(self): return self.annotate( turnover=Coalesce( - Sum(F("basket_items__quantity") * F("unit_price_cents")), 0 + Sum(F("basket_items__quantity") * F("basket_items__unit_price_cents")), + 0, ) ) @@ -140,9 +141,7 @@ class Product(Model): class BasketQuerySet(models.QuerySet): def priced(self) -> BasketQuerySet: return self.annotate( - price=Coalesce( - Sum(F("items__quantity") * F("items__product__unit_price_cents")), 0 - ) + price=Coalesce(Sum(F("items__quantity") * F("items__unit_price_cents")), 0) ) def average_basket(self) -> float: @@ -183,9 +182,7 @@ class Basket(Model): class BasketItemQuerySet(models.QuerySet): def priced(self): - return self.annotate( - price=Coalesce(F("quantity") * F("product__unit_price_cents"), 0) - ) + return self.annotate(price=Coalesce(F("quantity") * F("unit_price_cents"), 0)) class BasketItem(Model): @@ -202,6 +199,10 @@ class BasketItem(Model): verbose_name=_("basket"), ) quantity = models.PositiveIntegerField(verbose_name=_("quantity")) + unit_price_cents = models.PositiveIntegerField( + verbose_name=_("unit price (cents)"), + help_text=_("product's unit price in cents at the time of purchase"), + ) objects = BasketItemQuerySet.as_manager()