159 lines
7.2 KiB
Python
159 lines
7.2 KiB
Python
from django.db import models
|
||
from django.urls import reverse
|
||
|
||
class Category(models.Model):
|
||
name = models.CharField(max_length=100, verbose_name="Наименование")
|
||
|
||
class Meta:
|
||
verbose_name = "Категория"
|
||
verbose_name_plural = "Категории"
|
||
|
||
def __str__(self):
|
||
return self.name
|
||
|
||
class FleetUnit(models.Model):
|
||
STATUS_CHOICES = [
|
||
('active', 'В работе'),
|
||
('idle', 'Простаивает'),
|
||
('broken', 'Сломана'),
|
||
('repair', 'В ремонте'),
|
||
('waiting_parts', 'Ждёт деталь'),
|
||
]
|
||
|
||
name = models.CharField(max_length=255, verbose_name="Наименование")
|
||
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="Категория")
|
||
model_name = models.CharField(max_length=255, verbose_name="Модель")
|
||
vin = models.CharField(max_length=100, unique=True, verbose_name="VIN / Серийный номер")
|
||
plate_number = models.CharField(max_length=50, blank=True, null=True, verbose_name="Госномер")
|
||
year = models.PositiveIntegerField(verbose_name="Год выпуска")
|
||
photo = models.ImageField(upload_to='fleet_photos/', blank=True, null=True, verbose_name="Фото")
|
||
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='active', verbose_name="Статус")
|
||
commissioning_date = models.DateField(verbose_name="Дата ввода в эксплуатацию")
|
||
notes = models.TextField(blank=True, null=True, verbose_name="Примечания")
|
||
|
||
created_at = models.DateTimeField(auto_now_add=True)
|
||
updated_at = models.DateTimeField(auto_now=True)
|
||
|
||
class Meta:
|
||
verbose_name = "Техника"
|
||
verbose_name_plural = "Техника"
|
||
ordering = ['-created_at']
|
||
|
||
def __str__(self):
|
||
return f"{self.name} ({self.plate_number or self.vin})"
|
||
|
||
def get_absolute_url(self):
|
||
return reverse('fleet_detail', kwargs={'pk': self.pk})
|
||
|
||
def get_status_color(self):
|
||
colors = {
|
||
'active': 'success',
|
||
'idle': 'secondary',
|
||
'broken': 'danger',
|
||
'repair': 'warning',
|
||
'waiting_parts': 'info',
|
||
}
|
||
return colors.get(self.status, 'primary')
|
||
|
||
class Maintenance(models.Model):
|
||
TYPE_CHOICES = [
|
||
('TO-250', 'ТО-250'),
|
||
('TO-500', 'ТО-500'),
|
||
('seasonal', 'Сезонное'),
|
||
('individual', 'Индивидуальное'),
|
||
]
|
||
STATUS_CHOICES = [
|
||
('planned', 'Планируется'),
|
||
('in_progress', 'В процессе'),
|
||
('completed', 'Выполнено'),
|
||
]
|
||
|
||
fleet_unit = models.ForeignKey(FleetUnit, on_delete=models.CASCADE, related_name='maintenances', verbose_name="Техника")
|
||
m_type = models.CharField(max_length=50, choices=TYPE_CHOICES, verbose_name="Тип ТО")
|
||
planned_date = models.DateField(verbose_name="Плановая дата")
|
||
planned_runtime = models.PositiveIntegerField(verbose_name="Плановый пробег / моточасы")
|
||
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='planned', verbose_name="Статус")
|
||
|
||
actual_date = models.DateField(null=True, blank=True, verbose_name="Фактическая дата")
|
||
actual_runtime = models.PositiveIntegerField(null=True, blank=True, verbose_name="Фактический пробег / моточасы")
|
||
|
||
notes = models.TextField(blank=True, null=True, verbose_name="Примечания")
|
||
|
||
class Meta:
|
||
verbose_name = "ТО"
|
||
verbose_name_plural = "ТО"
|
||
|
||
def __str__(self):
|
||
return f"{self.m_type} - {self.fleet_unit.name} ({self.planned_date})"
|
||
|
||
class Breakdown(models.Model):
|
||
STATUS_CHOICES = [
|
||
('reported', 'Заявлено'),
|
||
('repaired', 'Отремонтировано'),
|
||
('need_part', 'Нужна деталь'),
|
||
]
|
||
|
||
fleet_unit = models.ForeignKey(FleetUnit, on_delete=models.CASCADE, related_name='breakdowns', verbose_name="Техника")
|
||
date = models.DateField(auto_now_add=True, verbose_name="Дата")
|
||
system_node = models.CharField(max_length=255, verbose_name="Узел / система")
|
||
description = models.TextField(verbose_name="Описание")
|
||
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='reported', verbose_name="Статус")
|
||
repair_date = models.DateField(null=True, blank=True, verbose_name="Дата ремонта")
|
||
cost = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name="Стоимость")
|
||
|
||
class Meta:
|
||
verbose_name = "Поломка"
|
||
verbose_name_plural = "Поломки"
|
||
|
||
def __str__(self):
|
||
return f"Поломка: {self.fleet_unit.name} - {self.system_node}"
|
||
|
||
class PartRequest(models.Model):
|
||
STATUS_CHOICES = [
|
||
('draft', 'Черновик'),
|
||
('sent', 'Отправлено'),
|
||
('ordered', 'Заказано'),
|
||
('delivered', 'Доставлено'),
|
||
]
|
||
|
||
fleet_unit = models.ForeignKey(FleetUnit, on_delete=models.CASCADE, related_name='part_requests', verbose_name="Техника")
|
||
part_name = models.CharField(max_length=255, verbose_name="Наименование детали")
|
||
article_number = models.CharField(max_length=100, blank=True, null=True, verbose_name="Артикул")
|
||
quantity = models.PositiveIntegerField(default=1, verbose_name="Количество")
|
||
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='draft', verbose_name="Статус")
|
||
photo = models.ImageField(upload_to='part_photos/', blank=True, null=True, verbose_name="Фото")
|
||
notes = models.TextField(blank=True, null=True, verbose_name="Примечание")
|
||
|
||
created_at = models.DateTimeField(auto_now_add=True)
|
||
|
||
class Meta:
|
||
verbose_name = "Заявка на запчасть"
|
||
verbose_name_plural = "Заявки на запчасти"
|
||
|
||
def __str__(self):
|
||
return f"{self.part_name} for {self.fleet_unit.name}"
|
||
|
||
class Document(models.Model):
|
||
TYPE_CHOICES = [
|
||
('passport', 'Паспорт'),
|
||
('maintenance_act', 'Акт ТО'),
|
||
('photo', 'Фото'),
|
||
('invoice', 'Счет'),
|
||
]
|
||
|
||
doc_type = models.CharField(max_length=50, choices=TYPE_CHOICES, verbose_name="Тип документа")
|
||
fleet_unit = models.ForeignKey(FleetUnit, on_delete=models.CASCADE, related_name='documents', null=True, blank=True)
|
||
maintenance = models.ForeignKey(Maintenance, on_delete=models.CASCADE, related_name='documents', null=True, blank=True)
|
||
breakdown = models.ForeignKey(Breakdown, on_delete=models.CASCADE, related_name='documents', null=True, blank=True)
|
||
part_request = models.ForeignKey(PartRequest, on_delete=models.CASCADE, related_name='documents', null=True, blank=True)
|
||
|
||
file = models.FileField(upload_to='documents/', verbose_name="Файл")
|
||
uploaded_at = models.DateTimeField(auto_now_add=True, verbose_name="Дата добавления")
|
||
|
||
class Meta:
|
||
verbose_name = "Документ"
|
||
verbose_name_plural = "Документы"
|
||
|
||
def __str__(self):
|
||
return f"{self.get_doc_type_display()} - {self.uploaded_at}"
|