diff --git a/shiftflow/popup_views.py b/shiftflow/popup_views.py
new file mode 100644
index 0000000..24d7f6a
--- /dev/null
+++ b/shiftflow/popup_views.py
@@ -0,0 +1,171 @@
+from django import forms
+from django.contrib.auth.mixins import LoginRequiredMixin
+from django.shortcuts import redirect
+from django.template.response import TemplateResponse
+from django.views.generic import CreateView, UpdateView
+
+from warehouse.models import Material, MaterialCategory, SteelGrade
+
+from .models import Company, Deal
+
+
+class _PopupRoleMixin(LoginRequiredMixin):
+ 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_target(self):
+ return (self.request.GET.get("target") or self.request.POST.get("target") or "").strip()
+
+ def form_valid(self, form):
+ self.object = form.save()
+ return TemplateResponse(
+ self.request,
+ "shiftflow/popup_done.html",
+ {"target": self.get_target(), "value": self.object.pk, "label": self.get_popup_label()},
+ )
+
+ def get_context_data(self, **kwargs):
+ ctx = super().get_context_data(**kwargs)
+ ctx["target"] = self.get_target()
+ return ctx
+
+ def get_popup_label(self):
+ return str(self.object)
+
+
+class _BootstrapModelForm(forms.ModelForm):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ for name, field in self.fields.items():
+ widget = field.widget
+ if isinstance(widget, (forms.Select, forms.SelectMultiple)):
+ cls = "form-select border-secondary"
+ elif isinstance(widget, forms.CheckboxInput):
+ cls = "form-check-input"
+ else:
+ cls = "form-control border-secondary"
+ widget.attrs["class"] = cls
+
+
+class DealForm(_BootstrapModelForm):
+ class Meta:
+ model = Deal
+ fields = ["number", "status", "company", "description"]
+
+
+class CompanyForm(_BootstrapModelForm):
+ class Meta:
+ model = Company
+ fields = ["name", "description"]
+
+
+class MaterialForm(_BootstrapModelForm):
+ class Meta:
+ model = Material
+ fields = ["category", "steel_grade", "name"]
+
+
+class MaterialCategoryForm(_BootstrapModelForm):
+ class Meta:
+ model = MaterialCategory
+ fields = ["name", "gost_standard"]
+
+
+class SteelGradeForm(_BootstrapModelForm):
+ class Meta:
+ model = SteelGrade
+ fields = ["name", "gost_standard"]
+
+
+class DealPopupCreateView(_PopupRoleMixin, CreateView):
+ template_name = "shiftflow/popup_form.html"
+ model = Deal
+ form_class = DealForm
+
+ def get_popup_label(self):
+ return self.object.number
+
+
+class DealPopupUpdateView(_PopupRoleMixin, UpdateView):
+ template_name = "shiftflow/popup_form.html"
+ model = Deal
+ form_class = DealForm
+
+ def get_popup_label(self):
+ return self.object.number
+
+
+class CompanyPopupCreateView(_PopupRoleMixin, CreateView):
+ template_name = "shiftflow/popup_form.html"
+ model = Company
+ form_class = CompanyForm
+
+ def get_popup_label(self):
+ return self.object.name
+
+
+class CompanyPopupUpdateView(_PopupRoleMixin, UpdateView):
+ template_name = "shiftflow/popup_form.html"
+ model = Company
+ form_class = CompanyForm
+
+ def get_popup_label(self):
+ return self.object.name
+
+
+class MaterialPopupCreateView(_PopupRoleMixin, CreateView):
+ template_name = "shiftflow/popup_form.html"
+ model = Material
+ form_class = MaterialForm
+
+ def get_popup_label(self):
+ return self.object.full_name
+
+
+class MaterialPopupUpdateView(_PopupRoleMixin, UpdateView):
+ template_name = "shiftflow/popup_form.html"
+ model = Material
+ form_class = MaterialForm
+
+ def get_popup_label(self):
+ return self.object.full_name
+
+
+class MaterialCategoryPopupCreateView(_PopupRoleMixin, CreateView):
+ template_name = "shiftflow/popup_form.html"
+ model = MaterialCategory
+ form_class = MaterialCategoryForm
+
+ def get_popup_label(self):
+ return self.object.name
+
+
+class MaterialCategoryPopupUpdateView(_PopupRoleMixin, UpdateView):
+ template_name = "shiftflow/popup_form.html"
+ model = MaterialCategory
+ form_class = MaterialCategoryForm
+
+ def get_popup_label(self):
+ return self.object.name
+
+
+class SteelGradePopupCreateView(_PopupRoleMixin, CreateView):
+ template_name = "shiftflow/popup_form.html"
+ model = SteelGrade
+ form_class = SteelGradeForm
+
+ def get_popup_label(self):
+ return self.object.name
+
+
+class SteelGradePopupUpdateView(_PopupRoleMixin, UpdateView):
+ template_name = "shiftflow/popup_form.html"
+ model = SteelGrade
+ form_class = SteelGradeForm
+
+ def get_popup_label(self):
+ return self.object.name
\ No newline at end of file
diff --git a/shiftflow/templates/shiftflow/customer_deals.html b/shiftflow/templates/shiftflow/customer_deals.html
new file mode 100644
index 0000000..2740cd3
--- /dev/null
+++ b/shiftflow/templates/shiftflow/customer_deals.html
@@ -0,0 +1,158 @@
+{% extends 'base.html' %}
+
+{% block content %}
+
+
+
+
+
+
+
+
+
+
+ {% for d in deals %}
+
+ | {{ d.number }} |
+ {{ d.description|default:"" }} |
+
+
+ {{ d.get_status_display }}
+
+ |
+
+ {% empty %}
+ | Сделок не найдено |
+ {% endfor %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/shiftflow/templates/shiftflow/customers.html b/shiftflow/templates/shiftflow/customers.html
new file mode 100644
index 0000000..3b0ee0f
--- /dev/null
+++ b/shiftflow/templates/shiftflow/customers.html
@@ -0,0 +1,115 @@
+{% extends 'base.html' %}
+
+{% block content %}
+
+
+
+
+
+
+
+
+
+
+ {% for c in companies %}
+
+ | {{ c.name }} |
+ {{ c.description|default:"" }} |
+
+ {% empty %}
+ | Заказчиков не найдено |
+ {% endfor %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/shiftflow/templates/shiftflow/item_detail.html b/shiftflow/templates/shiftflow/item_detail.html
index 397f7c8..523ad3a 100644
--- a/shiftflow/templates/shiftflow/item_detail.html
+++ b/shiftflow/templates/shiftflow/item_detail.html
@@ -1,4 +1,5 @@
{% extends 'base.html' %}
+{% load l10n %}
{% block content %}
@@ -72,13 +73,29 @@
-
+
{% else %}
Статус: {{ item.get_status_display }}. Сделано: {{ item.quantity_fact }} шт.
+ {% if user_role == 'master' %}
+
+ {% endif %}
{% endif %}
{% endif %}
@@ -124,7 +141,7 @@
-
+
diff --git a/shiftflow/templates/shiftflow/partials/_filter.html b/shiftflow/templates/shiftflow/partials/_filter.html
index 471a8b0..6fa6dbb 100644
--- a/shiftflow/templates/shiftflow/partials/_filter.html
+++ b/shiftflow/templates/shiftflow/partials/_filter.html
@@ -73,14 +73,63 @@
diff --git a/shiftflow/templates/shiftflow/planning.html b/shiftflow/templates/shiftflow/planning.html
index 086c4fd..d6bdeec 100644
--- a/shiftflow/templates/shiftflow/planning.html
+++ b/shiftflow/templates/shiftflow/planning.html
@@ -4,7 +4,7 @@