- Добавлена кнопка 'Добавить оборудование' на странице списка - Создан модал для добавления нового оборудования - Создан модал для редактирования существующего оборудования - Добавлена кнопка редактирования в dropdown меню каждой карточки - Реализованы JavaScript обработчики для создания/редактирования через API - Добавлен импорт User в views_frontend.py для передачи списка пользователей - Все поля модели Equipment доступны для редактирования (включая статус, отдел)
280 lines
8.6 KiB
Python
280 lines
8.6 KiB
Python
"""
|
||
HTML Views для модуля закупок (Frontend).
|
||
"""
|
||
|
||
from django.contrib.auth import get_user_model
|
||
from django.contrib.auth.decorators import login_required
|
||
from django.core.paginator import Paginator
|
||
from django.shortcuts import get_object_or_404, render, redirect
|
||
from django.utils import timezone
|
||
|
||
from employees.models import Department
|
||
from .models import (
|
||
Budget,
|
||
Equipment,
|
||
EquipmentCategory,
|
||
ProcurementRequest,
|
||
)
|
||
from .constants import ProcurementStatus
|
||
|
||
User = get_user_model()
|
||
|
||
|
||
@login_required
|
||
def dashboard(request):
|
||
"""Главная страница модуля закупок."""
|
||
user = request.user
|
||
now = timezone.now()
|
||
quarter = (now.month - 1) // 3 + 1
|
||
|
||
# Получаем отделы пользователя
|
||
user_departments = user.departments.filter(
|
||
employeedepartment__is_active=True
|
||
)
|
||
|
||
# Статистика
|
||
stats = {
|
||
'pending': ProcurementRequest.objects.filter(
|
||
status=ProcurementStatus.PENDING
|
||
).count(),
|
||
'approved': ProcurementRequest.objects.filter(
|
||
status=ProcurementStatus.APPROVED
|
||
).count(),
|
||
'equipment': Equipment.objects.count(),
|
||
}
|
||
|
||
# Бюджет отдела (берём первый отдел пользователя)
|
||
budget = None
|
||
if user_departments.exists():
|
||
budget = Budget.objects.filter(
|
||
department=user_departments.first(),
|
||
year=now.year,
|
||
quarter=quarter
|
||
).first()
|
||
|
||
# Последние заявки (мои или моего отдела)
|
||
recent_requests = ProcurementRequest.objects.filter(
|
||
department__in=user_departments
|
||
).select_related(
|
||
'department', 'requestor'
|
||
).order_by('-created_at')[:5]
|
||
|
||
# Права на согласование
|
||
can_approve = user.is_staff or user.headed_departments.exists()
|
||
|
||
context = {
|
||
'stats': stats,
|
||
'budget': budget,
|
||
'recent_requests': recent_requests,
|
||
'can_approve': can_approve,
|
||
}
|
||
return render(request, 'procurement/dashboard.html', context)
|
||
|
||
|
||
@login_required
|
||
def request_list(request):
|
||
"""Список заявок на закупку."""
|
||
user = request.user
|
||
scope = request.GET.get('scope', 'mine')
|
||
|
||
# Базовый queryset
|
||
queryset = ProcurementRequest.objects.select_related(
|
||
'department', 'requestor'
|
||
).prefetch_related('items')
|
||
|
||
# Фильтрация по области видимости
|
||
if scope == 'mine':
|
||
queryset = queryset.filter(requestor=user)
|
||
page_title = 'Мои заявки'
|
||
elif scope == 'department':
|
||
user_departments = user.departments.filter(
|
||
employeedepartment__is_active=True
|
||
)
|
||
queryset = queryset.filter(department__in=user_departments)
|
||
page_title = 'Заявки отдела'
|
||
elif scope == 'all' and user.is_staff:
|
||
page_title = 'Все заявки'
|
||
else:
|
||
queryset = queryset.filter(requestor=user)
|
||
page_title = 'Мои заявки'
|
||
scope = 'mine'
|
||
|
||
# Фильтры
|
||
filters = {}
|
||
if status := request.GET.get('status'):
|
||
queryset = queryset.filter(status=status)
|
||
filters['status'] = status
|
||
if urgency := request.GET.get('urgency'):
|
||
queryset = queryset.filter(urgency=urgency)
|
||
filters['urgency'] = urgency
|
||
|
||
# Сортировка
|
||
queryset = queryset.order_by('-created_at')
|
||
|
||
# Пагинация
|
||
paginator = Paginator(queryset, 20)
|
||
page_number = request.GET.get('page')
|
||
page_obj = paginator.get_page(page_number)
|
||
|
||
context = {
|
||
'requests': page_obj,
|
||
'page_obj': page_obj,
|
||
'page_title': page_title,
|
||
'scope': scope,
|
||
'filters': filters,
|
||
'can_view_all': user.is_staff or user.headed_departments.exists(),
|
||
}
|
||
return render(request, 'procurement/request_list.html', context)
|
||
|
||
|
||
@login_required
|
||
def my_requests(request):
|
||
"""Мои заявки."""
|
||
return redirect('procurement:request_list', permanent=False)
|
||
|
||
|
||
@login_required
|
||
def pending_approvals(request):
|
||
"""Заявки на согласовании (для руководителей)."""
|
||
user = request.user
|
||
|
||
# Получаем отделы, которыми руководит пользователь
|
||
headed_depts = user.headed_departments.all()
|
||
|
||
if not headed_depts.exists() and not user.is_staff:
|
||
return redirect('procurement:dashboard')
|
||
|
||
queryset = ProcurementRequest.objects.filter(
|
||
status=ProcurementStatus.PENDING
|
||
).select_related(
|
||
'department', 'requestor'
|
||
)
|
||
|
||
# Для не-staff показываем только заявки своих отделов
|
||
if not user.is_staff:
|
||
queryset = queryset.filter(department__in=headed_depts)
|
||
|
||
queryset = queryset.order_by('-created_at')
|
||
|
||
paginator = Paginator(queryset, 20)
|
||
page_obj = paginator.get_page(request.GET.get('page'))
|
||
|
||
context = {
|
||
'requests': page_obj,
|
||
'page_obj': page_obj,
|
||
'page_title': 'На согласовании',
|
||
'scope': 'pending',
|
||
'can_view_all': user.is_staff,
|
||
}
|
||
return render(request, 'procurement/request_list.html', context)
|
||
|
||
|
||
@login_required
|
||
def request_detail(request, pk):
|
||
"""Детальная страница заявки."""
|
||
procurement_request = get_object_or_404(
|
||
ProcurementRequest.objects.select_related(
|
||
'department', 'requestor'
|
||
).prefetch_related(
|
||
'items__supplier',
|
||
'approvals__approver'
|
||
),
|
||
pk=pk
|
||
)
|
||
|
||
context = {
|
||
'request_obj': procurement_request,
|
||
'can_edit': (
|
||
procurement_request.requestor == request.user and
|
||
procurement_request.status == ProcurementStatus.DRAFT
|
||
),
|
||
'can_approve': (
|
||
request.user.is_staff or
|
||
request.user.headed_departments.filter(
|
||
pk=procurement_request.department_id
|
||
).exists()
|
||
),
|
||
}
|
||
return render(request, 'procurement/request_detail.html', context)
|
||
|
||
|
||
@login_required
|
||
def request_create(request):
|
||
"""Страница/обработка создания заявки."""
|
||
if request.method == 'POST':
|
||
# Обработка формы - для простоты перенаправляем на API
|
||
# В реальности можно обработать здесь или использовать Django Forms
|
||
pass
|
||
|
||
context = {}
|
||
return render(request, 'procurement/request_form.html', context)
|
||
|
||
|
||
@login_required
|
||
def equipment_list(request):
|
||
"""Список оборудования."""
|
||
queryset = Equipment.objects.select_related(
|
||
'category', 'department', 'responsible_person'
|
||
)
|
||
|
||
# Фильтры
|
||
filters = {}
|
||
if category := request.GET.get('category'):
|
||
queryset = queryset.filter(category_id=category)
|
||
filters['category'] = category
|
||
if status := request.GET.get('status'):
|
||
queryset = queryset.filter(status=status)
|
||
filters['status'] = status
|
||
if department := request.GET.get('department'):
|
||
queryset = queryset.filter(department_id=department)
|
||
filters['department'] = department
|
||
|
||
# Поиск
|
||
if search := request.GET.get('q'):
|
||
queryset = queryset.filter(
|
||
name__icontains=search
|
||
) | queryset.filter(
|
||
inventory_number__icontains=search
|
||
)
|
||
|
||
queryset = queryset.order_by('-purchase_date')
|
||
|
||
# Пагинация
|
||
paginator = Paginator(queryset, 24)
|
||
page_obj = paginator.get_page(request.GET.get('page'))
|
||
|
||
context = {
|
||
'equipment_list': page_obj,
|
||
'page_obj': page_obj,
|
||
'filters': filters,
|
||
'categories': EquipmentCategory.objects.all(),
|
||
'departments': Department.objects.all(),
|
||
'users': User.objects.filter(
|
||
is_active=True
|
||
).order_by('last_name', 'first_name'),
|
||
'can_manage': request.user.is_staff,
|
||
}
|
||
return render(request, 'procurement/equipment_list.html', context)
|
||
|
||
|
||
@login_required
|
||
def equipment_detail(request, pk):
|
||
"""Детальная страница оборудования."""
|
||
equipment = get_object_or_404(
|
||
Equipment.objects.select_related(
|
||
'category', 'department', 'responsible_person'
|
||
).prefetch_related(
|
||
'maintenance_records', 'transfer_logs'
|
||
),
|
||
pk=pk
|
||
)
|
||
|
||
context = {
|
||
'equipment': equipment,
|
||
'can_manage': (
|
||
request.user.is_staff or
|
||
equipment.responsible_person == request.user
|
||
),
|
||
}
|
||
return render(request, 'procurement/equipment_detail.html', context)
|