import yangilandi
This commit is contained in:
@@ -9,6 +9,8 @@ class CategoryFilter(filters.FilterSet):
|
|||||||
fields = [
|
fields = [
|
||||||
"name",
|
"name",
|
||||||
"filial",
|
"filial",
|
||||||
|
"filial__name",
|
||||||
|
"type",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ class Command(BaseCommand):
|
|||||||
json_dir = base_dir / 'assets' / 'json'
|
json_dir = base_dir / 'assets' / 'json'
|
||||||
images_dir = base_dir / 'assets' / 'images'
|
images_dir = base_dir / 'assets' / 'images'
|
||||||
|
|
||||||
|
# 0. Clear Database
|
||||||
|
self.stdout.write(self.style.WARNING("Clearing existing data..."))
|
||||||
|
FilialModel.objects.all().delete()
|
||||||
|
# Cascading deletes should clear Categories, Subcategories, Products, and SubProducts
|
||||||
|
|
||||||
product_map = {} # Maps (filial_name, item_id) to ProductsModel instance
|
product_map = {} # Maps (filial_name, item_id) to ProductsModel instance
|
||||||
|
|
||||||
# 1. Process Main Food Containers
|
# 1. Process Main Food Containers
|
||||||
@@ -51,21 +56,34 @@ class Command(BaseCommand):
|
|||||||
price = item.get('price', 0)
|
price = item.get('price', 0)
|
||||||
image_name = item.get('image')
|
image_name = item.get('image')
|
||||||
json_id = item.get('id')
|
json_id = item.get('id')
|
||||||
|
item_type = item.get('type', '')
|
||||||
|
|
||||||
if is_header:
|
if is_header:
|
||||||
# Create Category and Subcategory
|
# Determine if this category is Bar or Restaurant
|
||||||
|
# Usually anything with "BAR" in type string is Bar
|
||||||
|
cat_type = CategoryModel.CategoryType.RESTAURANT
|
||||||
|
if "BAR" in item_type.upper():
|
||||||
|
cat_type = CategoryModel.CategoryType.BAR
|
||||||
|
|
||||||
|
# Create Category
|
||||||
current_category, created = CategoryModel.objects.get_or_create(
|
current_category, created = CategoryModel.objects.get_or_create(
|
||||||
filial=filial,
|
filial=filial,
|
||||||
name=name
|
name=name,
|
||||||
|
defaults={'type': cat_type}
|
||||||
)
|
)
|
||||||
if created and image_name:
|
if created and image_name:
|
||||||
self.attach_image(current_category, image_name, images_dir)
|
self.attach_image(current_category, image_name, images_dir)
|
||||||
|
elif not created and current_category.type != cat_type:
|
||||||
|
# Update type if it was created differently before
|
||||||
|
current_category.type = cat_type
|
||||||
|
current_category.save()
|
||||||
|
|
||||||
|
# Link Subcategory (using the same name for now as the JSON doesn't define a sub-level)
|
||||||
current_subcategory, created = SubcategoryModel.objects.get_or_create(
|
current_subcategory, created = SubcategoryModel.objects.get_or_create(
|
||||||
category=current_category,
|
category=current_category,
|
||||||
name=name
|
name=name
|
||||||
)
|
)
|
||||||
self.stdout.write(f" Category/Subcategory: {name}")
|
self.stdout.write(f" Category({cat_type}): {name}")
|
||||||
else:
|
else:
|
||||||
if not current_subcategory:
|
if not current_subcategory:
|
||||||
# Fallback if no header found yet
|
# Fallback if no header found yet
|
||||||
@@ -80,7 +98,7 @@ class Command(BaseCommand):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Create Product
|
# Create Product
|
||||||
# We use get_or_create with name and subcategory to avoid obvious duplicates
|
# We use get_or_create to avoid duplicates within the same subcategory
|
||||||
product, created = ProductsModel.objects.get_or_create(
|
product, created = ProductsModel.objects.get_or_create(
|
||||||
name=name,
|
name=name,
|
||||||
subcategory=current_subcategory,
|
subcategory=current_subcategory,
|
||||||
@@ -91,7 +109,6 @@ class Command(BaseCommand):
|
|||||||
self.attach_image(product, image_name, images_dir)
|
self.attach_image(product, image_name, images_dir)
|
||||||
self.stdout.write(f" Added Product: {name}")
|
self.stdout.write(f" Added Product: {name}")
|
||||||
|
|
||||||
# Store in map (scoped by filial and ID) for subproduct linking
|
|
||||||
product_map[(filial_name, json_id)] = product
|
product_map[(filial_name, json_id)] = product
|
||||||
|
|
||||||
# 2. Process Food Detail Containers (Subproducts)
|
# 2. Process Food Detail Containers (Subproducts)
|
||||||
@@ -124,12 +141,8 @@ class Command(BaseCommand):
|
|||||||
)
|
)
|
||||||
if created:
|
if created:
|
||||||
self.stdout.write(f" Added SubProduct: {name} for {parent_product.name}")
|
self.stdout.write(f" Added SubProduct: {name} for {parent_product.name}")
|
||||||
else:
|
|
||||||
# Sometimes subproducts might refer to products from other files or just missing
|
|
||||||
pass
|
|
||||||
|
|
||||||
def attach_image(self, instance, image_name, images_dir):
|
def attach_image(self, instance, image_name, images_dir):
|
||||||
# Try different extensions
|
|
||||||
if not image_name:
|
if not image_name:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
18
core/apps/api/migrations/0003_categorymodel_type.py
Normal file
18
core/apps/api/migrations/0003_categorymodel_type.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2026-03-27 14:29
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('api', '0002_filialmodel_categorymodel_filial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='categorymodel',
|
||||||
|
name='type',
|
||||||
|
field=models.CharField(choices=[('RESTAURANT', 'Restaurant'), ('BAR', 'Bar')], default='RESTAURANT', max_length=20, verbose_name='type'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -21,6 +21,10 @@ class FilialModel(AbstractBaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class CategoryModel(AbstractBaseModel):
|
class CategoryModel(AbstractBaseModel):
|
||||||
|
class CategoryType(models.TextChoices):
|
||||||
|
RESTAURANT = "RESTAURANT", _("Restaurant")
|
||||||
|
BAR = "BAR", _("Bar")
|
||||||
|
|
||||||
filial = models.ForeignKey(
|
filial = models.ForeignKey(
|
||||||
FilialModel,
|
FilialModel,
|
||||||
verbose_name=_("filial"),
|
verbose_name=_("filial"),
|
||||||
@@ -30,10 +34,16 @@ class CategoryModel(AbstractBaseModel):
|
|||||||
blank=True,
|
blank=True,
|
||||||
)
|
)
|
||||||
name = models.CharField(verbose_name=_("name"), max_length=255)
|
name = models.CharField(verbose_name=_("name"), max_length=255)
|
||||||
|
type = models.CharField(
|
||||||
|
verbose_name=_("type"),
|
||||||
|
max_length=20,
|
||||||
|
choices=CategoryType.choices,
|
||||||
|
default=CategoryType.RESTAURANT,
|
||||||
|
)
|
||||||
image = models.ImageField(verbose_name=_("image"), upload_to="categories/", null=True, blank=True)
|
image = models.ImageField(verbose_name=_("image"), upload_to="categories/", null=True, blank=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return f"{self.name} ({self.type})"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _baker(cls):
|
def _baker(cls):
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ class BaseCategorySerializer(serializers.ModelSerializer):
|
|||||||
fields = [
|
fields = [
|
||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
|
"type",
|
||||||
"image",
|
"image",
|
||||||
"subcategories",
|
"subcategories",
|
||||||
]
|
]
|
||||||
@@ -22,6 +23,7 @@ class ListCategorySerializer(BaseCategorySerializer):
|
|||||||
fields = [
|
fields = [
|
||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
|
"type",
|
||||||
"image",
|
"image",
|
||||||
"subcategories",
|
"subcategories",
|
||||||
]
|
]
|
||||||
|
|||||||
0
resources/logs/.gitignore
vendored
Normal file → Executable file
0
resources/logs/.gitignore
vendored
Normal file → Executable file
Reference in New Issue
Block a user