This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
polynum/polynum/base/models/entity.py

129 lines
5.0 KiB
Python

# -*- coding: utf-8 -*-
"""
PolyNum
Définition des entités administratives
"""
from django.db import models
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _
class EntityType(models.Model):
class Meta:
app_label = 'base'
verbose_name = _(u"Type d'entité administrative")
verbose_name_plural = _(u"Type d'entités administratives")
def __unicode__(self):
return self.name
name = models.CharField(max_length=128, verbose_name=_(u'Nom'))
description = models.TextField(verbose_name=_(u'Description'), blank=True)
class EntityManager(models.Manager):
def rebuild_bounds(self, start=0):
'''Reallocate left and right bounds, starting at start'''
def rec(start, entity):
entity.left_bound = start
start += 1
for child_entity in self.filter(parent=entity):
start = rec(start, child_entity)
entity.right_bound = start
entity.save()
return start + 1
return rec(start, self.get(parent__isnull=True))
class Entity(models.Model):
objects = EntityManager()
class Meta:
app_label = 'base'
verbose_name = _(u'Entité administrative')
verbose_name_plural = _(u'Entités administratives')
ordering = ('left_bound',)
def __unicode__(self):
return self.get_name()
code = models.CharField(max_length=64, verbose_name=_(u'Code'), db_index=True)
is_active = models.BooleanField(verbose_name=_(u'Active'), default=True, blank=True, db_index=True)
name = models.CharField(max_length=128, verbose_name=_(u'Nom'), blank=True, db_index=True)
description = models.TextField(verbose_name=_(u'Description'), blank=True, db_index=True)
entity_type = models.ForeignKey(EntityType, null=True, blank=True, related_name='+', on_delete=models.PROTECT)
name_override = models.CharField(max_length=128, verbose_name=_(u'Nom spécifique PolyNum'), blank=True, db_index=True)
description_override = models.TextField(verbose_name=_(u'Description spécifique PolyNum'), blank=True, db_index=True)
depth = models.PositiveIntegerField(verbose_name=_('Niveau'), default=0, db_index=True)
left_bound = models.PositiveIntegerField(unique=True, db_index=True)
right_bound = models.PositiveIntegerField(unique=True, db_index=True)
parent = models.ForeignKey('Entity', verbose_name=_(u'Entité parente'), blank=True, null=True, related_name='children_set')
def children(self, included=False):
if included:
return Entity.objects.filter(left_bound__lt=self.right_bound, left_bound__gte=self.left_bound)
else:
return Entity.objects.filter(left_bound__lt=self.right_bound, left_bound__gt=self.left_bound)
def parents(self, included=False):
if included:
return Entity.objects.filter(left_bound__lte=self.left_bound, right_bound__gte=self.right_bound)
else:
return Entity.objects.filter(left_bound__lt=self.left_bound, right_bound__gt=self.right_bound)
def parents_and_their_children(self):
parents = self.parents().order_by('depth')
filters = []
for parent in parents:
filters.append(
Q(left_bound__lt=parent.right_bound,
left_bound__gte=parent.left_bound,
depth__lte=parent.depth+1))
qs = Entity.objects.filter(
reduce(Q.__or__, filters)).order_by('depth')
return qs
def accounting_codes(self):
'''
return a set of "accounting" codes: one of the entity and those of all its parents
'''
for parent in self.parents(included=True).order_by('-depth').prefetch_related('accountingcode_set'):
if parent.accountingcode_set.all():
return parent.accountingcode_set.all()
return AccountingCode.objects.none()
def parent_of_type(self, type_name):
parent = self.parent
while parent:
if parent.entity_type.name == type_name:
break
parent = parent.parent
return parent
def get_name(self):
return self.name_override or self.name
get_name.short_description = _(u'Nom')
def get_description(self):
return self.description_override or self.description
get_description.short_description = _(u'Description')
def level1_parent(self):
'''
Show parent of level between 1 or 3 if found, self return the current entity.
'''
parents = self.parents()
if len(parents) > 3:
return parents[3]
return self
class AccountingCode(models.Model):
class Meta:
app_label = 'base'
verbose_name = _(u'Code de comptabilité/financier')
verbose_name_plural = _(u'Codes de comptabilité/financier')
ordering = ('entity', 'code')
entity = models.ForeignKey(Entity)
code = models.CharField(max_length=32, verbose_name=_('Code d\'imputation'), db_index=True)