This commit is contained in:
@@ -1,11 +1,19 @@
|
||||
from datetime import datetime
|
||||
|
||||
from django.shortcuts import redirect
|
||||
from django.db.models import Case, ExpressionWrapper, F, IntegerField, Sum, Value, When
|
||||
from django.db.models.functions import Coalesce
|
||||
from django.http import JsonResponse
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.urls import reverse_lazy
|
||||
from django.views.generic import TemplateView, ListView, UpdateView
|
||||
from django.views import View
|
||||
from django.views.generic import FormView, ListView, TemplateView, UpdateView
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.utils import timezone
|
||||
from .models import Item, Machine
|
||||
|
||||
from warehouse.models import Material, MaterialCategory, SteelGrade
|
||||
|
||||
from .forms import ProductionTaskCreateForm
|
||||
from .models import Company, Deal, Item, Machine, ProductionTask
|
||||
|
||||
# Класс главной страницы (роутер)
|
||||
class IndexView(TemplateView):
|
||||
@@ -208,6 +216,288 @@ class RegistryPrintView(LoginRequiredMixin, TemplateView):
|
||||
return context
|
||||
|
||||
|
||||
class PlanningView(LoginRequiredMixin, TemplateView):
|
||||
template_name = 'shiftflow/planning.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
|
||||
|
||||
tasks = ProductionTask.objects.select_related('deal', 'material').annotate(
|
||||
done_qty=Coalesce(Sum('items__quantity_fact'), 0),
|
||||
planned_qty=Coalesce(
|
||||
Sum(
|
||||
Case(
|
||||
When(items__status__in=['work', 'leftover'], then=F('items__quantity_plan')),
|
||||
default=Value(0),
|
||||
output_field=IntegerField(),
|
||||
)
|
||||
),
|
||||
0,
|
||||
),
|
||||
).annotate(
|
||||
remaining_qty=ExpressionWrapper(
|
||||
F('quantity_ordered') - F('done_qty') - F('planned_qty'),
|
||||
output_field=IntegerField(),
|
||||
)
|
||||
)
|
||||
|
||||
context['tasks'] = tasks
|
||||
context['machines'] = Machine.objects.all()
|
||||
return context
|
||||
|
||||
|
||||
class PlanningAddView(LoginRequiredMixin, View):
|
||||
def post(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('planning')
|
||||
|
||||
task_id = request.POST.get('task_id')
|
||||
machine_id = request.POST.get('machine_id')
|
||||
qty_raw = request.POST.get('quantity_plan')
|
||||
|
||||
if not (task_id and task_id.isdigit() and machine_id and machine_id.isdigit() and qty_raw and qty_raw.isdigit()):
|
||||
return redirect('planning')
|
||||
|
||||
qty = int(qty_raw)
|
||||
if qty <= 0:
|
||||
return redirect('planning')
|
||||
|
||||
Item.objects.create(
|
||||
task_id=int(task_id),
|
||||
machine_id=int(machine_id),
|
||||
date=timezone.localdate(),
|
||||
quantity_plan=qty,
|
||||
quantity_fact=0,
|
||||
status='work',
|
||||
is_synced_1c=False,
|
||||
)
|
||||
|
||||
return redirect('planning')
|
||||
|
||||
|
||||
class ProductionTaskCreateView(LoginRequiredMixin, FormView):
|
||||
template_name = 'shiftflow/task_create.html'
|
||||
form_class = ProductionTaskCreateForm
|
||||
success_url = reverse_lazy('planning')
|
||||
|
||||
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
|
||||
context['companies'] = Company.objects.all().order_by('name')
|
||||
context['material_categories'] = MaterialCategory.objects.all().order_by('name')
|
||||
context['steel_grades'] = SteelGrade.objects.all().order_by('name')
|
||||
return context
|
||||
|
||||
def form_valid(self, form):
|
||||
task = ProductionTask(
|
||||
deal=form.cleaned_data['deal'],
|
||||
drawing_name=form.cleaned_data.get('drawing_name') or 'Б/ч',
|
||||
size_value=form.cleaned_data['size_value'],
|
||||
material=form.cleaned_data['material'],
|
||||
quantity_ordered=form.cleaned_data['quantity_ordered'],
|
||||
is_bend=form.cleaned_data.get('is_bend') or False,
|
||||
)
|
||||
|
||||
if form.cleaned_data.get('drawing_file'):
|
||||
task.drawing_file = form.cleaned_data['drawing_file']
|
||||
if form.cleaned_data.get('extra_drawing'):
|
||||
task.extra_drawing = form.cleaned_data['extra_drawing']
|
||||
|
||||
task.save()
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
class DealDetailView(LoginRequiredMixin, View):
|
||||
def get(self, request, pk, *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 JsonResponse({'error': 'forbidden'}, status=403)
|
||||
|
||||
deal = get_object_or_404(Deal, pk=pk)
|
||||
return JsonResponse({
|
||||
'id': deal.id,
|
||||
'number': deal.number,
|
||||
'company_id': deal.company_id,
|
||||
'description': deal.description or '',
|
||||
})
|
||||
|
||||
|
||||
class DealUpsertView(LoginRequiredMixin, View):
|
||||
def post(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 JsonResponse({'error': 'forbidden'}, status=403)
|
||||
|
||||
deal_id = request.POST.get('id')
|
||||
number = (request.POST.get('number') or '').strip()
|
||||
description = (request.POST.get('description') or '').strip()
|
||||
company_id = request.POST.get('company_id')
|
||||
|
||||
if not number:
|
||||
return JsonResponse({'error': 'number_required'}, status=400)
|
||||
|
||||
if deal_id and str(deal_id).isdigit():
|
||||
deal = get_object_or_404(Deal, pk=int(deal_id))
|
||||
deal.number = number
|
||||
else:
|
||||
deal, _ = Deal.objects.get_or_create(number=number)
|
||||
|
||||
deal.description = description
|
||||
if company_id and str(company_id).isdigit():
|
||||
deal.company_id = int(company_id)
|
||||
else:
|
||||
deal.company_id = None
|
||||
|
||||
deal.save()
|
||||
return JsonResponse({'id': deal.id, 'label': deal.number})
|
||||
|
||||
|
||||
class MaterialDetailView(LoginRequiredMixin, View):
|
||||
def get(self, request, pk, *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 JsonResponse({'error': 'forbidden'}, status=403)
|
||||
|
||||
material = get_object_or_404(Material, pk=pk)
|
||||
return JsonResponse({
|
||||
'id': material.id,
|
||||
'category_id': material.category_id,
|
||||
'steel_grade_id': material.steel_grade_id,
|
||||
'name': material.name,
|
||||
'full_name': material.full_name,
|
||||
})
|
||||
|
||||
|
||||
class MaterialUpsertView(LoginRequiredMixin, View):
|
||||
def post(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 JsonResponse({'error': 'forbidden'}, status=403)
|
||||
|
||||
material_id = request.POST.get('id')
|
||||
category_id = request.POST.get('category_id')
|
||||
steel_grade_id = request.POST.get('steel_grade_id')
|
||||
name = (request.POST.get('name') or '').strip()
|
||||
|
||||
if not (category_id and str(category_id).isdigit() and name):
|
||||
return JsonResponse({'error': 'invalid'}, status=400)
|
||||
|
||||
if material_id and str(material_id).isdigit():
|
||||
material = get_object_or_404(Material, pk=int(material_id))
|
||||
else:
|
||||
material = Material()
|
||||
|
||||
material.category_id = int(category_id)
|
||||
material.name = name
|
||||
if steel_grade_id and str(steel_grade_id).isdigit():
|
||||
material.steel_grade_id = int(steel_grade_id)
|
||||
else:
|
||||
material.steel_grade_id = None
|
||||
|
||||
material.save()
|
||||
return JsonResponse({'id': material.id, 'label': material.full_name})
|
||||
|
||||
|
||||
class CompanyUpsertView(LoginRequiredMixin, View):
|
||||
def post(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 JsonResponse({'error': 'forbidden'}, status=403)
|
||||
|
||||
company_id = request.POST.get('id')
|
||||
name = (request.POST.get('name') or '').strip()
|
||||
description = (request.POST.get('description') or '').strip()
|
||||
|
||||
if not name:
|
||||
return JsonResponse({'error': 'name_required'}, status=400)
|
||||
|
||||
if company_id and str(company_id).isdigit():
|
||||
company = get_object_or_404(Company, pk=int(company_id))
|
||||
company.name = name
|
||||
else:
|
||||
company, _ = Company.objects.get_or_create(name=name)
|
||||
|
||||
company.description = description
|
||||
company.save()
|
||||
return JsonResponse({'id': company.id, 'label': company.name})
|
||||
|
||||
|
||||
class MaterialCategoryUpsertView(LoginRequiredMixin, View):
|
||||
def post(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 JsonResponse({'error': 'forbidden'}, status=403)
|
||||
|
||||
category_id = request.POST.get('id')
|
||||
name = (request.POST.get('name') or '').strip()
|
||||
gost_standard = (request.POST.get('gost_standard') or '').strip()
|
||||
|
||||
if not name:
|
||||
return JsonResponse({'error': 'name_required'}, status=400)
|
||||
|
||||
if category_id and str(category_id).isdigit():
|
||||
category = get_object_or_404(MaterialCategory, pk=int(category_id))
|
||||
category.name = name
|
||||
else:
|
||||
category, _ = MaterialCategory.objects.get_or_create(name=name)
|
||||
|
||||
category.gost_standard = gost_standard
|
||||
category.save()
|
||||
return JsonResponse({'id': category.id, 'label': category.name})
|
||||
|
||||
|
||||
class SteelGradeUpsertView(LoginRequiredMixin, View):
|
||||
def post(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 JsonResponse({'error': 'forbidden'}, status=403)
|
||||
|
||||
grade_id = request.POST.get('id')
|
||||
name = (request.POST.get('name') or '').strip()
|
||||
gost_standard = (request.POST.get('gost_standard') or '').strip()
|
||||
|
||||
if not name:
|
||||
return JsonResponse({'error': 'name_required'}, status=400)
|
||||
|
||||
if grade_id and str(grade_id).isdigit():
|
||||
grade = get_object_or_404(SteelGrade, pk=int(grade_id))
|
||||
grade.name = name
|
||||
else:
|
||||
grade, _ = SteelGrade.objects.get_or_create(name=name)
|
||||
|
||||
grade.gost_standard = gost_standard
|
||||
grade.save()
|
||||
return JsonResponse({'id': grade.id, 'label': grade.name})
|
||||
|
||||
|
||||
# Вьюха детального вида и редактирования
|
||||
class ItemUpdateView(LoginRequiredMixin, UpdateView):
|
||||
model = Item
|
||||
|
||||
Reference in New Issue
Block a user