# -*- 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', null=True, on_delete=models.SET_NULL) 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'