refactor: Заменить сущность Магазин (Shop) на Склад (Warehouse)
Упрощена логика системы путём замены отдельной сущности "Магазин" на универсальную сущность "Склад", которая может использоваться как точка самовывоза. Изменения: - Расширена модель Warehouse: добавлены адрес, контакты, флаг is_pickup_point - Модель Order: поле pickup_shop заменено на pickup_warehouse - Обновлены все формы, сервисы, views, admin для работы со складами - Обновлены шаблоны HTML и JavaScript код - Удалено приложение shops полностью - Пересозданы миграции БД - Обновлён навбар (удалена ссылка на магазины) Преимущества: - Упрощена архитектура системы - Единая точка управления складами и точками самовывоза - Интеграция с системой инвентаризации 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
# Generated by Django 5.0.10 on 2025-11-13 13:12
|
||||
# Generated by Django 5.0.10 on 2025-11-14 20:45
|
||||
|
||||
import phonenumber_field.modelfields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
@@ -216,8 +217,13 @@ class Migration(migrations.Migration):
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=200, verbose_name='Название')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='Описание')),
|
||||
('street', models.CharField(blank=True, max_length=255, null=True, verbose_name='Улица')),
|
||||
('building_number', models.CharField(blank=True, max_length=20, null=True, verbose_name='Номер здания')),
|
||||
('phone', phonenumber_field.modelfields.PhoneNumberField(blank=True, max_length=128, null=True, region='BY', verbose_name='Телефон')),
|
||||
('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='Email')),
|
||||
('is_active', models.BooleanField(default=True, verbose_name='Активен')),
|
||||
('is_default', models.BooleanField(default=False, help_text='Автоматически выбирается при создании новых документов', verbose_name='Склад по умолчанию')),
|
||||
('is_pickup_point', models.BooleanField(default=True, help_text='Можно ли выбрать этот склад как точку самовывоза заказа', verbose_name='Доступен для самовывоза')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')),
|
||||
],
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.0.10 on 2025-11-13 13:12
|
||||
# Generated by Django 5.0.10 on 2025-11-14 20:45
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
@@ -128,6 +128,10 @@ class Migration(migrations.Migration):
|
||||
model_name='warehouse',
|
||||
index=models.Index(fields=['is_default'], name='inventory_w_is_defa_4b7615_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='warehouse',
|
||||
index=models.Index(fields=['is_pickup_point'], name='inventory_w_is_pick_e86268_idx'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transferbatch',
|
||||
name='from_warehouse',
|
||||
|
||||
@@ -3,20 +3,38 @@ from django.utils import timezone
|
||||
from django.core.exceptions import ValidationError
|
||||
from decimal import Decimal
|
||||
from products.models import Product
|
||||
from phonenumber_field.modelfields import PhoneNumberField
|
||||
|
||||
|
||||
class Warehouse(models.Model):
|
||||
"""
|
||||
Склад (физическое или логическое место хранения).
|
||||
Может использоваться как точка самовывоза для заказов.
|
||||
"""
|
||||
name = models.CharField(max_length=200, verbose_name="Название")
|
||||
description = models.TextField(blank=True, null=True, verbose_name="Описание")
|
||||
|
||||
# Адрес
|
||||
street = models.CharField(max_length=255, blank=True, null=True, verbose_name="Улица")
|
||||
building_number = models.CharField(max_length=20, blank=True, null=True, verbose_name="Номер здания")
|
||||
|
||||
# Контакты
|
||||
phone = PhoneNumberField(region='BY', blank=True, null=True, verbose_name="Телефон")
|
||||
email = models.EmailField(blank=True, null=True, verbose_name="Email")
|
||||
|
||||
# Настройки
|
||||
is_active = models.BooleanField(default=True, verbose_name="Активен")
|
||||
is_default = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name="Склад по умолчанию",
|
||||
help_text="Автоматически выбирается при создании новых документов"
|
||||
)
|
||||
is_pickup_point = models.BooleanField(
|
||||
default=True,
|
||||
verbose_name="Доступен для самовывоза",
|
||||
help_text="Можно ли выбрать этот склад как точку самовывоза заказа"
|
||||
)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Дата создания")
|
||||
updated_at = models.DateTimeField(auto_now=True, verbose_name="Дата обновления")
|
||||
|
||||
@@ -26,11 +44,24 @@ class Warehouse(models.Model):
|
||||
indexes = [
|
||||
models.Index(fields=['is_active']),
|
||||
models.Index(fields=['is_default']),
|
||||
models.Index(fields=['is_pickup_point']),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
if self.street and self.building_number:
|
||||
return f"{self.name} ({self.street}, {self.building_number})"
|
||||
return self.name
|
||||
|
||||
@property
|
||||
def full_address(self):
|
||||
"""Полный адрес склада"""
|
||||
parts = []
|
||||
if self.street:
|
||||
parts.append(self.street)
|
||||
if self.building_number:
|
||||
parts.append(self.building_number)
|
||||
return ', '.join(parts) if parts else "Адрес не указан"
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
"""Обеспечиваем что только один склад может быть по умолчанию в рамках одного тенанта"""
|
||||
if self.is_default:
|
||||
|
||||
Reference in New Issue
Block a user