summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2020-04-08 18:06:26 +0200
committerÉtienne Loks <etienne.loks@iggdrasil.net>2021-02-28 12:15:20 +0100
commit721cf51b30ed646f2073bc56aaf62ff1878aef94 (patch)
tree47c2df9adb1820c3993f1e50743dafcf86262e15
parent5c0a4d451ec653d76ae26c444da8c000460c9db6 (diff)
downloadIshtar-721cf51b30ed646f2073bc56aaf62ff1878aef94.tar.bz2
Ishtar-721cf51b30ed646f2073bc56aaf62ff1878aef94.zip
New container management - merge action
-rw-r--r--archaeological_warehouse/forms.py170
-rw-r--r--archaeological_warehouse/ishtar_menu.py8
-rw-r--r--archaeological_warehouse/migrations/0107_auto_20200407_1553.py35
-rw-r--r--archaeological_warehouse/models.py104
-rw-r--r--archaeological_warehouse/templates/ishtar/merge_container.html23
-rw-r--r--archaeological_warehouse/tests.py61
-rw-r--r--archaeological_warehouse/urls.py9
-rw-r--r--archaeological_warehouse/views.py97
-rw-r--r--ishtar_common/forms_common.py355
-rw-r--r--ishtar_common/models.py4
-rw-r--r--ishtar_common/views.py7
11 files changed, 532 insertions, 341 deletions
diff --git a/archaeological_warehouse/forms.py b/archaeological_warehouse/forms.py
index a7390a890..83289819e 100644
--- a/archaeological_warehouse/forms.py
+++ b/archaeological_warehouse/forms.py
@@ -44,12 +44,13 @@ from ishtar_common.forms import name_validator, reverse_lazy, \
get_form_selection, ManageOldType, FinalForm, FormSet, \
CustomForm, FieldType, DocumentItemSelect, FormHeader, TableSelect, \
CustomFormSearch, MultiSearchForm, LockForm
-from ishtar_common.forms_common import get_town_field
+from ishtar_common.forms_common import get_town_field, MergeForm, ManualMerge,\
+ MergeIntoForm
from archaeological_finds.forms import FindMultipleFormSelection, \
SelectFindBasketForm
-def get_warehouse_field(label=_(u"Warehouse"), required=True):
+def get_warehouse_field(label=_("Warehouse"), required=True):
# !FIXME hard_link, reverse_lazy doen't seem to work with formsets
url = "/" + settings.URL_PATH + 'autocomplete-warehouse'
widget = widgets.JQueryAutoComplete(url, associated_model=models.Warehouse)
@@ -58,14 +59,14 @@ def get_warehouse_field(label=_(u"Warehouse"), required=True):
class SelectedDivisionForm(ManageOldType, forms.Form):
- form_label = _(u"Division")
+ form_label = _("Division")
base_model = 'associated_division'
associated_models = {'division': models.WarehouseDivision,
'associated_division': models.WarehouseDivisionLink}
division = forms.ChoiceField(
- label=_(u"Division"), choices=(),
+ label=_("Division"), choices=(),
validators=[valid_id(models.WarehouseDivision)])
- order = forms.IntegerField(label=_(u"Order"), min_value=0, required=False)
+ order = forms.IntegerField(label=_("Order"), min_value=0, required=False)
def __init__(self, *args, **kwargs):
super(SelectedDivisionForm, self).__init__(*args, **kwargs)
@@ -79,24 +80,24 @@ class DivisionFormSet(FormSet):
def clean(self):
"""Checks that no divisions are duplicated."""
self.check_duplicate(('division',), _("There are identical divisions."))
- self.check_duplicate(('order',), _(u"Order fields must be different."),
+ self.check_duplicate(('order',), _("Order fields must be different."),
check_null=True)
SelectedDivisionFormset = formset_factory(
SelectedDivisionForm, can_delete=True, formset=DivisionFormSet)
-SelectedDivisionFormset.form_label = _(u"Divisions")
-SelectedDivisionFormset.form_admin_name = _(u"Warehouse - 020 - Divisions")
+SelectedDivisionFormset.form_label = _("Divisions")
+SelectedDivisionFormset.form_admin_name = _("Warehouse - 020 - Divisions")
SelectedDivisionFormset.form_slug = "warehouse-020-divisions"
class WarehouseSelect(CustomForm, TableSelect):
_model = models.Warehouse
- form_admin_name = _(u"Warehouse - 001 - Search")
+ form_admin_name = _("Warehouse - 001 - Search")
form_slug = "warehouse-001-search"
search_vector = forms.CharField(
- label=_(u"Full text search"), widget=widgets.SearchWidget(
+ label=_("Full text search"), widget=widgets.SearchWidget(
'archaeological-warehouse', 'warehouse'
))
name = forms.CharField(label=_("Name"))
@@ -139,8 +140,8 @@ class WarehouseFormMultiSelection(LockForm, MultiSearchForm):
class WarehouseForm(CustomForm, ManageOldType, forms.Form):
HEADERS = {}
- form_label = _(u"Warehouse")
- form_admin_name = _(u"Warehouse - 010 - General")
+ form_label = _("Warehouse")
+ form_admin_name = _("Warehouse - 010 - General")
form_slug = "warehouse-010-general"
extra_form_modals = ["organization", "person"]
associated_models = {
@@ -151,9 +152,9 @@ class WarehouseForm(CustomForm, ManageOldType, forms.Form):
'spatial_reference_system': SpatialReferenceSystem
}
- name = forms.CharField(label=_(u"Name"), max_length=200,
+ name = forms.CharField(label=_("Name"), max_length=200,
validators=[name_validator])
- warehouse_type = forms.ChoiceField(label=_(u"Warehouse type"),
+ warehouse_type = forms.ChoiceField(label=_("Warehouse type"),
choices=[])
organization = forms.IntegerField(
label=_("Organization"),
@@ -173,28 +174,28 @@ class WarehouseForm(CustomForm, ManageOldType, forms.Form):
label=_("Create a new organization from this warehouse"),
required=False
)
- comment = forms.CharField(label=_(u"Comment"), widget=forms.Textarea,
+ comment = forms.CharField(label=_("Comment"), widget=forms.Textarea,
required=False)
HEADERS['address'] = FormHeader(
- _(u"Address"), collapse=True,
+ _("Address"), collapse=True,
help_message=_(
"Only fill the following fields if no organization is provided or "
"if the address of the warehouse is different from the one of the "
"organization. If a new organization is created from this "
"warehouse, the following fields are used for the organization."))
- address = forms.CharField(label=_(u"Address"), widget=forms.Textarea,
+ address = forms.CharField(label=_("Address"), widget=forms.Textarea,
required=False)
- address_complement = forms.CharField(label=_(u"Address complement"),
+ address_complement = forms.CharField(label=_("Address complement"),
widget=forms.Textarea, required=False)
- postal_code = forms.CharField(label=_(u"Postal code"), max_length=10,
+ postal_code = forms.CharField(label=_("Postal code"), max_length=10,
required=False)
- town = forms.CharField(label=_(u"Town (freeform)"), max_length=150,
+ town = forms.CharField(label=_("Town (freeform)"), max_length=150,
required=False)
precise_town = get_town_field(required=False)
- country = forms.CharField(label=_(u"Country"), max_length=30,
+ country = forms.CharField(label=_("Country"), max_length=30,
required=False)
- phone = forms.CharField(label=_(u"Phone"), max_length=18, required=False)
- mobile_phone = forms.CharField(label=_(u"Mobile phone"), max_length=18,
+ phone = forms.CharField(label=_("Phone"), max_length=18, required=False)
+ mobile_phone = forms.CharField(label=_("Mobile phone"), max_length=18,
required=False)
HEADERS['x'] = FormHeader(_("Coordinates"))
x = forms.FloatField(label=_("X"), required=False)
@@ -250,13 +251,13 @@ class WarehouseModifyForm(WarehouseForm):
class WarehouseDeletionForm(FinalForm):
- confirm_msg = _(u"Would you like to delete this warehouse?")
- confirm_end_msg = _(u"Would you like to delete this warehouse?")
+ confirm_msg = _("Would you like to delete this warehouse?")
+ confirm_end_msg = _("Would you like to delete this warehouse?")
class ContainerForm(CustomForm, ManageOldType, forms.Form):
- form_label = _(u"Container")
- form_admin_name = _(u"Container - 010 - General")
+ form_label = _("Container")
+ form_admin_name = _("Container - 010 - General")
form_slug = "container-010-general"
file_upload = True
extra_form_modals = ["warehouse", "organization", "person", "container"]
@@ -264,10 +265,10 @@ class ContainerForm(CustomForm, ManageOldType, forms.Form):
'location': models.Warehouse,
'parent': models.Container,
'responsible': models.Warehouse}
- reference = forms.CharField(label=_(u"Ref."), max_length=200)
- old_reference = forms.CharField(label=_(u"Old reference"), required=False,
+ reference = forms.CharField(label=_("Ref."), max_length=200)
+ old_reference = forms.CharField(label=_("Old reference"), required=False,
max_length=200)
- container_type = forms.ChoiceField(label=_(u"Container type"), choices=[])
+ container_type = forms.ChoiceField(label=_("Container type"), choices=[])
parent = forms.IntegerField(
label=_("Parent container"),
widget=widgets.JQueryAutoComplete(
@@ -277,18 +278,18 @@ class ContainerForm(CustomForm, ManageOldType, forms.Form):
required=False
)
responsible = forms.IntegerField(
- label=_(u"Responsible warehouse"),
+ label=_("Responsible warehouse"),
widget=widgets.JQueryAutoComplete(
reverse_lazy('autocomplete-warehouse'),
associated_model=models.Warehouse, new=True),
validators=[valid_id(models.Warehouse)])
location = forms.IntegerField(
- label=_(u"Current location (warehouse)"),
+ label=_("Current location (warehouse)"),
widget=widgets.JQueryAutoComplete(
reverse_lazy('autocomplete-warehouse'),
associated_model=models.Warehouse, new=True),
validators=[valid_id(models.Warehouse)])
- comment = forms.CharField(label=_(u"Comment"),
+ comment = forms.CharField(label=_("Comment"),
widget=forms.Textarea, required=False)
TYPES = [
FieldType('container_type', models.ContainerType),
@@ -306,12 +307,15 @@ class ContainerForm(CustomForm, ManageOldType, forms.Form):
cleaned_data = self.cleaned_data
warehouse = cleaned_data.get("location")
q = models.Container.objects.filter(
- reference=cleaned_data.get("reference"), location__pk=warehouse)
+ reference=cleaned_data.get("reference"), location__pk=warehouse,
+ container_type_id=cleaned_data.get("container_type"),
+ parent_id=cleaned_data.get("parent")
+ )
if 'pk' in cleaned_data and cleaned_data['pk']:
q = q.exclude(pk=int(cleaned_data['pk']))
if q.count():
- raise forms.ValidationError(_(u"This reference already exists for "
- u"this warehouse."))
+ raise forms.ValidationError(_("This reference already exists for "
+ "this warehouse."))
return cleaned_data
def save(self, user):
@@ -328,7 +332,7 @@ class ContainerForm(CustomForm, ManageOldType, forms.Form):
class ContainerModifyForm(ContainerForm):
pk = forms.IntegerField(required=False, widget=forms.HiddenInput)
- index = forms.IntegerField(label=_(u"ID"), required=False)
+ index = forms.IntegerField(label=_("ID"), required=False)
def __init__(self, *args, **kwargs):
super(ContainerModifyForm, self).__init__(*args, **kwargs)
@@ -358,25 +362,25 @@ class ContainerModifyForm(ContainerForm):
if 'pk' in cleaned_data and cleaned_data['pk']:
q = q.exclude(pk=int(cleaned_data['pk']))
if q.count():
- raise forms.ValidationError(_(u"This ID already exists for "
- u"this warehouse."))
+ raise forms.ValidationError(_("This ID already exists for "
+ "this warehouse."))
return cleaned_data
class ContainerSelect(DocumentItemSelect):
_model = models.Container
- form_admin_name = _(u"Container - 001 - Search")
+ form_admin_name = _("Container - 001 - Search")
form_slug = "container-001-search"
search_vector = forms.CharField(
- label=_(u"Full text search"), widget=widgets.SearchWidget(
+ label=_("Full text search"), widget=widgets.SearchWidget(
'archaeological-warehouse', 'container'
))
location_name = get_warehouse_field(label=_("Warehouse"))
container_type = forms.ChoiceField(label=_("Container type"), choices=[])
reference = forms.CharField(label=_("Ref."))
old_reference = forms.CharField(label=_("Old reference"))
- comment = forms.CharField(label=_(u"Comment"))
+ comment = forms.CharField(label=_("Comment"))
contain_containers = forms.NullBooleanField(label=_("Contain containers"))
empty = forms.NullBooleanField(label=_("Currently empty"))
is_stationary = forms.NullBooleanField(label=_("Is stationary"))
@@ -388,7 +392,7 @@ class ContainerSelect(DocumentItemSelect):
associated_model=ArchaeologicalSite),
validators=[valid_id(ArchaeologicalSite)])
archaeological_sites_name = forms.CharField(
- label=_(u"Archaeological site name (attached to the operation)")
+ label=_("Archaeological site name (attached to the operation)")
)
archaeological_sites_context_record = forms.IntegerField(
label=_("Archaeological site (attached to the context record)"),
@@ -397,7 +401,7 @@ class ContainerSelect(DocumentItemSelect):
associated_model=ArchaeologicalSite),
validators=[valid_id(ArchaeologicalSite)])
archaeological_sites_context_record_name = forms.CharField(
- label=_(u"Archaeological site name (attached to the context record)")
+ label=_("Archaeological site name (attached to the context record)")
)
code_patriarche = forms.IntegerField(label=_("Operation - Code PATRIARCHE"),
widget=OAWidget)
@@ -415,33 +419,33 @@ class ContainerSelect(DocumentItemSelect):
validators=[valid_id(ContextRecord)])
find_label = forms.CharField(label=_("Find - Label"))
find_denomination = forms.CharField(label=_("Find - Denomination"))
- description = forms.CharField(label=_(u"Find - Description"))
+ description = forms.CharField(label=_("Find - Description"))
material_types = forms.IntegerField(
- label=_(u"Material type"),
+ label=_("Material type"),
widget=widgets.JQueryAutoComplete(
reverse_lazy('autocomplete-materialtype'),
associated_model=MaterialType),
)
object_types = forms.IntegerField(
- label=_(u"Object type"),
+ label=_("Object type"),
widget=widgets.JQueryAutoComplete(
reverse_lazy('autocomplete-objecttype'),
associated_model=ObjectType),
)
- integrities = forms.ChoiceField(label=_(u"Integrity / interest"),
+ integrities = forms.ChoiceField(label=_("Integrity / interest"),
choices=[])
- remarkabilities = forms.ChoiceField(label=_(u"Remarkability"),
+ remarkabilities = forms.ChoiceField(label=_("Remarkability"),
choices=[])
- conservatory_state = forms.ChoiceField(label=_(u"Conservatory state"),
+ conservatory_state = forms.ChoiceField(label=_("Conservatory state"),
choices=[])
alterations = forms.ChoiceField(
- label=_(u"Alteration"), choices=[])
+ label=_("Alteration"), choices=[])
alteration_causes = forms.ChoiceField(
- label=_(u"Alteration cause"), choices=[])
+ label=_("Alteration cause"), choices=[])
preservation_to_considers = forms.ChoiceField(
- choices=[], label=_(u"Preservation type"))
+ choices=[], label=_("Preservation type"))
treatment_emergency = forms.ChoiceField(
- choices=[], label=_(u"Treatment emergency")
+ choices=[], label=_("Treatment emergency")
)
TYPES = [
@@ -463,56 +467,82 @@ class ContainerSelect(DocumentItemSelect):
ContainerFormSelection = get_form_selection(
- 'ContainerFormSelection', _(u"Container search"), 'container',
+ 'ContainerFormSelection', _("Container search"), 'container',
models.Container, ContainerSelect, 'get-container',
- _(u"You should select a container."), new=True,
- new_message=_(u"Add a new container"),
+ _("You should select a container."), new=True,
+ new_message=_("Add a new container"),
base_form_select=(LockForm, CustomFormSearch)
)
MainContainerFormSelection = get_form_selection(
- 'ContainerFormSelection', _(u"Container search"), 'pk',
+ 'ContainerFormSelection', _("Container search"), 'pk',
models.Container, ContainerSelect, 'get-container',
- _(u"You should select a container."), gallery=True, map=True,
+ _("You should select a container."), gallery=True, map=True,
base_form_select=CustomFormSearch
)
MainContainerFormMultiSelection = get_form_selection(
- 'ContainerFormSelection', _(u"Container search"), 'pks',
+ 'ContainerFormSelection', _("Container search"), 'pks',
models.Container, ContainerSelect, 'get-container',
- _(u"You should select a container."), gallery=True, map=True,
+ _("You should select a container."), gallery=True, map=True,
alt_pk_field="pk",
multi=True, base_form_select=(LockForm, MultiSearchForm)
)
+class MergeContainerForm(MergeForm):
+ class Meta:
+ model = models.Container
+ fields = []
+
+ FROM_KEY = 'from_container'
+ TO_KEY = 'to_container'
+
+
+class ContainerMergeFormSelection(ManualMerge, forms.Form):
+ SEARCH_AND_SELECT = True
+ form_label = _("Container to merge")
+ associated_models = {'to_merge': models.Container}
+ currents = {'to_merge': models.Container}
+ to_merge = forms.CharField(
+ label="", required=False,
+ widget=widgets.DataTable(
+ reverse_lazy('get-container'), ContainerSelect,
+ models.Container,
+ multiple_select=True,),)
+
+
+class ContainerMergeIntoForm(MergeIntoForm):
+ associated_model = models.Container
+
+
class BasePackagingForm(SelectFindBasketForm):
- form_label = _(u"Packaging")
+ form_label = _("Packaging")
associated_models = {'treatment_type': TreatmentType,
'person': Person,
'location': models.Warehouse,
'basket': FindBasket}
person = forms.IntegerField(
- label=_(u"Packager"),
+ label=_("Packager"),
widget=widgets.JQueryAutoComplete(
reverse_lazy('autocomplete-person'),
associated_model=Person, new=True),
validators=[valid_id(Person)])
start_date = forms.DateField(
- label=_(u"Date"), required=False, widget=DatePicker,
+ label=_("Date"), required=False, widget=DatePicker,
initial=datetime.date.today
)
class FindPackagingFormSelection(FindMultipleFormSelection):
- form_label = _(u"Packaged finds")
+ form_label = _("Packaged finds")
class LocalisationForm(CustomForm, forms.Form):
- form_admin_name = _(u"Container - 020 - Localisation")
+ form_admin_name = _("Container - 020 - Localisation")
form_slug = "container-020-localisation"
- form_label = _(u"Localisation")
+ form_label = _("Localisation")
def __init__(self, *args, **kwargs):
self.container, self.warehouse = None, None
@@ -524,7 +554,7 @@ class LocalisationForm(CustomForm, forms.Form):
if not self.warehouse:
return
for divlink in self.warehouse.divisions.order_by('order').all():
- initial = u"-"
+ initial = "-"
if self.container:
q = models.ContainerLocalisation.objects.filter(
division__division=divlink.division,
@@ -537,5 +567,5 @@ class LocalisationForm(CustomForm, forms.Form):
class ContainerDeletionForm(FinalForm):
- confirm_msg = _(u"Would you like to delete this container?")
- confirm_end_msg = _(u"Would you like to delete this container?")
+ confirm_msg = _("Would you like to delete this container?")
+ confirm_end_msg = _("Would you like to delete this container?")
diff --git a/archaeological_warehouse/ishtar_menu.py b/archaeological_warehouse/ishtar_menu.py
index b7c820d13..17acae47a 100644
--- a/archaeological_warehouse/ishtar_menu.py
+++ b/archaeological_warehouse/ishtar_menu.py
@@ -58,6 +58,14 @@ MENU_SECTIONS = [
model=models.Warehouse,
access_controls=['change_container',
'change_own_container']),
+ MenuItem(
+ 'container-merge', _(u"Automatic merge"),
+ model=models.Container,
+ access_controls=['administrator']),
+ MenuItem(
+ 'container-manual-merge', _(u"Manual merge"),
+ model=models.Container,
+ access_controls=['administrator']),
MenuItem('container_deletion', _(u"Deletion"),
model=models.Warehouse,
access_controls=['change_container',
diff --git a/archaeological_warehouse/migrations/0107_auto_20200407_1553.py b/archaeological_warehouse/migrations/0107_auto_20200407_1553.py
new file mode 100644
index 000000000..56aeddd47
--- /dev/null
+++ b/archaeological_warehouse/migrations/0107_auto_20200407_1553.py
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.27 on 2020-04-07 15:53
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('archaeological_warehouse', '0106_auto_20200407_1414'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='container',
+ name='archived',
+ field=models.NullBooleanField(default=False),
+ ),
+ migrations.AddField(
+ model_name='container',
+ name='merge_candidate',
+ field=models.ManyToManyField(blank=True, related_name='_container_merge_candidate_+', to='archaeological_warehouse.Container'),
+ ),
+ migrations.AddField(
+ model_name='container',
+ name='merge_exclusion',
+ field=models.ManyToManyField(blank=True, related_name='_container_merge_exclusion_+', to='archaeological_warehouse.Container'),
+ ),
+ migrations.AddField(
+ model_name='container',
+ name='merge_key',
+ field=models.TextField(blank=True, null=True, verbose_name='Merge key'),
+ ),
+ ]
diff --git a/archaeological_warehouse/models.py b/archaeological_warehouse/models.py
index e62575ccf..53e50976d 100644
--- a/archaeological_warehouse/models.py
+++ b/archaeological_warehouse/models.py
@@ -35,7 +35,8 @@ from ishtar_common.models import Document, GeneralType, get_external_id, \
LightHistorizedItem, OwnPerms, Address, Person, post_save_cache, \
DashboardFormItem, ShortMenuItem, Organization, OrganizationType, \
document_attached_changed, SearchAltName, DynamicRequest, GeoItem, \
- QRCodeItem, SearchVectorConfig, DocumentItem, QuickAction, MainItem
+ QRCodeItem, SearchVectorConfig, DocumentItem, QuickAction, MainItem, \
+ Merge
from ishtar_common.model_merging import merge_model_objects
from ishtar_common.utils import cached_label_changed, \
cached_label_and_geo_changed
@@ -43,8 +44,8 @@ from ishtar_common.utils import cached_label_changed, \
class WarehouseType(GeneralType):
class Meta:
- verbose_name = _(u"Warehouse type")
- verbose_name_plural = _(u"Warehouse types")
+ verbose_name = _("Warehouse type")
+ verbose_name_plural = _("Warehouse types")
ordering = ('label',)
@@ -97,7 +98,7 @@ class Warehouse(Address, DocumentItem, GeoItem, QRCodeItem, DashboardFormItem,
QA_LOCK = QuickAction(
url="warehouse-qa-lock", icon_class="fa fa-lock",
- text=_(u"Lock/Unlock"), target="many",
+ text=_("Lock/Unlock"), target="many",
rights=['change_warehouse', 'change_own_warehouse']
)
QUICK_ACTIONS = [QA_LOCK]
@@ -105,41 +106,41 @@ class Warehouse(Address, DocumentItem, GeoItem, QRCodeItem, DashboardFormItem,
objects = UUIDModelManager()
uuid = models.UUIDField(default=uuid.uuid4)
- name = models.CharField(_(u"Name"), max_length=200)
+ name = models.CharField(_("Name"), max_length=200)
warehouse_type = models.ForeignKey(WarehouseType,
- verbose_name=_(u"Warehouse type"))
+ verbose_name=_("Warehouse type"))
person_in_charge = models.ForeignKey(
Person, on_delete=models.SET_NULL, related_name='warehouse_in_charge',
- verbose_name=_(u"Person in charge"), null=True, blank=True)
+ verbose_name=_("Person in charge"), null=True, blank=True)
organization = models.ForeignKey(
Organization, blank=True, null=True, related_name='warehouses',
verbose_name=_("Organization"), on_delete=models.SET_NULL)
- comment = models.TextField(_(u"Comment"), null=True, blank=True)
+ comment = models.TextField(_("Comment"), null=True, blank=True)
associated_divisions = models.ManyToManyField(
'WarehouseDivision', verbose_name=_("Divisions"), blank=True,
through='WarehouseDivisionLink'
)
documents = models.ManyToManyField(
- Document, related_name='warehouses', verbose_name=_(u"Documents"),
+ Document, related_name='warehouses', verbose_name=_("Documents"),
blank=True)
main_image = models.ForeignKey(
Document, related_name='main_image_warehouses',
on_delete=models.SET_NULL,
- verbose_name=_(u"Main image"), blank=True, null=True)
- external_id = models.TextField(_(u"External ID"), blank=True, null=True)
+ verbose_name=_("Main image"), blank=True, null=True)
+ external_id = models.TextField(_("External ID"), blank=True, null=True)
auto_external_id = models.BooleanField(
- _(u"External ID is set automatically"), default=False)
+ _("External ID is set automatically"), default=False)
SUB_ADDRESSES = ["organization", "person_in_charge"]
class Meta:
- verbose_name = _(u"Warehouse")
- verbose_name_plural = _(u"Warehouses")
+ verbose_name = _("Warehouse")
+ verbose_name_plural = _("Warehouses")
permissions = (
- ("view_warehouse", u"Can view all Warehouses"),
- ("view_own_warehouse", u"Can view own Warehouse"),
- ("add_own_warehouse", u"Can add own Warehouse"),
- ("change_own_warehouse", u"Can change own Warehouse"),
- ("delete_own_warehouse", u"Can delete own Warehouse"),
+ ("view_warehouse", "Can view all Warehouses"),
+ ("view_own_warehouse", "Can view own Warehouse"),
+ ("add_own_warehouse", "Can add own Warehouse"),
+ ("change_own_warehouse", "Can change own Warehouse"),
+ ("delete_own_warehouse", "Can delete own Warehouse"),
)
indexes = [
GinIndex(fields=['data']),
@@ -152,7 +153,7 @@ class Warehouse(Address, DocumentItem, GeoItem, QRCodeItem, DashboardFormItem,
return (self.uuid, )
def _get_base_image_path(self):
- return u"{}/{}".format(self.SLUG, self.external_id)
+ return "{}/{}".format(self.SLUG, self.external_id)
def create_attached_organization(self):
"""
@@ -360,8 +361,8 @@ post_save.connect(cached_label_and_geo_changed, sender=Warehouse)
class WarehouseDivision(GeneralType):
class Meta:
- verbose_name = _(u"Warehouse division type")
- verbose_name_plural = _(u"Warehouse division types")
+ verbose_name = _("Warehouse division type")
+ verbose_name_plural = _("Warehouse division types")
post_save.connect(post_save_cache, sender=WarehouseDivision)
@@ -379,16 +380,16 @@ class ContainerType(GeneralType):
_("Stationary"), default=False,
help_text=_("Container that usually will not be moved. Ex: building, "
"room."))
- length = models.IntegerField(_(u"Length (mm)"), blank=True, null=True)
- width = models.IntegerField(_(u"Width (mm)"), blank=True, null=True)
- height = models.IntegerField(_(u"Height (mm)"), blank=True, null=True)
- volume = models.FloatField(_(u"Volume (l)"), blank=True, null=True)
- reference = models.CharField(_(u"Ref."), max_length=300, blank=True,
+ length = models.IntegerField(_("Length (mm)"), blank=True, null=True)
+ width = models.IntegerField(_("Width (mm)"), blank=True, null=True)
+ height = models.IntegerField(_("Height (mm)"), blank=True, null=True)
+ volume = models.FloatField(_("Volume (l)"), blank=True, null=True)
+ reference = models.CharField(_("Ref."), max_length=300, blank=True,
null=True)
class Meta:
- verbose_name = _(u"Container type")
- verbose_name_plural = _(u"Container types")
+ verbose_name = _("Container type")
+ verbose_name_plural = _("Container types")
ordering = ('label',)
@@ -413,7 +414,7 @@ class WarehouseDivisionLink(models.Model):
unique_together = ('warehouse', 'division')
def __str__(self):
- return u"{} - {}".format(self.warehouse, self.division)
+ return "{} - {}".format(self.warehouse, self.division)
def natural_key(self):
return self.warehouse.uuid, self.division.txt_idx
@@ -458,7 +459,7 @@ class ContainerTree:
"""
-class Container(DocumentItem, LightHistorizedItem, QRCodeItem, GeoItem,
+class Container(DocumentItem, Merge, LightHistorizedItem, QRCodeItem, GeoItem,
OwnPerms, MainItem):
SLUG = 'container'
APP = "archaeological-warehouse"
@@ -659,7 +660,7 @@ class Container(DocumentItem, LightHistorizedItem, QRCodeItem, GeoItem,
QA_LOCK = QuickAction(
url="container-qa-lock", icon_class="fa fa-lock",
- text=_(u"Lock/Unlock"), target="many",
+ text=_("Lock/Unlock"), target="many",
rights=['change_container', 'change_own_container']
)
QUICK_ACTIONS = [QA_LOCK]
@@ -678,13 +679,13 @@ class Container(DocumentItem, LightHistorizedItem, QRCodeItem, GeoItem,
)
container_type = models.ForeignKey(ContainerType,
verbose_name=_("Container type"))
- reference = models.TextField(_(u"Container ref."))
- comment = models.TextField(_(u"Comment"), null=True, blank=True)
- cached_label = models.TextField(_(u"Localisation"), null=True, blank=True,
+ reference = models.TextField(_("Container ref."))
+ comment = models.TextField(_("Comment"), null=True, blank=True)
+ cached_label = models.TextField(_("Localisation"), null=True, blank=True,
db_index=True)
- cached_location = models.TextField(_(u"Cached location"),
+ cached_location = models.TextField(_("Cached location"),
null=True, blank=True, db_index=True)
- cached_division = models.TextField(_(u"Cached division"),
+ cached_division = models.TextField(_("Cached division"),
null=True, blank=True, db_index=True)
parent = models.ForeignKey("Container", verbose_name=_("Parent container"),
on_delete=models.SET_NULL,
@@ -712,11 +713,11 @@ class Container(DocumentItem, LightHistorizedItem, QRCodeItem, GeoItem,
('location', 'container_type', 'parent',
'reference')]
permissions = (
- ("view_container", u"Can view all Containers"),
- ("view_own_container", u"Can view own Container"),
- ("add_own_container", u"Can add own Container"),
- ("change_own_container", u"Can change own Container"),
- ("delete_own_container", u"Can delete own Container"),
+ ("view_container", "Can view all Containers"),
+ ("view_own_container", "Can view own Container"),
+ ("add_own_container", "Can add own Container"),
+ ("change_own_container", "Can change own Container"),
+ ("delete_own_container", "Can delete own Container"),
)
indexes = [
GinIndex(fields=['data']),
@@ -726,6 +727,10 @@ class Container(DocumentItem, LightHistorizedItem, QRCodeItem, GeoItem,
return self.cached_label or ""
@property
+ def name(self):
+ return "{} - {}".format(self.container_type.name, self.reference)
+
+ @property
def short_label(self):
return "{} {}".format(self.container_type.label, self.reference)
@@ -767,6 +772,7 @@ class Container(DocumentItem, LightHistorizedItem, QRCodeItem, GeoItem,
return self.location._get_base_image_path() + "/" + self.external_id
def merge(self, item, keep_old=False):
+ # TODO: change localisation management
locas = [
cl.division.division.txt_idx
for cl in ContainerLocalisation.objects.filter(container=self).all()
@@ -1050,7 +1056,7 @@ class Container(DocumentItem, LightHistorizedItem, QRCodeItem, GeoItem,
if can_edit_find:
actions += [
(reverse('container-add-treatment', args=[self.pk]),
- _(u"Add treatment"), "fa fa-flask", "", "", False),
+ _("Add treatment"), "fa fa-flask", "", "", False),
]
return actions
@@ -1137,21 +1143,21 @@ class ContainerLocalisationManager(models.Manager):
class ContainerLocalisation(models.Model):
- container = models.ForeignKey(Container, verbose_name=_(u"Container"),
+ container = models.ForeignKey(Container, verbose_name=_("Container"),
related_name='division')
division = models.ForeignKey(WarehouseDivisionLink,
- verbose_name=_(u"Division"))
- reference = models.CharField(_(u"Reference"), max_length=200, default='')
+ verbose_name=_("Division"))
+ reference = models.CharField(_("Reference"), max_length=200, default='')
objects = ContainerLocalisationManager()
class Meta:
- verbose_name = _(u"Container localisation")
- verbose_name_plural = _(u"Container localisations")
+ verbose_name = _("Container localisation")
+ verbose_name_plural = _("Container localisations")
unique_together = ('container', 'division')
ordering = ('container', 'division__order')
def __str__(self):
- lbl = u" - ".join((str(self.container),
+ lbl = " - ".join((str(self.container),
str(self.division), self.reference))
return lbl
diff --git a/archaeological_warehouse/templates/ishtar/merge_container.html b/archaeological_warehouse/templates/ishtar/merge_container.html
new file mode 100644
index 000000000..558828586
--- /dev/null
+++ b/archaeological_warehouse/templates/ishtar/merge_container.html
@@ -0,0 +1,23 @@
+{% extends "ishtar/merge.html" %}
+{% block merge_field_row %}
+ {% if form.non_field_errors %}<tr><td colspan='4'></td><td colspan='3' class='errorlist'>{% for error in form.non_field_errors %}{{error}} {% endfor%}</tr>{% endif %}
+ <tr>
+ <td>
+ <a href="#" onclick="load_window('{% url 'show-container' form.instance.from_container.pk '' %}', 'container');" class="display_details"><i class="fa fa-info-circle" aria-hidden="true"></i></a>
+ </td>
+ <td>
+ {{form.instance.from_container}} ({{form.instance.from_container.pk}})<br/>
+ {{form.instance.from_container.address_lbl|linebreaksbr}}
+ </td>
+ <td>
+ <a href="#" onclick="load_window('{% url 'show-container' form.instance.to_container.pk '' %}', 'container');" class="display_details"><i class="fa fa-info-circle" aria-hidden="true"></i></a>
+ </td>
+ <td>
+ {{form.instance.to_container}} ({{form.instance.to_container.pk}})<br/>
+ {{form.instance.to_container.address_lbl|linebreaksbr}}
+ </td>
+ <td class='check'>{{form.b_is_duplicate_a}}</td>
+ <td class='check'>{{form.a_is_duplicate_b}}</td>
+ <td class='check'>{{form.not_duplicate}}</td>
+ </tr>
+{% endblock %}
diff --git a/archaeological_warehouse/tests.py b/archaeological_warehouse/tests.py
index a342dc1f9..37babf1b2 100644
--- a/archaeological_warehouse/tests.py
+++ b/archaeological_warehouse/tests.py
@@ -538,6 +538,10 @@ class ContainerTest(FindInit, TestCase):
label='division2')
self.div_link = models.WarehouseDivisionLink.objects.create(
warehouse=self.main_warehouse, division=self.division)
+ self.alt_warehouse = models.Warehouse.objects.create(
+ name="Alt",
+ warehouse_type=models.WarehouseType.objects.all()[0]
+ )
def test_form_creation(self):
data = {
@@ -718,3 +722,60 @@ class ContainerTest(FindInit, TestCase):
container_2.external_id, ct.txt_idx,
container_3.reference))
+ def test_merge_candidate(self):
+ ct = models.ContainerType.objects.all()[0]
+ container_1 = models.Container.objects.create(
+ reference="Test", responsible=self.main_warehouse,
+ location=self.main_warehouse,
+ container_type=ct)
+ init_mc = container_1.merge_candidate.count()
+ models.Container.objects.create(
+ reference="TEST", responsible=self.main_warehouse,
+ location=self.main_warehouse,
+ container_type=ct)
+ self.assertEqual(container_1.merge_candidate.count(),
+ init_mc + 1)
+ container_1.archive()
+ self.assertEqual(container_1.merge_candidate.count(),
+ init_mc)
+
+ def test_merge_container(self):
+ ct = models.ContainerType.objects.all()[0]
+ ct2 = models.ContainerType.objects.all()[1]
+ self.create_finds()
+ self.create_finds()
+ self.create_finds()
+ find0 = self.finds[0]
+ find1 = self.finds[1]
+ find2 = self.finds[2]
+
+ container_1 = models.Container.objects.create(
+ reference="Test 1",
+ location=self.main_warehouse,
+ container_type=ct)
+ find0.container = container_1
+ find0.container_ref = container_1
+ find0.save()
+ find1.container = container_1
+ find1.container_ref = container_1
+ find1.save()
+
+ container_2 = models.Container.objects.create(
+ reference="Test 2",
+ location=self.alt_warehouse,
+ container_type=ct2)
+ find2.container = container_2
+ find2.container_ref = container_2
+ find2.save()
+
+ container_1.merge(container_2)
+ container_1 = models.Container.objects.get(pk=container_1.pk)
+ self.assertEqual(
+ models.Container.objects.filter(pk=container_2.pk).count(), 0)
+
+ # preserve existing fields
+ self.assertEqual(container_1.reference, 'Test 1')
+ self.assertEqual(container_1.container_type, ct)
+ find_lst = [f for f in container_1.finds.all()]
+ for f in [find0, find1, find2]:
+ self.assertIn(f, find_lst)
diff --git a/archaeological_warehouse/urls.py b/archaeological_warehouse/urls.py
index 6519a5db4..5c08af2ad 100644
--- a/archaeological_warehouse/urls.py
+++ b/archaeological_warehouse/urls.py
@@ -103,4 +103,13 @@ urlpatterns = [
url(r'^container-qa-lock/(?P<pks>[0-9-]+)?/$',
views.QAContainerLockView.as_view(), name='container-qa-lock',
kwargs={"model": models.Container}),
+
+ url(r'container-merge/(?:(?P<page>\d+)/)?$', views.container_merge,
+ name='container_merge'),
+ url(r'container-manual-merge/$',
+ views.ContainerManualMerge.as_view(),
+ name='container_manual_merge'),
+ url(r'container-manual-merge-items/(?P<pks>[0-9_]+?)/$',
+ views.ContainerManualMergeItems.as_view(),
+ name='container_manual_merge_items'),
]
diff --git a/archaeological_warehouse/views.py b/archaeological_warehouse/views.py
index 29f33dc04..cb74b49f9 100644
--- a/archaeological_warehouse/views.py
+++ b/archaeological_warehouse/views.py
@@ -21,21 +21,19 @@ import json
from django.core.urlresolvers import reverse
from django.db.models import Q
+from django.views.generic.edit import FormView
from django.http import HttpResponse, Http404, HttpResponseRedirect
from django.shortcuts import redirect
from ishtar_common.utils import ugettext_lazy as _
from archaeological_warehouse import models
+from archaeological_warehouse import forms
-from archaeological_warehouse.forms import WarehouseForm, ContainerForm, \
- ContainerFormSelection, BasePackagingForm, WarehouseFormSelection, \
- WarehouseModifyForm, SelectedDivisionFormset, WarehouseDeletionForm, \
- MainContainerFormSelection, ContainerModifyForm, LocalisationForm, \
- ContainerDeletionForm, ContainerSelect, WarehouseSelect, \
- MainContainerFormMultiSelection, WarehouseFormMultiSelection
from ishtar_common.forms import FinalForm
-from ishtar_common.views import QABaseLockView, wizard_is_available
+from ishtar_common.views import QABaseLockView, wizard_is_available, \
+ merge_action, ManualMergeMixin, ManualMergeItemsMixin, IshtarMixin, \
+ LoginRequiredMixin
from ishtar_common.views_item import get_item, show_item, new_qa_item
from archaeological_finds.views import treatment_add
@@ -44,18 +42,17 @@ from archaeological_warehouse.wizards import PackagingWizard, WarehouseSearch, \
ContainerSearch, ContainerWizard, ContainerModificationWizard, \
ContainerDeletionWizard
-from ishtar_common.utils import put_session_message
get_container = get_item(models.Container, 'get_container', 'container',
- search_form=ContainerSelect)
+ search_form=forms.ContainerSelect)
show_container = show_item(models.Container, 'container')
get_warehouse = get_item(models.Warehouse, 'get_warehouse', 'warehouse',
- search_form=WarehouseSelect)
+ search_form=forms.WarehouseSelect)
show_warehouse = show_item(models.Warehouse, 'warehouse')
-new_warehouse = new_qa_item(models.Warehouse, WarehouseForm)
-new_container = new_qa_item(models.Container, ContainerForm)
+new_warehouse = new_qa_item(models.Warehouse, forms.WarehouseForm)
+new_container = new_qa_item(models.Container, forms.ContainerForm)
def autocomplete_warehouse(request):
@@ -115,36 +112,36 @@ def autocomplete_container(request):
return HttpResponse(data, content_type='text/plain')
warehouse_packaging_wizard = PackagingWizard.as_view([ # AFAC
- ('seleccontainer-packaging', ContainerFormSelection),
- ('base-packaging', BasePackagingForm),
+ ('seleccontainer-packaging', forms.ContainerFormSelection),
+ ('base-packaging', forms.BasePackagingForm),
('final-packaging', FinalForm)],
- label=_(u"Packaging"),
+ label=_("Packaging"),
url_name='warehouse_packaging',)
warehouse_search_wizard = WarehouseSearch.as_view([
- ('selec-warehouse_search', WarehouseFormSelection)],
- label=_(u"Warehouse search"),
+ ('selec-warehouse_search', forms.WarehouseFormSelection)],
+ label=_("Warehouse search"),
url_name='warehouse_search',
)
warehouse_creation_steps = [
- ("warehouse-warehouse_creation", WarehouseForm),
- ('divisions-warehouse_creation', SelectedDivisionFormset),
+ ("warehouse-warehouse_creation", forms.WarehouseForm),
+ ('divisions-warehouse_creation', forms.SelectedDivisionFormset),
('final-warehouse_creation', FinalForm)]
warehouse_creation_wizard = WarehouseWizard.as_view(
warehouse_creation_steps,
- label=_(u"Warehouse creation"),
+ label=_("Warehouse creation"),
url_name='warehouse_creation',
)
warehouse_modification_wizard = WarehouseModificationWizard.as_view([
- ('selec-warehouse_modification', WarehouseFormSelection),
- ("warehouse-warehouse_modification", WarehouseModifyForm),
- ('divisions-warehouse_modification', SelectedDivisionFormset),
+ ('selec-warehouse_modification', forms.WarehouseFormSelection),
+ ("warehouse-warehouse_modification", forms.WarehouseModifyForm),
+ ('divisions-warehouse_modification', forms.SelectedDivisionFormset),
('final-warehouse_modification', FinalForm)],
- label=_(u"Warehouse modification"),
+ label=_("Warehouse modification"),
url_name='warehouse_modification',
)
@@ -161,9 +158,9 @@ def warehouse_modify(request, pk):
warehouse_deletion_wizard = WarehouseDeletionWizard.as_view([
- ('selec-warehouse_deletion', WarehouseFormMultiSelection),
- ('final-warehouse_deletion', WarehouseDeletionForm)],
- label=_(u"Warehouse deletion"),
+ ('selec-warehouse_deletion', forms.WarehouseFormMultiSelection),
+ ('final-warehouse_deletion', forms.WarehouseDeletionForm)],
+ label=_("Warehouse deletion"),
url_name='warehouse_deletion',)
@@ -184,28 +181,28 @@ class QAWarehouseLockView(QABaseLockView):
container_search_wizard = ContainerSearch.as_view([
- ('selec-container_search', MainContainerFormSelection)],
- label=_(u"Container search"),
+ ('selec-container_search', forms.MainContainerFormSelection)],
+ label=_("Container search"),
url_name='container_search',
)
container_creation_steps = [
- ('container-container_creation', ContainerForm),
- ('localisation-container_creation', LocalisationForm),
+ ('container-container_creation', forms.ContainerForm),
+ ('localisation-container_creation', forms.LocalisationForm),
('final-container_creation', FinalForm)]
container_creation_wizard = ContainerWizard.as_view(
container_creation_steps,
- label=_(u"Container creation"),
+ label=_("Container creation"),
url_name='container_creation',
)
container_modification_wizard = ContainerModificationWizard.as_view([
- ('selec-container_modification', MainContainerFormSelection),
- ('container-container_modification', ContainerModifyForm),
- ('localisation-container_modification', LocalisationForm),
+ ('selec-container_modification', forms.MainContainerFormSelection),
+ ('container-container_modification', forms.ContainerModifyForm),
+ ('localisation-container_modification', forms.LocalisationForm),
('final-container_modification', FinalForm)],
- label=_(u"Container modification"),
+ label=_("Container modification"),
url_name='container_modification',
)
@@ -222,9 +219,9 @@ def container_modify(request, pk):
container_deletion_wizard = ContainerDeletionWizard.as_view([
- ('selec-container_deletion', MainContainerFormMultiSelection),
- ('final-container_deletion', ContainerDeletionForm)],
- label=_(u"Container deletion"),
+ ('selec-container_deletion', forms.MainContainerFormMultiSelection),
+ ('final-container_deletion', forms.ContainerDeletionForm)],
+ label=_("Container deletion"),
url_name='container_deletion',)
@@ -255,6 +252,28 @@ warehouse_packaging_wizard = ItemSourceWizard.as_view([
"""
+container_merge = merge_action(models.Container, forms.MergeContainerForm,
+ 'container', name_key="reference")
+
+
+class ContainerManualMerge(ManualMergeMixin, IshtarMixin, LoginRequiredMixin,
+ FormView):
+ form_class = forms.ContainerMergeFormSelection
+ template_name = 'ishtar/form.html'
+ page_name = _("Merge containers")
+ current_url = 'container-manual-merge'
+ redir_url = 'container_manual_merge_items'
+
+
+class ContainerManualMergeItems(ManualMergeItemsMixin, IshtarMixin,
+ LoginRequiredMixin, FormView):
+ form_class = forms.ContainerMergeIntoForm
+ template_name = 'ishtar/form.html'
+ page_name = _("Select the main container")
+ current_url = 'container-manual-merge-items'
+ item_type = 'container'
+
+
class QAContainerLockView(QABaseLockView):
model = models.Container
base_url = "container-qa-lock"
diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py
index 390672b51..df8535240 100644
--- a/ishtar_common/forms_common.py
+++ b/ishtar_common/forms_common.py
@@ -60,13 +60,13 @@ from archaeological_warehouse.models import Container
def get_town_field(label=_("Town"), required=True):
help_text = _(
- u"<p>Type name, department code of the "
- u"town you would like to select. The search is insensitive to case."
- u"</p>\n<p>Only the first twenty results are displayed but specifying "
- u"the department code is generally sufficient to get the appropriate "
- u"result.</p>\n<p class='example'>For instance type \"saint denis 93\""
- u" for getting the french town Saint-Denis in the Seine-Saint-Denis "
- u"department.</p>")
+ "<p>Type name, department code of the "
+ "town you would like to select. The search is insensitive to case."
+ "</p>\n<p>Only the first twenty results are displayed but specifying "
+ "the department code is generally sufficient to get the appropriate "
+ "result.</p>\n<p class='example'>For instance type \"saint denis 93\""
+ " for getting the french town Saint-Denis in the Seine-Saint-Denis "
+ "department.</p>")
# !FIXME hard_link, reverse_lazy doen't seem to work with formsets
return forms.IntegerField(
widget=widgets.JQueryAutoComplete(
@@ -76,7 +76,7 @@ def get_town_field(label=_("Town"), required=True):
help_text=mark_safe(help_text), required=required)
-def get_advanced_town_field(label=_(u"Town"), required=True):
+def get_advanced_town_field(label=_("Town"), required=True):
# !FIXME hard_link, reverse_lazy doen't seem to work with formsets
return forms.IntegerField(
widget=widgets.JQueryTown(
@@ -85,7 +85,7 @@ def get_advanced_town_field(label=_(u"Town"), required=True):
required=required)
-def get_person_field(label=_(u"Person"), required=True, person_types=[]):
+def get_person_field(label=_("Person"), required=True, person_types=[]):
# !FIXME hard_link, reverse_lazy doen't seem to work with formsets
widget = None
url = "/" + settings.URL_PATH + 'autocomplete-person'
@@ -93,7 +93,7 @@ def get_person_field(label=_(u"Person"), required=True, person_types=[]):
person_types = [
str(models.PersonType.objects.get(txt_idx=person_type).pk)
for person_type in person_types]
- url += u"/" + u'_'.join(person_types)
+ url += "/" + u'_'.join(person_types)
widget = widgets.JQueryAutoComplete(url, associated_model=models.Person)
return forms.IntegerField(widget=widget, label=label, required=required,
validators=[models.valid_id(models.Person)])
@@ -126,7 +126,7 @@ class NewImportForm(BSForm, forms.ModelForm):
error_css_class = 'error'
required_css_class = 'required'
imported_images_link = forms.URLField(
- label=_(u"Associated images (web link to a zip file)"),
+ label=_("Associated images (web link to a zip file)"),
required=False
)
@@ -164,13 +164,13 @@ class NewImportForm(BSForm, forms.ModelForm):
and data.get('importer_type') \
and not data.get('importer_type').unicity_keys:
raise forms.ValidationError(
- _(u"This import type have no unicity type defined. "
- u"Conservative import is not possible."))
+ _("This import type have no unicity type defined. "
+ "Conservative import is not possible."))
if data.get('imported_images_link', None) \
and data.get('imported_images', None):
raise forms.ValidationError(
- _(u"You put either a file or a download link for images "
- u"but not both."))
+ _("You put either a file or a download link for images "
+ "but not both."))
return data
def clean_imported_images_link(self):
@@ -180,7 +180,7 @@ class NewImportForm(BSForm, forms.ModelForm):
assert is_downloadable(value)
except (AssertionError, requests.exceptions.RequestException):
raise forms.ValidationError(
- _(u"Invalid link or no file is available for this link."))
+ _("Invalid link or no file is available for this link."))
return value
def save(self, user, commit=True):
@@ -209,11 +209,11 @@ class TargetKeyForm(forms.ModelForm):
'key': forms.TextInput(attrs={'readonly': 'readonly'}),
}
target = widgets.SelectReadonlyField(
- model=models.ImportTarget, label=_(u"Target"))
+ model=models.ImportTarget, label=_("Target"))
value = widgets.Select2SimpleField(
- label=_(u"Value"), required=False
+ label=_("Value"), required=False
)
- remember = forms.ChoiceField(label=_(u"Remember"), choices=[],
+ remember = forms.ChoiceField(label=_("Remember"), choices=[],
required=False)
NULL_VALUE = '<NONE>'
@@ -238,14 +238,14 @@ class TargetKeyForm(forms.ModelForm):
self.fields['value'].required = False
choices = [
- ('import', _(u"this import only")),
- ('me', _(u"me")),
+ ('import', _("this import only")),
+ ('me', _("me")),
]
if self.associated_import and self.associated_import.associated_group \
and (self.associated_import.associated_group.all_user_can_modify
or self.user.is_superuser):
choices += [
- ('group', str(_(u"the current group: {}")).format(
+ ('group', str(_("the current group: {}")).format(
self.associated_import.associated_group))]
if self.user.is_superuser:
choices += [('all', _("all users"))]
@@ -323,24 +323,24 @@ class OrganizationForm(ManageOldType, NewItemForm):
associated_models = {'organization_type': models.OrganizationType,
"precise_town": models.Town}
name = forms.CharField(
- label=_(u"Name"), max_length=300, validators=[name_validator])
- organization_type = forms.ChoiceField(label=_(u"Organization type"),
+ label=_("Name"), max_length=300, validators=[name_validator])
+ organization_type = forms.ChoiceField(label=_("Organization type"),
choices=[])
url = forms.URLField(label=_("Web address"), required=False)
- address = forms.CharField(label=_(u"Address"), widget=forms.Textarea,
+ address = forms.CharField(label=_("Address"), widget=forms.Textarea,
required=False)
- address_complement = forms.CharField(label=_(u"Address complement"),
+ address_complement = forms.CharField(label=_("Address complement"),
widget=forms.Textarea, required=False)
- postal_code = forms.CharField(label=_(u"Postal code"), max_length=10,
+ postal_code = forms.CharField(label=_("Postal code"), max_length=10,
required=False)
town = forms.CharField(label=_("Town (freeform)"), max_length=30,
required=False)
precise_town = get_town_field(required=False)
- country = forms.CharField(label=_(u"Country"), max_length=30,
+ country = forms.CharField(label=_("Country"), max_length=30,
required=False)
- email = forms.EmailField(label=_(u"Email"), required=False)
- phone = forms.CharField(label=_(u"Phone"), max_length=18, required=False)
- mobile_phone = forms.CharField(label=_(u"Mobile phone"), max_length=18,
+ email = forms.EmailField(label=_("Email"), required=False)
+ phone = forms.CharField(label=_("Phone"), max_length=18, required=False)
+ mobile_phone = forms.CharField(label=_("Mobile phone"), max_length=18,
required=False)
def __init__(self, *args, **kwargs):
@@ -377,11 +377,11 @@ class OrganizationSelect(CustomForm, TableSelect):
_model = models.Organization
search_vector = forms.CharField(
- label=_(u"Full text search"), widget=widgets.SearchWidget(
+ label=_("Full text search"), widget=widgets.SearchWidget(
'ishtar-common', 'organization'
))
- name = forms.CharField(label=_(u"Name"), max_length=300)
- organization_type = forms.ChoiceField(label=_(u"Type"), choices=[])
+ name = forms.CharField(label=_("Name"), max_length=300)
+ organization_type = forms.ChoiceField(label=_("Type"), choices=[])
def __init__(self, *args, **kwargs):
super(OrganizationSelect, self).__init__(*args, **kwargs)
@@ -391,7 +391,7 @@ class OrganizationSelect(CustomForm, TableSelect):
class OrganizationFormSelection(CustomFormSearch):
SEARCH_AND_SELECT = True
- form_label = _(u"Organization search")
+ form_label = _("Organization search")
associated_models = {'pk': models.Organization}
currents = {'pk': models.Organization}
pk = forms.IntegerField(
@@ -404,7 +404,7 @@ class OrganizationFormSelection(CustomFormSearch):
class OrganizationFormMultiSelection(MultiSearchForm):
- form_label = _(u"Organization search")
+ form_label = _("Organization search")
associated_models = {'pks': models.Organization}
pk = forms.CharField(
label="",
@@ -418,7 +418,7 @@ class OrganizationFormMultiSelection(MultiSearchForm):
class QAOrganizationFormMulti(QAForm):
- form_admin_name = _(u"Organization - Quick action - Modify")
+ form_admin_name = _("Organization - Quick action - Modify")
form_slug = "organization-quickaction-modify"
base_models = ['qa_organization_type']
associated_models = {
@@ -430,7 +430,7 @@ class QAOrganizationFormMulti(QAForm):
'qa_organization_type',
]
qa_organization_type = forms.ChoiceField(
- label=_(u"Organization type"), required=False
+ label=_("Organization type"), required=False
)
TYPES = [
@@ -450,8 +450,8 @@ class ManualMerge(object):
except ValueError:
pass
if len(values) < 2:
- raise forms.ValidationError(_(u"At least two items have to be "
- u"selected."))
+ raise forms.ValidationError(_("At least two items have to be "
+ "selected."))
self.cleaned_data['to_merge'] = values
return values
@@ -481,8 +481,8 @@ class MergeIntoForm(forms.Form):
except self.associated_model.DoesNotExist:
continue
self.fields['main_item'].choices.append(
- (item.pk, mark_safe(u"{} {}".format(simple_link_to_window(item),
- str(item)))))
+ (item.pk, mark_safe("{} {}".format(simple_link_to_window(item),
+ str(item)))))
def merge(self):
model = self.associated_model
@@ -503,7 +503,7 @@ class MergeIntoForm(forms.Form):
class OrgaMergeFormSelection(ManualMerge, forms.Form):
SEARCH_AND_SELECT = True
- form_label = _(u"Organization to merge")
+ form_label = _("Organization to merge")
associated_models = {'to_merge': models.Organization}
currents = {'to_merge': models.Organization}
to_merge = forms.CharField(
@@ -532,13 +532,13 @@ class PersonSelect(CustomForm, TableSelect):
_model = models.Person
search_vector = forms.CharField(
- label=_(u"Full text search"), widget=widgets.SearchWidget(
+ label=_("Full text search"), widget=widgets.SearchWidget(
'ishtar-common', 'person'
))
- name = forms.CharField(label=_(u"Name"), max_length=200)
- surname = forms.CharField(label=_(u"Surname"), max_length=50)
- email = forms.CharField(label=_(u"Email"), max_length=75)
- person_types = forms.ChoiceField(label=_(u"Type"), choices=[])
+ name = forms.CharField(label=_("Name"), max_length=200)
+ surname = forms.CharField(label=_("Surname"), max_length=50)
+ email = forms.CharField(label=_("Email"), max_length=75)
+ person_types = forms.ChoiceField(label=_("Type"), choices=[])
attached_to = forms.IntegerField(
label=_("Organization"),
widget=widgets.JQueryAutoComplete(
@@ -553,7 +553,7 @@ class PersonSelect(CustomForm, TableSelect):
class PersonFormSelection(CustomFormSearch):
SEARCH_AND_SELECT = True
- form_label = _(u"Person search")
+ form_label = _("Person search")
associated_models = {'pk': models.Person}
currents = {'pk': models.Person}
pk = forms.IntegerField(
@@ -565,7 +565,7 @@ class PersonFormSelection(CustomFormSearch):
class PersonFormMultiSelection(MultiSearchForm):
- form_label = _(u"Person search")
+ form_label = _("Person search")
associated_models = {'pks': models.Person}
pk = forms.CharField(
@@ -579,7 +579,7 @@ class PersonFormMultiSelection(MultiSearchForm):
class QAPersonFormMulti(QAForm):
- form_admin_name = _(u"Person - Quick action - Modify")
+ form_admin_name = _("Person - Quick action - Modify")
form_slug = "person-quickaction-modify"
base_models = ['qa_title']
associated_models = {
@@ -593,7 +593,7 @@ class QAPersonFormMulti(QAForm):
'qa_attached_to'
]
qa_title = forms.ChoiceField(
- label=_(u"Title"), required=False
+ label=_("Title"), required=False
)
qa_attached_to = forms.IntegerField(
label=_("Organization"),
@@ -643,25 +643,25 @@ class SimplePersonForm(ManageOldType, NewItemForm):
title = forms.ChoiceField(label=_("Title"), choices=[], required=False)
salutation = forms.CharField(label=_("Salutation"), max_length=200,
required=False)
- surname = forms.CharField(label=_(u"Surname"), max_length=50,
+ surname = forms.CharField(label=_("Surname"), max_length=50,
validators=[name_validator])
- name = forms.CharField(label=_(u"Name"), max_length=200,
+ name = forms.CharField(label=_("Name"), max_length=200,
validators=[name_validator])
- raw_name = forms.CharField(label=_(u"Raw name"), max_length=300,
+ raw_name = forms.CharField(label=_("Raw name"), max_length=300,
required=False)
- email = forms.EmailField(label=_(u"Email"), required=False)
- phone_desc = forms.CharField(label=_(u"Phone description"), max_length=300,
+ email = forms.EmailField(label=_("Email"), required=False)
+ phone_desc = forms.CharField(label=_("Phone description"), max_length=300,
required=False)
- phone = forms.CharField(label=_(u"Phone"), max_length=18, required=False)
- phone_desc2 = forms.CharField(label=_(u"Phone description 2"),
+ phone = forms.CharField(label=_("Phone"), max_length=18, required=False)
+ phone_desc2 = forms.CharField(label=_("Phone description 2"),
max_length=300, required=False)
- phone2 = forms.CharField(label=_(u"Phone 2"), max_length=18,
+ phone2 = forms.CharField(label=_("Phone 2"), max_length=18,
required=False)
- phone_desc3 = forms.CharField(label=_(u"Phone description 3"),
+ phone_desc3 = forms.CharField(label=_("Phone description 3"),
max_length=300, required=False)
- phone3 = forms.CharField(label=_(u"Phone 3"), max_length=18,
+ phone3 = forms.CharField(label=_("Phone 3"), max_length=18,
required=False)
- mobile_phone = forms.CharField(label=_(u"Mobile phone"), max_length=18,
+ mobile_phone = forms.CharField(label=_("Mobile phone"), max_length=18,
required=False)
attached_to = forms.IntegerField(
label=_("Current organization"),
@@ -669,27 +669,27 @@ class SimplePersonForm(ManageOldType, NewItemForm):
reverse_lazy('autocomplete-organization'),
associated_model=models.Organization, new=True),
validators=[models.valid_id(models.Organization)], required=False)
- address = forms.CharField(label=_(u"Address"), widget=forms.Textarea,
+ address = forms.CharField(label=_("Address"), widget=forms.Textarea,
required=False)
address_complement = forms.CharField(
- label=_(u"Address complement"), widget=forms.Textarea, required=False)
- postal_code = forms.CharField(label=_(u"Postal code"), max_length=10,
+ label=_("Address complement"), widget=forms.Textarea, required=False)
+ postal_code = forms.CharField(label=_("Postal code"), max_length=10,
required=False)
town = forms.CharField(label=_("Town (freeform)"), max_length=30,
required=False)
precise_town = get_town_field(required=False)
- country = forms.CharField(label=_(u"Country"), max_length=30,
+ country = forms.CharField(label=_("Country"), max_length=30,
required=False)
- alt_address = forms.CharField(label=_(u"Other address: address"),
+ alt_address = forms.CharField(label=_("Other address: address"),
widget=forms.Textarea, required=False)
alt_address_complement = forms.CharField(
- label=_(u"Other address: address complement"),
+ label=_("Other address: address complement"),
widget=forms.Textarea, required=False)
- alt_postal_code = forms.CharField(label=_(u"Other address: postal code"),
+ alt_postal_code = forms.CharField(label=_("Other address: postal code"),
max_length=10, required=False)
- alt_town = forms.CharField(label=_(u"Other address: town"), max_length=30,
+ alt_town = forms.CharField(label=_("Other address: town"), max_length=30,
required=False)
- alt_country = forms.CharField(label=_(u"Other address: country"),
+ alt_country = forms.CharField(label=_("Other address: country"),
max_length=30, required=False)
def __init__(self, *args, **kwargs):
@@ -701,12 +701,12 @@ class SimplePersonForm(ManageOldType, NewItemForm):
class PersonUserSelect(PersonSelect):
ishtaruser__isnull = forms.NullBooleanField(
- label=_(u"Already has an account"))
+ label=_("Already has an account"))
class PersonUserFormSelection(PersonFormSelection):
SEARCH_AND_SELECT = True
- form_label = _(u"Person search")
+ form_label = _("Person search")
associated_models = {'pk': models.Person}
currents = {'pk': models.Person}
pk = forms.IntegerField(
@@ -721,14 +721,14 @@ class IshtarUserSelect(TableSelect):
_model = models.IshtarUser
search_vector = forms.CharField(
- label=_(u"Full text search"), widget=widgets.SearchWidget(
+ label=_("Full text search"), widget=widgets.SearchWidget(
'ishtar-common', 'ishtaruser'
))
- username = forms.CharField(label=_(u"Username"), max_length=200)
- name = forms.CharField(label=_(u"Name"), max_length=200)
- surname = forms.CharField(label=_(u"Surname"), max_length=50)
- email = forms.CharField(label=_(u"Email"), max_length=75)
- person_types = forms.ChoiceField(label=_(u"Type"), choices=[])
+ username = forms.CharField(label=_("Username"), max_length=200)
+ name = forms.CharField(label=_("Name"), max_length=200)
+ surname = forms.CharField(label=_("Surname"), max_length=50)
+ email = forms.CharField(label=_("Email"), max_length=75)
+ person_types = forms.ChoiceField(label=_("Type"), choices=[])
attached_to = forms.IntegerField(
label=_("Organization"),
widget=widgets.JQueryAutoComplete(
@@ -743,7 +743,7 @@ class IshtarUserSelect(TableSelect):
class AccountFormSelection(forms.Form):
SEARCH_AND_SELECT = True
- form_label = _(u"Account search")
+ form_label = _("Account search")
associated_models = {'pk': models.IshtarUser}
currents = {'pk': models.IshtarUser}
pk = forms.IntegerField(
@@ -854,21 +854,21 @@ class AccountForm(IshtarForm):
form_label = _("Account")
associated_models = {'pk': models.Person}
currents = {'pk': models.Person}
- pk = forms.IntegerField(label=u"", widget=forms.HiddenInput,
+ pk = forms.IntegerField(label="", widget=forms.HiddenInput,
required=False)
- username = forms.CharField(label=_(u"Account"), max_length=30)
- email = forms.CharField(label=_(u"Email"), max_length=75,
+ username = forms.CharField(label=_("Account"), max_length=30)
+ email = forms.CharField(label=_("Email"), max_length=75,
validators=[validators.validate_email])
hidden_password = forms.CharField(
- label=_(u"New password"), max_length=128, widget=forms.PasswordInput,
+ label=_("New password"), max_length=128, widget=forms.PasswordInput,
required=False, validators=[validators.MinLengthValidator(4)])
hidden_password_confirm = forms.CharField(
- label=_(u"New password (confirmation)"), max_length=128,
+ label=_("New password (confirmation)"), max_length=128,
widget=forms.PasswordInput, required=False)
HEADERS = {
'hidden_password': FormHeader(
- _(u"New password"),
+ _("New password"),
help_message=_("Keep theses fields empty if you do not want to "
"change password. On creation, if you leave these "
"fields empty, the user will not be able to "
@@ -905,20 +905,20 @@ class AccountForm(IshtarForm):
password = cleaned_data.get("hidden_password")
if password and \
password != cleaned_data.get("hidden_password_confirm"):
- raise forms.ValidationError(_(u"Your password and confirmation "
- u"password do not match."))
+ raise forms.ValidationError(_("Your password and confirmation "
+ "password do not match."))
if not cleaned_data.get("pk"):
models.is_unique(User, 'username')(cleaned_data.get("username"))
if not password:
- raise forms.ValidationError(_(u"You must provide a correct "
- u"password."))
+ raise forms.ValidationError(_("You must provide a correct "
+ "password."))
# check username unicity
q = models.IshtarUser.objects.filter(
user_ptr__username=cleaned_data.get('username'))
if cleaned_data.get('pk'):
q = q.exclude(person__pk=cleaned_data.get('pk'))
if q.count():
- raise forms.ValidationError(_(u"This username already exists."))
+ raise forms.ValidationError(_("This username already exists."))
return cleaned_data
@@ -929,9 +929,9 @@ class ProfileForm(ManageOldType):
'profile_type': models.ProfileType,
'area': models.Area
}
- profile_type = forms.ChoiceField(label=_(u"Type"), choices=[])
- area = widgets.Select2MultipleField(label=_(u"Areas"), required=False)
- name = forms.CharField(label=_(u"Name"), required=False)
+ profile_type = forms.ChoiceField(label=_("Type"), choices=[])
+ area = widgets.Select2MultipleField(label=_("Areas"), required=False)
+ name = forms.CharField(label=_("Name"), required=False)
pk = forms.IntegerField(label=" ", widget=forms.HiddenInput, required=False)
TYPES = [
@@ -943,15 +943,15 @@ class ProfileForm(ManageOldType):
ProfileFormset = formset_factory(ProfileForm, can_delete=True,
formset=FormSetWithDeleteSwitches)
ProfileFormset.form_label = _("Profiles")
-ProfileFormset.form_admin_name = _(u"Profiles")
+ProfileFormset.form_admin_name = _("Profiles")
ProfileFormset.form_slug = "profiles"
class FinalAccountForm(forms.Form):
final = True
form_label = _("Confirm")
- send_password = forms.BooleanField(label=_(u"Send the new password by "
- u"email?"), required=False)
+ send_password = forms.BooleanField(label=_("Send the new password by "
+ "email?"), required=False)
def __init__(self, *args, **kwargs):
self.is_hidden = True
@@ -962,22 +962,22 @@ class ProfilePersonForm(forms.Form):
"""
Edit the current profile
"""
- current_profile = forms.ChoiceField(label=_(u"Current profile"),
+ current_profile = forms.ChoiceField(label=_("Current profile"),
choices=[])
- name = forms.CharField(label=_(u"Name"), required=False)
- profile_type = forms.ChoiceField(label=_(u"Profile type"), required=False,
+ name = forms.CharField(label=_("Name"), required=False)
+ profile_type = forms.ChoiceField(label=_("Profile type"), required=False,
disabled=True, choices=[])
auto_pin = forms.BooleanField(
- label=_(u"Pin automatically items on creation and modification"),
+ label=_("Pin automatically items on creation and modification"),
required=False)
display_pin_menu = forms.BooleanField(
- label=_(u"Show pin menu"),
+ label=_("Show pin menu"),
required=False)
duplicate_profile = forms.BooleanField(
- label=_(u"Duplicate this profile"), required=False)
+ label=_("Duplicate this profile"), required=False)
delete_profile = forms.BooleanField(
- label=_(u"Delete this profile"), required=False,
+ label=_("Delete this profile"), required=False,
)
def __init__(self, *args, **kwargs):
@@ -1028,7 +1028,7 @@ class ProfilePersonForm(forms.Form):
person__ishtaruser=self.user.ishtaruser,
name=name).exclude(pk=profile.pk).count():
raise forms.ValidationError(
- _(u"A profile with the same name exists."))
+ _("A profile with the same name exists."))
return data
def save(self, session):
@@ -1060,7 +1060,7 @@ class ProfilePersonForm(forms.Form):
if self.cleaned_data.get('duplicate_profile', None):
profile_name = profile.name or profile.profile_type.label
if name == profile_name:
- name += str(_(u" (duplicate)"))
+ name += str(_(" (duplicate)"))
profile.duplicate(name=name)
return
@@ -1088,7 +1088,7 @@ class TownFormSet(FormSet):
TownFormset = formset_factory(TownForm, can_delete=True, formset=TownFormSet)
TownFormset.form_label = _("Towns")
-TownFormset.form_admin_name = _(u"Towns")
+TownFormset.form_admin_name = _("Towns")
TownFormset.form_slug = "towns"
@@ -1161,7 +1161,7 @@ class MergeFormSet(BaseModelFormSet):
class MergeForm(forms.ModelForm):
id = forms.IntegerField(
- label=u"", widget=forms.HiddenInput, required=False)
+ label="", widget=forms.HiddenInput, required=False)
a_is_duplicate_b = forms.BooleanField(required=False)
b_is_duplicate_a = forms.BooleanField(required=False)
not_duplicate = forms.BooleanField(required=False)
@@ -1170,7 +1170,7 @@ class MergeForm(forms.ModelForm):
checked = [True for k in ['a_is_duplicate_b', 'b_is_duplicate_a',
'not_duplicate'] if self.cleaned_data.get(k)]
if len(checked) > 1:
- raise forms.ValidationError(_(u"Only one choice can be checked."))
+ raise forms.ValidationError(_("Only one choice can be checked."))
return self.cleaned_data
def merge(self, *args, **kwargs):
@@ -1218,11 +1218,10 @@ def get_image_help():
if not settings.IMAGE_MAX_SIZE:
return max_size_help()
return str(
- _(u"Heavy images are resized to: %(width)dx%(height)d "
- u"(ratio is preserved).") \
- % {'width': settings.IMAGE_MAX_SIZE[0],
- 'height': settings.IMAGE_MAX_SIZE[1]}) + " " + str(
- max_size_help())
+ _("Heavy images are resized to: %(width)dx%(height)d "
+ "(ratio is preserved).") % {
+ 'width': settings.IMAGE_MAX_SIZE[0],
+ 'height': settings.IMAGE_MAX_SIZE[1]}) + " " + str(max_size_help())
#######################
@@ -1231,7 +1230,7 @@ def get_image_help():
class DocumentForm(forms.ModelForm, CustomForm, ManageOldType):
- form_label = _(u"Documentation")
+ form_label = _("Documentation")
form_admin_name = _("Document - General")
form_slug = "document-general"
file_upload = True
@@ -1239,48 +1238,48 @@ class DocumentForm(forms.ModelForm, CustomForm, ManageOldType):
associated_models = {'source_type': models.SourceType}
pk = forms.IntegerField(label="", required=False, widget=forms.HiddenInput)
- title = forms.CharField(label=_(u"Title"), required=False,
+ title = forms.CharField(label=_("Title"), required=False,
validators=[validators.MaxLengthValidator(200)])
source_type = widgets.ModelChoiceField(
- model=models.SourceType, label=_(u"Source type"), choices=[],
+ model=models.SourceType, label=_("Source type"), choices=[],
required=False)
authors = widgets.ModelJQueryAutocompleteField(
- model=models.Author, multiple=True, label=_(u"Authors"), new=True,
+ model=models.Author, multiple=True, label=_("Authors"), new=True,
long_widget=True, required=False)
associated_url = forms.URLField(
max_length=1000, required=False,
- label=_(u"Numerical ressource (web address)"))
+ label=_("Numerical ressource (web address)"))
image = forms.ImageField(
- label=_(u"Image"), help_text=mark_safe(get_image_help()),
+ label=_("Image"), help_text=mark_safe(get_image_help()),
max_length=255, required=False, widget=widgets.ImageFileInput(),
validators=[file_size_validator]
)
associated_file = forms.FileField(
- label=pgettext(u"Not directory", u"File"), max_length=255,
+ label=pgettext("Not directory", "File"), max_length=255,
required=False, help_text=max_size_help(),
validators=[file_size_validator]
)
reference = forms.CharField(
- label=_(u"Reference"),
+ label=_("Reference"),
validators=[validators.MaxLengthValidator(100)], required=False)
internal_reference = forms.CharField(
- label=_(u"Internal reference"),
+ label=_("Internal reference"),
validators=[validators.MaxLengthValidator(100)], required=False)
- receipt_date = forms.DateField(label=_(u"Receipt date"), required=False,
+ receipt_date = forms.DateField(label=_("Receipt date"), required=False,
widget=DatePicker)
- creation_date = forms.DateField(label=_(u"Creation date"), required=False,
+ creation_date = forms.DateField(label=_("Creation date"), required=False,
widget=DatePicker)
receipt_date_in_documentation = forms.DateField(
- label=_(u"Receipt date in documentation"), required=False,
+ label=_("Receipt date in documentation"), required=False,
widget=DatePicker)
- comment = forms.CharField(label=_(u"Comment"), widget=forms.Textarea,
+ comment = forms.CharField(label=_("Comment"), widget=forms.Textarea,
required=False)
- description = forms.CharField(label=_(u"Description"),
+ description = forms.CharField(label=_("Description"),
widget=forms.Textarea, required=False)
additional_information = forms.CharField(
- label=_(u"Additional information"), widget=forms.Textarea,
+ label=_("Additional information"), widget=forms.Textarea,
required=False)
- duplicate = forms.NullBooleanField(label=_(u"Has a duplicate"),
+ duplicate = forms.NullBooleanField(label=_("Has a duplicate"),
required=False)
TYPES = [
@@ -1298,12 +1297,12 @@ class DocumentForm(forms.ModelForm, CustomForm, ManageOldType):
]
HEADERS = {
- 'title': FormHeader(_(u"Identification")),
- 'image': FormHeader(_(u"Content")),
- 'authors': FormHeader(_(u"Authors")),
- 'receipt_date': FormHeader(_(u"Dates")),
- 'comment': FormHeader(_(u"Advanced"), collapse=True),
- 'finds': FormHeader(_(u"Related items")),
+ 'title': FormHeader(_("Identification")),
+ 'image': FormHeader(_("Content")),
+ 'authors': FormHeader(_("Authors")),
+ 'receipt_date': FormHeader(_("Dates")),
+ 'comment': FormHeader(_("Advanced"), collapse=True),
+ 'finds': FormHeader(_("Related items")),
}
def __init__(self, *args, **kwargs):
@@ -1341,8 +1340,8 @@ class DocumentForm(forms.ModelForm, CustomForm, ManageOldType):
for rel in models.Document.RELATED_MODELS:
if cleaned_data.get(rel, None):
return cleaned_data
- raise forms.ValidationError(_(u"A document has to be attached at least "
- u"to one item"))
+ raise forms.ValidationError(_("A document has to be attached at least "
+ "to one item"))
def save(self, commit=True):
if not self.cleaned_data.get('authors', None):
@@ -1378,38 +1377,38 @@ class DocumentForm(forms.ModelForm, CustomForm, ManageOldType):
class DocumentSelect(HistorySelect):
_model = models.Document
- form_admin_name = _(u"Document - 001 - Search")
+ form_admin_name = _("Document - 001 - Search")
form_slug = "document-001-search"
search_vector = forms.CharField(
- label=_(u"Full text search"), widget=widgets.SearchWidget(
+ label=_("Full text search"), widget=widgets.SearchWidget(
'ishtar-common', 'document'
))
authors = forms.IntegerField(
widget=widgets.JQueryAutoComplete(
"/" + settings.URL_PATH + 'autocomplete-author',
associated_model=models.Author),
- validators=[models.valid_id(models.Author)], label=_(u"Author"),
+ validators=[models.valid_id(models.Author)], label=_("Author"),
required=False)
- title = forms.CharField(label=_(u"Title"))
+ title = forms.CharField(label=_("Title"))
source_type = forms.ChoiceField(label=_("Source type"), choices=[])
- reference = forms.CharField(label=_(u"Reference"))
- internal_reference = forms.CharField(label=_(u"Internal reference"))
- description = forms.CharField(label=_(u"Description"))
- comment = forms.CharField(label=_(u"Comment"))
+ reference = forms.CharField(label=_("Reference"))
+ internal_reference = forms.CharField(label=_("Internal reference"))
+ description = forms.CharField(label=_("Description"))
+ comment = forms.CharField(label=_("Comment"))
additional_information = forms.CharField(
- label=_(u"Additional informations"))
- duplicate = forms.NullBooleanField(label=_(u"Has a duplicate"))
- image__isnull = forms.NullBooleanField(label=_(u"Has an image?"))
+ label=_("Additional informations"))
+ duplicate = forms.NullBooleanField(label=_("Has a duplicate"))
+ image__isnull = forms.NullBooleanField(label=_("Has an image?"))
operation = forms.IntegerField(
- label=_(u"Operation"), required=False,
+ label=_("Operation"), required=False,
widget=widgets.JQueryAutoComplete(
reverse_lazy('autocomplete-operation'),
associated_model=Operation),
validators=[models.valid_id(Operation)])
context_record = forms.IntegerField(
- label=_(u"Context record"), required=False,
+ label=_("Context record"), required=False,
widget=widgets.JQueryAutoComplete(
reverse_lazy('autocomplete-contextrecord'),
associated_model=ContextRecord),
@@ -1421,15 +1420,15 @@ class DocumentSelect(HistorySelect):
associated_model=FindBasket),
validators=[models.valid_id(FindBasket)], required=False)
find = forms.IntegerField(
- label=_(u"Find"), required=False,
+ label=_("Find"), required=False,
widget=widgets.JQueryAutoComplete(
reverse_lazy('autocomplete-find'),
associated_model=Find),
validators=[models.valid_id(Find)])
- find__denomination = forms.CharField(label=_(u"Find - denomination"),
+ find__denomination = forms.CharField(label=_("Find - denomination"),
required=False)
container = forms.IntegerField(
- label=_(u"Container"), required=False,
+ label=_("Container"), required=False,
widget=widgets.JQueryAutoComplete(
reverse_lazy('autocomplete-container'),
associated_model=Container),
@@ -1448,7 +1447,7 @@ class DocumentSelect(HistorySelect):
class DocumentFormSelection(LockForm, CustomFormSearch):
SEARCH_AND_SELECT = True
- form_label = _(u"Document search")
+ form_label = _("Document search")
associated_models = {'pk': models.Document}
currents = {'pk': models.Document}
@@ -1463,7 +1462,7 @@ class DocumentFormSelection(LockForm, CustomFormSearch):
class DocumentFormMultiSelection(LockForm, MultiSearchForm):
- form_label = _(u"Document search")
+ form_label = _("Document search")
associated_models = {'pks': models.Document}
pk_key = 'pks'
@@ -1479,7 +1478,7 @@ class DocumentFormMultiSelection(LockForm, MultiSearchForm):
class QADocumentFormMulti(QAForm):
- form_admin_name = _(u"Document - Quick action - Modify")
+ form_admin_name = _("Document - Quick action - Modify")
form_slug = "document-quickaction-modify"
base_models = ['qa_source_type']
associated_models = {
@@ -1493,10 +1492,10 @@ class QADocumentFormMulti(QAForm):
'qa_creation_date',
]
qa_source_type = forms.ChoiceField(
- label=_(u"Source type"), required=False
+ label=_("Source type"), required=False
)
qa_authors = widgets.ModelJQueryAutocompleteField(
- model=models.Author, label=_(u"Author"), new=True,
+ model=models.Author, label=_("Author"), new=True,
required=False)
qa_creation_date = forms.DateField(
label=_("Creation date"), widget=DatePicker, required=False)
@@ -1598,7 +1597,7 @@ class QALockForm(forms.Form):
class SourceDeletionForm(FinalForm):
confirm_msg = " "
- confirm_end_msg = _(u"Would you like to delete this documentation?")
+ confirm_end_msg = _("Would you like to delete this documentation?")
######################
# Authors management #
@@ -1606,15 +1605,15 @@ class SourceDeletionForm(FinalForm):
class AuthorForm(ManageOldType, NewItemForm):
- form_label = _(u"Author")
+ form_label = _("Author")
associated_models = {'person': models.Person,
'author_type': models.AuthorType}
person = forms.IntegerField(
widget=widgets.JQueryAutoComplete(
"/" + settings.URL_PATH + 'autocomplete-person',
associated_model=models.Person, new=True),
- validators=[models.valid_id(models.Person)], label=_(u"Person"))
- author_type = forms.ChoiceField(label=_(u"Author type"), choices=[])
+ validators=[models.valid_id(models.Person)], label=_("Person"))
+ author_type = forms.ChoiceField(label=_("Author type"), choices=[])
def __init__(self, *args, **kwargs):
super(AuthorForm, self).__init__(*args, **kwargs)
@@ -1642,7 +1641,7 @@ class AuthorForm(ManageOldType, NewItemForm):
class AuthorFormSelection(forms.Form):
- form_label = _(u"Author selection")
+ form_label = _("Author selection")
base_model = 'author'
associated_models = {'author': models.Author}
author = forms.IntegerField(
@@ -1650,7 +1649,7 @@ class AuthorFormSelection(forms.Form):
widget=widgets.JQueryAutoComplete(
"/" + settings.URL_PATH + 'autocomplete-author',
associated_model=models.Author, new=True),
- validators=[models.valid_id(models.Author)], label=_(u"Author"))
+ validators=[models.valid_id(models.Author)], label=_("Author"))
class AuthorFormSet(FormSet):
@@ -1663,20 +1662,20 @@ class AuthorFormSet(FormSet):
AuthorFormset = formset_factory(AuthorFormSelection, can_delete=True,
formset=AuthorFormSet)
AuthorFormset.form_label = _("Authors")
-AuthorFormset.form_admin_name = _(u"Authors")
+AuthorFormset.form_admin_name = _("Authors")
AuthorFormset.form_slug = "authors"
class SearchQueryForm(forms.Form):
- query = forms.CharField(max_length=None, label=_(u"Query"), initial='*',
+ query = forms.CharField(max_length=None, label=_("Query"), initial='*',
widget=forms.HiddenInput)
search_query = forms.ChoiceField(label="", required=False,
choices=[])
label = forms.CharField(label="", max_length=None, required=False)
- is_alert = forms.BooleanField(label=_(u"Is an alert"), required=False)
+ is_alert = forms.BooleanField(label=_("Is an alert"), required=False)
create_or_update = forms.ChoiceField(
- choices=(('create', _(u"Create")),
- ('update', _(u"Update"))), initial='create')
+ choices=(('create', _("Create")),
+ ('update', _("Update"))), initial='create')
def __init__(self, profile, content_type, *args, **kwargs):
self.profile = profile
@@ -1691,17 +1690,17 @@ class SearchQueryForm(forms.Form):
def clean(self):
data = self.cleaned_data
if data['create_or_update'] == 'create' and not data['label']:
- raise forms.ValidationError(_(u"A label is required for a new "
- u"search query."))
+ raise forms.ValidationError(_("A label is required for a new "
+ "search query."))
elif data['create_or_update'] == 'update':
if not data['search_query']:
- raise forms.ValidationError(_(u"Select the search query to "
- u"update"))
+ raise forms.ValidationError(_("Select the search query to "
+ "update"))
q = models.SearchQuery.objects.filter(
profile=self.profile, content_type=self.content_type,
pk=data['search_query'])
if not q.count():
- raise forms.ValidationError(_(u"Query does not exist."))
+ raise forms.ValidationError(_("Query does not exist."))
return data
def save(self):
@@ -1716,14 +1715,14 @@ class SearchQueryForm(forms.Form):
profile=self.profile, content_type=self.content_type,
pk=data['search_query'])
except models.SearchQuery.DoesNotExist:
- raise forms.ValidationError(_(u"Query does not exist."))
+ raise forms.ValidationError(_("Query does not exist."))
sq.query = data['query']
sq.save()
return sq
class QRSearchForm(forms.Form):
- query = forms.CharField(max_length=None, label=_(u"Query"), initial='*')
+ query = forms.CharField(max_length=None, label=_("Query"), initial='*')
current_url = forms.CharField(max_length=None, label="",
widget=forms.HiddenInput())
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index 38e5b2fb4..071b05598 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -4284,8 +4284,8 @@ class Merge(models.Model):
for m in self.merge_exclusion.all():
m.delete()
- def merge(self, item):
- merge_model_objects(self, item)
+ def merge(self, item, keep_old=False):
+ merge_model_objects(self, item, keep_old=keep_old)
self.generate_merge_candidate()
diff --git a/ishtar_common/views.py b/ishtar_common/views.py
index b662c1a4d..2176c4519 100644
--- a/ishtar_common/views.py
+++ b/ishtar_common/views.py
@@ -948,7 +948,7 @@ def reset_wizards(request):
ITEM_PER_PAGE = 20
-def merge_action(model, form, key):
+def merge_action(model, form, key, name_key="name"):
def merge(request, page=1):
current_url = key + '_merge'
if not page:
@@ -974,7 +974,8 @@ def merge_action(model, form, key):
item_nb_1 = item_nb + ITEM_PER_PAGE
from_key = 'from_' + key
to_key = 'to_' + key
- queryset = q.all().order_by(from_key + '__name')[item_nb:item_nb_1]
+ queryset = q.all().order_by(
+ from_key + '__' + name_key)[item_nb:item_nb_1]
FormSet.from_key = from_key
FormSet.to_key = to_key
if request.method == 'POST':
@@ -1016,7 +1017,7 @@ organization_merge = merge_action(
class IshtarMixin(object):
- page_name = u""
+ page_name = ""
def get_context_data(self, **kwargs):
context = super(IshtarMixin, self).get_context_data(**kwargs)