from django.db import models from polymorphic.models import PolymorphicModel class Gost(models.Model): """Справочник нормативных документов (ГОСТ, ТУ, ОСТ)""" name = models.CharField("Название", max_length=100, help_text="Например, ГОСТ 19903-2015") description = models.TextField("Описание", blank=True, null=True) # Файлы будут загружаться в /media/gosts/ pdf_file = models.FileField("Файл (PDF)", upload_to='gosts/', blank=True, null=True) class Meta: verbose_name = "ГОСТ/ТУ" verbose_name_plural = "ГОСТы и ТУ" def __str__(self): return self.name class MaterialGrade(models.Model): """Справочник марок стали""" name = models.CharField("Марка стали", max_length=50) # Теперь ссылка на таблицу ГОСТов (например, ГОСТ на хим. состав) gost = models.ForeignKey(Gost, on_delete=models.SET_NULL, verbose_name="ГОСТ на марку", blank=True, null=True) density = models.PositiveIntegerField("Плотность, кг/м³", default=7850) class Meta: verbose_name = "Марка материала" verbose_name_plural = "Марки материалов" def __str__(self): return f"{self.name} ({self.gost.name})" if self.gost else self.name class BaseMaterial(PolymorphicModel): """Базовая модель для всех типов заготовок""" title = models.CharField("Наименование заготовки", max_length=255, help_text="Пример: Лист 10мм или Труба 40х40х2") grade = models.ForeignKey(MaterialGrade, on_delete=models.PROTECT, verbose_name="Марка стали") # ГОСТ на сортамент (например, ГОСТ на прокат листа или трубы) gost = models.ForeignKey(Gost, on_delete=models.SET_NULL, verbose_name="ГОСТ на сортамент", blank=True, null=True) class Meta: verbose_name = "Заготовка" verbose_name_plural = "Заготовки" def __str__(self): return f"{self.title} [{self.grade.name}]" class SheetMaterial(BaseMaterial): """Листовой прокат""" thickness = models.PositiveIntegerField("Толщина, мм") class Meta: verbose_name = "Листовой материал" verbose_name_plural = "Листовые материалы" class ProfileMaterial(BaseMaterial): """Линейный прокат""" SECTION_TYPES = [ ('round_tube', 'Труба круглая'), ('square_tube', 'Труба профильная'), ('channel', 'Швеллер'), ('angle', 'Уголок'), ('bar', 'Круг/Пруток'), ('other', 'Прочее'), ] profile_type = models.CharField("Тип сечения", max_length=20, choices=SECTION_TYPES) weight_per_meter = models.FloatField("Вес 1 м.п., кг", help_text="Табличный вес по ГОСТ") max_dimension = models.PositiveIntegerField("Макс. габарит сечения, мм", help_text="Для проверки входимости детали") class Meta: verbose_name = "Профильный материал" verbose_name_plural = "Профильные материалы" class StockItem(models.Model): """Складская единица (налицо)""" material = models.ForeignKey(BaseMaterial, on_delete=models.CASCADE, related_name='stock_items', verbose_name="Тип заготовки") length = models.PositiveIntegerField("Длина, мм") width = models.PositiveIntegerField("Ширина, мм", blank=True, null=True) quantity = models.PositiveIntegerField("Количество, шт", default=1) order_reference = models.CharField("Заказ/Сделка", max_length=100, blank=True, null=True) is_scrap = models.BooleanField("Деловой остаток", default=False) location = models.CharField("Место хранения", max_length=100, blank=True, null=True) class Meta: verbose_name = "Складская единица" verbose_name_plural = "Склад налицо" def __str__(self): dim = f"{self.length}x{self.width}" if self.width else f"L={self.length}" return f"{self.material.title} ({dim})"