sforkowany z mtyton/comfy
Merge remote-tracking branch 'upstream/main'
commit
1ad080d9a0
|
@ -143,3 +143,4 @@ artel/static/
|
||||||
|
|
||||||
# media
|
# media
|
||||||
artel/media/*
|
artel/media/*
|
||||||
|
artel/store/data/*
|
||||||
|
|
|
@ -20,8 +20,8 @@ class ProductCategoryAdmin(ModelAdmin):
|
||||||
list_display = ("name", )
|
list_display = ("name", )
|
||||||
|
|
||||||
|
|
||||||
class ProductCategoryParamAdmin(ModelAdmin):
|
class ProductTemplateParamAdmin(ModelAdmin):
|
||||||
model = models.ProductCategoryParam
|
model = models.ProductTemplateParam
|
||||||
list_display = ("key", "param_type")
|
list_display = ("key", "param_type")
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ class StoreAdminGroup(ModelAdminGroup):
|
||||||
items = (
|
items = (
|
||||||
ProductAuthorAdmin,
|
ProductAuthorAdmin,
|
||||||
ProductCategoryAdmin,
|
ProductCategoryAdmin,
|
||||||
ProductCategoryParamAdmin,
|
ProductTemplateParamAdmin,
|
||||||
ProductTemplateAdmin,
|
ProductTemplateAdmin,
|
||||||
ProductAdmin,
|
ProductAdmin,
|
||||||
DocumentTemplateAdmin,
|
DocumentTemplateAdmin,
|
||||||
|
|
|
@ -5,7 +5,7 @@ from django.db.models import Model
|
||||||
|
|
||||||
from store.models import (
|
from store.models import (
|
||||||
ProductTemplate,
|
ProductTemplate,
|
||||||
ProductCategoryParamValue,
|
ProductTemplateParamValue,
|
||||||
Product,
|
Product,
|
||||||
PaymentMethod,
|
PaymentMethod,
|
||||||
DeliveryMethod
|
DeliveryMethod
|
||||||
|
@ -71,11 +71,16 @@ class ButtonToggleSelect(forms.RadioSelect):
|
||||||
class ProductTemplateConfigForm(forms.Form):
|
class ProductTemplateConfigForm(forms.Form):
|
||||||
|
|
||||||
def _create_dynamic_fields(self, template: ProductTemplate):
|
def _create_dynamic_fields(self, template: ProductTemplate):
|
||||||
category_params = template.category.category_params.all()
|
template_params = template.template_params.all()
|
||||||
for param in category_params:
|
for param in template_params:
|
||||||
|
queryset = ProductTemplateParamValue.objects.filter(param=param)
|
||||||
|
if queryset.count() >= 4:
|
||||||
|
widget = forms.Select(attrs={"class": "form-select"})
|
||||||
|
else:
|
||||||
|
widget = ButtonToggleSelect(attrs={"class": "btn-group btn-group-toggle"})
|
||||||
self.fields[param.key] = forms.ModelChoiceField(
|
self.fields[param.key] = forms.ModelChoiceField(
|
||||||
queryset=ProductCategoryParamValue.objects.filter(param=param),
|
queryset=queryset,
|
||||||
widget=ButtonToggleSelect(attrs={"class": "btn-group btn-group-toggle"}),
|
widget=widget,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
import logging
|
import logging
|
||||||
|
import time
|
||||||
import requests
|
import requests
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
from django.core import files
|
from django.core.files.base import ContentFile
|
||||||
|
from django.conf import settings
|
||||||
from store.models import (
|
from store.models import (
|
||||||
ProductTemplate,
|
ProductTemplate,
|
||||||
ProductCategoryParamValue,
|
ProductTemplateParam,
|
||||||
|
ProductTemplateParamValue,
|
||||||
Product,
|
Product,
|
||||||
ProductImage
|
ProductImage
|
||||||
)
|
)
|
||||||
|
@ -29,36 +31,46 @@ class TemplateLoader(BaseLoader):
|
||||||
|
|
||||||
class ProductLoader(BaseLoader):
|
class ProductLoader(BaseLoader):
|
||||||
|
|
||||||
def _get_images(self, row) -> list[files.ContentFile]:
|
def _clear(self):
|
||||||
urls = row["images"]
|
Product.objects.all().delete()
|
||||||
|
|
||||||
|
def __init__(self, path, param_names, clear=False):
|
||||||
|
super().__init__(path)
|
||||||
|
self.param_names = param_names
|
||||||
|
if clear:
|
||||||
|
self._clear()
|
||||||
|
|
||||||
|
def _get_images(self, row) -> list[ContentFile]:
|
||||||
|
url = row["images"]
|
||||||
images = []
|
images = []
|
||||||
for url in urls:
|
response = requests.get(
|
||||||
response = requests.get(url, stream=True)
|
url+"/preview", stream=True
|
||||||
if response.status_code == 200:
|
)
|
||||||
data = response.raw
|
if response.status_code == 200:
|
||||||
file_name = url.split("/")[-1]
|
data = response.content
|
||||||
image = files.ContentFile(data, name=file_name)
|
image = ContentFile(data, name=row["template"])
|
||||||
images.append(image)
|
images.append(image)
|
||||||
return images
|
return images
|
||||||
|
|
||||||
def _process_row(self, row):
|
def _process_row(self, row):
|
||||||
template = ProductTemplate.objects.get(code=row["template"])
|
template = ProductTemplate.objects.get(code=row["template"])
|
||||||
price = float(row["price"])
|
price = float(row["price"].strip("zł").replace(",", "."))
|
||||||
name = row["name"]
|
name = row["name"]
|
||||||
available = bool(row["available"])
|
available = bool(row["available"])
|
||||||
params = []
|
params = []
|
||||||
for param in row["params"]:
|
for key in self.param_names:
|
||||||
key, value = param
|
value = row[key]
|
||||||
param = ProductCategoryParamValue.objects.get(param__key=key, value=value)
|
param, _ = ProductTemplateParam.objects.get_or_create(key=key, template=template)
|
||||||
params.append(param)
|
param_value, _ = ProductTemplateParamValue.objects.get_or_create(param=param, value=value)
|
||||||
|
params.append(param_value)
|
||||||
product = Product.objects.get_or_create_by_params(template=template, params=params)
|
product = Product.objects.get_or_create_by_params(template=template, params=params)
|
||||||
product.price = price
|
product.price = price
|
||||||
product.name = name
|
product.name = name
|
||||||
product.available = available
|
product.available = available
|
||||||
|
# NOTE - temporary solution
|
||||||
images = self._get_images(row)
|
# images = self._get_images(row)
|
||||||
for i, image in enumerate(images):
|
# for i, image in enumerate(images):
|
||||||
ProductImage.objects.create(product=product, image=image, is_main=bool(i==0))
|
# ProductImage.objects.create(product=product, image=image, is_main=bool(i==0))
|
||||||
product.save()
|
product.save()
|
||||||
return product
|
return product
|
||||||
|
|
||||||
|
@ -66,6 +78,7 @@ class ProductLoader(BaseLoader):
|
||||||
data = self.load_data()
|
data = self.load_data()
|
||||||
products = []
|
products = []
|
||||||
for _, row in data.iterrows():
|
for _, row in data.iterrows():
|
||||||
|
time.sleep(5)
|
||||||
try:
|
try:
|
||||||
product = self._process_row(row)
|
product = self._process_row(row)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
@ -9,5 +9,5 @@ class Command(BaseCommand):
|
||||||
help = "Load products from csv file"
|
help = "Load products from csv file"
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
loader = ProductLoader(settings.PRODUCTS_CSV_PATH)
|
loader = ProductLoader(settings.PRODUCTS_CSV_PATH, ["mocowanie", "format", "wykonanie"], True)
|
||||||
loader.process()
|
loader.process()
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
# Generated by Django 4.1.10 on 2023-08-15 10:44
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import modelcluster.fields
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("store", "0012_deliverymethod_order_uuid_product_uuid_and_more"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="ProductTemplateParam",
|
||||||
|
fields=[
|
||||||
|
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||||
|
("key", models.CharField(max_length=200)),
|
||||||
|
(
|
||||||
|
"param_type",
|
||||||
|
models.CharField(choices=[("int", "Int"), ("str", "String"), ("float", "Float")], max_length=200),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"template",
|
||||||
|
modelcluster.fields.ParentalKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="template_params",
|
||||||
|
to="store.producttemplate",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"abstract": False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="product",
|
||||||
|
name="params",
|
||||||
|
field=models.ManyToManyField(
|
||||||
|
blank=True,
|
||||||
|
limit_choices_to=models.Q(("param__template", models.F("product__template"))),
|
||||||
|
through="store.ProductParam",
|
||||||
|
to="store.productcategoryparamvalue",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.RenameModel(
|
||||||
|
old_name="ProductCategoryParamValue",
|
||||||
|
new_name="ProductTemplateParamValue",
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name="ProductCategoryParam",
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="producttemplateparamvalue",
|
||||||
|
name="param",
|
||||||
|
field=modelcluster.fields.ParentalKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="param_values",
|
||||||
|
to="store.producttemplateparam",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -90,59 +90,16 @@ class ProductCategory(ClusterableModel):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
panels = [
|
panels = [
|
||||||
FieldPanel("name"),
|
FieldPanel("name")
|
||||||
InlinePanel("category_params")
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class CategoryParamTypeChoices(models.TextChoices):
|
|
||||||
INT = "int"
|
|
||||||
STRING = "str"
|
|
||||||
FLOAT = "float"
|
|
||||||
|
|
||||||
|
|
||||||
class ProductCategoryParam(ClusterableModel):
|
|
||||||
category = ParentalKey(ProductCategory, on_delete=models.CASCADE, related_name="category_params")
|
|
||||||
key = models.CharField(max_length=200)
|
|
||||||
param_type = models.CharField(max_length=200, choices=CategoryParamTypeChoices.choices)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.key
|
|
||||||
|
|
||||||
panels = [
|
|
||||||
FieldPanel("category"),
|
|
||||||
FieldPanel("key"),
|
|
||||||
FieldPanel("param_type"),
|
|
||||||
InlinePanel("param_values")
|
|
||||||
]
|
|
||||||
|
|
||||||
def get_available_values(self) -> Iterator[any]:
|
|
||||||
for elem in self.param_values.all():
|
|
||||||
yield elem.get_value()
|
|
||||||
|
|
||||||
|
|
||||||
class ProductCategoryParamValue(ClusterableModel):
|
|
||||||
param = ParentalKey(ProductCategoryParam, on_delete=models.CASCADE, related_name="param_values")
|
|
||||||
value = models.CharField(max_length=255)
|
|
||||||
|
|
||||||
def get_value(self):
|
|
||||||
try:
|
|
||||||
func = getattr(builtins, self.param.param_type)
|
|
||||||
return func(self.value)
|
|
||||||
except ValueError:
|
|
||||||
return
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.param.key}: {self.value}"
|
|
||||||
|
|
||||||
|
|
||||||
class ProductTemplate(ClusterableModel):
|
class ProductTemplate(ClusterableModel):
|
||||||
category = models.ForeignKey(ProductCategory, on_delete=models.CASCADE)
|
category = models.ForeignKey(ProductCategory, on_delete=models.CASCADE)
|
||||||
author = models.ForeignKey(ProductAuthor, on_delete=models.CASCADE)
|
author = models.ForeignKey(ProductAuthor, on_delete=models.CASCADE)
|
||||||
title = models.CharField(max_length=255)
|
title = models.CharField(max_length=255)
|
||||||
code = models.CharField(max_length=255)
|
code = models.CharField(max_length=255)
|
||||||
description = models.TextField(blank=True)
|
description = models.TextField(blank=True)
|
||||||
# TODO - add mechanism for enabling params
|
|
||||||
|
|
||||||
tags = TaggableManager()
|
tags = TaggableManager()
|
||||||
|
|
||||||
|
@ -164,6 +121,7 @@ class ProductTemplate(ClusterableModel):
|
||||||
FieldPanel('description'),
|
FieldPanel('description'),
|
||||||
InlinePanel("template_images", label="Template Images"),
|
InlinePanel("template_images", label="Template Images"),
|
||||||
FieldPanel("tags"),
|
FieldPanel("tags"),
|
||||||
|
InlinePanel("template_params")
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -175,9 +133,50 @@ class ProductTemplateImage(BaseImageModel):
|
||||||
is_main = models.BooleanField(default=False)
|
is_main = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateParamValueChoices(models.TextChoices):
|
||||||
|
INT = "int"
|
||||||
|
STRING = "str"
|
||||||
|
FLOAT = "float"
|
||||||
|
|
||||||
|
|
||||||
|
class ProductTemplateParam(ClusterableModel):
|
||||||
|
template = ParentalKey(ProductTemplate, on_delete=models.CASCADE, related_name="template_params")
|
||||||
|
key = models.CharField(max_length=200)
|
||||||
|
param_type = models.CharField(max_length=200, choices=TemplateParamValueChoices.choices)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.key
|
||||||
|
|
||||||
|
panels = [
|
||||||
|
FieldPanel("template"),
|
||||||
|
FieldPanel("key"),
|
||||||
|
FieldPanel("param_type"),
|
||||||
|
InlinePanel("param_values")
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_available_values(self) -> Iterator[any]:
|
||||||
|
for elem in self.param_values.all():
|
||||||
|
yield elem.get_value()
|
||||||
|
|
||||||
|
|
||||||
|
class ProductTemplateParamValue(ClusterableModel):
|
||||||
|
param = ParentalKey(ProductTemplateParam, on_delete=models.CASCADE, related_name="param_values")
|
||||||
|
value = models.CharField(max_length=255)
|
||||||
|
|
||||||
|
def get_value(self):
|
||||||
|
try:
|
||||||
|
func = getattr(builtins, self.param.param_type)
|
||||||
|
return func(self.value)
|
||||||
|
except ValueError:
|
||||||
|
return
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.param.key}: {self.value}"
|
||||||
|
|
||||||
|
|
||||||
class ProductManager(models.Manager):
|
class ProductManager(models.Manager):
|
||||||
|
|
||||||
def get_or_create_by_params(self, params: list[ProductCategoryParamValue], template: ProductTemplate):
|
def get_or_create_by_params(self, params: list[ProductTemplateParam], template: ProductTemplate):
|
||||||
products = self.filter(template=template)
|
products = self.filter(template=template)
|
||||||
|
|
||||||
for param in params:
|
for param in params:
|
||||||
|
@ -208,8 +207,8 @@ class Product(ClusterableModel):
|
||||||
name = models.CharField(max_length=255, blank=True)
|
name = models.CharField(max_length=255, blank=True)
|
||||||
template = models.ForeignKey(ProductTemplate, on_delete=models.CASCADE, related_name="products")
|
template = models.ForeignKey(ProductTemplate, on_delete=models.CASCADE, related_name="products")
|
||||||
params = models.ManyToManyField(
|
params = models.ManyToManyField(
|
||||||
ProductCategoryParamValue, blank=True, through="ProductParam",
|
ProductTemplateParamValue, blank=True, through="ProductParam",
|
||||||
limit_choices_to=models.Q(param__category=models.F("product__template__category"))
|
limit_choices_to=models.Q(param__template=models.F("product__template"))
|
||||||
)
|
)
|
||||||
price = models.FloatField()
|
price = models.FloatField()
|
||||||
available = models.BooleanField(default=True)
|
available = models.BooleanField(default=True)
|
||||||
|
@ -260,7 +259,7 @@ class ProductImage(BaseImageModel):
|
||||||
|
|
||||||
class ProductParam(models.Model):
|
class ProductParam(models.Model):
|
||||||
product = ParentalKey(Product, on_delete=models.CASCADE, related_name="product_params")
|
product = ParentalKey(Product, on_delete=models.CASCADE, related_name="product_params")
|
||||||
param_value = models.ForeignKey(ProductCategoryParamValue, on_delete=models.CASCADE)
|
param_value = models.ForeignKey(ProductTemplateParamValue, on_delete=models.CASCADE)
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
self.full_clean()
|
self.full_clean()
|
||||||
|
@ -277,8 +276,8 @@ def validate_param(sender, **kwargs):
|
||||||
errors = []
|
errors = []
|
||||||
for pk in pk_set:
|
for pk in pk_set:
|
||||||
try:
|
try:
|
||||||
param = ProductCategoryParamValue.objects.get(pk=pk).param
|
param = ProductTemplateParamValue.objects.get(pk=pk).param
|
||||||
except ProductCategoryParamValue.DoesNotExist as e:
|
except ProductTemplateParamValue.DoesNotExist as e:
|
||||||
logger.exception(f"Product param validation failed with exception: {str(e)}")
|
logger.exception(f"Product param validation failed with exception: {str(e)}")
|
||||||
count = product_instance.params.filter(productparam__param_value__param=param).count()
|
count = product_instance.params.filter(productparam__param_value__param=param).count()
|
||||||
if count >= 1:
|
if count >= 1:
|
||||||
|
|
|
@ -10,19 +10,3 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
<!--
|
|
||||||
{% with id=widget.attrs.id %}
|
|
||||||
<div{% if id %} id="{{ id }}"{% endif %}
|
|
||||||
{% if widget.attrs.class %} class="{{ widget.attrs.class }}"{% endif %}
|
|
||||||
>
|
|
||||||
{% for group, options, index in widget.optgroups %}
|
|
||||||
{% if group %}
|
|
||||||
<div><label>{{ group }}</label>{% endif %}{% for option in options %}<div>
|
|
||||||
{% include option.template_name with widget=option %}</div>{% endfor %}{% if group %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endwith %}
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
|
@ -31,23 +31,6 @@ class ProductCategoryFactory(DjangoModelFactory):
|
||||||
name = Faker('name')
|
name = Faker('name')
|
||||||
|
|
||||||
|
|
||||||
class ProductCategoryParamFactory(DjangoModelFactory):
|
|
||||||
class Meta:
|
|
||||||
model = 'store.ProductCategoryParam'
|
|
||||||
|
|
||||||
key = Faker('name')
|
|
||||||
category = SubFactory(ProductCategoryFactory)
|
|
||||||
param_type = 'str'
|
|
||||||
|
|
||||||
|
|
||||||
class ProductCategoryParamValueFactory(DjangoModelFactory):
|
|
||||||
class Meta:
|
|
||||||
model = 'store.ProductCategoryParamValue'
|
|
||||||
|
|
||||||
param = SubFactory(ProductCategoryParamFactory)
|
|
||||||
value = Faker('name')
|
|
||||||
|
|
||||||
|
|
||||||
class ProductTemplateFactory(DjangoModelFactory):
|
class ProductTemplateFactory(DjangoModelFactory):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = 'store.ProductTemplate'
|
model = 'store.ProductTemplate'
|
||||||
|
@ -59,6 +42,23 @@ class ProductTemplateFactory(DjangoModelFactory):
|
||||||
category = SubFactory(ProductCategoryFactory)
|
category = SubFactory(ProductCategoryFactory)
|
||||||
|
|
||||||
|
|
||||||
|
class ProductTemplateParamFactory(DjangoModelFactory):
|
||||||
|
class Meta:
|
||||||
|
model = 'store.ProductTemplateParam'
|
||||||
|
|
||||||
|
key = Faker('name')
|
||||||
|
template = SubFactory(ProductTemplateFactory)
|
||||||
|
param_type = 'str'
|
||||||
|
|
||||||
|
|
||||||
|
class ProductTemplateParamValueFactory(DjangoModelFactory):
|
||||||
|
class Meta:
|
||||||
|
model = 'store.ProductTemplateParamValue'
|
||||||
|
|
||||||
|
param = SubFactory(ProductTemplateParamFactory)
|
||||||
|
value = Faker('name')
|
||||||
|
|
||||||
|
|
||||||
class ProductFactory(DjangoModelFactory):
|
class ProductFactory(DjangoModelFactory):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = 'store.Product'
|
model = 'store.Product'
|
||||||
|
@ -74,7 +74,7 @@ class ProductParamFactory(DjangoModelFactory):
|
||||||
model = 'store.ProductParam'
|
model = 'store.ProductParam'
|
||||||
|
|
||||||
product = SubFactory(ProductFactory)
|
product = SubFactory(ProductFactory)
|
||||||
param = SubFactory(ProductCategoryParamFactory)
|
param = SubFactory(ProductTemplateParamValueFactory)
|
||||||
|
|
||||||
|
|
||||||
class PaymentMethodFactory(DjangoModelFactory):
|
class PaymentMethodFactory(DjangoModelFactory):
|
||||||
|
|
|
@ -10,23 +10,21 @@ class TestProductLoader(TestCase):
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
self.category = factories.ProductCategoryFactory()
|
self.category = factories.ProductCategoryFactory()
|
||||||
self.template = factories.ProductTemplateFactory(category=self.category)
|
self.template = factories.ProductTemplateFactory(category=self.category)
|
||||||
self.category_params = [factories.ProductCategoryParamFactory(category=self.category) for _ in range(3)]
|
self.template_params = [factories.ProductTemplateParamFactory(template=self.template) for _ in range(3)]
|
||||||
self.category_param_values = [factories.ProductCategoryParamValueFactory(param=param) for param in self.category_params]
|
self.templat_params_values = [factories.ProductTemplateParamValueFactory(param=param) for param in self.template_params]
|
||||||
|
|
||||||
def test_load_products_single_product_success(self):
|
def test_load_products_single_product_success(self):
|
||||||
fake_df = pd.DataFrame({
|
fake_df = pd.DataFrame({
|
||||||
"template": [self.template.code],
|
"template": [self.template.code],
|
||||||
"price": [10.0],
|
"price": str(10.0),
|
||||||
"name": ["Test product"],
|
"name": ["Test product"],
|
||||||
"available": [True],
|
"available": [True],
|
||||||
"params": [[
|
self.template_params[0].key: self.templat_params_values[0].value,
|
||||||
(self.category_params[0].key, self.category_param_values[0].value),
|
self.template_params[1].key: self.templat_params_values[1].value,
|
||||||
(self.category_params[1].key, self.category_param_values[1].value),
|
self.template_params[2].key: self.templat_params_values[2].value
|
||||||
(self.category_params[2].key, self.category_param_values[2].value),
|
|
||||||
]]
|
|
||||||
})
|
})
|
||||||
with patch("store.loader.BaseLoader.load_data", return_value=fake_df):
|
with patch("store.loader.BaseLoader.load_data", return_value=fake_df):
|
||||||
loader = ProductLoader("fake_path")
|
loader = ProductLoader("fake_path", [p.key for p in self.template_params])
|
||||||
loader.process()
|
loader.process()
|
||||||
|
|
||||||
self.assertEqual(self.template.products.count(), 1)
|
self.assertEqual(self.template.products.count(), 1)
|
||||||
|
@ -42,14 +40,12 @@ class TestProductLoader(TestCase):
|
||||||
"price": ["FASDSADQAW"],
|
"price": ["FASDSADQAW"],
|
||||||
"name": ["Test product"],
|
"name": ["Test product"],
|
||||||
"available": [True],
|
"available": [True],
|
||||||
"params": [[
|
self.template_params[0].key: self.templat_params_values[0].value,
|
||||||
(self.category_params[0].key, self.category_param_values[0].value),
|
self.template_params[1].key: self.templat_params_values[1].value,
|
||||||
(self.category_params[1].key, self.category_param_values[1].value),
|
self.template_params[2].key: self.templat_params_values[2].value
|
||||||
(self.category_params[2].key, self.category_param_values[2].value),
|
|
||||||
]]
|
|
||||||
})
|
})
|
||||||
with patch("store.loader.BaseLoader.load_data", return_value=fake_df):
|
with patch("store.loader.BaseLoader.load_data", return_value=fake_df):
|
||||||
loader = ProductLoader("fake_path")
|
loader = ProductLoader("fake_path", [p.key for p in self.template_params])
|
||||||
loader.process()
|
loader.process()
|
||||||
|
|
||||||
self.assertEqual(self.template.products.count(), 0)
|
self.assertEqual(self.template.products.count(), 0)
|
||||||
|
@ -59,39 +55,17 @@ class TestProductLoader(TestCase):
|
||||||
def test_load_no_existing_template_code_failure(self, mock_logger):
|
def test_load_no_existing_template_code_failure(self, mock_logger):
|
||||||
fake_df = pd.DataFrame({
|
fake_df = pd.DataFrame({
|
||||||
"template": ["NOTEEXISTINGTEMPLATE"],
|
"template": ["NOTEEXISTINGTEMPLATE"],
|
||||||
"price": [10.0],
|
"price": str(10.0),
|
||||||
"name": ["Test product"],
|
"name": ["Test product"],
|
||||||
"available": [True],
|
"available": [True],
|
||||||
"params": [[
|
self.template_params[0].key: self.templat_params_values[0].value,
|
||||||
(self.category_params[0].key, self.category_param_values[0].value),
|
self.template_params[1].key: self.templat_params_values[1].value,
|
||||||
(self.category_params[1].key, self.category_param_values[1].value),
|
self.template_params[2].key: self.templat_params_values[2].value
|
||||||
(self.category_params[2].key, self.category_param_values[2].value),
|
|
||||||
]]
|
|
||||||
})
|
})
|
||||||
with patch("store.loader.BaseLoader.load_data", return_value=fake_df):
|
with patch("store.loader.BaseLoader.load_data", return_value=fake_df):
|
||||||
loader = ProductLoader("fake_path")
|
loader = ProductLoader("fake_path", [p.key for p in self.template_params])
|
||||||
loader.process()
|
loader.process()
|
||||||
|
|
||||||
self.assertEqual(self.template.products.count(), 0)
|
self.assertEqual(self.template.products.count(), 0)
|
||||||
mock_logger.exception.assert_called_with("ProductTemplate matching query does not exist.")
|
mock_logger.exception.assert_called_with("ProductTemplate matching query does not exist.")
|
||||||
|
|
||||||
@patch("store.loader.logger")
|
|
||||||
def test_not_existing_params_key_value_pairs_failure(self, mock_logger):
|
|
||||||
fake_df = pd.DataFrame({
|
|
||||||
"template": [self.template.code],
|
|
||||||
"price": [10.0],
|
|
||||||
"name": ["Test product"],
|
|
||||||
"available": [True],
|
|
||||||
"params": [[
|
|
||||||
(self.category_params[0].key, self.category_param_values[2].value),
|
|
||||||
(self.category_params[1].key, self.category_param_values[0].value),
|
|
||||||
(self.category_params[2].key, self.category_param_values[1].value),
|
|
||||||
]]
|
|
||||||
})
|
|
||||||
with patch("store.loader.BaseLoader.load_data", return_value=fake_df):
|
|
||||||
loader = ProductLoader("fake_path")
|
|
||||||
loader.process()
|
|
||||||
|
|
||||||
self.assertEqual(self.template.products.count(), 0)
|
|
||||||
mock_logger.exception.assert_called_with("ProductCategoryParamValue matching query does not exist.")
|
|
||||||
|
|
|
@ -15,8 +15,9 @@ class ProductCategoryParamTestCase(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.category = factories.ProductCategoryFactory()
|
self.category = factories.ProductCategoryFactory()
|
||||||
self.param = factories.ProductCategoryParamFactory(
|
self.template = factories.ProductTemplateFactory(category=self.category)
|
||||||
category=self.category,
|
self.param = factories.ProductTemplateParamFactory(
|
||||||
|
template=self.template,
|
||||||
param_type="int",
|
param_type="int",
|
||||||
key="test_param"
|
key="test_param"
|
||||||
)
|
)
|
||||||
|
@ -26,72 +27,73 @@ class ProductCategoryParamTestCase(TestCase):
|
||||||
self.assertEqual(available_values, [])
|
self.assertEqual(available_values, [])
|
||||||
|
|
||||||
def test_get_available_values_one_value_success(self):
|
def test_get_available_values_one_value_success(self):
|
||||||
factories.ProductCategoryParamValueFactory(param=self.param, value="23")
|
factories.ProductTemplateParamValueFactory(param=self.param, value="23")
|
||||||
available_values = [v for v in self.param.get_available_values()]
|
available_values = [v for v in self.param.get_available_values()]
|
||||||
self.assertEqual(available_values, [23])
|
self.assertEqual(available_values, [23])
|
||||||
self.assertEqual(len(available_values), 1)
|
self.assertEqual(len(available_values), 1)
|
||||||
|
|
||||||
def test_get_available_values_multiple_values_success(self):
|
def test_get_available_values_multiple_values_success(self):
|
||||||
factories.ProductCategoryParamValueFactory(param=self.param, value="23")
|
factories.ProductTemplateParamValueFactory(param=self.param, value="23")
|
||||||
factories.ProductCategoryParamValueFactory(param=self.param, value="24")
|
factories.ProductTemplateParamValueFactory(param=self.param, value="24")
|
||||||
factories.ProductCategoryParamValueFactory(param=self.param, value="25")
|
factories.ProductTemplateParamValueFactory(param=self.param, value="25")
|
||||||
available_values = [v for v in self.param.get_available_values()]
|
available_values = [v for v in self.param.get_available_values()]
|
||||||
self.assertEqual(available_values, [23, 24, 25])
|
self.assertEqual(available_values, [23, 24, 25])
|
||||||
self.assertEqual(len(available_values), 3)
|
self.assertEqual(len(available_values), 3)
|
||||||
|
|
||||||
|
|
||||||
class ProductCategoryParamValueTestCase(TestCase):
|
class ProductTemplateParamValueTestCase(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.category = factories.ProductCategoryFactory()
|
self.category = factories.ProductCategoryFactory()
|
||||||
|
self.template = factories.ProductTemplateFactory(category=self.category)
|
||||||
|
|
||||||
|
|
||||||
def test_get_value_success(self):
|
def test_get_value_success(self):
|
||||||
param = factories.ProductCategoryParamFactory(
|
param = factories.ProductTemplateParamFactory(
|
||||||
category=self.category,
|
template=self.template,
|
||||||
param_type="int",
|
param_type="int",
|
||||||
key="test_param"
|
key="test_param"
|
||||||
)
|
)
|
||||||
param_value = factories.ProductCategoryParamValueFactory(param=param, value="23")
|
param_value = factories.ProductTemplateParamValueFactory(param=param, value="23")
|
||||||
proper_value = param_value.get_value()
|
proper_value = param_value.get_value()
|
||||||
self.assertEqual(proper_value, 23)
|
self.assertEqual(proper_value, 23)
|
||||||
|
|
||||||
def test_get_value_failure_wrong_value(self):
|
def test_get_value_failure_wrong_value(self):
|
||||||
param = factories.ProductCategoryParamFactory(
|
param = factories.ProductTemplateParamFactory(
|
||||||
category=self.category,
|
template=self.template,
|
||||||
param_type="int",
|
param_type="int",
|
||||||
key="test_param"
|
key="test_param"
|
||||||
)
|
)
|
||||||
param_value = factories.ProductCategoryParamValueFactory(param=param, value="wrong_value")
|
param_value = factories.ProductTemplateParamValueFactory(param=param, value="wrong_value")
|
||||||
proper_value = param_value.get_value()
|
proper_value = param_value.get_value()
|
||||||
self.assertEqual(proper_value, None)
|
self.assertEqual(proper_value, None)
|
||||||
|
|
||||||
|
|
||||||
class ProductTestCase(TestCase):
|
class ProductTestCase(TestCase):
|
||||||
|
|
||||||
def test_category_params_one_value_success(self):
|
def test_template_params_one_value_success(self):
|
||||||
product = factories.ProductFactory()
|
product = factories.ProductFactory()
|
||||||
param = factories.ProductCategoryParamFactory(
|
param = factories.ProductTemplateParamFactory(
|
||||||
category=product.template.category,
|
template=product.template,
|
||||||
param_type="int",
|
param_type="int",
|
||||||
key="test_param"
|
key="test_param"
|
||||||
)
|
)
|
||||||
param_value = factories.ProductCategoryParamValueFactory(param=param, value="23")
|
param_value = factories.ProductTemplateParamValueFactory(param=param, value="23")
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
product.params.add(param_value)
|
product.params.add(param_value)
|
||||||
product.save()
|
product.save()
|
||||||
self.assertEqual(product.params.count(), 1)
|
self.assertEqual(product.params.count(), 1)
|
||||||
self.assertEqual(product.params.first().get_value(), 23)
|
self.assertEqual(product.params.first().get_value(), 23)
|
||||||
|
|
||||||
def test_category_params_multiple_values_failure(self):
|
def test_template_params_multiple_values_failure(self):
|
||||||
product = factories.ProductFactory()
|
product = factories.ProductFactory()
|
||||||
param = factories.ProductCategoryParamFactory(
|
param = factories.ProductTemplateParamFactory(
|
||||||
category=product.template.category,
|
template=product.template,
|
||||||
param_type="int",
|
param_type="int",
|
||||||
key="test_param"
|
key="test_param"
|
||||||
)
|
)
|
||||||
param_value = factories.ProductCategoryParamValueFactory(param=param, value="23")
|
param_value = factories.ProductTemplateParamValueFactory(param=param, value="23")
|
||||||
sec_param_value = factories.ProductCategoryParamValueFactory(param=param, value="24")
|
sec_param_value = factories.ProductTemplateParamValueFactory(param=param, value="24")
|
||||||
with self.assertRaises(ValidationError):
|
with self.assertRaises(ValidationError):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
product.params.add(param_value)
|
product.params.add(param_value)
|
||||||
|
@ -100,8 +102,8 @@ class ProductTestCase(TestCase):
|
||||||
|
|
||||||
def test_get_or_create_by_params_success(self):
|
def test_get_or_create_by_params_success(self):
|
||||||
product = factories.ProductFactory(available=True)
|
product = factories.ProductFactory(available=True)
|
||||||
value1 = factories.ProductCategoryParamValueFactory()
|
value1 = factories.ProductTemplateParamValueFactory()
|
||||||
value2 = factories.ProductCategoryParamValueFactory()
|
value2 = factories.ProductTemplateParamValueFactory()
|
||||||
product.params.add(value1)
|
product.params.add(value1)
|
||||||
product.params.add(value2)
|
product.params.add(value2)
|
||||||
product.save()
|
product.save()
|
||||||
|
@ -114,8 +116,8 @@ class ProductTestCase(TestCase):
|
||||||
|
|
||||||
def test_get_or_create_by_params_success_not_existing_product(self):
|
def test_get_or_create_by_params_success_not_existing_product(self):
|
||||||
product = factories.ProductFactory(available=True)
|
product = factories.ProductFactory(available=True)
|
||||||
value1 = factories.ProductCategoryParamValueFactory()
|
value1 = factories.ProductTemplateParamValueFactory()
|
||||||
value2 = factories.ProductCategoryParamValueFactory()
|
value2 = factories.ProductTemplateParamValueFactory()
|
||||||
product.params.add(value1)
|
product.params.add(value1)
|
||||||
product.price = 13.0
|
product.price = 13.0
|
||||||
product.save()
|
product.save()
|
||||||
|
@ -130,8 +132,8 @@ class ProductTestCase(TestCase):
|
||||||
|
|
||||||
def test_get_or_create_by_params_success_not_existing_product_no_other_products(self):
|
def test_get_or_create_by_params_success_not_existing_product_no_other_products(self):
|
||||||
template = factories.ProductTemplateFactory()
|
template = factories.ProductTemplateFactory()
|
||||||
value1 = factories.ProductCategoryParamValueFactory()
|
value1 = factories.ProductTemplateParamValueFactory()
|
||||||
value2 = factories.ProductCategoryParamValueFactory()
|
value2 = factories.ProductTemplateParamValueFactory()
|
||||||
|
|
||||||
prod = store_models.Product.objects.get_or_create_by_params(
|
prod = store_models.Product.objects.get_or_create_by_params(
|
||||||
params=[value1, value2], template=template,
|
params=[value1, value2], template=template,
|
||||||
|
|
|
@ -2,15 +2,15 @@ from django.test import TestCase
|
||||||
from django.shortcuts import reverse
|
from django.shortcuts import reverse
|
||||||
|
|
||||||
from store.models import (
|
from store.models import (
|
||||||
ProductCategoryParam,
|
ProductTemplateParam,
|
||||||
ProductCategoryParamValue,
|
ProductTemplateParamValue,
|
||||||
CategoryParamTypeChoices
|
TemplateParamValueChoices
|
||||||
)
|
)
|
||||||
from store.tests.factories import (
|
from store.tests.factories import (
|
||||||
ProductTemplateFactory,
|
ProductTemplateFactory,
|
||||||
ProductCategoryFactory,
|
ProductCategoryFactory,
|
||||||
ProductFactory,
|
ProductFactory,
|
||||||
ProductCategoryParamValueFactory
|
ProductTemplateParamValueFactory
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,18 +21,18 @@ class ConfigureProductViewTestCase(TestCase):
|
||||||
self.category = ProductCategoryFactory()
|
self.category = ProductCategoryFactory()
|
||||||
self.product_template = ProductTemplateFactory(category=self.category)
|
self.product_template = ProductTemplateFactory(category=self.category)
|
||||||
# create template params and values for those params
|
# create template params and values for those params
|
||||||
self.param1 = ProductCategoryParam.objects.create(
|
self.param1 = ProductTemplateParam.objects.create(
|
||||||
key="Mocowanie", category=self.category,
|
key="Mocowanie", template=self.product_template,
|
||||||
param_type=CategoryParamTypeChoices.STRING
|
param_type=TemplateParamValueChoices.STRING
|
||||||
)
|
)
|
||||||
self.param1_value1 = ProductCategoryParamValueFactory(param=self.param1)
|
self.param1_value1 = ProductTemplateParamValueFactory(param=self.param1)
|
||||||
self.param1_value2 = ProductCategoryParamValueFactory(param=self.param1)
|
self.param1_value2 = ProductTemplateParamValueFactory(param=self.param1)
|
||||||
self.param2 = ProductCategoryParam.objects.create(
|
self.param2 = ProductTemplateParam.objects.create(
|
||||||
key="Format", category=self.category,
|
key="Format", template=self.product_template,
|
||||||
param_type=CategoryParamTypeChoices.STRING
|
param_type=TemplateParamValueChoices.STRING
|
||||||
)
|
)
|
||||||
self.param2_value1 = ProductCategoryParamValueFactory(param=self.param2)
|
self.param2_value1 = ProductTemplateParamValueFactory(param=self.param2)
|
||||||
self.param2_value2 = ProductCategoryParamValueFactory(param=self.param2)
|
self.param2_value2 = ProductTemplateParamValueFactory(param=self.param2)
|
||||||
# create product variant
|
# create product variant
|
||||||
self.variant1 = ProductFactory(
|
self.variant1 = ProductFactory(
|
||||||
template=self.product_template
|
template=self.product_template
|
||||||
|
|
Ładowanie…
Reference in New Issue