diff options
Diffstat (limited to 'archaeological_finds/models.py')
-rw-r--r-- | archaeological_finds/models.py | 215 |
1 files changed, 184 insertions, 31 deletions
diff --git a/archaeological_finds/models.py b/archaeological_finds/models.py index b52aabbf2..dc626feee 100644 --- a/archaeological_finds/models.py +++ b/archaeological_finds/models.py @@ -23,15 +23,17 @@ from django.conf import settings from django.contrib.gis.db import models from django.core.urlresolvers import reverse from django.db.models import Max, Q +from django.db.models.signals import m2m_changed from django.utils.translation import ugettext_lazy as _, ugettext from ishtar_common.models import GeneralType, ImageModel, BaseHistorizedItem, \ ShortMenuItem, LightHistorizedItem, HistoricalRecords, OwnPerms, Source, \ - Person + Person, Basket, get_external_id from archaeological_operations.models import AdministrativeAct from archaeological_context_records.models import ContextRecord, Dating +from ishtar_common.models import PRIVATE_FIELDS from archaeological_warehouse.models import Warehouse, Container @@ -102,8 +104,9 @@ IS_ISOLATED_CHOICES = ( class BaseFind(BaseHistorizedItem, OwnPerms): IS_ISOLATED_DICT = dict(IS_ISOLATED_CHOICES) label = models.TextField(_(u"Free ID")) - external_id = models.CharField(_(u"External ID"), blank=True, null=True, - max_length=120) + external_id = models.TextField(_(u"External ID"), blank=True, null=True) + auto_external_id = models.BooleanField( + _(u"External ID is set automatically"), default=False) description = models.TextField(_(u"Description"), blank=True, null=True) comment = models.TextField(_(u"Comment"), blank=True, null=True) topographic_localisation = models.CharField( @@ -118,7 +121,10 @@ class BaseFind(BaseHistorizedItem, OwnPerms): batch = models.CharField(_(u"Batch/object"), max_length=1, default="U", choices=IS_ISOLATED_CHOICES) index = models.IntegerField(u"Index", default=0) - material_index = models.IntegerField(u"Material index", default=0) + material_index = models.IntegerField(_(u"Material index"), default=0) + point = models.PointField(_(u"Point"), blank=True, null=True, dim=3) + line = models.LineStringField(_(u"Line"), blank=True, null=True) + polygon = models.PolygonField(_(u"Polygon"), blank=True, null=True) cache_short_id = models.TextField( _(u"Short ID"), blank=True, null=True, help_text=_(u"Cached value - do not edit")) @@ -231,6 +237,20 @@ class BaseFind(BaseHistorizedItem, OwnPerms): fields['find'] = field.related.model return fields + def save(self, *args, **kwargs): + returned = super(BaseFind, self).save(*args, **kwargs) + + updated = False + if not self.external_id or self.auto_external_id: + external_id = get_external_id('base_find_external_id', self) + if external_id != self.external_id: + updated = True + self.auto_external_id = True + self.external_id = external_id + if updated: + self.save() + return returned + WEIGHT_UNIT = (('g', _(u"g")), ('kg', _(u"kg")),) @@ -240,6 +260,11 @@ CHECK_CHOICES = (('NC', _(u"Not checked")), ) +class FindBasket(Basket): + items = models.ManyToManyField('Find', blank=True, null=True, + related_name='basket') + + class Find(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem): CHECK_DICT = dict(CHECK_CHOICES) SHOW_URL = 'show-find' @@ -278,8 +303,9 @@ class Find(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem): ATTRS_EQUIV = {'get_first_base_find': 'base_finds'} base_finds = models.ManyToManyField(BaseFind, verbose_name=_(u"Base find"), related_name='find') - external_id = models.CharField(_(u"External ID"), blank=True, null=True, - max_length=120) + external_id = models.TextField(_(u"External ID"), blank=True, null=True) + auto_external_id = models.BooleanField( + _(u"External ID is set automatically"), default=False) order = models.IntegerField(_(u"Order"), default=1) label = models.TextField(_(u"Free ID")) description = models.TextField(_(u"Description"), blank=True, null=True) @@ -288,6 +314,8 @@ class Find(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem): conservatory_state = models.ForeignKey( ConservatoryState, verbose_name=_(u"Conservatory state"), blank=True, null=True) + conservatory_comment = models.TextField(_(u"Conservatory comment"), + blank=True, null=True) preservation_to_considers = models.ManyToManyField( PreservationType, verbose_name=_(u"Type of preservation to consider"), related_name='finds') @@ -298,10 +326,10 @@ class Find(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem): find_number = models.IntegerField(_("Find number"), blank=True, null=True) upstream_treatment = models.ForeignKey( "Treatment", blank=True, null=True, - related_name='downstream_treatment', + related_name='downstream', verbose_name=_("Upstream treatment")) downstream_treatment = models.ForeignKey( - "Treatment", blank=True, null=True, related_name='upstream_treatment', + "Treatment", blank=True, null=True, related_name='upstream', verbose_name=_("Downstream treatment")) datings = models.ManyToManyField(Dating, verbose_name=_(u"Dating"), related_name='find') @@ -318,6 +346,8 @@ class Find(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem): width = models.FloatField(_(u"Width (cm)"), blank=True, null=True) height = models.FloatField(_(u"Height (cm)"), blank=True, null=True) diameter = models.FloatField(_(u"Diameter (cm)"), blank=True, null=True) + dimensions_comment = models.TextField(_(u"Dimensions comment"), + blank=True, null=True) mark = models.TextField(_(u"Mark"), blank=True, null=True) comment = models.TextField(_(u"Comment"), blank=True, null=True) dating_comment = models.TextField(_(u"Comment on dating"), blank=True, @@ -329,6 +359,7 @@ class Find(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem): check_date = models.DateField(_(u"Check date"), default=datetime.date.today) history = HistoricalRecords() + BASKET_MODEL = FindBasket def __init__(self, *args, **kwargs): super(Find, self).__init__(*args, **kwargs) @@ -372,6 +403,18 @@ class Find(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem): return u" - ".join([base_find.name for base_find in self.base_finds.all()]) + @property + def full_label(self): + lbl = u" - ".join([ + getattr(self, attr) + for attr in ('label', 'administrative_index') + if getattr(self, attr)]) + base = u" - ".join([base_find.complete_id() + for base_find in self.base_finds.all()]) + if base: + lbl += u' ({})'.format(base) + return lbl + def get_first_base_find(self): q = self.base_finds if not q.count(): @@ -394,6 +437,44 @@ class Find(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem): bf.context_record.operation.get_reference(), self.index) + def upstream_treatments(self): + treatments = [] + base_finds = [bf.pk for bf in self.base_finds.all()] + if self.upstream_treatment and \ + self.upstream_treatment.pk not in treatments: + treatments.append( + (self.upstream_treatment.upstream.distinct( + ).order_by('label').all(), self.upstream_treatment)) + for upstream in self.upstream_treatment.upstream.all(): + if upstream.pk != self.pk and not [ + bf.pk for bf in upstream.base_finds.all() + if bf.pk in base_finds]: + continue + for items, treatment in upstream.upstream_treatments(): + if treatment.pk not in treatments: + treatments.append((treatment.upstream.order_by( + 'label').all(), treatment)) + return treatments + + def downstream_treatments(self): + treatments = [] + base_finds = [bf.pk for bf in self.base_finds.all()] + if self.downstream_treatment and \ + self.downstream_treatment.pk not in treatments: + treatments.append( + (self.downstream_treatment.downstream.distinct( + ).order_by('label').all(), self.downstream_treatment)) + for downstream in self.downstream_treatment.downstream.all(): + if downstream.pk != self.pk and not [ + bf.pk for bf in downstream.base_finds.all() + if bf.pk in base_finds]: + continue + for items, treatment in downstream.downstream_treatments(): + if treatment.pk not in treatments: + treatments.append((treatment.downstream.order_by( + 'label').all(), treatment)) + return treatments + def get_department(self): bf = self.get_first_base_find() if not bf: @@ -460,19 +541,24 @@ class Find(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem): return q.filter(downstream_treatment__isnull=True).count() def duplicate(self, user): - # TODO - raise + model = self.__class__ + # base fields + table_cols = [field.name for field in model._meta.fields + if field.name not in PRIVATE_FIELDS or + field.name == 'order'] dct = dict([(attr, getattr(self, attr)) for attr in - ('order', 'label', 'description', - 'volume', 'weight', 'find_number', 'dating', - 'conservatory_state', 'preservation_to_consider', - 'weight_unit', )]) + table_cols]) dct['order'] += 1 dct['history_modifier'] = user new = self.__class__(**dct) new.save() - for base_find in self.base_finds.all(): - new.base_finds.add(base_find) + + # m2m fields + m2m = [field.name for field in model._meta.many_to_many + if field.name not in PRIVATE_FIELDS] + for field in m2m: + for val in getattr(self, field).all(): + getattr(new, field).add(val) return new @classmethod @@ -485,21 +571,36 @@ class Find(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem): def save(self, *args, **kwargs): super(Find, self).save(*args, **kwargs) + + updated = False + if not self.external_id or self.auto_external_id: + external_id = get_external_id('find_external_id', self) + if external_id != self.external_id: + updated = True + self.auto_external_id = True + self.external_id = external_id + if updated: + self.save() + return + q = self.base_finds if not self.index and q.count(): - operation = q.order_by( - '-context_record__operation__start_date')\ - .all()[0].context_record.operation - q = Find.objects\ - .filter(base_finds__context_record__operation=operation) - if self.pk: - q = q.exclude(pk=self.pk) - if q.count(): - self.index = q.aggregate(Max('index'))['index__max'] + 1 - else: - self.index = 1 - self.save() - for base_find in self.base_finds.all(): + operation = q.filter( + context_record__operation__pk__isnull=False).order_by( + '-context_record__operation__start_date') + if operation.count(): + operation = operation.all()[0].context_record.operation + q = Find.objects\ + .filter(base_finds__context_record__operation=operation) + if self.pk: + q = q.exclude(pk=self.pk) + if q.count(): + self.index = q.aggregate(Max('index'))['index__max'] + 1 + else: + self.index = 1 + self.save() + for base_find in self.base_finds.filter( + context_record__operation__pk__isnull=False).all(): modified = False if not base_find.index: modified = True @@ -528,8 +629,18 @@ class Find(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem): # idx and idx['material_index__max'] + 1 or 1 +def base_find_find_changed(sender, **kwargs): + obj = kwargs.get('instance', None) + if not obj: + return + # recalculate complete id and external id + obj.save() + +m2m_changed.connect(base_find_find_changed, sender=Find.base_finds.through) + class FindSource(Source): SHOW_URL = 'show-findsource' + MODIFY_URL = 'find_source_modify' class Meta: verbose_name = _(u"Find documentation") @@ -544,6 +655,16 @@ class FindSource(Source): class TreatmentType(GeneralType): virtual = models.BooleanField(_(u"Virtual")) + upstream_is_many = models.BooleanField( + _(u"Upstream is many"), default=False, + help_text=_( + u"Check this if for this treatment from many finds you'll get " + u"one.")) + downstream_is_many = models.BooleanField( + _(u"Downstream is many"), default=False, + help_text=_( + u"Check this if for this treatment from one find you'll get " + u"many.")) class Meta: verbose_name = _(u"Treatment type") @@ -560,8 +681,11 @@ class Treatment(BaseHistorizedItem, OwnPerms): comment = models.TextField(_(u"Comment"), blank=True, null=True) treatment_type = models.ForeignKey(TreatmentType, verbose_name=_(u"Treatment type")) - location = models.ForeignKey(Warehouse, verbose_name=_(u"Location"), - blank=True, null=True) + location = models.ForeignKey( + Warehouse, verbose_name=_(u"Location"), blank=True, null=True, + help_text=_( + u"Location where the treatment is done. Target warehouse for " + u"a move.")) other_location = models.CharField(_(u"Other location"), max_length=200, blank=True, null=True) person = models.ForeignKey( @@ -588,6 +712,35 @@ class Treatment(BaseHistorizedItem, OwnPerms): lbl += u" %s %s" % (_(u"by"), unicode(self.person)) return lbl + def save(self, *args, **kwargs): + items, user, extra_args_for_new = [], None, [] + if "items" in kwargs: + items = kwargs.pop('items') + if "user" in kwargs: + user = kwargs.pop('user') + if "extra_args_for_new" in kwargs: + extra_args_for_new = kwargs.pop('extra_args_for_new') + is_new = self.pk is None + super(Treatment, self).save(*args, **kwargs) + if not is_new or not items: + return + basket = None + if hasattr(items, "items"): + basket = items + items = basket.items.all() + for item in items: + new = item.duplicate(user) + item.downstream_treatment = self + item.save() + new.upstream_treatment = self + for k in extra_args_for_new: + setattr(new, k, extra_args_for_new[k]) + new.save() + # update baskets + for basket in FindBasket.objects.filter(items__pk=item.pk).all(): + basket.items.remove(item) + basket.items.add(new) + class TreatmentSource(Source): class Meta: |