diff options
Diffstat (limited to 'archaeological_operations/models.py')
-rw-r--r-- | archaeological_operations/models.py | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py new file mode 100644 index 000000000..48baa57ba --- /dev/null +++ b/archaeological_operations/models.py @@ -0,0 +1,300 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2012 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +from django.conf import settings +from django.contrib.gis.db import models +from django.db.models.signals import post_save +from django.utils.translation import ugettext_lazy as _, ugettext + +from ishtar_common.models import GeneralType, BaseHistorizedItem, \ + HistoricalRecords, OwnPerms, Department, Source, Person, Organization, Town +FILES_AVAILABLE = 'archaeological_files' in settings.INSTALLED_APPS +if FILES_AVAILABLE: + from archaeological_files.models import File + +class OperationType(GeneralType): + class Meta: + verbose_name = _(u"Operation type") + verbose_name_plural = _(u"Operation types") + + @classmethod + def is_preventive(cls, ope_type_id, key=''): + key = key or 'prev_excavation' + try: + preventive = OperationType.objects.get(txt_idx=key).pk + return ope_type_id == preventive + except ObjectDoesNotExist: + return False + +class RemainType(GeneralType): + class Meta: + verbose_name = _(u"Remain type") + verbose_name_plural = _(u"Remain types") + +class Period(GeneralType) : + order = models.IntegerField(_(u"Order")) + start_date = models.IntegerField(_(u"Start date")) + end_date = models.IntegerField(_(u"End date")) + parent = models.ForeignKey("Period", verbose_name=_(u"Parent period"), + blank=True, null=True) + + class Meta: + verbose_name = _(u"Type Period") + verbose_name_plural = _(u"Types Period") + + def __unicode__(self): + return self.label + +class Operation(BaseHistorizedItem, OwnPerms): + TABLE_COLS = ['year_index', 'operation_type', 'remains', 'towns', + 'associated_file', 'start_date', 'excavation_end_date'] + start_date = models.DateField(_(u"Start date"), null=True, blank=True) + excavation_end_date = models.DateField(_(u"Excavation end date"), null=True, + blank=True) + end_date = models.DateField(_(u"Closing date"), null=True, blank=True) + in_charge = models.ForeignKey(Person, related_name='+', null=True, + blank=True, verbose_name=_(u"In charge")) + year = models.IntegerField(_(u"Year")) + operation_code = models.IntegerField(_(u"Operation code")) + if FILES_AVAILABLE: + associated_file = models.ForeignKey(File, related_name='operations', + verbose_name=_(u"File"), blank=True, null=True) + operation_type = models.ForeignKey(OperationType, related_name='+', + verbose_name=_(u"Operation type")) + surface = models.IntegerField(_(u"Surface (m²)"), blank=True, null=True) + remains = models.ManyToManyField("RemainType", verbose_name=_(u'Remains')) + towns = models.ManyToManyField(Town, verbose_name=_(u"Towns")) + cost = models.IntegerField(_(u"Cost (€)"), blank=True, null=True) + periods = models.ManyToManyField(Period, verbose_name=_(u"Periods")) + scheduled_man_days = models.IntegerField(_(u"Scheduled man-days"), + blank=True, null=True) + optional_man_days = models.IntegerField(_(u"Optional man-days"), + blank=True, null=True) + effective_man_days = models.IntegerField(_(u"Effective man-days"), + blank=True, null=True) + if settings.COUNTRY == 'fr': + code_patriarche = models.IntegerField(u"Code PATRIARCHE", null=True, + blank=True) + TABLE_COLS = ['code_patriarche'] + TABLE_COLS + code_dracar = models.CharField(u"Code DRACAR", max_length=10, null=True, + blank=True) + fnap_financing = models.FloatField(u"Financement FNAP (%)", + blank=True, null=True) + fnap_cost = models.IntegerField(u"Financement FNAP (€)", + blank=True, null=True) + zoning_prescription = models.NullBooleanField( + _(u"Prescription on zoning"), blank=True, null=True) + large_area_prescription = models.NullBooleanField( + _(u"Prescription on large area"), blank=True, null=True) + geoarchaeological_context_prescription = models.NullBooleanField( + _(u"Prescription on geoarchaeological context"), blank=True, null=True) + operator_reference = models.CharField(_(u"Operator reference"), + max_length=20, null=True, blank=True) + common_name = models.CharField(_(u"Generic name"), max_length=120, null=True, + blank=True) + comment = models.TextField(_(u"Comment"), null=True, blank=True) + history = HistoricalRecords() + + class Meta: + verbose_name = _(u"Operation") + verbose_name_plural = _(u"Operations") + permissions = ( + ("view_own_operation", ugettext(u"Can view own Operation")), + ("add_own_operation", ugettext(u"Can add own Operation")), + ("change_own_operation", ugettext(u"Can change own Operation")), + ("delete_own_operation", ugettext(u"Can delete own Operation")), + ) + + def __unicode__(self): + items = [unicode(_('Intercommunal'))] + if self.towns.count() == 1: + items[0] = unicode(self.towns.all()[0]) + items.append("-".join((unicode(self.year), + unicode(self.operation_code)))) + return JOINT.join(items) + + @classmethod + def get_available_operation_code(cls, year=None): + if not year: + year = datetime.date.today().year + max_val = cls.objects.filter(year=year).aggregate( + Max('operation_code'))["operation_code__max"] + return (max_val + 1) if max_val else 1 + + @classmethod + def get_years(cls): + return [res['year'] for res in list(cls.objects.values('year').annotate( + Count("id")).order_by())] + + @classmethod + def get_by_year(cls, year): + return cls.objects.filter(year=year) + + @classmethod + def get_total_number(cls): + return cls.objects.count() + + year_index_lbl = _(u"Operation code") + @property + def year_index(self): + lbl = unicode(self.operation_code) + lbl = u"%d-%s%s" % (self.year, (3-len(lbl))*"0", lbl) + return lbl + + def clean(self): + objs = self.__class__.objects.filter(year=self.year, + operation_code=self.operation_code) + if self.pk: + objs = objs.exclude(pk=self.pk) + if objs.count(): + raise ValidationError(_(u"This operation code already exists for " + u"this year")) + + def is_own(self, person): + return False + + @property + def surface_ha(self): + if self.surface: + return self.surface/10000.0 + + @property + def cost_by_m2(self): + if not self.surface or not self.cost: + return + return round(float(self.cost)/self.surface, 2) + + @property + def cost_by_m2(self): + if not self.surface or not self.cost: + return + return round(float(self.cost)/self.surface, 2) + + @classmethod + def get_query_owns(cls, user): + return Q(in_charge=user.person)|Q(history_modifier=user)\ + & Q(end_date__isnull=True) + + def is_active(self): + return not bool(self.end_date) + + def closing(self): + if self.is_active(): + return + for item in self.history.all(): + if not item.end_date: + break + return {'date':item.history_date, + 'user':IshtarUser.objects.get(pk=item.history_modifier_id)} + +def operation_post_save(sender, **kwargs): + if not kwargs['instance']: + return + operation = kwargs['instance'] + if operation.fnap_financing and operation.cost: + fnap_cost = int(float(operation.cost)/100*operation.fnap_financing) + if not operation.fnap_cost or operation.fnap_cost != fnap_cost: + operation.fnap_cost = fnap_cost + operation.save() + elif operation.fnap_cost and operation.cost: + fnap_percent = float(operation.fnap_cost)*100/operation.cost + operation.fnap_financing = fnap_percent + operation.save() +post_save.connect(operation_post_save, sender=Operation) + +class OperationByDepartment(models.Model): + ''' + Database view: don't forget to create it + + create view operation_department (id, department_id, operation_id) as + select town."id", town."departement_id", operation_towns."operation_id" + from ishtar_base_town town + inner join ishtar_base_operation_towns operation_towns on + operation_towns."town_id"=town."id" order by town."departement_id"; + CREATE RULE operation_department_delete + AS ON DELETE TO operation_department DO INSTEAD(); + ''' + operation = models.ForeignKey(Operation, verbose_name=_(u"Operation")) + department = models.ForeignKey(Department, verbose_name=_(u"Department"), + blank=True, null=True) + class Meta: + managed = False + db_table = 'operation_department' + +class OperationSource(Source): + class Meta: + verbose_name = _(u"Operation documentation") + verbose_name_plural = _(u"Operation documentations") + operation = models.ForeignKey(Operation, verbose_name=_(u"Operation"), + related_name="source") + index = models.IntegerField(verbose_name=_(u"Index")) + TABLE_COLS = ['operation.year', 'operation.operation_code'] + \ + Source.TABLE_COLS + +class ActType(GeneralType): + TYPE = (('F', _(u'Archaelogical file')), + ('O', _(u'Operation')), + ) + intented_to = models.CharField(_(u"Intended to"), max_length=1, + choices=TYPE) + class Meta: + verbose_name = _(u"Act type") + verbose_name_plural = _(u"Act types") + +class AdministrativeAct(BaseHistorizedItem, OwnPerms): + TABLE_COLS = ['act_type', 'associated_file', 'operation', + 'associated_file.towns', 'operation.towns'] + TABLE_COLS_FILE = ['act_type', 'associated_file', 'associated_file.towns',] + TABLE_COLS_OPE = ['act_type', 'operation', 'operation.towns'] + act_type = models.ForeignKey(ActType, verbose_name=_(u"Act type")) + in_charge = models.ForeignKey(Person, blank=True, null=True, + related_name='+', verbose_name=_(u"Person in charge of the operation")) + operator = models.ForeignKey(Organization, blank=True, null=True, + verbose_name=_(u"Archaeological preventive operator")) + scientific = models.ForeignKey(Person, blank=True, null=True, +related_name='+', verbose_name=_(u"Person in charge of the scientific part")) + signatory = models.ForeignKey(Person, blank=True, null=True, + related_name='+', verbose_name=_(u"Signatory")) + operation = models.ForeignKey(Operation, blank=True, null=True, + related_name='administrative_act', verbose_name=_(u"Operation")) + if FILES_AVAILABLE: + associated_file = models.ForeignKey(File, blank=True, null=True, + related_name='administrative_act', + verbose_name=_(u"Archaelogical file")) + signature_date = models.DateField(_(u"Signature date"), blank=True, + null=True) + act_object = models.CharField(_(u"Object"), max_length=200) + if settings.COUNTRY == 'fr': + ref_sra = models.CharField(u"Référence SRA", max_length=15) + history = HistoricalRecords() + + class Meta: + verbose_name = _(u"Administrative act") + verbose_name_plural = _(u"Administrative acts") + permissions = ( +("view_own_administrativeact", ugettext(u"Can view own Administrative act")), +("add_own_administrativeact", ugettext(u"Can add own Administrative act")), +("change_own_administrativeact", ugettext(u"Can change own Administrative act")), +("delete_own_administrativeact", ugettext(u"Can delete own Administrative act")), + ) + + def __unicode__(self): + return JOINT.join([unicode(item) + for item in [self.operation, self.associated_file, self.act_object] + if item]) |