This commit is contained in:
Flatlogic Bot 2026-01-27 20:34:31 +00:00
parent d58a583044
commit 6ed717407d
9 changed files with 129 additions and 21 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 KiB

View File

@ -43,10 +43,18 @@
{% endif %}
</td>
<td class="text-end px-4">
<a href="{{ b.fleet_unit.get_absolute_url }}" class="btn btn-sm btn-outline-primary rounded-pill px-3">К технике</a>
{% if b.status == 'need_part' %}
<a href="{% url 'part_request_add' %}?breakdown={{ b.pk }}" class="btn btn-sm btn-outline-warning rounded-pill px-3">Заказать запчасть</a>
{% endif %}
<div class="btn-group">
<a href="{{ b.fleet_unit.get_absolute_url }}" class="btn btn-sm btn-outline-primary rounded-pill px-3 me-2">К технике</a>
{% if b.status == 'need_part' %}
<a href="{% url 'part_request_add' %}?breakdown={{ b.pk }}" class="btn btn-sm btn-outline-warning rounded-pill px-3 me-2">Заказать запчасть</a>
{% endif %}
{% if user.is_staff %}
<form action="{% url 'breakdown_delete' b.pk %}" method="POST" class="d-inline" onsubmit="return confirm('Удалить запись о поломке?')">
{% csrf_token %}
<button type="submit" class="btn btn-sm btn-outline-danger rounded-pill px-2" title="Удалить"><i class="bi bi-trash"></i></button>
</form>
{% endif %}
</div>
</td>
</tr>
{% empty %}
@ -59,4 +67,4 @@
</div>
</div>
</div>
{% endblock %}
{% endblock %}

View File

@ -51,6 +51,12 @@
<div class="d-grid gap-2">
<a href="{% url 'fleet_edit' unit.pk %}" class="btn btn-outline-primary rounded-pill">Редактировать</a>
{% if user.is_staff %}
<form action="{% url 'fleet_delete' unit.pk %}" method="POST" class="d-inline" onsubmit="return confirm('Вы уверены, что хотите удалить эту единицу техники? Все связанные данные будут удалены.')">
{% csrf_token %}
<button type="submit" class="btn btn-outline-danger rounded-pill w-100 mb-2">Удалить технику</button>
</form>
{% endif %}
<a href="{% url 'breakdown_add' %}?fleet_unit={{ unit.pk }}" class="btn btn-danger rounded-pill">Заявить о поломке</a>
</div>
</div>
@ -114,7 +120,15 @@
<td><span class="badge bg-{{ m.status|yesno:'success,warning,secondary' }} rounded-pill small">{{ m.get_status_display }}</span></td>
<td>{{ m.mechanic|default:"-" }}</td>
<td class="text-end">
<a href="{% url 'maintenance_detail' m.pk %}" class="btn btn-sm btn-link text-primary">Открыть</a>
<div class="btn-group">
<a href="{% url 'maintenance_detail' m.pk %}" class="btn btn-sm btn-link text-primary p-0 me-2">Открыть</a>
{% if user.is_staff %}
<form action="{% url 'maintenance_delete' m.pk %}" method="POST" class="d-inline" onsubmit="return confirm('Удалить запись ТО?')">
{% csrf_token %}
<button type="submit" class="btn btn-sm btn-link text-danger p-0"><i class="bi bi-trash"></i></button>
</form>
{% endif %}
</div>
</td>
</tr>
{% empty %}
@ -136,7 +150,15 @@
<div class="list-group-item px-0 py-3">
<div class="d-flex justify-content-between mb-1">
<h6 class="mb-0 fw-bold text-danger">{{ b.system_node }}</h6>
<span class="badge bg-light text-dark border small">{{ b.get_status_display }}</span>
<div>
<span class="badge bg-light text-dark border small me-2">{{ b.get_status_display }}</span>
{% if user.is_staff %}
<form action="{% url 'breakdown_delete' b.pk %}" method="POST" class="d-inline" onsubmit="return confirm('Удалить запись о поломке?')">
{% csrf_token %}
<button type="submit" class="btn btn-sm btn-link text-danger p-0"><i class="bi bi-trash"></i></button>
</form>
{% endif %}
</div>
</div>
<p class="small mb-1 text-muted">{{ b.date|date:"d.m.Y" }} — {{ b.description }}</p>
<div class="d-flex align-items-center mt-2">
@ -164,6 +186,7 @@
<th>Кол-во</th>
<th>Статус</th>
<th>Дата</th>
<th></th>
</tr>
</thead>
<tbody>
@ -173,9 +196,17 @@
<td>{{ r.quantity }}</td>
<td><span class="badge bg-light text-dark border rounded-pill small">{{ r.get_status_display }}</span></td>
<td class="small">{{ r.created_at|date:"d.m.Y" }}</td>
<td class="text-end">
{% if user.is_staff %}
<form action="{% url 'part_request_delete' r.pk %}" method="POST" class="d-inline" onsubmit="return confirm('Удалить заявку?')">
{% csrf_token %}
<button type="submit" class="btn btn-sm btn-link text-danger p-0"><i class="bi bi-trash"></i></button>
</form>
{% endif %}
</td>
</tr>
{% empty %}
<tr><td colspan="4" class="text-center py-4 text-muted">Нет заявок</td></tr>
<tr><td colspan="5" class="text-center py-4 text-muted">Нет заявок</td></tr>
{% endfor %}
</tbody>
</table>
@ -223,6 +254,7 @@
<th>Деталь</th>
<th>Статус</th>
<th>Дата</th>
<th></th>
</tr>
</thead>
<tbody>
@ -231,9 +263,17 @@
<td>{{ r.part_name }}</td>
<td><span class="badge bg-light text-dark border rounded-pill small">{{ r.get_status_display }}</span></td>
<td class="small">{{ r.created_at|date:"d.m.Y" }}</td>
<td class="text-end">
{% if user.is_staff %}
<form action="{% url 'part_request_delete' r.pk %}" method="POST" class="d-inline" onsubmit="return confirm('Удалить заявку?')">
{% csrf_token %}
<button type="submit" class="btn btn-sm btn-link text-danger p-0"><i class="bi bi-trash"></i></button>
</form>
{% endif %}
</td>
</tr>
{% empty %}
<tr><td colspan="3" class="text-center py-4 text-muted">Нет заявок</td></tr>
<tr><td colspan="4" class="text-center py-4 text-muted">Нет заявок</td></tr>
{% endfor %}
</tbody>
</table>
@ -252,4 +292,4 @@
</div>
</div>
</div>
{% endblock %}
{% endblock %}

View File

@ -41,7 +41,15 @@
</td>
<td>{{ m.mechanic|default:"-" }}</td>
<td class="text-end px-4">
<a href="{% url 'maintenance_detail' m.pk %}" class="btn btn-sm btn-outline-primary rounded-pill px-3">Открыть</a>
<div class="btn-group">
<a href="{% url 'maintenance_detail' m.pk %}" class="btn btn-sm btn-outline-primary rounded-pill px-3 me-2">Открыть</a>
{% if user.is_staff %}
<form action="{% url 'maintenance_delete' m.pk %}" method="POST" class="d-inline" onsubmit="return confirm('Удалить запись ТО?')">
{% csrf_token %}
<button type="submit" class="btn btn-sm btn-outline-danger rounded-pill px-2" title="Удалить"><i class="bi bi-trash"></i></button>
</form>
{% endif %}
</div>
</td>
</tr>
{% empty %}
@ -54,4 +62,4 @@
</div>
</div>
</div>
{% endblock %}
{% endblock %}

View File

@ -43,7 +43,17 @@
</span>
</td>
<td>
<a href="#" class="btn btn-sm btn-outline-primary">Управление</a>
<div class="btn-group">
<a href="#" class="btn btn-sm btn-outline-primary">Управление</a>
{% if user.is_staff %}
<form action="{% url 'part_request_delete' req.pk %}" method="POST" class="d-inline" onsubmit="return confirm('Удалить заявку?')">
{% csrf_token %}
<button type="submit" class="btn btn-sm btn-outline-danger ms-1" title="Удалить">
<i class="bi bi-trash"></i>
</button>
</form>
{% endif %}
</div>
</td>
</tr>
{% empty %}
@ -63,7 +73,7 @@
<div class="card shadow-sm">
<div class="card-header bg-white py-3 d-flex justify-content-between align-items-center">
<h5 class="card-title mb-0">Поставщики</h5>
<a href="{% url 'supplier_add' %}" class="btn btn-sm btn-primary">
<a href="{% url 'supplier_create' %}" class="btn btn-sm btn-primary">
<i class="bi bi-plus-lg"></i> Добавить
</a>
</div>
@ -73,9 +83,19 @@
<div class="list-group-item px-0 py-3">
<div class="d-flex w-100 justify-content-between align-items-center">
<h6 class="mb-1">{{ supplier.name }}</h6>
<a href="{% url 'supplier_edit' supplier.pk %}" class="btn btn-sm btn-link p-0 text-muted">
<i class="bi bi-pencil-square"></i>
</a>
<div class="btn-group">
<a href="{% url 'supplier_edit' supplier.pk %}" class="btn btn-sm btn-link p-0 text-muted me-2" title="Редактировать">
<i class="bi bi-pencil-square"></i>
</a>
{% if user.is_staff %}
<form action="{% url 'supplier_delete' supplier.pk %}" method="POST" class="d-inline" onsubmit="return confirm('Удалить поставщика?')">
{% csrf_token %}
<button type="submit" class="btn btn-sm btn-link p-0 text-danger" title="Удалить">
<i class="bi bi-trash"></i>
</button>
</form>
{% endif %}
</div>
</div>
<p class="mb-1 small text-muted">
<strong>Менеджер:</strong> {{ supplier.representative_name|default:"-" }}<br>

View File

@ -9,12 +9,14 @@ urlpatterns = [
path('fleet/<int:pk>/', views.FleetDetailView.as_view(), name='fleet_detail'),
path('fleet/add/', views.FleetCreateView.as_view(), name='fleet_add'),
path('fleet/<int:pk>/edit/', views.FleetUpdateView.as_view(), name='fleet_edit'),
path('fleet/<int:pk>/delete/', views.FleetUnitDeleteView.as_view(), name='fleet_delete'),
# Maintenance
path('maintenance/', views.MaintenanceListView.as_view(), name='maintenance_list'),
path('maintenance/<int:pk>/', views.MaintenanceDetailView.as_view(), name='maintenance_detail'),
path('maintenance/add/', views.MaintenanceCreateView.as_view(), name='maintenance_add'),
path('maintenance/<int:pk>/edit/', views.MaintenanceUpdateView.as_view(), name='maintenance_edit'),
path('maintenance/<int:pk>/delete/', views.MaintenanceDeleteView.as_view(), name='maintenance_delete'),
path('maintenance/<int:pk>/process/', views.MaintenanceProcessView.as_view(), name='maintenance_process'),
path('maintenance/<int:pk>/complete/', views.MaintenanceCompleteView.as_view(), name='maintenance_complete'),
path('maintenance/<int:pk>/pdf/', views.MaintenancePDFView.as_view(), name='maintenance_pdf'),
@ -22,13 +24,16 @@ urlpatterns = [
# Breakdown
path('breakdown/', views.BreakdownListView.as_view(), name='breakdown_list'),
path('breakdown/add/', views.BreakdownCreateView.as_view(), name='breakdown_add'),
path('breakdown/<int:pk>/delete/', views.BreakdownDeleteView.as_view(), name='breakdown_delete'),
# Part Request
path('part-request/', views.PartRequestListView.as_view(), name='part_request_list'),
path('part-request/add/', views.PartRequestCreateView.as_view(), name='part_request_add'),
path('part-request/<int:pk>/delete/', views.PartRequestDeleteView.as_view(), name='part_request_delete'),
# Supply
path('supply/', views.SupplyListView.as_view(), name='supply_list'),
path('supplier/add/', views.SupplierCreateView.as_view(), name='supplier_add'),
path('supplier/add/', views.SupplierCreateView.as_view(), name='supplier_create'),
path('supplier/<int:pk>/edit/', views.SupplierUpdateView.as_view(), name='supplier_edit'),
path('supplier/<int:pk>/delete/', views.SupplierDeleteView.as_view(), name='supplier_delete'),
]

View File

@ -1,11 +1,11 @@
import json
from io import BytesIO
from django.shortcuts import render, redirect, get_object_or_404
from django.views.generic import ListView, DetailView, CreateView, UpdateView, TemplateView, View
from django.views.generic import ListView, DetailView, CreateView, UpdateView, TemplateView, View, DeleteView
from django.urls import reverse_lazy, reverse
from django import forms
from django.db.models import Count, Q
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.http import HttpResponse
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
@ -13,6 +13,11 @@ from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from .models import FleetUnit, Maintenance, Breakdown, PartRequest, Category, Document, Supplier
# Mixins
class StaffRequiredMixin(UserPassesTestMixin):
def test_func(self):
return self.request.user.is_staff
# Forms
class FleetUnitForm(forms.ModelForm):
class Meta:
@ -159,6 +164,10 @@ class FleetUpdateView(UpdateView):
def get_success_url(self):
return reverse_lazy('fleet_detail', kwargs={'pk': self.object.pk})
class FleetUnitDeleteView(LoginRequiredMixin, StaffRequiredMixin, DeleteView):
model = FleetUnit
success_url = reverse_lazy('fleet_list')
# Maintenance Views
class MaintenanceListView(ListView):
model = Maintenance
@ -205,6 +214,10 @@ class MaintenanceUpdateView(UpdateView):
def get_success_url(self):
return reverse('maintenance_detail', kwargs={'pk': self.object.pk})
class MaintenanceDeleteView(LoginRequiredMixin, StaffRequiredMixin, DeleteView):
model = Maintenance
success_url = reverse_lazy('maintenance_list')
class MaintenanceProcessView(View):
def post(self, request, pk):
maintenance = get_object_or_404(Maintenance, pk=pk)
@ -299,6 +312,11 @@ class BreakdownCreateView(CreateView):
def get_success_url(self):
return reverse('fleet_detail', kwargs={'pk': self.object.fleet_unit.pk})
class BreakdownDeleteView(LoginRequiredMixin, StaffRequiredMixin, DeleteView):
model = Breakdown
def get_success_url(self):
return reverse('fleet_detail', kwargs={'pk': self.object.fleet_unit.pk})
# Part Request Views
class PartRequestListView(ListView):
model = PartRequest
@ -325,6 +343,11 @@ class PartRequestCreateView(CreateView):
def get_success_url(self):
return reverse('fleet_detail', kwargs={'pk': self.object.fleet_unit.pk})
class PartRequestDeleteView(LoginRequiredMixin, StaffRequiredMixin, DeleteView):
model = PartRequest
def get_success_url(self):
return reverse('supply_list')
class SupplyListView(ListView):
model = PartRequest
template_name = 'core/supply_list.html'
@ -345,4 +368,8 @@ class SupplierUpdateView(UpdateView):
model = Supplier
form_class = SupplierForm
template_name = 'core/supplier_form.html'
success_url = reverse_lazy('supply_list')
success_url = reverse_lazy('supply_list')
class SupplierDeleteView(LoginRequiredMixin, StaffRequiredMixin, DeleteView):
model = Supplier
success_url = reverse_lazy('supply_list')