# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models from django.db.models import Q from django.conf import settings from django.utils import timezone from .fields import MACAddressField class ItemType(models.Model): name = models.CharField(max_length=100, verbose_name="nom") def __unicode__(self): return self.name class Meta: verbose_name = "type d’objet" verbose_name_plural = "types d’objet" class ItemQuerySet(models.QuerySet): def _get_borrowed_pks(self): return Loan.objects.running().values_list("item", flat=True) def available(self): return self.exclude(pk__in=self._get_borrowed_pks()).exclude(deployed=True) def borrowed(self): return self.filter(pk__in=self._get_borrowed_pks()) def deployed(self): return self.filter(deployed=True) def unavailable(self): """ deployed or borrowed """ return self.filter(Q(pk__in=self._get_borrowed_pks()) | Q(deployed=True)) class Item(models.Model): type = models.ForeignKey( ItemType, verbose_name="type de matériel", related_name="items" ) designation = models.CharField(max_length=100, verbose_name="désignation") storage = models.ForeignKey( "Storage", related_name="items", verbose_name="Lieu de stockage", null=True, blank=True, help_text="Laisser vide si inconnu", ) mac_address = MACAddressField( verbose_name="adresse MAC", blank=True, null=True, unique=True, help_text="préférable au n° de série si possible", ) serial = models.CharField( verbose_name="N° de série", max_length=250, blank=True, null=True, unique=True, help_text="ou toute autre référence unique", ) buy_date = models.DateField(verbose_name="date d’achat", blank=True, null=True) owner = models.ForeignKey( settings.AUTH_USER_MODEL, verbose_name="Propriétaire", related_name="items", null=True, blank=True, help_text="dans le cas de matériel n'appartenant pas à l'association", ) deployed = models.BooleanField( verbose_name="déployé", default=False, help_text="Cocher si le matériel est en production", ) comment = models.TextField(verbose_name="commentaire", blank=True, null=True) objects = ItemQuerySet().as_manager() def __unicode__(self): return self.designation def save(self, *args, **kwargs): # workaround for unique=True, null=True # see https://code.djangoproject.com/ticket/4136#comment:33 self.mac_address = self.mac_address or None self.serial = self.serial or None return super(Item, self).save(*args, **kwargs) def get_current_loan(self): """ Returns the current Loan for this Item, if exists, or None. """ try: return self.loans.get(loan_date_end__isnull=True) except Loan.DoesNotExist: return None def is_available(self): """ Returns the status of the Item. If a running loan exists, or if the item is deployed, returns False (else True). """ return (not self.deployed) and (not self.loans.running().exists()) is_available.boolean = True is_available.short_description = "disponible" def get_mac_and_serial(self): mac = self.mac_address serial = self.serial if mac and serial: return "{} / {}".format(mac, serial) else: return mac or serial or "" class Meta: verbose_name = "objet" ordering = ["designation", "mac_address", "serial"] def give_back(self, storage=None): self.storage = storage self.save() self.loans.running().update(loan_date_end=timezone.now()) class LoanQuerySet(models.QuerySet): @staticmethod def _running_filter(): return models.Q(loan_date_end__gt=timezone.now()) | models.Q( loan_date_end__isnull=True ) def running(self): return self.filter(self._running_filter()) def finished(self): return self.exclude(self._running_filter()) class Loan(models.Model): item = models.ForeignKey(Item, verbose_name="objet", related_name="loans") user = models.ForeignKey( settings.AUTH_USER_MODEL, verbose_name="membre", related_name="loans" ) loan_date = models.DateTimeField(verbose_name="date de prêt") loan_date_end = models.DateTimeField( verbose_name="date de fin de prêt", null=True, blank=True ) notes = models.TextField(null=True, blank=True) def __unicode__(self): return "prêt de {item} à {user}".format(item=self.item, user=self.user) def get_mac_and_serial(self): return self.item.get_mac_and_serial() get_mac_and_serial.short_description = "Adresse MAC / n° de série" def user_can_close(self, user): return (not self.item.is_available()) and (self.user == user) def is_running(self): return not self.loan_date_end or self.loan_date_end > timezone.now() is_running.boolean = True is_running.short_description = "En cours ?" class Meta: verbose_name = "prêt d’objet" verbose_name_plural = "prêts d’objets" objects = LoanQuerySet().as_manager() class Storage(models.Model): name = models.CharField(max_length=100, verbose_name="nom") notes = models.TextField(blank=True, help_text="Lisible par tous les adhérents") def __unicode__(self): return self.name def items_count(self): return self.items.count() items_count.short_description = "Nb. items stockés" class Meta: verbose_name = "lieu de stockage" verbose_name_plural = "lieux de stockage"