Консолидация миграций и добавление unit_service
- Обновлены начальные миграции для всех приложений - Удалены устаревшие миграции для единиц измерения и SKU - Добавлен новый сервис unit_service.py для управления единицами - Обновлены команды инициализации данных тенанта
This commit is contained in:
147
myproject/products/services/unit_service.py
Normal file
147
myproject/products/services/unit_service.py
Normal file
@@ -0,0 +1,147 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Сервис для управления единицами измерения.
|
||||
|
||||
Отвечает за создание и управление справочником единиц измерения (UnitOfMeasure).
|
||||
"""
|
||||
import logging
|
||||
from typing import List, Dict, Any
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class UnitOfMeasureService:
|
||||
"""
|
||||
Сервис для управления единицами измерения.
|
||||
|
||||
Предоставляет методы для создания и управления базовыми единицами измерения,
|
||||
которые используются в системе для товаров и продаж.
|
||||
"""
|
||||
|
||||
# Базовый набор единиц измерения для новых тенантов
|
||||
DEFAULT_UNITS = [
|
||||
# Базовые единицы (из старых UNIT_CHOICES)
|
||||
{'code': 'шт', 'name': 'Штука', 'short_name': 'шт.', 'position': 1},
|
||||
{'code': 'м', 'name': 'Метр', 'short_name': 'м.', 'position': 2},
|
||||
{'code': 'г', 'name': 'Грамм', 'short_name': 'г.', 'position': 3},
|
||||
{'code': 'л', 'name': 'Литр', 'short_name': 'л.', 'position': 4},
|
||||
{'code': 'кг', 'name': 'Килограмм', 'short_name': 'кг.', 'position': 5},
|
||||
|
||||
# Флористические единицы
|
||||
{'code': 'банч', 'name': 'Банч', 'short_name': 'банч', 'position': 10},
|
||||
{'code': 'ветка', 'name': 'Ветка', 'short_name': 'вет.', 'position': 11},
|
||||
{'code': 'пучок', 'name': 'Пучок', 'short_name': 'пуч.', 'position': 12},
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def create_default_units(cls) -> List:
|
||||
"""
|
||||
Создает базовый набор единиц измерения для тенанта.
|
||||
|
||||
Использует get_or_create, поэтому безопасно вызывать повторно.
|
||||
|
||||
Returns:
|
||||
List[UnitOfMeasure]: Список созданных/существующих единиц измерения
|
||||
"""
|
||||
from products.models import UnitOfMeasure
|
||||
|
||||
created_units = []
|
||||
|
||||
for unit_data in cls.DEFAULT_UNITS:
|
||||
unit, created = UnitOfMeasure.objects.get_or_create(
|
||||
code=unit_data['code'],
|
||||
defaults={
|
||||
'name': unit_data['name'],
|
||||
'short_name': unit_data['short_name'],
|
||||
'position': unit_data['position'],
|
||||
'is_active': True,
|
||||
}
|
||||
)
|
||||
created_units.append(unit)
|
||||
|
||||
if created:
|
||||
logger.debug(f"Создана единица измерения: {unit.code} - {unit.name}")
|
||||
|
||||
logger.info(f"Инициализация единиц измерения завершена: {len(created_units)} единиц")
|
||||
return created_units
|
||||
|
||||
@classmethod
|
||||
def reset_default_units(cls) -> List:
|
||||
"""
|
||||
Удаляет все единицы измерения и создаёт их заново.
|
||||
|
||||
ВНИМАНИЕ: Используйте только при инициализации тенанта или в тестах!
|
||||
Удаление единиц может нарушить связи с существующими товарами.
|
||||
|
||||
Returns:
|
||||
List[UnitOfMeasure]: Список созданных единиц измерения
|
||||
"""
|
||||
from products.models import UnitOfMeasure
|
||||
|
||||
logger.warning("Удаление всех единиц измерения...")
|
||||
UnitOfMeasure.objects.all().delete()
|
||||
|
||||
return cls.create_default_units()
|
||||
|
||||
@classmethod
|
||||
def get_or_create_unit(cls, code: str, name: str, short_name: str,
|
||||
position: int = 0) -> tuple:
|
||||
"""
|
||||
Получает или создаёт единицу измерения.
|
||||
|
||||
Args:
|
||||
code: Уникальный код единицы
|
||||
name: Полное название
|
||||
short_name: Короткое название для UI
|
||||
position: Позиция для сортировки
|
||||
|
||||
Returns:
|
||||
tuple: (UnitOfMeasure, created) - единица и флаг создания
|
||||
"""
|
||||
from products.models import UnitOfMeasure
|
||||
|
||||
unit, created = UnitOfMeasure.objects.get_or_create(
|
||||
code=code,
|
||||
defaults={
|
||||
'name': name,
|
||||
'short_name': short_name,
|
||||
'position': position,
|
||||
'is_active': True,
|
||||
}
|
||||
)
|
||||
|
||||
if created:
|
||||
logger.info(f"Создана единица измерения: {code} - {name}")
|
||||
|
||||
return unit, created
|
||||
|
||||
@classmethod
|
||||
def get_unit_by_code(cls, code: str):
|
||||
"""
|
||||
Получает единицу измерения по коду.
|
||||
|
||||
Args:
|
||||
code: Код единицы измерения
|
||||
|
||||
Returns:
|
||||
UnitOfMeasure или None, если не найдена
|
||||
"""
|
||||
from products.models import UnitOfMeasure
|
||||
|
||||
try:
|
||||
return UnitOfMeasure.objects.get(code=code, is_active=True)
|
||||
except UnitOfMeasure.DoesNotExist:
|
||||
logger.warning(f"Единица измерения с кодом '{code}' не найдена")
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def get_active_units(cls) -> List:
|
||||
"""
|
||||
Возвращает все активные единицы измерения.
|
||||
|
||||
Returns:
|
||||
List[UnitOfMeasure]: Список активных единиц, отсортированных по position
|
||||
"""
|
||||
from products.models import UnitOfMeasure
|
||||
|
||||
return list(UnitOfMeasure.objects.filter(is_active=True).order_by('position', 'code'))
|
||||
Reference in New Issue
Block a user