#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2012 Étienne Loks # 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 . # 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])