Добавил приложение склад и модели заготовок
All checks were successful
Auto-Deploy-prodman / deploy (push) Successful in 6s

This commit is contained in:
2026-02-16 08:00:16 +03:00
parent 5d454c9ae3
commit 56dd6644e2
14 changed files with 17278 additions and 0 deletions

135
stock/admin.py Normal file
View File

@@ -0,0 +1,135 @@
from django.contrib import admin
from django.utils.html import format_html
from polymorphic.admin import (
PolymorphicChildModelAdmin,
PolymorphicParentModelAdmin,
PolymorphicChildModelFilter
)
from .models import Gost, MaterialGrade, BaseMaterial, SheetMaterial, ProfileMaterial, StockItem
# --- 1. Справочники (ГОСТ и Марки) ---
@admin.register(Gost)
class GostAdmin(admin.ModelAdmin):
list_display = ('name', 'description', 'get_pdf_link')
search_fields = ('name',)
def get_pdf_link(self, obj):
if obj.pdf_file:
return format_html('<a href="{}" target="_blank">📄 PDF</a>', obj.pdf_file.url)
return ""
get_pdf_link.short_description = "Файл"
@admin.register(MaterialGrade)
class MaterialGradeAdmin(admin.ModelAdmin):
list_display = ('name', 'gost', 'density')
search_fields = ('name', 'gost__name')
# --- 2. Дочерние админки для заготовок ---
class BaseChildAdmin(PolymorphicChildModelAdmin):
base_model = BaseMaterial
# Делаем название кликабельным и в дочерних списках
list_display_links = ('title',)
@admin.register(SheetMaterial)
class SheetMaterialAdmin(BaseChildAdmin):
list_display = ('title', 'thickness', 'grade', 'gost')
@admin.register(ProfileMaterial)
class ProfileMaterialAdmin(BaseChildAdmin):
list_display = ('title', 'profile_type', 'weight_per_meter', 'grade', 'gost')
# --- 3. Главная (родительская) админка заготовок ---
@admin.register(BaseMaterial)
class BaseMaterialParentAdmin(PolymorphicParentModelAdmin):
base_model = BaseMaterial
child_models = (SheetMaterial, ProfileMaterial)
# Заменяем обычный title на наш кликабельный метод
list_display = ('clickable_title', 'grade', 'gost', 'get_specs')
list_display_links = ('clickable_title',)
list_filter = (PolymorphicChildModelFilter, 'grade', 'gost')
search_fields = ('title',)
def clickable_title(self, obj):
"""Объединяет иконку и название в одну ссылку"""
# Безопасно получаем реальный тип (Лист или Профиль)
real_obj = obj.get_real_instance()
icon = ""
if isinstance(real_obj, SheetMaterial):
icon = "📄"
elif isinstance(real_obj, ProfileMaterial):
icon = "🏗️"
return format_html(
'<span style="margin-right: 8px; font-size: 1.1rem;">{}</span> <b>{}</b>',
icon,
obj.title
)
clickable_title.short_description = "Наименование заготовки"
clickable_title.admin_order_field = 'title' # Чтобы работала сортировка
def get_specs(self, obj):
"""Вывод ключевых параметров в общий список"""
real_obj = obj.get_real_instance()
if isinstance(real_obj, SheetMaterial):
return f"t = {real_obj.thickness} мм"
if isinstance(real_obj, ProfileMaterial):
return f"{real_obj.get_profile_type_display()}: {real_obj.weight_per_meter} кг/м"
return "-"
get_specs.short_description = "Характеристики"
# --- 4. Складской учет ---
@admin.register(StockItem)
class StockItemAdmin(admin.ModelAdmin):
list_display = (
'get_material_name',
'display_dimensions',
'quantity',
'colored_status',
'order_reference',
'location'
)
list_display_links = ('get_material_name',)
list_filter = ('is_scrap', 'material__grade', 'material')
search_fields = ('order_reference', 'material__title', 'location')
def get_material_name(self, obj):
return obj.material.title
get_material_name.short_description = "Заготовка"
def display_dimensions(self, obj):
"""Красивое отображение габаритов"""
if obj.width:
return format_html(f"<b>{obj.length} × {obj.width}</b>")
return format_html(f"L = <b>{obj.length}</b>")
display_dimensions.short_description = "Размеры (мм)"
def colored_status(self, obj):
"""Цветовая маркировка остатков"""
if obj.is_scrap:
return format_html('<b style="color: #ca8a04;">ОБРЕЗОК</b>')
return format_html('<b style="color: #16a34a;">ЦЕЛЫЙ</b>')
colored_status.short_description = "Статус"
fieldsets = (
(None, {
'fields': ('material', 'quantity')
}),
('Габариты (мм)', {
'fields': (('length', 'width'),)
}),
('Учет и хранение', {
'fields': ('is_scrap', 'order_reference', 'location')
}),
)