summaryrefslogtreecommitdiff
path: root/archaeological_operations/models.py
diff options
context:
space:
mode:
Diffstat (limited to 'archaeological_operations/models.py')
-rw-r--r--archaeological_operations/models.py144
1 files changed, 93 insertions, 51 deletions
diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py
index c4fd0d96e..54ed96cec 100644
--- a/archaeological_operations/models.py
+++ b/archaeological_operations/models.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-# Copyright (C) 2012-2016 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
+# Copyright (C) 2012-2017 É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
@@ -24,6 +24,7 @@ from django.conf import settings
from django.contrib.gis.db import models
from django.core.cache import cache
from django.core.urlresolvers import reverse
+from django.db import IntegrityError, transaction
from django.db.models import Q, Count, Sum, Max, Avg
from django.db.models.signals import post_save, m2m_changed, post_delete
from django.forms import ValidationError
@@ -37,7 +38,7 @@ from ishtar_common.models import GeneralType, BaseHistorizedItem, \
SourceType, Person, Organization, Town, Dashboard, IshtarUser, ValueGetter,\
DocumentTemplate, ShortMenuItem, DashboardFormItem, GeneralRelationType,\
GeneralRecordRelations, post_delete_record_relation, OperationType, \
- get_external_id, ImageModel, post_save_cache
+ ImageModel, post_save_cache
class RemainType(GeneralType):
@@ -86,24 +87,24 @@ class ArchaeologicalSite(BaseHistorizedItem):
name = models.CharField(_(u"Name"), max_length=200,
null=True, blank=True)
periods = models.ManyToManyField(Period, verbose_name=_(u"Periods"),
- blank=True, null=True)
+ blank=True)
remains = models.ManyToManyField("RemainType", verbose_name=_(u'Remains'),
- blank=True, null=True)
+ blank=True)
class Meta:
verbose_name = _(u"Archaeological site")
verbose_name_plural = _(u"Archaeological sites")
permissions = (
("view_archaeologicalsite",
- ugettext(u"Can view all Archaeological sites")),
+ u"Can view all Archaeological sites"),
("view_own_archaeologicalsite",
- ugettext(u"Can view own Archaeological site")),
+ u"Can view own Archaeological site"),
("add_own_archaeologicalsite",
- ugettext(u"Can add own Archaeological site")),
+ u"Can add own Archaeological site"),
("change_own_archaeologicalsite",
- ugettext(u"Can change own Archaeological site")),
+ u"Can change own Archaeological site"),
("delete_own_archaeologicalsite",
- ugettext(u"Can delete own Archaeological site")),
+ u"Can delete own Archaeological site"),
)
def __unicode__(self):
@@ -179,7 +180,6 @@ class Operation(ClosedItem, BaseHistorizedItem, ImageModel, OwnPerms,
SHOW_URL = 'show-operation'
TABLE_COLS = ['year', 'towns', 'common_name', 'operation_type',
'start_date', 'excavation_end_date', 'remains']
- IMAGE_PREFIX = 'operations/'
SLUG = 'operation'
# search parameters
@@ -270,7 +270,7 @@ class Operation(ClosedItem, BaseHistorizedItem, ImageModel, OwnPerms,
on_delete=models.SET_NULL,
related_name='operation_responsability')
collaborators = models.ManyToManyField(
- Person, blank=True, null=True, verbose_name=_(u"Collaborators"),
+ Person, blank=True, verbose_name=_(u"Collaborators"),
related_name='operation_collaborator'
)
year = models.IntegerField(_(u"Year"), null=True, blank=True)
@@ -284,13 +284,13 @@ class Operation(ClosedItem, BaseHistorizedItem, ImageModel, OwnPerms,
verbose_name=_(u"Operation type"))
surface = models.IntegerField(_(u"Surface (m2)"), blank=True, null=True)
remains = models.ManyToManyField("RemainType", verbose_name=_(u'Remains'),
- null=True, blank=True)
+ blank=True)
towns = models.ManyToManyField(Town, verbose_name=_(u"Towns"),
related_name='operations')
cost = models.IntegerField(_(u"Cost (euros)"),
blank=True, null=True) # preventive
periods = models.ManyToManyField(Period, verbose_name=_(u"Periods"),
- null=True, blank=True)
+ blank=True)
# preventive
scheduled_man_days = models.IntegerField(_(u"Scheduled man-days"),
blank=True, null=True)
@@ -343,7 +343,7 @@ class Operation(ClosedItem, BaseHistorizedItem, ImageModel, OwnPerms,
null=True, blank=True)
archaeological_sites = models.ManyToManyField(
ArchaeologicalSite, verbose_name=_(u"Archaeological sites"),
- null=True, blank=True)
+ blank=True, related_name='operations')
virtual_operation = models.BooleanField(
_(u"Virtual operation"),
default=False, help_text=_(
@@ -372,12 +372,12 @@ class Operation(ClosedItem, BaseHistorizedItem, ImageModel, OwnPerms,
verbose_name = _(u"Operation")
verbose_name_plural = _(u"Operations")
permissions = (
- ("view_operation", ugettext(u"Can view all Operations")),
- ("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")),
- ("close_operation", ugettext(u"Can close Operation")),
+ ("view_operation", u"Can view all Operations"),
+ ("view_own_operation", u"Can view own Operation"),
+ ("add_own_operation", u"Can add own Operation"),
+ ("change_own_operation", u"Can change own Operation"),
+ ("delete_own_operation", u"Can delete own Operation"),
+ ("close_operation", u"Can close Operation"),
)
ordering = ('cached_label',)
@@ -479,6 +479,10 @@ class Operation(ClosedItem, BaseHistorizedItem, ImageModel, OwnPerms,
self.context_record.model.cached_label_bulk_update(operation_id=self.pk)
return True
+ def _get_base_image_path(self):
+ return u"operation/{}/{}".format(
+ self.year, self.reference)
+
def get_town_label(self):
lbl = unicode(_('Intercommunal'))
if self.towns.count() == 1:
@@ -573,12 +577,12 @@ class Operation(ClosedItem, BaseHistorizedItem, ImageModel, OwnPerms,
return round(float(self.cost) / self.surface, 2)
@classmethod
- def get_query_owns(cls, user):
+ def get_query_owns(cls, ishtaruser):
return (
- Q(in_charge=user.ishtaruser.person) |
- Q(scientist=user.ishtaruser.person) |
- Q(collaborators__pk=user.ishtaruser.person.pk) |
- Q(history_creator=user)) & Q(end_date__isnull=True)
+ Q(in_charge=ishtaruser.person) |
+ Q(scientist=ishtaruser.person) |
+ Q(collaborators__pk=ishtaruser.person.pk) |
+ Q(history_creator=ishtaruser.user_ptr)) & Q(end_date__isnull=True)
def is_active(self):
return not bool(self.end_date)
@@ -812,13 +816,19 @@ def operation_post_save(sender, **kwargs):
# manage parcel association
for parcel in operation.parcels.all():
parcel.copy_to_file()
+
+ # external id update
+ for parcel in operation.parcels.all():
+ parcel.update_external_id(save=True)
+
+ for cr in operation.context_record.all():
+ cr.update_external_id(save=True)
+
+
post_save.connect(operation_post_save, sender=Operation)
class RelationType(GeneralRelationType):
- inverse_relation = models.ForeignKey(
- 'RelationType', verbose_name=_(u"Inverse relation"), blank=True,
- null=True)
class Meta:
verbose_name = _(u"Operation relation type")
@@ -839,6 +849,7 @@ class RecordRelations(GeneralRecordRelations, models.Model):
verbose_name_plural = _(u"Operation record relations")
ordering = ('left_record', 'relation_type')
+
post_delete.connect(post_delete_record_relation, sender=RecordRelations)
@@ -846,6 +857,22 @@ class OperationByDepartment(models.Model):
"""
Database view for dashboard
"""
+ CREATE_SQL = """
+ CREATE VIEW operation_department (id, department_id, operation_id) as
+ select town."id", town."departement_id",
+ operation_towns."operation_id"
+ from ishtar_common_town town
+ inner join archaeological_operations_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();
+ """
+ DELETE_SQL = """
+ DROP VIEW operation_department;
+ """
+
operation = models.ForeignKey(Operation, verbose_name=_(u"Operation"))
department = models.ForeignKey(Department, verbose_name=_(u"Department"),
blank=True, null=True)
@@ -908,14 +935,16 @@ class OperationSource(Source):
@property
def code(self):
+ if not self.index:
+ return u"{}-".format(self.operation.code_patriarche or '')
return u"{}-{:04d}".format(self.operation.code_patriarche or '',
self.index)
@classmethod
- def get_query_owns(cls, user):
- return (Q(operation__in_charge=user.ishtaruser.person) |
- Q(operation__scientist=user.ishtaruser.person) |
- Q(operation__collaborators__pk=user.ishtaruser.person.pk)) \
+ def get_query_owns(cls, ishtaruser):
+ return (Q(operation__in_charge=ishtaruser.person) |
+ Q(operation__scientist=ishtaruser.person) |
+ Q(operation__collaborators__pk=ishtaruser.person.pk)) \
& Q(operation__end_date__isnull=True)
@@ -929,7 +958,7 @@ class ActType(GeneralType):
choices=TYPE)
code = models.CharField(_(u"Code"), max_length=10, blank=True, null=True)
associated_template = models.ManyToManyField(
- DocumentTemplate, blank=True, null=True,
+ DocumentTemplate, blank=True,
verbose_name=_(u"Associated template"), related_name='acttypes')
indexed = models.BooleanField(_(u"Indexed"), default=False)
@@ -1064,15 +1093,15 @@ class AdministrativeAct(BaseHistorizedItem, OwnPerms, ValueGetter):
verbose_name_plural = _(u"Administrative acts")
permissions = (
("view_administrativeact",
- ugettext(u"Can view all Administrative acts")),
+ u"Can view all Administrative acts"),
("view_own_administrativeact",
- ugettext(u"Can view own Administrative act")),
+ u"Can view own Administrative act"),
("add_own_administrativeact",
- ugettext(u"Can add own Administrative act")),
+ u"Can add own Administrative act"),
("change_own_administrativeact",
- ugettext(u"Can change own Administrative act")),
+ u"Can change own Administrative act"),
("delete_own_administrativeact",
- ugettext(u"Can delete own Administrative act")),
+ u"Can delete own Administrative act"),
)
def __unicode__(self):
@@ -1228,6 +1257,8 @@ def strip_zero(value):
class Parcel(LightHistorizedItem):
+ EXTERNAL_ID_KEY = 'parcel_external_id'
+
associated_file = models.ForeignKey(
'archaeological_files.File',
related_name='parcels', verbose_name=_(u"File"),
@@ -1408,13 +1439,6 @@ def parcel_post_save(sender, **kwargs):
parcel.delete()
return
- if not parcel.external_id or parcel.auto_external_id:
- external_id = get_external_id('parcel_external_id', parcel)
- if external_id != parcel.external_id:
- updated = True
- parcel._updated_id = True
- parcel.auto_external_id = True
- parcel.external_id = external_id
if updated:
parcel.save()
return
@@ -1429,12 +1453,22 @@ def parcel_post_save(sender, **kwargs):
parcel_id=parcel.id)
if parcel.operation and parcel.operation.pk and \
- parcel.town not in list(parcel.operation.towns.all()):
- parcel.operation.towns.add(parcel.town)
+ parcel.town not in list(parcel.operation.towns.all()):
+ try:
+ # multiple save can cause multiple add
+ with transaction.atomic():
+ parcel.operation.towns.add(parcel.town)
+ except IntegrityError:
+ pass
if parcel.associated_file and \
- parcel.associated_file.pk and \
- parcel.town not in list(parcel.associated_file.towns.all()):
- parcel.associated_file.towns.add(parcel.town)
+ parcel.associated_file.pk and \
+ parcel.town not in list(parcel.associated_file.towns.all()):
+ try:
+ # multiple save can cause multiple add
+ with transaction.atomic():
+ parcel.associated_file.towns.add(parcel.town)
+ except IntegrityError:
+ pass
if parcel.operation and parcel.associated_file:
# parcels are copied between files and operations
parcel.copy_to_operation()
@@ -1455,7 +1489,15 @@ class ParcelOwner(LightHistorizedItem):
verbose_name_plural = _(u"Parcel owners")
def __unicode__(self):
- return self.owner + settings.JOINT + self.parcel
+ return "{}{}{}".format(self.owner, settings.JOINT, self.parcel)
+
+ @property
+ def operation(self):
+ return self.parcel.operation
+
+ @property
+ def associated_file(self):
+ return self.parcel.associated_file
class OperationDashboard: