Фильтры сохраняются, мастер получил расширенные возможности
All checks were successful
Deploy MES Core / deploy (push) Successful in 10s
All checks were successful
Deploy MES Core / deploy (push) Successful in 10s
This commit is contained in:
@@ -286,6 +286,83 @@ class DealPlanningView(LoginRequiredMixin, TemplateView):
|
||||
return context
|
||||
|
||||
|
||||
class TaskItemsView(LoginRequiredMixin, TemplateView):
|
||||
template_name = 'shiftflow/task_items.html'
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
profile = getattr(request.user, 'profile', None)
|
||||
role = profile.role if profile else ('admin' if request.user.is_superuser else 'operator')
|
||||
if role not in ['admin', 'technologist']:
|
||||
return redirect('registry')
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
profile = getattr(self.request.user, 'profile', None)
|
||||
role = profile.role if profile else ('admin' if self.request.user.is_superuser else 'operator')
|
||||
context['user_role'] = role
|
||||
|
||||
task = get_object_or_404(
|
||||
ProductionTask.objects.select_related('deal', 'deal__company', 'material'),
|
||||
pk=self.kwargs['pk'],
|
||||
)
|
||||
context['task'] = task
|
||||
|
||||
items = Item.objects.filter(task=task).select_related('machine').order_by('-date', 'machine__name', '-id')
|
||||
context['items'] = items
|
||||
return context
|
||||
|
||||
|
||||
class CustomersView(LoginRequiredMixin, TemplateView):
|
||||
template_name = 'shiftflow/customers.html'
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
profile = getattr(request.user, 'profile', None)
|
||||
role = profile.role if profile else ('admin' if request.user.is_superuser else 'operator')
|
||||
if role not in ['admin', 'technologist']:
|
||||
return redirect('registry')
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
profile = getattr(self.request.user, 'profile', None)
|
||||
role = profile.role if profile else ('admin' if self.request.user.is_superuser else 'operator')
|
||||
context['user_role'] = role
|
||||
|
||||
companies = Company.objects.all().order_by('name')
|
||||
context['companies'] = companies
|
||||
return context
|
||||
|
||||
|
||||
class CustomerDealsView(LoginRequiredMixin, TemplateView):
|
||||
template_name = 'shiftflow/customer_deals.html'
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
profile = getattr(request.user, 'profile', None)
|
||||
role = profile.role if profile else ('admin' if request.user.is_superuser else 'operator')
|
||||
if role not in ['admin', 'technologist']:
|
||||
return redirect('registry')
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
profile = getattr(self.request.user, 'profile', None)
|
||||
role = profile.role if profile else ('admin' if self.request.user.is_superuser else 'operator')
|
||||
context['user_role'] = role
|
||||
|
||||
company = get_object_or_404(Company, pk=self.kwargs['pk'])
|
||||
context['company'] = company
|
||||
|
||||
status = (self.request.GET.get('status') or 'work').strip()
|
||||
allowed = {k for k, _ in Deal.STATUS_CHOICES}
|
||||
if status not in allowed:
|
||||
status = 'work'
|
||||
|
||||
context['selected_status'] = status
|
||||
context['deals'] = Deal.objects.select_related('company').filter(company=company, status=status).order_by('-id')
|
||||
return context
|
||||
|
||||
|
||||
class PlanningAddView(LoginRequiredMixin, View):
|
||||
def post(self, request, *args, **kwargs):
|
||||
profile = getattr(request.user, 'profile', None)
|
||||
@@ -366,7 +443,12 @@ class ProductionTaskCreateView(LoginRequiredMixin, FormView):
|
||||
task.extra_drawing = form.cleaned_data['extra_drawing']
|
||||
|
||||
task.save()
|
||||
return super().form_valid(form)
|
||||
|
||||
next_url = (self.request.POST.get('next') or '').strip()
|
||||
if next_url.startswith('/'):
|
||||
return redirect(next_url)
|
||||
|
||||
return redirect('planning_deal', pk=task.deal_id)
|
||||
|
||||
|
||||
class DealDetailView(LoginRequiredMixin, View):
|
||||
@@ -608,20 +690,24 @@ class ItemUpdateView(LoginRequiredMixin, UpdateView):
|
||||
return redirect('registry')
|
||||
|
||||
if role in ['operator', 'master']:
|
||||
if self.object.status != 'work':
|
||||
return redirect('registry')
|
||||
|
||||
material_taken = (request.POST.get('material_taken') or '').strip()
|
||||
usable_waste = (request.POST.get('usable_waste') or '').strip()
|
||||
scrap_weight_raw = (request.POST.get('scrap_weight') or '').strip()
|
||||
status = request.POST.get('status', self.object.status)
|
||||
|
||||
# Разрешаем мастеру редактировать операторские поля всегда,
|
||||
# оператору — только в процессе закрытия
|
||||
if role == 'operator' and self.object.status != 'work':
|
||||
return redirect('registry')
|
||||
|
||||
errors = []
|
||||
if not material_taken:
|
||||
errors.append('Заполни поле "Взятый материал"')
|
||||
if not usable_waste:
|
||||
errors.append('Заполни поле "Остаток ДО"')
|
||||
if scrap_weight_raw == '':
|
||||
errors.append('Заполни поле "Лом (кг)" (можно 0)')
|
||||
if role == 'operator' and self.object.status == 'work':
|
||||
if not material_taken:
|
||||
errors.append('Заполни поле "Взятый материал"')
|
||||
if not usable_waste:
|
||||
errors.append('Заполни поле "Остаток ДО"')
|
||||
if scrap_weight_raw == '':
|
||||
errors.append('Заполни поле "Лом (кг)" (можно 0)')
|
||||
|
||||
scrap_weight = None
|
||||
if scrap_weight_raw != '':
|
||||
@@ -630,25 +716,26 @@ class ItemUpdateView(LoginRequiredMixin, UpdateView):
|
||||
except ValueError:
|
||||
errors.append('Поле "Лом (кг)" должно быть числом')
|
||||
|
||||
status = request.POST.get('status', self.object.status)
|
||||
|
||||
if errors:
|
||||
context = self.get_context_data()
|
||||
context['errors'] = errors
|
||||
return self.render_to_response(context)
|
||||
|
||||
self.object.material_taken = material_taken
|
||||
self.object.usable_waste = usable_waste
|
||||
if material_taken:
|
||||
self.object.material_taken = material_taken
|
||||
if usable_waste:
|
||||
self.object.usable_waste = usable_waste
|
||||
if scrap_weight is not None:
|
||||
self.object.scrap_weight = scrap_weight
|
||||
|
||||
if status == 'done':
|
||||
# Логика закрытия доступна и мастеру, и оператору, но только из 'work'
|
||||
if self.object.status == 'work' and status == 'done':
|
||||
self.object.quantity_fact = self.object.quantity_plan
|
||||
self.object.status = 'done'
|
||||
self.object.save()
|
||||
return redirect('registry')
|
||||
|
||||
if status == 'partial':
|
||||
if self.object.status == 'work' and status == 'partial':
|
||||
try:
|
||||
fact = int(request.POST.get('quantity_fact', '0'))
|
||||
except ValueError:
|
||||
@@ -677,6 +764,8 @@ class ItemUpdateView(LoginRequiredMixin, UpdateView):
|
||||
|
||||
return redirect('registry')
|
||||
|
||||
# Если статус не менялся (или не 'work'), просто сохраняем поля
|
||||
self.object.save(update_fields=['material_taken', 'usable_waste', 'scrap_weight'])
|
||||
return redirect('registry')
|
||||
|
||||
if role == 'clerk':
|
||||
|
||||
Reference in New Issue
Block a user