From 679cff236693b2af0da16b08e52d7ab101dcdabe Mon Sep 17 00:00:00 2001 From: Brunobrno Date: Sun, 25 Jan 2026 00:40:52 +0100 Subject: [PATCH] Consolidate and update initial migrations and models Regenerated initial migrations for account, advertisement, commerce, configuration, and social apps to include recent schema changes and remove obsolete migration files. Added new migrations for Deutsche Post and Zasilkovna integrations, including new fields and choices. Updated commerce models to improve currency handling and discount code logic. This unifies the database schema and prepares for new features and integrations. --- .idea/misc.xml | 3 + backend/account/migrations/0001_initial.py | 3 +- .../advertisement/migrations/0001_initial.py | 2 +- backend/commerce/migrations/0001_initial.py | 100 +++++++++++++++--- ...e_options_carrier_deutschepost_and_more.py | 83 --------------- .../0003_remove_product_currency.py | 36 ------- backend/commerce/models.py | 29 ++--- .../configuration/migrations/0001_initial.py | 32 +++++- ...iguration_deutschepost_api_url_and_more.py | 38 ------- .../social/chat/migrations/0001_initial.py | 2 +- ...hepostbulkorder_bulk_label_pdf_and_more.py | 43 ++++++++ .../0002_alter_zasilkovnapacket_state.py | 18 ++++ backups/backup-20260124-224819.sql | 0 13 files changed, 196 insertions(+), 193 deletions(-) delete mode 100644 backend/commerce/migrations/0002_alter_productimage_options_carrier_deutschepost_and_more.py delete mode 100644 backend/commerce/migrations/0003_remove_product_currency.py delete mode 100644 backend/configuration/migrations/0002_siteconfiguration_deutschepost_api_url_and_more.py create mode 100644 backend/thirdparty/deutschepost/migrations/0002_deutschepostbulkorder_bulk_label_pdf_and_more.py create mode 100644 backend/thirdparty/zasilkovna/migrations/0002_alter_zasilkovnapacket_state.py create mode 100644 backups/backup-20260124-224819.sql diff --git a/.idea/misc.xml b/.idea/misc.xml index 430eb9f..eecf704 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,7 @@ + + \ No newline at end of file diff --git a/backend/account/migrations/0001_initial.py b/backend/account/migrations/0001_initial.py index 9e0eabf..3730b23 100644 --- a/backend/account/migrations/0001_initial.py +++ b/backend/account/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.7 on 2025-12-18 15:11 +# Generated by Django 5.2.7 on 2026-01-24 22:44 import account.models import django.contrib.auth.validators @@ -36,6 +36,7 @@ class Migration(migrations.Migration): ('email', models.EmailField(db_index=True, max_length=254, unique=True)), ('email_verification_token', models.CharField(blank=True, db_index=True, max_length=128, null=True)), ('email_verification_sent_at', models.DateTimeField(blank=True, null=True)), + ('newsletter', models.BooleanField(default=True)), ('gdpr', models.BooleanField(default=False)), ('is_active', models.BooleanField(default=False)), ('create_time', models.DateTimeField(auto_now_add=True)), diff --git a/backend/advertisement/migrations/0001_initial.py b/backend/advertisement/migrations/0001_initial.py index b2360dc..c875f9a 100644 --- a/backend/advertisement/migrations/0001_initial.py +++ b/backend/advertisement/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.9 on 2025-12-14 02:23 +# Generated by Django 5.2.7 on 2026-01-24 22:44 from django.db import migrations, models diff --git a/backend/commerce/migrations/0001_initial.py b/backend/commerce/migrations/0001_initial.py index c0f0d33..e9bceff 100644 --- a/backend/commerce/migrations/0001_initial.py +++ b/backend/commerce/migrations/0001_initial.py @@ -1,8 +1,9 @@ -# Generated by Django 5.2.7 on 2025-12-19 08:55 +# Generated by Django 5.2.7 on 2026-01-24 22:44 import django.core.validators import django.db.models.deletion import django.utils.timezone +from decimal import Decimal from django.conf import settings from django.db import migrations, models @@ -12,8 +13,10 @@ class Migration(migrations.Migration): initial = True dependencies = [ + ('configuration', '0001_initial'), + ('deutschepost', '0002_deutschepostbulkorder_bulk_label_pdf_and_more'), ('stripe', '0001_initial'), - ('zasilkovna', '0001_initial'), + ('zasilkovna', '0002_alter_zasilkovnapacket_state'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] @@ -32,14 +35,29 @@ class Migration(migrations.Migration): name='Carrier', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('shipping_method', models.CharField(choices=[('packeta', 'cz#Zásilkovna'), ('store', 'cz#Osobní odběr')], default='store', max_length=20)), - ('state', models.CharField(choices=[('ordered', 'cz#Objednávka se připravuje'), ('shipped', 'cz#Odesláno'), ('delivered', 'cz#Doručeno'), ('ready_to_pickup', 'cz#Připraveno k vyzvednutí')], default='ordered', max_length=20)), + ('shipping_method', models.CharField(choices=[('packeta', 'Zásilkovna'), ('deutschepost', 'Deutsche Post'), ('store', 'Osobní odběr')], default='store', max_length=20)), + ('state', models.CharField(choices=[('ordered', 'Objednávka se připravuje'), ('shipped', 'Odesláno'), ('delivered', 'Doručeno'), ('ready_to_pickup', 'Připraveno k vyzvednutí')], default='ordered', max_length=20)), ('weight', models.DecimalField(blank=True, decimal_places=2, help_text='Hmotnost zásilky v kg', max_digits=10, null=True)), ('returning', models.BooleanField(default=False, help_text='Zda je tato zásilka na vrácení')), - ('shipping_price', models.DecimalField(decimal_places=2, default=0, max_digits=10)), + ('shipping_price', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=10)), + ('deutschepost', models.ManyToManyField(blank=True, related_name='carriers', to='deutschepost.deutschepostorder')), ('zasilkovna', models.ManyToManyField(blank=True, related_name='carriers', to='zasilkovna.zasilkovnapacket')), ], ), + migrations.CreateModel( + name='Cart', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('session_key', models.CharField(blank=True, help_text='Session key for anonymous users', max_length=40, null=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('user', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='cart', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'Cart', + 'verbose_name_plural': 'Carts', + }, + ), migrations.CreateModel( name='Category', fields=[ @@ -61,7 +79,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50, unique=True)), ('description', models.CharField(blank=True, max_length=255)), ('percent', models.PositiveIntegerField(blank=True, help_text='Procento sleva 0-100', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(100)])), - ('amount', models.DecimalField(blank=True, decimal_places=2, help_text='Fixní sleva v CZK', max_digits=10, null=True)), + ('amount', models.DecimalField(blank=True, decimal_places=2, help_text='Fixed discount amount in site currency', max_digits=10, null=True)), ('valid_from', models.DateTimeField(default=django.utils.timezone.now)), ('valid_to', models.DateTimeField(blank=True, null=True)), ('active', models.BooleanField(default=True)), @@ -74,7 +92,8 @@ class Migration(migrations.Migration): name='Payment', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('payment_method', models.CharField(choices=[('Site', 'cz#Platba v obchodě'), ('stripe', 'cz#Bankovní převod'), ('cash_on_delivery', 'cz#Dobírka')], default='Site', max_length=30)), + ('payment_method', models.CharField(choices=[('shop', 'Platba v obchodě'), ('stripe', 'Platební Brána'), ('cash_on_delivery', 'Dobírka')], default='shop', max_length=30)), + ('payed_at_shop', models.BooleanField(blank=True, default=False, null=True)), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('stripe', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='payment', to='stripe.stripemodel')), @@ -84,9 +103,9 @@ class Migration(migrations.Migration): name='Order', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('status', models.CharField(blank=True, choices=[('created', 'cz#Vytvořeno'), ('cancelled', 'cz#Zrušeno'), ('completed', 'cz#Dokončeno'), ('refunding', 'cz#Vrácení v procesu'), ('refunded', 'cz#Vráceno')], default='created', max_length=20, null=True)), - ('total_price', models.DecimalField(decimal_places=2, default=0, max_digits=10)), - ('currency', models.CharField(default='CZK', max_length=10)), + ('status', models.CharField(blank=True, choices=[('created', 'Vytvořeno'), ('cancelled', 'Zrušeno'), ('completed', 'Dokončeno'), ('refunding', 'Vrácení v procesu'), ('refunded', 'Vráceno')], default='created', max_length=20, null=True)), + ('total_price', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=10)), + ('currency', models.CharField(default='', help_text='Order currency - captured from site configuration at order creation and never changes', max_length=10)), ('first_name', models.CharField(max_length=100)), ('last_name', models.CharField(max_length=100)), ('email', models.EmailField(max_length=254)), @@ -98,11 +117,11 @@ class Migration(migrations.Migration): ('note', models.TextField(blank=True)), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), - ('carrier', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='orders', to='commerce.carrier')), + ('carrier', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='order', to='commerce.carrier')), ('discount', models.ManyToManyField(blank=True, related_name='orders', to='commerce.discountcode')), ('invoice', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='order', to='commerce.invoice')), ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='orders', to=settings.AUTH_USER_MODEL)), - ('payment', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='orders', to='commerce.payment')), + ('payment', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='order', to='commerce.payment')), ], ), migrations.CreateModel( @@ -112,16 +131,18 @@ class Migration(migrations.Migration): ('name', models.CharField(max_length=200)), ('description', models.TextField(blank=True)), ('code', models.CharField(blank=True, max_length=100, null=True, unique=True)), - ('price', models.DecimalField(decimal_places=2, max_digits=10)), + ('price', models.DecimalField(decimal_places=2, help_text='Net price (without VAT)', max_digits=10)), ('url', models.SlugField(unique=True)), ('stock', models.PositiveIntegerField(default=0)), ('is_active', models.BooleanField(default=True)), ('limited_to', models.DateTimeField(blank=True, null=True)), + ('include_in_week_summary_email', models.BooleanField(default=False)), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('category', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='products', to='commerce.category')), ('default_carrier', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='default_for_products', to='commerce.carrier')), - ('variants', models.ManyToManyField(blank=True, help_text='Symetrické varianty produktu: pokud přidáte variantu A → B, Django automaticky přidá i variantu B → A. Všechny varianty jsou rovnocenné a zobrazí se vzájemně.', related_name='variant_of', to='commerce.product')), + ('variants', models.ManyToManyField(blank=True, help_text='Symetrické varianty produktu: pokud přidáte variantu A → B, Django automaticky přidá i variantu B → A. Všechny varianty jsou rovnocenné a zobrazí se vzájemně.', to='commerce.product')), + ('vat_rate', models.ForeignKey(blank=True, help_text='VAT rate for this product. Leave empty to use default rate.', null=True, on_delete=django.db.models.deletion.PROTECT, to='configuration.vatrate')), ], ), migrations.CreateModel( @@ -145,18 +166,67 @@ class Migration(migrations.Migration): ('image', models.ImageField(upload_to='products/')), ('alt_text', models.CharField(blank=True, max_length=150)), ('is_main', models.BooleanField(default=False)), + ('order', models.PositiveIntegerField(default=0, help_text='Display order (lower numbers first)')), ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='images', to='commerce.product')), ], + options={ + 'ordering': ['order', '-is_main', 'id'], + }, ), migrations.CreateModel( name='Refund', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('reason_choice', models.CharField(choices=[('retuning_before_fourteen_day_period', 'cz#Vrácení před uplynutím 14-ti denní lhůty'), ('damaged_product', 'cz#Poškozený produkt'), ('wrong_item', 'cz#Špatná položka'), ('other', 'cz#Jiný důvod')], max_length=40)), + ('reason_choice', models.CharField(choices=[('retuning_before_fourteen_day_period', 'Vrácení před uplynutím 14-ti denní lhůty'), ('damaged_product', 'Poškozený produkt'), ('wrong_item', 'Špatná položka'), ('other', 'Jiný důvod')], max_length=40)), ('reason_text', models.TextField(blank=True)), ('verified', models.BooleanField(default=False)), ('created_at', models.DateTimeField(auto_now_add=True)), ('order', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='refunds', to='commerce.order')), ], ), + migrations.CreateModel( + name='Wishlist', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('products', models.ManyToManyField(blank=True, help_text='Products saved by the user', related_name='wishlisted_by', to='commerce.product')), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='wishlist', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'Wishlist', + 'verbose_name_plural': 'Wishlists', + }, + ), + migrations.CreateModel( + name='CartItem', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('quantity', models.PositiveIntegerField(default=1)), + ('added_at', models.DateTimeField(auto_now_add=True)), + ('cart', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='commerce.cart')), + ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='commerce.product')), + ], + options={ + 'verbose_name': 'Cart Item', + 'verbose_name_plural': 'Cart Items', + 'unique_together': {('cart', 'product')}, + }, + ), + migrations.CreateModel( + name='Review', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('rating', models.PositiveIntegerField(validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(5)])), + ('comment', models.TextField(blank=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reviews', to='commerce.product')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reviews', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'indexes': [models.Index(fields=['product', 'rating'], name='commerce_re_product_9cd1a8_idx'), models.Index(fields=['created_at'], name='commerce_re_created_fe14ef_idx')], + 'unique_together': {('product', 'user')}, + }, + ), ] diff --git a/backend/commerce/migrations/0002_alter_productimage_options_carrier_deutschepost_and_more.py b/backend/commerce/migrations/0002_alter_productimage_options_carrier_deutschepost_and_more.py deleted file mode 100644 index 41016c5..0000000 --- a/backend/commerce/migrations/0002_alter_productimage_options_carrier_deutschepost_and_more.py +++ /dev/null @@ -1,83 +0,0 @@ -# Generated by Django 5.2.7 on 2026-01-17 01:37 - -import django.core.validators -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('commerce', '0001_initial'), - ('deutschepost', '0001_initial'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.AlterModelOptions( - name='productimage', - options={'ordering': ['order', '-is_main', 'id']}, - ), - migrations.AddField( - model_name='carrier', - name='deutschepost', - field=models.ManyToManyField(blank=True, related_name='carriers', to='deutschepost.deutschepostorder'), - ), - migrations.AddField( - model_name='productimage', - name='order', - field=models.PositiveIntegerField(default=0, help_text='Display order (lower numbers first)'), - ), - migrations.AlterField( - model_name='carrier', - name='shipping_method', - field=models.CharField(choices=[('packeta', 'cz#Zásilkovna'), ('deutschepost', 'cz#Deutsche Post'), ('store', 'cz#Osobní odběr')], default='store', max_length=20), - ), - migrations.AlterField( - model_name='product', - name='variants', - field=models.ManyToManyField(blank=True, help_text='Symetrické varianty produktu: pokud přidáte variantu A → B, Django automaticky přidá i variantu B → A. Všechny varianty jsou rovnocenné a zobrazí se vzájemně.', to='commerce.product'), - ), - migrations.CreateModel( - name='Cart', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('session_key', models.CharField(blank=True, help_text='Session key for anonymous users', max_length=40, null=True)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('user', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='cart', to=settings.AUTH_USER_MODEL)), - ], - options={ - 'verbose_name': 'Cart', - 'verbose_name_plural': 'Carts', - }, - ), - migrations.CreateModel( - name='Review', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('rating', models.PositiveIntegerField(validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(5)])), - ('comment', models.TextField(blank=True)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reviews', to='commerce.product')), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reviews', to=settings.AUTH_USER_MODEL)), - ], - ), - migrations.CreateModel( - name='CartItem', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('quantity', models.PositiveIntegerField(default=1)), - ('added_at', models.DateTimeField(auto_now_add=True)), - ('cart', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='commerce.cart')), - ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='commerce.product')), - ], - options={ - 'verbose_name': 'Cart Item', - 'verbose_name_plural': 'Cart Items', - 'unique_together': {('cart', 'product')}, - }, - ), - ] diff --git a/backend/commerce/migrations/0003_remove_product_currency.py b/backend/commerce/migrations/0003_remove_product_currency.py deleted file mode 100644 index 3e47ff7..0000000 --- a/backend/commerce/migrations/0003_remove_product_currency.py +++ /dev/null @@ -1,36 +0,0 @@ -# Generated migration to remove Product.currency field and use global currency system -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('commerce', '0002_alter_productimage_options_carrier_deutschepost_and_more'), - ] - - operations = [ - migrations.RemoveField( - model_name='product', - name='currency', - ), - migrations.AlterField( - model_name='order', - name='currency', - field=models.CharField( - default='', - help_text='Order currency - auto-filled from site configuration', - max_length=10 - ), - ), - migrations.AlterField( - model_name='discountcode', - name='amount', - field=models.DecimalField( - blank=True, - decimal_places=2, - help_text='Fixed discount amount in site currency', - max_digits=10, - null=True - ), - ), - ] \ No newline at end of file diff --git a/backend/commerce/models.py b/backend/commerce/models.py index 07e7e51..fc84954 100644 --- a/backend/commerce/models.py +++ b/backend/commerce/models.py @@ -165,8 +165,9 @@ class Order(models.Model): # Stored order grand total; recalculated on save total_price = models.DecimalField(max_digits=10, decimal_places=2, default=Decimal('0.00')) -# Currency - captured from site configuration at creation time, never changes - currency = models.CharField(max_length=10, default="", help_text="Order currency - captured from site configuration at order creation and never changes") + + # Currency - captured from site configuration at creation time, never changes + currency = models.CharField(max_length=10, default="", help_text="Order currency - captured from site configuration at order creation and never changes") # fakturační údaje (zkopírované z user profilu při objednávce) user = models.ForeignKey( @@ -261,23 +262,23 @@ class Order(models.Model): raise ValidationError("Order must have at least one item.") def get_currency(self): - \"\"\"Get order currency - falls back to site configuration if not set\"\"\" + """Get order currency - falls back to site configuration if not set""" if self.currency: return self.currency config = SiteConfiguration.get_solo() return config.currency def save(self, *args, **kwargs): - is_new = self.pk is None - - # CRITICAL: Set currency from site configuration ONLY at creation time - # Once set, currency should NEVER change to maintain order integrity - if is_new and not self.currency: - config = SiteConfiguration.get_solo() - self.currency = config.currency - - # Keep total_price always in sync with items and discount - self.total_price = self.calculate_total_price() + is_new = self.pk is None + + # CRITICAL: Set currency from site configuration ONLY at creation time + # Once set, currency should NEVER change to maintain order integrity + if is_new and not self.currency: + config = SiteConfiguration.get_solo() + self.currency = config.currency + + # Keep total_price always in sync with items and discount + self.total_price = self.calculate_total_price() if self.user and is_new: self.import_data_from_user() @@ -503,7 +504,7 @@ class DiscountCode(models.Model): ) # nebo fixní částka - amount = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, help_text=\"Fixed discount amount in site currency\") + amount = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, help_text="Fixed discount amount in site currency") valid_from = models.DateTimeField(default=timezone.now) valid_to = models.DateTimeField(null=True, blank=True) diff --git a/backend/configuration/migrations/0001_initial.py b/backend/configuration/migrations/0001_initial.py index 182adee..d3f9406 100644 --- a/backend/configuration/migrations/0001_initial.py +++ b/backend/configuration/migrations/0001_initial.py @@ -1,5 +1,7 @@ -# Generated by Django 5.2.7 on 2025-12-18 15:11 +# Generated by Django 5.2.7 on 2026-01-24 22:44 +import django.core.validators +from decimal import Decimal from django.db import migrations, models @@ -27,17 +29,39 @@ class Migration(migrations.Migration): ('youtube_url', models.URLField(blank=True, null=True)), ('tiktok_url', models.URLField(blank=True, null=True)), ('whatsapp_number', models.CharField(blank=True, max_length=20, null=True)), - ('zasilkovna_shipping_price', models.DecimalField(decimal_places=2, default=50, max_digits=10)), + ('zasilkovna_shipping_price', models.DecimalField(decimal_places=2, default=Decimal('50.00'), max_digits=10)), ('zasilkovna_api_key', models.CharField(blank=True, help_text='API klíč pro přístup k Zásilkovna API (zatím není využito)', max_length=255, null=True)), ('zasilkovna_api_password', models.CharField(blank=True, help_text='API heslo pro přístup k Zásilkovna API (zatím není využito)', max_length=255, null=True)), - ('free_shipping_over', models.DecimalField(decimal_places=2, default=2000, max_digits=10)), + ('free_shipping_over', models.DecimalField(decimal_places=2, default=Decimal('2000.00'), max_digits=10)), + ('deutschepost_api_url', models.URLField(default='https://gw.sandbox.deutschepost.com', help_text='Deutsche Post API URL (sandbox/production)', max_length=255)), + ('deutschepost_client_id', models.CharField(blank=True, help_text='Deutsche Post OAuth Client ID', max_length=255, null=True)), + ('deutschepost_client_secret', models.CharField(blank=True, help_text='Deutsche Post OAuth Client Secret', max_length=255, null=True)), + ('deutschepost_customer_ekp', models.CharField(blank=True, help_text='Deutsche Post Customer EKP number', max_length=20, null=True)), + ('deutschepost_shipping_price', models.DecimalField(decimal_places=2, default=Decimal('6.00'), help_text='Default Deutsche Post shipping price in EUR', max_digits=10)), ('multiplying_coupons', models.BooleanField(default=True, help_text='Násobení kupónů v objednávce (ano/ne), pokud ne tak se použije pouze nejvyšší slevový kupón')), ('addition_of_coupons_amount', models.BooleanField(default=False, help_text='Sčítání slevových kupónů v objednávce (ano/ne), pokud ne tak se použije pouze nejvyšší slevový kupón')), - ('currency', models.CharField(choices=[('CZK', 'cz#Czech Koruna'), ('EUR', 'cz#Euro')], default='CZK', max_length=10)), + ('currency', models.CharField(choices=[('EUR', 'Euro'), ('CZK', 'Czech Koruna'), ('USD', 'US Dollar'), ('GBP', 'British Pound'), ('PLN', 'Polish Zloty'), ('HUF', 'Hungarian Forint'), ('SEK', 'Swedish Krona'), ('DKK', 'Danish Krone'), ('NOK', 'Norwegian Krone'), ('CHF', 'Swiss Franc')], default='EUR', max_length=10)), ], options={ 'verbose_name': 'Shop Configuration', 'verbose_name_plural': 'Shop Configuration', }, ), + migrations.CreateModel( + name='VATRate', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(help_text="E.g. 'German Standard', 'German Reduced', 'Czech Standard'", max_length=100)), + ('description', models.TextField(blank=True, help_text="Optional description: 'Standard rate for most products', 'Books and food', etc.")), + ('rate', models.DecimalField(decimal_places=4, help_text='VAT rate as percentage (e.g. 19.00 for 19%)', max_digits=5, validators=[django.core.validators.MinValueValidator(Decimal('0')), django.core.validators.MaxValueValidator(Decimal('100'))])), + ('is_default', models.BooleanField(default=False, help_text='Default rate for new products')), + ('is_active', models.BooleanField(default=True, help_text='Whether this VAT rate is active and available for use')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ], + options={ + 'verbose_name': 'VAT Rate', + 'verbose_name_plural': 'VAT Rates', + 'ordering': ['-is_default', 'rate', 'name'], + }, + ), ] diff --git a/backend/configuration/migrations/0002_siteconfiguration_deutschepost_api_url_and_more.py b/backend/configuration/migrations/0002_siteconfiguration_deutschepost_api_url_and_more.py deleted file mode 100644 index 76d1c32..0000000 --- a/backend/configuration/migrations/0002_siteconfiguration_deutschepost_api_url_and_more.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 5.2.7 on 2026-01-17 01:37 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('configuration', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='siteconfiguration', - name='deutschepost_api_url', - field=models.URLField(default='https://gw.sandbox.deutschepost.com', help_text='Deutsche Post API URL (sandbox/production)', max_length=255), - ), - migrations.AddField( - model_name='siteconfiguration', - name='deutschepost_client_id', - field=models.CharField(blank=True, help_text='Deutsche Post OAuth Client ID', max_length=255, null=True), - ), - migrations.AddField( - model_name='siteconfiguration', - name='deutschepost_client_secret', - field=models.CharField(blank=True, help_text='Deutsche Post OAuth Client Secret', max_length=255, null=True), - ), - migrations.AddField( - model_name='siteconfiguration', - name='deutschepost_customer_ekp', - field=models.CharField(blank=True, help_text='Deutsche Post Customer EKP number', max_length=20, null=True), - ), - migrations.AddField( - model_name='siteconfiguration', - name='deutschepost_shipping_price', - field=models.DecimalField(decimal_places=2, default=150, help_text='Default Deutsche Post shipping price', max_digits=10), - ), - ] diff --git a/backend/social/chat/migrations/0001_initial.py b/backend/social/chat/migrations/0001_initial.py index 54b4b7a..4663f07 100644 --- a/backend/social/chat/migrations/0001_initial.py +++ b/backend/social/chat/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.7 on 2026-01-17 01:37 +# Generated by Django 5.2.7 on 2026-01-24 22:44 import django.db.models.deletion from django.conf import settings diff --git a/backend/thirdparty/deutschepost/migrations/0002_deutschepostbulkorder_bulk_label_pdf_and_more.py b/backend/thirdparty/deutschepost/migrations/0002_deutschepostbulkorder_bulk_label_pdf_and_more.py new file mode 100644 index 0000000..a34517c --- /dev/null +++ b/backend/thirdparty/deutschepost/migrations/0002_deutschepostbulkorder_bulk_label_pdf_and_more.py @@ -0,0 +1,43 @@ +# Generated by Django 5.2.7 on 2026-01-24 22:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('deutschepost', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='deutschepostbulkorder', + name='bulk_label_pdf', + field=models.FileField(blank=True, help_text='Bulk shipment label PDF', null=True, upload_to='deutschepost/bulk_labels/'), + ), + migrations.AddField( + model_name='deutschepostbulkorder', + name='paperwork_pdf', + field=models.FileField(blank=True, help_text='Bulk shipment paperwork PDF', null=True, upload_to='deutschepost/paperwork/'), + ), + migrations.AddField( + model_name='deutschepostorder', + name='label_pdf', + field=models.FileField(blank=True, help_text='Shipping label PDF', null=True, upload_to='deutschepost/labels/'), + ), + migrations.AddField( + model_name='deutschepostorder', + name='label_size', + field=models.CharField(choices=[('A4', 'A4 (210x297mm)'), ('A5', 'A5 (148x210mm)'), ('A6', 'A6 (105x148mm)')], default='A4', max_length=10), + ), + migrations.AlterField( + model_name='deutschepostbulkorder', + name='status', + field=models.CharField(choices=[('CREATED', 'Vytvořeno'), ('PROCESSING', 'Zpracovává se'), ('COMPLETED', 'Dokončeno'), ('ERROR', 'Chyba')], default='CREATED', max_length=20), + ), + migrations.AlterField( + model_name='deutschepostorder', + name='state', + field=models.CharField(choices=[('CREATED', 'Vytvořeno'), ('FINALIZED', 'Dokončeno'), ('SHIPPED', 'Odesláno'), ('DELIVERED', 'Doručeno'), ('CANCELLED', 'Zrušeno'), ('ERROR', 'Chyba')], default='CREATED', max_length=20), + ), + ] diff --git a/backend/thirdparty/zasilkovna/migrations/0002_alter_zasilkovnapacket_state.py b/backend/thirdparty/zasilkovna/migrations/0002_alter_zasilkovnapacket_state.py new file mode 100644 index 0000000..82cdbf6 --- /dev/null +++ b/backend/thirdparty/zasilkovna/migrations/0002_alter_zasilkovnapacket_state.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.7 on 2026-01-24 22:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('zasilkovna', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='zasilkovnapacket', + name='state', + field=models.CharField(choices=[('WAITING_FOR_ORDERING_SHIPMENT', 'Čeká na objednání zásilkovny'), ('PENDING', 'Podáno'), ('SENDED', 'Odesláno'), ('ARRIVED', 'Doručeno'), ('CANCELED', 'Zrušeno'), ('RETURNING', 'Posláno zpátky'), ('RETURNED', 'Vráceno')], default='PENDING', max_length=35), + ), + ] diff --git a/backups/backup-20260124-224819.sql b/backups/backup-20260124-224819.sql new file mode 100644 index 0000000..e69de29