Skip to content

Commit

Permalink
Implement productrecommendations
Browse files Browse the repository at this point in the history
  • Loading branch information
viggo-devries committed Feb 23, 2024
1 parent 67446e6 commit 8a0a811
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 10 deletions.
12 changes: 12 additions & 0 deletions oscar_odin/mappings/catalogue.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,13 @@ def stockrecords(

return []

@odin.map_list_field
def recommended_products(self, values):
if values:
return RecommendedProductToModel.apply(values)

return []

@odin.map_field
def product_class(self, value) -> ProductClassModel:
if not value or self.source.structure == ProductModel.CHILD:
Expand All @@ -297,6 +304,11 @@ def product_class(self, value) -> ProductClassModel:
return ProductClassToModel.apply(value)


class RecommendedProductToModel(OscarBaseMapping):
from_obj = resources.catalogue.ProductRecommentation
to_obj = ProductModel


class ParentToModel(OscarBaseMapping):
from_obj = resources.catalogue.ParentProduct
to_obj = ProductModel
Expand Down
30 changes: 20 additions & 10 deletions oscar_odin/mappings/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,21 +278,23 @@ def bulk_update_or_create_many_to_many(self):
m2m_to_create, m2m_to_update, _ = self.get_all_m2m_relations

# Create many to many's
for relation, instances in m2m_to_create.items():
for relation, instances_to_create in m2m_to_create.items():
fields = self.get_fields_to_update(relation.related_model)
if fields is not None:
validated_m2m_instances = self.validate_instances(instances)
relation.related_model.objects.bulk_create(validated_m2m_instances)
if relation.related_model != self.Model:
instances_to_create = self.validate_instances(instances_to_create)
relation.related_model.objects.bulk_create(instances_to_create)

# Update many to many's
for relation, instances in m2m_to_update.items():
for relation, instances_to_update in m2m_to_update.items():
fields = self.get_fields_to_update(relation.related_model)
if fields is not None:
validated_instances_to_update = self.validate_instances(
instances, fields=fields
)
if relation.related_model != self.Model:
instances_to_update = self.validate_instances(
instances_to_update, fields=fields
)
relation.related_model.objects.bulk_update(
validated_instances_to_update, fields=fields
instances_to_update, fields=fields
)

for relation, values in self.many_to_many_items.items():
Expand All @@ -319,7 +321,10 @@ def bulk_update_or_create_many_to_many(self):
# Delete throughs if no instances are passed for the field
if self.delete_related:
Through.objects.filter(
product_id__in=to_delete_throughs_product_ids
**{
"%s_id__in"
% relation.m2m_field_name(): to_delete_throughs_product_ids
}
).all().delete()

if throughs:
Expand All @@ -341,7 +346,12 @@ def bulk_update_or_create_many_to_many(self):
# Delete remaining non-existing through models
if self.delete_related:
Through.objects.filter(
product_id__in=[item[0] for item in bulk_troughs.keys()]
**{
"%s_id__in"
% relation.m2m_field_name(): [
item[0] for item in bulk_troughs.keys()
]
}
).exclude(id__in=bulk_troughs.values()).delete()

# Save only new through models
Expand Down
6 changes: 6 additions & 0 deletions oscar_odin/resources/catalogue.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ class ParentProduct(OscarCatalogue):
upc: str


class ProductRecommentation(OscarCatalogue):
upc: str


class Product(OscarCatalogue):
"""A product within Django Oscar."""

Expand All @@ -111,6 +115,8 @@ class Product(OscarCatalogue):
attributes: Dict[str, Union[Any, None]]
categories: List[Category]

recommended_products: List[ProductRecommentation]

date_created: Optional[datetime]
date_updated: Optional[datetime]

Expand Down
60 changes: 60 additions & 0 deletions tests/reverse/test_catalogue.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
ProductClass as ProductClassResource,
Category as CategoryResource,
ParentProduct as ParentProductResource,
ProductRecommentation as ProductRecommentationResource,
)
from oscar_odin.exceptions import OscarOdinException
from oscar_odin.mappings.constants import (
Expand All @@ -23,6 +24,7 @@
STOCKRECORD_NUM_ALLOCATED,
PRODUCTIMAGE_ORIGINAL,
PRODUCT_TITLE,
PRODUCT_UPC,
PRODUCT_DESCRIPTION,
PRODUCTCLASS_REQUIRESSHIPPING,
)
Expand All @@ -33,6 +35,7 @@
ProductImage = get_model("catalogue", "ProductImage")
Category = get_model("catalogue", "Category")
Partner = get_model("partner", "Partner")
ProductRecommendation = get_model("catalogue", "ProductRecommendation")


class SingleProductReverseTest(TestCase):
Expand Down Expand Up @@ -482,6 +485,63 @@ def test_create_product_with_related_fields(self):
self.assertEqual(prd2.attr.harrie, 1)


class ProductRecommendationTest(TestCase):
def setUp(self):
super().setUp()
ProductClass.objects.create(
name="Klaas", slug="klaas", requires_shipping=True, track_stock=True
)
Partner.objects.create(name="klaas")

def test_recommendation(self):
product_resource = [
ProductResource(
upc="recommended_product1",
title="asdf2",
slug="asdf-asdfasdf2",
description="description",
structure=Product.STANDALONE,
product_class=ProductClassResource(slug="klaas"),
),
ProductResource(
upc="recommended_product2",
title="asdf2",
slug="asdf-asdasdfasdf2",
description="description",
structure=Product.STANDALONE,
product_class=ProductClassResource(slug="klaas"),
),
]

_, errors = products_to_db(product_resource)
self.assertEqual(len(errors), 0)

product_resource = ProductResource(
upc="harses",
title="asdf2",
slug="asdf-asdfas23df2",
description="description",
structure=Product.STANDALONE,
product_class=ProductClassResource(slug="klaas"),
recommended_products=[
ProductRecommentationResource(upc="recommended_product1"),
ProductRecommentationResource(upc="recommended_product2"),
],
)

_, errors = products_to_db(product_resource, fields_to_update=[PRODUCT_UPC])
self.assertEqual(len(errors), 0)

prd = Product.objects.get(upc="harses")

self.assertEquals(ProductRecommendation.objects.count(), 2)
self.assertEquals(prd.recommended_products.count(), 2)
self.assertEquals(
sorted(list(prd.recommended_products.values_list("upc", flat=True))),
sorted(["recommended_product1", "recommended_product2"]),
)


class ParentChildTest(TestCase):
def setUp(self):
super().setUp()
Expand Down

0 comments on commit 8a0a811

Please sign in to comment.