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.
This commit is contained in:
2026-01-25 00:40:52 +01:00
parent 775709bd08
commit 679cff2366
13 changed files with 196 additions and 193 deletions

3
.idea/misc.xml generated
View File

@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.13 (vontor-cz)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 (vontor-cz)" project-jdk-type="Python SDK" /> <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 (vontor-cz)" project-jdk-type="Python SDK" />
</project> </project>

View File

@@ -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 account.models
import django.contrib.auth.validators 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', 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_token', models.CharField(blank=True, db_index=True, max_length=128, null=True)),
('email_verification_sent_at', models.DateTimeField(blank=True, null=True)), ('email_verification_sent_at', models.DateTimeField(blank=True, null=True)),
('newsletter', models.BooleanField(default=True)),
('gdpr', models.BooleanField(default=False)), ('gdpr', models.BooleanField(default=False)),
('is_active', models.BooleanField(default=False)), ('is_active', models.BooleanField(default=False)),
('create_time', models.DateTimeField(auto_now_add=True)), ('create_time', models.DateTimeField(auto_now_add=True)),

View File

@@ -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 from django.db import migrations, models

View File

@@ -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.core.validators
import django.db.models.deletion import django.db.models.deletion
import django.utils.timezone import django.utils.timezone
from decimal import Decimal
from django.conf import settings from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
@@ -12,8 +13,10 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('configuration', '0001_initial'),
('deutschepost', '0002_deutschepostbulkorder_bulk_label_pdf_and_more'),
('stripe', '0001_initial'), ('stripe', '0001_initial'),
('zasilkovna', '0001_initial'), ('zasilkovna', '0002_alter_zasilkovnapacket_state'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL), migrations.swappable_dependency(settings.AUTH_USER_MODEL),
] ]
@@ -32,14 +35,29 @@ class Migration(migrations.Migration):
name='Carrier', name='Carrier',
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('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)), ('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', '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)), ('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)), ('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í')), ('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')), ('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( migrations.CreateModel(
name='Category', name='Category',
fields=[ fields=[
@@ -61,7 +79,7 @@ class Migration(migrations.Migration):
('code', models.CharField(max_length=50, unique=True)), ('code', models.CharField(max_length=50, unique=True)),
('description', models.CharField(blank=True, max_length=255)), ('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)])), ('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_from', models.DateTimeField(default=django.utils.timezone.now)),
('valid_to', models.DateTimeField(blank=True, null=True)), ('valid_to', models.DateTimeField(blank=True, null=True)),
('active', models.BooleanField(default=True)), ('active', models.BooleanField(default=True)),
@@ -74,7 +92,8 @@ class Migration(migrations.Migration):
name='Payment', name='Payment',
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('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)), ('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=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')), ('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', name='Order',
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('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)), ('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=0, max_digits=10)), ('total_price', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=10)),
('currency', models.CharField(default='CZK', max_length=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)), ('first_name', models.CharField(max_length=100)),
('last_name', models.CharField(max_length=100)), ('last_name', models.CharField(max_length=100)),
('email', models.EmailField(max_length=254)), ('email', models.EmailField(max_length=254)),
@@ -98,11 +117,11 @@ class Migration(migrations.Migration):
('note', models.TextField(blank=True)), ('note', models.TextField(blank=True)),
('created_at', models.DateTimeField(auto_now_add=True)), ('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=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')), ('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')), ('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)), ('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( migrations.CreateModel(
@@ -112,16 +131,18 @@ class Migration(migrations.Migration):
('name', models.CharField(max_length=200)), ('name', models.CharField(max_length=200)),
('description', models.TextField(blank=True)), ('description', models.TextField(blank=True)),
('code', models.CharField(blank=True, max_length=100, null=True, unique=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)), ('url', models.SlugField(unique=True)),
('stock', models.PositiveIntegerField(default=0)), ('stock', models.PositiveIntegerField(default=0)),
('is_active', models.BooleanField(default=True)), ('is_active', models.BooleanField(default=True)),
('limited_to', models.DateTimeField(blank=True, null=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)), ('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)), ('updated_at', models.DateTimeField(auto_now=True)),
('category', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='products', to='commerce.category')), ('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')), ('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( migrations.CreateModel(
@@ -145,18 +166,67 @@ class Migration(migrations.Migration):
('image', models.ImageField(upload_to='products/')), ('image', models.ImageField(upload_to='products/')),
('alt_text', models.CharField(blank=True, max_length=150)), ('alt_text', models.CharField(blank=True, max_length=150)),
('is_main', models.BooleanField(default=False)), ('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')), ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='images', to='commerce.product')),
], ],
options={
'ordering': ['order', '-is_main', 'id'],
},
), ),
migrations.CreateModel( migrations.CreateModel(
name='Refund', name='Refund',
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('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)), ('reason_text', models.TextField(blank=True)),
('verified', models.BooleanField(default=False)), ('verified', models.BooleanField(default=False)),
('created_at', models.DateTimeField(auto_now_add=True)), ('created_at', models.DateTimeField(auto_now_add=True)),
('order', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='refunds', to='commerce.order')), ('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')},
},
),
] ]

View File

@@ -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')},
},
),
]

View File

@@ -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
),
),
]

View File

@@ -165,6 +165,7 @@ class Order(models.Model):
# Stored order grand total; recalculated on save # Stored order grand total; recalculated on save
total_price = models.DecimalField(max_digits=10, decimal_places=2, default=Decimal('0.00')) 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 - 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 = models.CharField(max_length=10, default="", help_text="Order currency - captured from site configuration at order creation and never changes")
@@ -261,7 +262,7 @@ class Order(models.Model):
raise ValidationError("Order must have at least one item.") raise ValidationError("Order must have at least one item.")
def get_currency(self): 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: if self.currency:
return self.currency return self.currency
config = SiteConfiguration.get_solo() config = SiteConfiguration.get_solo()
@@ -503,7 +504,7 @@ class DiscountCode(models.Model):
) )
# nebo fixní částka # 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_from = models.DateTimeField(default=timezone.now)
valid_to = models.DateTimeField(null=True, blank=True) valid_to = models.DateTimeField(null=True, blank=True)

View File

@@ -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 from django.db import migrations, models
@@ -27,17 +29,39 @@ class Migration(migrations.Migration):
('youtube_url', models.URLField(blank=True, null=True)), ('youtube_url', models.URLField(blank=True, null=True)),
('tiktok_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)), ('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_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)), ('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')), ('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')), ('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={ options={
'verbose_name': 'Shop Configuration', 'verbose_name': 'Shop Configuration',
'verbose_name_plural': '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'],
},
),
] ]

View File

@@ -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),
),
]

View File

@@ -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 import django.db.models.deletion
from django.conf import settings from django.conf import settings

View File

@@ -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),
),
]

View File

@@ -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),
),
]

View File