This commit is contained in:
@@ -1,28 +1,94 @@
|
||||
import os
|
||||
from django.contrib import admin
|
||||
from .models import Company, EmployeeProfile, Machine, Deal, ProductionTask, Item
|
||||
from django.contrib import admin, messages
|
||||
|
||||
from shiftflow.services.sessions import close_cutting_session
|
||||
from warehouse.models import StockItem
|
||||
|
||||
from .models import (
|
||||
Company,
|
||||
CuttingSession,
|
||||
Deal,
|
||||
DealItem,
|
||||
DxfPreviewJob,
|
||||
DxfPreviewSettings,
|
||||
EmployeeProfile,
|
||||
Item,
|
||||
Machine,
|
||||
MaterialRequirement,
|
||||
ProductionReportConsumption,
|
||||
ProductionReportRemnant,
|
||||
ProductionTask,
|
||||
ShiftItem,
|
||||
Workshop,
|
||||
)
|
||||
|
||||
# --- Настройка отображения Компаний ---
|
||||
@admin.register(Company)
|
||||
class CompanyAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'description')
|
||||
search_fields = ('name',)
|
||||
"""
|
||||
Панель администрирования Компаний
|
||||
"""
|
||||
list_display = ('name', 'description') # Что видим в общем списке
|
||||
search_fields = ('name',) # Поиск по имени
|
||||
|
||||
class DealItemInline(admin.TabularInline):
|
||||
model = DealItem
|
||||
fields = ('entity', 'quantity')
|
||||
autocomplete_fields = ('entity',)
|
||||
extra = 10
|
||||
|
||||
|
||||
# --- Настройка отображения Сделок ---
|
||||
@admin.register(Deal)
|
||||
class DealAdmin(admin.ModelAdmin):
|
||||
list_display = ('number', 'status', 'company')
|
||||
"""
|
||||
Панель администрирования Сделок
|
||||
"""
|
||||
list_display = ('number', 'id', 'status', 'company')
|
||||
list_display_links = ('number',)
|
||||
search_fields = ('number', 'company__name')
|
||||
list_filter = ('status', 'company')
|
||||
inlines = (DealItemInline,)
|
||||
|
||||
# --- Задания на производство (База) ---
|
||||
"""
|
||||
Панель администрирования Заданий на производство
|
||||
"""
|
||||
@admin.register(ProductionTask)
|
||||
class ProductionTaskAdmin(admin.ModelAdmin):
|
||||
list_display = ('drawing_name', 'deal', 'material', 'quantity_ordered', 'created_at')
|
||||
search_fields = ('drawing_name', 'deal__number')
|
||||
list_display = ('drawing_name', 'deal', 'entity', 'material', 'quantity_ordered', 'created_at')
|
||||
search_fields = ('drawing_name', 'deal__number', 'entity__name', 'entity__drawing_number')
|
||||
list_filter = ('deal', 'material', 'is_bend')
|
||||
autocomplete_fields = ('deal', 'entity', 'material')
|
||||
|
||||
# --- Сменные задания (Выполнение) ---
|
||||
|
||||
"""
|
||||
Панель администрирования Сделочных элементов
|
||||
"""
|
||||
@admin.register(DealItem)
|
||||
class DealItemAdmin(admin.ModelAdmin):
|
||||
"""
|
||||
Панель администрирования Сделочных элементов
|
||||
"""
|
||||
list_display = ('deal', 'entity', 'quantity')
|
||||
search_fields = ('deal__number', 'entity__name', 'entity__drawing_number')
|
||||
list_filter = ('deal',)
|
||||
autocomplete_fields = ('deal', 'entity')
|
||||
|
||||
|
||||
@admin.register(MaterialRequirement)
|
||||
class MaterialRequirementAdmin(admin.ModelAdmin):
|
||||
"""
|
||||
Панель администрирования Требований к Материалам
|
||||
"""
|
||||
list_display = ('deal', 'material', 'required_qty', 'unit', 'status')
|
||||
search_fields = ('deal__number', 'material__name', 'material__full_name')
|
||||
list_filter = ('status', 'unit', 'material__category')
|
||||
autocomplete_fields = ('deal', 'material')
|
||||
|
||||
"""
|
||||
Панель администрирования Сменных задания (Выполнение)
|
||||
"""
|
||||
@admin.register(Item)
|
||||
class ItemAdmin(admin.ModelAdmin):
|
||||
# Что видим в общем списке (используем task__ для доступа к полям базы)
|
||||
@@ -53,13 +119,147 @@ class ItemAdmin(admin.ModelAdmin):
|
||||
return obj.task.drawing_name if obj.task else "-"
|
||||
get_drawing.short_description = 'Деталь'
|
||||
|
||||
@admin.register(Workshop)
|
||||
class WorkshopAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'location')
|
||||
search_fields = ('name',)
|
||||
list_filter = ('location',)
|
||||
|
||||
|
||||
@admin.register(Machine)
|
||||
class MachineAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'machine_type')
|
||||
list_filter = ('machine_type',)
|
||||
list_display = ('name', 'machine_type', 'workshop', 'location')
|
||||
list_display_links = ('name',)
|
||||
list_filter = ('machine_type', 'workshop')
|
||||
search_fields = ('name',)
|
||||
fields = ('name', 'machine_type', 'workshop', 'location')
|
||||
|
||||
|
||||
class ProductionReportLineInline(admin.TabularInline):
|
||||
model = ShiftItem
|
||||
fk_name = 'session'
|
||||
fields = ('task', 'quantity_fact', 'material_substitution')
|
||||
extra = 5
|
||||
|
||||
|
||||
class ProductionReportConsumptionInline(admin.TabularInline):
|
||||
model = ProductionReportConsumption
|
||||
fk_name = 'report'
|
||||
fields = ('stock_item', 'quantity')
|
||||
autocomplete_fields = ('stock_item',)
|
||||
extra = 3
|
||||
|
||||
def formfield_for_foreignkey(self, db_field, request, **kwargs):
|
||||
if db_field.name == 'stock_item':
|
||||
report = getattr(request, '_production_report_obj', None)
|
||||
if report and getattr(report, 'machine_id', None):
|
||||
machine = report.machine
|
||||
work_location = None
|
||||
if getattr(machine, 'workshop_id', None) and getattr(machine.workshop, 'location_id', None):
|
||||
work_location = machine.workshop.location
|
||||
elif getattr(machine, 'location_id', None):
|
||||
work_location = machine.location
|
||||
|
||||
if work_location:
|
||||
kwargs['queryset'] = StockItem.objects.filter(location=work_location, material__isnull=False)
|
||||
else:
|
||||
kwargs['queryset'] = StockItem.objects.none()
|
||||
|
||||
return super().formfield_for_foreignkey(db_field, request, **kwargs)
|
||||
|
||||
|
||||
class ProductionReportRemnantInline(admin.TabularInline):
|
||||
model = ProductionReportRemnant
|
||||
fk_name = 'report'
|
||||
fields = ('material', 'quantity', 'current_length', 'current_width')
|
||||
autocomplete_fields = ('material',)
|
||||
extra = 3
|
||||
|
||||
|
||||
@admin.register(CuttingSession)
|
||||
class CuttingSessionAdmin(admin.ModelAdmin):
|
||||
"""
|
||||
Панель администрирования Производственных отчетов.
|
||||
|
||||
Ограничение по складу:
|
||||
- списание сырья доступно только со склада цеха выбранного станка.
|
||||
"""
|
||||
list_display = ('date', 'id', 'machine', 'operator', 'used_stock_item', 'is_closed')
|
||||
list_display_links = ('date',)
|
||||
list_filter = ('date', 'machine', 'is_closed')
|
||||
search_fields = ('operator__username',)
|
||||
actions = ('action_close_sessions',)
|
||||
inlines = (ProductionReportLineInline, ProductionReportConsumptionInline, ProductionReportRemnantInline)
|
||||
|
||||
def get_form(self, request, obj=None, **kwargs):
|
||||
request._production_report_obj = obj
|
||||
return super().get_form(request, obj, **kwargs)
|
||||
|
||||
def formfield_for_foreignkey(self, db_field, request, **kwargs):
|
||||
if db_field.name == 'used_stock_item':
|
||||
report = getattr(request, '_production_report_obj', None)
|
||||
if report and getattr(report, 'machine_id', None):
|
||||
machine = report.machine
|
||||
work_location = None
|
||||
if getattr(machine, 'workshop_id', None) and getattr(machine.workshop, 'location_id', None):
|
||||
work_location = machine.workshop.location
|
||||
elif getattr(machine, 'location_id', None):
|
||||
work_location = machine.location
|
||||
|
||||
if work_location:
|
||||
kwargs['queryset'] = StockItem.objects.filter(location=work_location, material__isnull=False)
|
||||
else:
|
||||
kwargs['queryset'] = StockItem.objects.none()
|
||||
|
||||
return super().formfield_for_foreignkey(db_field, request, **kwargs)
|
||||
|
||||
@admin.action(description='Закрыть производственный отчет')
|
||||
def action_close_sessions(self, request, queryset):
|
||||
ok = 0
|
||||
skipped = 0
|
||||
failed = 0
|
||||
|
||||
for s in queryset:
|
||||
try:
|
||||
if s.is_closed:
|
||||
skipped += 1
|
||||
continue
|
||||
close_cutting_session(s.id)
|
||||
ok += 1
|
||||
except Exception as e:
|
||||
failed += 1
|
||||
self.message_user(request, f'Отчет id={s.id}: {e}', level=messages.ERROR)
|
||||
|
||||
if ok:
|
||||
self.message_user(request, f'Закрыто: {ok}.', level=messages.SUCCESS)
|
||||
if skipped:
|
||||
self.message_user(request, f'Пропущено (уже закрыто): {skipped}.', level=messages.WARNING)
|
||||
if failed:
|
||||
self.message_user(request, f'Ошибок: {failed}.', level=messages.ERROR)
|
||||
@admin.register(ShiftItem)
|
||||
class ShiftItemAdmin(admin.ModelAdmin):
|
||||
list_display = ('session', 'task', 'quantity_fact', 'material_substitution')
|
||||
list_filter = ('material_substitution',)
|
||||
autocomplete_fields = ('session', 'task')
|
||||
class DxfPreviewSettingsAdmin(admin.ModelAdmin):
|
||||
list_display = (
|
||||
'line_color',
|
||||
'lineweight_scaling',
|
||||
'min_lineweight',
|
||||
'keep_original_colors',
|
||||
'per_task_timeout_sec',
|
||||
'updated_at',
|
||||
)
|
||||
|
||||
|
||||
@admin.register(DxfPreviewJob)
|
||||
class DxfPreviewJobAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'status', 'created_by', 'processed', 'total', 'updated', 'errors', 'started_at', 'finished_at')
|
||||
list_filter = ('status',)
|
||||
search_fields = ('last_message',)
|
||||
|
||||
|
||||
@admin.register(EmployeeProfile)
|
||||
class EmployeeProfileAdmin(admin.ModelAdmin):
|
||||
list_display = ('user', 'role')
|
||||
filter_horizontal = ('machines',) # Красивый выбор станков двумя колонками
|
||||
filter_horizontal = ('machines',)
|
||||
Reference in New Issue
Block a user