315 lines
9.3 KiB
Python
315 lines
9.3 KiB
Python
from django.db import models
|
|
from django.core.exceptions import ValidationError
|
|
from django.utils.translation import ugettext_lazy as _
|
|
from django.contrib.auth.models import Group
|
|
from event.models import Activity, EventSpecificMixin
|
|
from django.db.models import Q
|
|
|
|
from .fields import IdField
|
|
|
|
from datetime import date
|
|
|
|
|
|
class EquipmentCategory(models.Model):
|
|
name = models.CharField(
|
|
_("nom"),
|
|
max_length=200,
|
|
)
|
|
parent = models.ForeignKey(
|
|
'self',
|
|
blank=True,
|
|
null=True,
|
|
default=None,
|
|
on_delete=models.SET_NULL,
|
|
related_name="children",
|
|
help_text=_("merci de ne pas faire de référence cyclique"),
|
|
verbose_name=_("parent"),
|
|
)
|
|
|
|
def has_parent(self, cat):
|
|
current = self
|
|
for k in range(100):
|
|
if current is None:
|
|
return False
|
|
if current == cat:
|
|
return True
|
|
current = current.parent
|
|
|
|
def full_name(self):
|
|
current = self
|
|
res = ""
|
|
for k in range(100):
|
|
res = "/{current}{old}".format(
|
|
current=current.name,
|
|
old=res)
|
|
if current.parent is None:
|
|
break
|
|
current = current.parent
|
|
return res
|
|
|
|
full_name.short_description = _("Chemin complet")
|
|
full_name_p = property(full_name)
|
|
|
|
class Meta:
|
|
verbose_name = _("catégories")
|
|
verbose_name_plural = _("catégories")
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
def save(self, *args, **kwargs):
|
|
if self.pk:
|
|
done = False
|
|
current = self
|
|
while not done:
|
|
if current.parent == self:
|
|
self.parent = None
|
|
done = True
|
|
elif current.parent is None:
|
|
done = True
|
|
current = current.parent
|
|
return super().save(*args, **kwargs)
|
|
|
|
|
|
class EquipmentQuerySet(models.QuerySet):
|
|
def in_category(self, cat):
|
|
filtre = Q(id__lt=0)
|
|
childs_id = [c.id for c in EquipmentCategory.objects.all()
|
|
if c.has_parent(cat)]
|
|
for pk in childs_id:
|
|
filtre |= Q(category__id=pk)
|
|
return self.filter(filtre)
|
|
|
|
|
|
class Equipment(EventSpecificMixin, models.Model):
|
|
name = models.CharField(
|
|
_("nom du matériel"),
|
|
max_length=200,
|
|
)
|
|
stock = models.PositiveSmallIntegerField(_("quantité totale"))
|
|
description = models.TextField(
|
|
_("description"),
|
|
blank=True,
|
|
)
|
|
activities = models.ManyToManyField(
|
|
Activity,
|
|
related_name="equipment",
|
|
through="EquipmentAttribution",
|
|
)
|
|
owner = models.ForeignKey(
|
|
Group,
|
|
verbose_name=_("propriétaire"),
|
|
blank=True,
|
|
null=True,
|
|
on_delete=models.SET_NULL,
|
|
)
|
|
category = models.ForeignKey(
|
|
EquipmentCategory,
|
|
verbose_name=_("catégorie"),
|
|
on_delete=models.PROTECT,
|
|
)
|
|
|
|
added_at = models.DateTimeField(
|
|
_("ajouté le"),
|
|
auto_now_add=True,
|
|
)
|
|
modified_at = models.DateTimeField(
|
|
_("dernière modification"),
|
|
auto_now=True,
|
|
)
|
|
|
|
objects = EquipmentQuerySet.as_manager()
|
|
|
|
def is_in_category(self, cat):
|
|
current = self.category
|
|
for k in range(100):
|
|
if current is None:
|
|
return False
|
|
if current == cat:
|
|
return True
|
|
current = current.parent
|
|
|
|
def ids_aviable(self):
|
|
if self.stock is None:
|
|
return []
|
|
res = list(map(lambda x: x+1, range(self.stock)))
|
|
for lost in self.losts.all():
|
|
res = [x
|
|
for x in res
|
|
if x not in lost.ids]
|
|
# TODO cassé
|
|
# TODO utilisés
|
|
return res
|
|
|
|
def ids_lost(self):
|
|
res = []
|
|
for lost in self.losts.all():
|
|
res = res + [x
|
|
for x in lost.ids
|
|
if x not in res]
|
|
return res
|
|
|
|
def stock_aviable(self):
|
|
aviable = self.ids_aviable()
|
|
return len(aviable)
|
|
|
|
def stock_lost(self):
|
|
return len(self.ids_lost())
|
|
|
|
def full_category(self):
|
|
return self.category.full_name()
|
|
|
|
full_category.short_description = _("Chemin complet")
|
|
ids_aviable.short_description = _("disponibles")
|
|
ids_lost.short_description = _("perdus")
|
|
stock_aviable.short_description = _("quantité disponible")
|
|
stock_lost.short_description = _("quantité perdue")
|
|
|
|
full_category_p = property(full_category)
|
|
ids_aviable_p = property(ids_aviable)
|
|
ids_lost_p = property(ids_lost)
|
|
stock_aviable_p = property(stock_aviable)
|
|
stock_lost_p = property(stock_lost)
|
|
|
|
class Meta:
|
|
verbose_name = _("matériel")
|
|
verbose_name_plural = _("matériels")
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
|
|
class EquipmentAttribute(models.Model):
|
|
name = models.CharField(
|
|
_("nom"),
|
|
max_length=200,
|
|
unique=True,
|
|
)
|
|
|
|
class Meta:
|
|
verbose_name = _("attribut")
|
|
verbose_name_plural = _("attributs")
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
|
|
class EquipmentAttributeValue(models.Model):
|
|
equipment = models.ForeignKey(
|
|
Equipment,
|
|
on_delete=models.CASCADE,
|
|
related_name="attributes",
|
|
verbose_name=_("matériel"),
|
|
help_text=_("Matériel concerné par le defaut"),
|
|
)
|
|
attribute = models.ForeignKey(
|
|
EquipmentAttribute,
|
|
verbose_name=_("attribut"),
|
|
on_delete=models.CASCADE,
|
|
)
|
|
value = models.CharField(
|
|
_("valeur"),
|
|
max_length=200,
|
|
)
|
|
|
|
class Meta:
|
|
verbose_name = _("attribut de matériel")
|
|
verbose_name_plural = _("attributs de matériel")
|
|
|
|
def __str__(self):
|
|
return "{attr}={value}".format(attr=self.attribute.name,
|
|
value=self.value)
|
|
|
|
|
|
class EquipmentAttribution(models.Model):
|
|
equipment = models.ForeignKey(
|
|
Equipment,
|
|
verbose_name=_("matériel"),
|
|
on_delete=models.CASCADE,
|
|
)
|
|
activity = models.ForeignKey(
|
|
Activity,
|
|
on_delete=models.CASCADE,
|
|
)
|
|
amount = models.BigIntegerField(_("quantité attribuée"))
|
|
remarks = models.TextField(
|
|
_("remarques concernant l'attribution"),
|
|
blank=True,
|
|
)
|
|
|
|
class Meta:
|
|
verbose_name = _("attribution de matériel")
|
|
verbose_name_plural = _("attributions de matériel")
|
|
|
|
def __str__(self):
|
|
return "%s (%d) -> %s" % (self.equipment.name,
|
|
self.amount,
|
|
self.activity.get_herited('title'))
|
|
|
|
def save(self, *args, **kwargs):
|
|
if (self.equipment.event
|
|
and self.equipment.event != self.activity.event):
|
|
raise ValidationError
|
|
|
|
super(EquipmentAttribution, self).save(*args, **kwargs)
|
|
|
|
|
|
class EquipmentDefault(models.Model):
|
|
remark = models.TextField(_("remarque sur le défaut"))
|
|
equipment = models.ForeignKey(
|
|
Equipment,
|
|
verbose_name=_("matériel"),
|
|
on_delete=models.CASCADE,
|
|
related_name="remarks",
|
|
help_text=_("Matériel concerné par le defaut"),
|
|
)
|
|
ids = IdField()
|
|
is_unusable = models.BooleanField(_("inutilisable"))
|
|
send_repare = models.BooleanField(_("à envoyer réparareur"))
|
|
|
|
class Meta:
|
|
verbose_name = _("defaut matériel")
|
|
verbose_name_plural = _("défauts sur le matériel")
|
|
|
|
def __str__(self):
|
|
return "%s : %s" % (self.equipment.name,
|
|
self.remark)
|
|
|
|
|
|
class EquipmentLost(models.Model):
|
|
lost_at = models.DateField(
|
|
_("perdu le"),
|
|
default=date.today,
|
|
)
|
|
equipment = models.ForeignKey(
|
|
Equipment,
|
|
verbose_name=_("matériel"),
|
|
on_delete=models.CASCADE,
|
|
related_name="losts",
|
|
help_text=_("Matériel concerné par la perte"),
|
|
)
|
|
ids = IdField()
|
|
|
|
|
|
class EquipmentRevision(models.Model):
|
|
date = models.DateField(
|
|
_("date"),
|
|
default=date.today,
|
|
)
|
|
equipment = models.ForeignKey(
|
|
Equipment,
|
|
verbose_name=_("matériel"),
|
|
on_delete=models.CASCADE,
|
|
related_name="revisions",
|
|
help_text=_("Matériel concerné par les révisions"),
|
|
)
|
|
remark = models.TextField(_("remarque sur la révision"))
|
|
ids = IdField()
|
|
|
|
class Meta:
|
|
verbose_name = _("révision de matériel")
|
|
verbose_name_plural = _("révisions de matériel")
|
|
|
|
def __str__(self):
|
|
return "%s : %s" % (self.equipment.name,
|
|
self.remark)
|