diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2019-01-11 16:19:59 +0100 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2019-01-11 16:19:59 +0100 |
commit | 2aa223c0cac8c445e9f3855db66524cfdeae9380 (patch) | |
tree | 8b9137dd9b68121db86e4e22dfdb7b7016a6f1ad | |
parent | 23697dd97eb201dd557272293227ec42a1c95a54 (diff) | |
parent | daeeeb175835559724c8520f4f5a8dcd5957a469 (diff) | |
download | Ishtar-2aa223c0cac8c445e9f3855db66524cfdeae9380.tar.bz2 Ishtar-2aa223c0cac8c445e9f3855db66524cfdeae9380.zip |
Merge branch 'develop'
123 files changed, 15002 insertions, 4735 deletions
diff --git a/archaeological_context_records/forms.py b/archaeological_context_records/forms.py index a4577df40..8bd3db9f5 100644 --- a/archaeological_context_records/forms.py +++ b/archaeological_context_records/forms.py @@ -28,7 +28,13 @@ from django.core import validators from django.forms.formsets import formset_factory from django.utils.translation import ugettext_lazy as _ -import models +from ishtar_common.models import valid_id, IshtarSiteProfile, Town +from archaeological_context_records import models + +from ishtar_common.forms import FinalForm, FormSet, \ + reverse_lazy, get_form_selection, TableSelect, ManageOldType, CustomForm, \ + FieldType, CustomFormSearch, IshtarForm +from ishtar_common.forms_common import get_town_field from archaeological_operations.forms import OperationSelect, ParcelField, \ RecordRelationsForm as OpeRecordRelationsForm, RecordRelationsFormSetBase from archaeological_operations.models import Period, Parcel, Operation, \ @@ -36,11 +42,6 @@ from archaeological_operations.models import Period, Parcel, Operation, \ from archaeological_operations.widgets import OAWidget from bootstrap_datepicker.widgets import DatePicker from ishtar_common import widgets -from ishtar_common.forms import FinalForm, FormSet, \ - reverse_lazy, get_form_selection, TableSelect, ManageOldType, CustomForm, \ - FieldType, CustomFormSearch -from ishtar_common.forms_common import get_town_field -from ishtar_common.models import valid_id, IshtarSiteProfile, Town class OperationFormSelection(CustomForm, forms.Form): @@ -154,6 +155,8 @@ class RecordFormGeneral(CustomForm, ManageOldType): ) label = forms.CharField(label=_(u"ID"), validators=[validators.MaxLengthValidator(200)]) + unit = forms.ChoiceField(label=_(u"Context record type"), required=False, + choices=[]) description = forms.CharField(label=_(u"Description"), widget=forms.Textarea, required=False) comment = forms.CharField(label=_(u"General comment"), @@ -167,8 +170,6 @@ class RecordFormGeneral(CustomForm, ManageOldType): depth = forms.FloatField(label=_(u"Depth (m)"), required=False) depth_of_appearance = forms.FloatField( label=_(u"Depth of appearance (m)"), required=False) - unit = forms.ChoiceField(label=_(u"Context record type"), required=False, - choices=[]) opening_date = forms.DateField(label=_(u"Opening date"), widget=DatePicker, required=False) closing_date = forms.DateField(label=_(u"Closing date"), @@ -374,3 +375,46 @@ class RecordDeletionForm(FinalForm): confirm_msg = " " confirm_end_msg = _(u"Would you like to delete this context record?") + +class QAOperationCR(IshtarForm): + town = forms.ChoiceField(label=_(u"Town"), choices=[]) + archaeological_site = forms.ChoiceField( + label=" ", choices=[], required=False, + help_text=_(u"Only the items associated to the operation can be " + u"selected.") + ) + label = forms.CharField(label=_(u"ID"), + validators=[validators.MaxLengthValidator(200)]) + unit = forms.ChoiceField(label=_(u"Context record type"), required=False, + choices=[]) + + TYPES = [ + FieldType('unit', models.Unit), + ] + + def __init__(self, *args, **kwargs): + self.items = kwargs.pop('items') + super(QAOperationCR, self).__init__(*args, **kwargs) + site_label = IshtarSiteProfile.get_default_site_label() + self.fields['archaeological_site'].label = site_label + self.fields['archaeological_site'].choices = [('', '--')] + + if not self.items: + return + operation = self.items[0] + self.fields['town'].choices = [(t.pk, unicode(t)) + for t in operation.towns.all()] + self.fields['archaeological_site'].choices += [ + (site.pk, unicode(site)) + for site in operation.archaeological_sites.all() + ] + + def save(self, items): + operation = items[0] + cr = models.ContextRecord.objects.create( + town_id=self.cleaned_data['town'], operation=operation, + archaeological_site_id= + self.cleaned_data['archaeological_site'] or None, + label=self.cleaned_data['label'], + unit_id=self.cleaned_data['unit'] or None + ) diff --git a/archaeological_context_records/locale/django.pot b/archaeological_context_records/locale/django.pot index fbd1d8d86..e76ef5dc7 100644 --- a/archaeological_context_records/locale/django.pot +++ b/archaeological_context_records/locale/django.pot @@ -13,242 +13,242 @@ msgstr "" msgid "Point" msgstr "" -#: admin.py:51 models.py:410 +#: admin.py:51 models.py:427 msgid "Multi polygon" msgstr "" -#: forms.py:47 forms.py:53 models.py:352 wizards.py:81 +#: forms.py:48 forms.py:54 models.py:369 wizards.py:81 msgid "Operation" msgstr "" -#: forms.py:48 +#: forms.py:49 msgid "Context record - 010 - Operation choice" msgstr "" -#: forms.py:63 +#: forms.py:64 msgid "Context record - 001 - Search" msgstr "" -#: forms.py:66 +#: forms.py:67 msgid "Full text search" msgstr "" -#: forms.py:69 forms.py:155 models.py:357 models.py:737 +#: forms.py:70 forms.py:156 forms.py:386 models.py:374 models.py:754 msgid "ID" msgstr "" -#: forms.py:75 +#: forms.py:76 msgid "Code PATRIARCHE" msgstr "" -#: forms.py:76 +#: forms.py:77 msgid "Operation's year" msgstr "" -#: forms.py:78 +#: forms.py:79 msgid "Operation's number (index by year)" msgstr "" -#: forms.py:80 models.py:355 +#: forms.py:81 models.py:372 msgid "Archaeological site" msgstr "" -#: forms.py:86 +#: forms.py:87 msgid "Search within related operations" msgstr "" -#: forms.py:87 forms.py:288 models.py:66 +#: forms.py:88 forms.py:289 models.py:66 msgid "Period" msgstr "" -#: forms.py:88 +#: forms.py:89 msgid "Unit type" msgstr "" -#: forms.py:89 forms.py:148 models.py:231 models.py:232 models.py:347 -#: models.py:739 +#: forms.py:90 forms.py:149 models.py:248 models.py:249 models.py:364 +#: models.py:756 msgid "Parcel" msgstr "" -#: forms.py:91 +#: forms.py:92 msgid "Search within relations" msgstr "" -#: forms.py:115 views.py:95 +#: forms.py:116 views.py:99 msgid "Context record search" msgstr "" -#: forms.py:130 +#: forms.py:131 msgid "You should at least select one context record." msgstr "" -#: forms.py:136 +#: forms.py:137 msgid "General" msgstr "" -#: forms.py:137 +#: forms.py:138 msgid "Context record - 020 - General" msgstr "" -#: forms.py:149 models.py:228 models.py:229 models.py:350 +#: forms.py:150 forms.py:380 models.py:245 models.py:246 models.py:367 msgid "Town" msgstr "" -#: forms.py:152 +#: forms.py:153 forms.py:383 msgid "Only the items associated to the operation can be selected." msgstr "" -#: forms.py:157 models.py:358 models.py:740 +#: forms.py:158 forms.py:388 models.py:396 models.py:755 +msgid "Context record type" +msgstr "" + +#: forms.py:160 models.py:375 models.py:757 #: templates/ishtar/sheet_contextrecord.html:45 msgid "Description" msgstr "" -#: forms.py:159 models.py:359 +#: forms.py:162 models.py:376 msgid "General comment" msgstr "" -#: forms.py:162 models.py:405 +#: forms.py:165 models.py:422 msgid "Excavation technique" msgstr "" -#: forms.py:163 models.py:363 +#: forms.py:166 models.py:380 msgid "Length (m)" msgstr "" -#: forms.py:164 models.py:364 +#: forms.py:167 models.py:381 msgid "Width (m)" msgstr "" -#: forms.py:165 models.py:365 +#: forms.py:168 models.py:382 msgid "Thickness (m)" msgstr "" -#: forms.py:166 models.py:367 +#: forms.py:169 models.py:384 msgid "Diameter (m)" msgstr "" -#: forms.py:167 models.py:368 +#: forms.py:170 models.py:385 msgid "Depth (m)" msgstr "" -#: forms.py:169 models.py:370 +#: forms.py:172 models.py:387 msgid "Depth of appearance (m)" msgstr "" -#: forms.py:170 models.py:379 models.py:738 -msgid "Context record type" -msgstr "" - -#: forms.py:172 models.py:360 +#: forms.py:173 models.py:377 msgid "Opening date" msgstr "" -#: forms.py:174 models.py:362 templates/ishtar/sheet_contextrecord.html:140 +#: forms.py:175 models.py:379 templates/ishtar/sheet_contextrecord.html:140 msgid "Closing date" msgstr "" -#: forms.py:177 +#: forms.py:178 msgid "Documentation" msgstr "" -#: forms.py:180 models.py:372 +#: forms.py:181 models.py:389 msgid "Location" msgstr "" -#: forms.py:273 +#: forms.py:274 msgid "This ID already exists for this operation." msgstr "" -#: forms.py:277 +#: forms.py:278 msgid "You have to choose a town or a parcel." msgstr "" -#: forms.py:283 forms.py:304 models.py:77 +#: forms.py:284 forms.py:305 models.py:77 msgid "Dating" msgstr "" -#: forms.py:289 models.py:67 +#: forms.py:290 models.py:67 msgid "Start date" msgstr "" -#: forms.py:290 models.py:68 +#: forms.py:291 models.py:68 msgid "End date" msgstr "" -#: forms.py:291 models.py:71 +#: forms.py:292 models.py:71 msgid "Quality" msgstr "" -#: forms.py:292 models.py:45 models.py:69 +#: forms.py:293 models.py:45 models.py:69 msgid "Dating type" msgstr "" -#: forms.py:305 +#: forms.py:306 msgid "Context record - 030 - Dating" msgstr "" -#: forms.py:315 ishtar_menu.py:29 models.py:91 +#: forms.py:316 ishtar_menu.py:29 models.py:108 views.py:185 msgid "Context record" msgstr "" -#: forms.py:331 +#: forms.py:332 msgid "Relations" msgstr "" -#: forms.py:332 +#: forms.py:333 msgid "Context record - 050 - Relations" msgstr "" -#: forms.py:337 forms.py:348 models.py:382 +#: forms.py:338 forms.py:349 models.py:399 #: templates/ishtar/sheet_contextrecord.html:64 msgid "Interpretation" msgstr "" -#: forms.py:338 +#: forms.py:339 msgid "Context record - 040 - Interpretation" msgstr "" -#: forms.py:344 +#: forms.py:345 msgid "Comments on dating" msgstr "" -#: forms.py:346 models.py:381 +#: forms.py:347 models.py:398 msgid "Filling" msgstr "" -#: forms.py:350 models.py:402 +#: forms.py:351 models.py:419 msgid "Activity" msgstr "" -#: forms.py:352 models.py:400 +#: forms.py:353 models.py:417 msgid "Identification" msgstr "" -#: forms.py:354 models.py:385 +#: forms.py:355 models.py:402 msgid "TAQ" msgstr "" -#: forms.py:355 models.py:389 +#: forms.py:356 models.py:406 msgid "Estimated TAQ" msgstr "" -#: forms.py:357 models.py:392 +#: forms.py:358 models.py:409 msgid "TPQ" msgstr "" -#: forms.py:358 models.py:396 +#: forms.py:359 models.py:413 msgid "Estimated TPQ" msgstr "" -#: forms.py:368 +#: forms.py:369 msgid "Operation search" msgstr "" -#: forms.py:370 +#: forms.py:371 msgid "You should select an operation." msgstr "" -#: forms.py:375 +#: forms.py:376 msgid "Would you like to delete this context record?" msgstr "" @@ -288,263 +288,273 @@ msgstr "" msgid "Datings" msgstr "" -#: models.py:98 +#: models.py:115 msgid "Find" msgstr "" -#: models.py:117 models.py:136 models.py:152 +#: models.py:134 models.py:153 models.py:169 msgid "Order" msgstr "" -#: models.py:119 +#: models.py:136 msgid "Parent context record type" msgstr "" -#: models.py:123 +#: models.py:140 msgid "Context record Type" msgstr "" -#: models.py:124 +#: models.py:141 msgid "Context record Types" msgstr "" -#: models.py:139 +#: models.py:156 msgid "Activity Type" msgstr "" -#: models.py:140 +#: models.py:157 msgid "Activity Types" msgstr "" -#: models.py:155 +#: models.py:172 msgid "Identification Type" msgstr "" -#: models.py:156 +#: models.py:173 msgid "Identification Types" msgstr "" -#: models.py:169 +#: models.py:186 msgid "Excavation technique type" msgstr "" -#: models.py:170 +#: models.py:187 msgid "Excavation technique types" msgstr "" -#: models.py:180 +#: models.py:197 msgid "Documentation type" msgstr "" -#: models.py:181 +#: models.py:198 msgid "Documentation types" msgstr "" -#: models.py:222 models.py:741 +#: models.py:239 models.py:758 msgid "Periods" msgstr "" -#: models.py:223 +#: models.py:240 msgid "Datings (period)" msgstr "" -#: models.py:224 +#: models.py:241 msgid "Related context records" msgstr "" -#: models.py:225 +#: models.py:242 msgid "Operation (Patriarche code)" msgstr "" -#: models.py:226 +#: models.py:243 msgid "Operation (name)" msgstr "" -#: models.py:227 +#: models.py:244 msgid "Parcel (external ID)" msgstr "" -#: models.py:230 +#: models.py:247 msgid "Parcel (year)" msgstr "" -#: models.py:265 +#: models.py:282 msgctxt "key for text search" msgid "id" msgstr "" -#: models.py:269 +#: models.py:286 msgctxt "key for text search" msgid "town" msgstr "" -#: models.py:273 +#: models.py:290 msgctxt "key for text search" msgid "operation-year" msgstr "" -#: models.py:277 +#: models.py:294 msgctxt "key for text search" msgid "patriarche" msgstr "" -#: models.py:281 +#: models.py:298 msgctxt "key for text search" msgid "operation-code" msgstr "" -#: models.py:285 models.py:327 +#: models.py:302 models.py:344 msgctxt "key for text search" msgid "operation" msgstr "" -#: models.py:289 models.py:330 +#: models.py:306 models.py:347 msgctxt "key for text search" msgid "site" msgstr "" -#: models.py:293 +#: models.py:310 msgctxt "key for text search" msgid "operation-relation-type" msgstr "" -#: models.py:297 +#: models.py:314 msgctxt "key for text search" msgid "period" msgstr "" -#: models.py:301 +#: models.py:318 msgctxt "key for text search" msgid "unit-type" msgstr "" -#: models.py:305 +#: models.py:322 msgctxt "key for text search" msgid "parcel" msgstr "" -#: models.py:309 +#: models.py:326 msgctxt "key for text search" msgid "record-relation-type" msgstr "" -#: models.py:343 +#: models.py:360 msgid "External ID" msgstr "" -#: models.py:345 +#: models.py:362 msgid "External ID is set automatically" msgstr "" -#: models.py:373 +#: models.py:390 msgid "A short description of the location of the context record" msgstr "" -#: models.py:377 +#: models.py:394 msgid "Comment on datings" msgstr "" -#: models.py:386 +#: models.py:403 msgid "" "\"Terminus Ante Quem\" the context record can't have been created after this " "date" msgstr "" -#: models.py:390 +#: models.py:407 msgid "Estimation of a \"Terminus Ante Quem\"" msgstr "" -#: models.py:393 +#: models.py:410 msgid "" "\"Terminus Post Quem\" the context record can't have been created before " "this date" msgstr "" -#: models.py:397 +#: models.py:414 msgid "Estimation of a \"Terminus Post Quem\"" msgstr "" -#: models.py:408 +#: models.py:425 msgid "Point (2D)" msgstr "" -#: models.py:409 +#: models.py:426 msgid "Point (3D)" msgstr "" -#: models.py:413 +#: models.py:430 msgid "Documents" msgstr "" -#: models.py:415 +#: models.py:432 msgid "Cached name" msgstr "" -#: models.py:419 models.py:420 templates/ishtar/sheet_contextrecord.html:4 +#: models.py:436 models.py:437 templates/ishtar/sheet_contextrecord.html:4 msgid "Context Record" msgstr "" -#: models.py:439 +#: models.py:456 msgctxt "short" msgid "Context record" msgstr "" -#: models.py:668 models.py:691 models.py:736 +#: models.py:685 models.py:708 models.py:753 msgid "Relation type" msgstr "" -#: models.py:669 +#: models.py:686 msgid "Relation types" msgstr "" -#: models.py:686 +#: models.py:703 msgid "ID (left)" msgstr "" -#: models.py:687 +#: models.py:704 msgid "Context record type (left)" msgstr "" -#: models.py:688 +#: models.py:705 msgid "Parcel (left)" msgstr "" -#: models.py:689 +#: models.py:706 msgid "Description (left)" msgstr "" -#: models.py:690 +#: models.py:707 msgid "Periods (left)" msgstr "" -#: models.py:692 +#: models.py:709 msgid "ID (right)" msgstr "" -#: models.py:693 +#: models.py:710 msgid "Context record type (right)" msgstr "" -#: models.py:694 +#: models.py:711 msgid "Parcel (right)" msgstr "" -#: models.py:695 +#: models.py:712 msgid "Description (right)" msgstr "" -#: models.py:696 +#: models.py:713 msgid "Periods (right)" msgstr "" -#: models.py:705 +#: models.py:722 msgid "Record relation" msgstr "" -#: models.py:706 +#: models.py:723 msgid "Record relations" msgstr "" +#: templates/ishtar/forms/qa_operation_contextrecord.html:11 +msgid "Quick add context record" +msgstr "" + +#: templates/ishtar/forms/qa_operation_contextrecord.html:25 +msgid "" +"To put more information to the context record use the full form on the top " +"menu: \\" +msgstr "" + #: templates/ishtar/sheet_contextrecord.html:75 msgid "Datations" msgstr "" @@ -613,18 +623,22 @@ msgstr "" msgid "Documents from associated finds" msgstr "" -#: views.py:109 +#: views.py:113 msgid "New context record" msgstr "" -#: views.py:125 +#: views.py:129 msgid "Context record modification" msgstr "" -#: views.py:136 +#: views.py:140 msgid "You don't have sufficient permissions to do this action." msgstr "" -#: views.py:149 +#: views.py:153 msgid "Context record deletion" msgstr "" + +#: views.py:190 +msgid "Add context record" +msgstr "" diff --git a/archaeological_context_records/migrations/0033_auto_20181203_1442.py b/archaeological_context_records/migrations/0033_auto_20181203_1442.py new file mode 100644 index 000000000..0497d68e3 --- /dev/null +++ b/archaeological_context_records/migrations/0033_auto_20181203_1442.py @@ -0,0 +1,590 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-12-03 14:42 +from __future__ import unicode_literals + +from django.conf import settings +import django.contrib.gis.db.models.fields +import django.contrib.postgres.search +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import ishtar_common.models +import re + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_context_records', '0032_auto_20181017_1854'), + ] + + operations = [ + migrations.AlterModelOptions( + name='activitytype', + options={'ordering': ('order',), 'verbose_name': "Type d'activit\xe9", 'verbose_name_plural': "Types d'activit\xe9"}, + ), + migrations.AlterModelOptions( + name='contextrecord', + options={'ordering': ('cached_label',), 'permissions': (('view_contextrecord', 'Can view all Context Records'), ('view_own_contextrecord', 'Can view own Context Record'), ('add_own_contextrecord', 'Can add own Context Record'), ('change_own_contextrecord', 'Can change own Context Record'), ('delete_own_contextrecord', 'Can delete own Context Record')), 'verbose_name': "Unit\xe9 d'Enregistrement", 'verbose_name_plural': "Unit\xe9 d'Enregistrement"}, + ), + migrations.AlterModelOptions( + name='dating', + options={'verbose_name': 'Datation', 'verbose_name_plural': 'Datations'}, + ), + migrations.AlterModelOptions( + name='datingquality', + options={'ordering': ('label',), 'verbose_name': 'Type de qualit\xe9 de datation', 'verbose_name_plural': 'Types de qualit\xe9 de datation'}, + ), + migrations.AlterModelOptions( + name='datingtype', + options={'ordering': ('label',), 'verbose_name': 'Type de datation', 'verbose_name_plural': 'Types de datation'}, + ), + migrations.AlterModelOptions( + name='documentationtype', + options={'ordering': ('label',), 'verbose_name': 'Type de documentation', 'verbose_name_plural': 'Types de documentation'}, + ), + migrations.AlterModelOptions( + name='excavationtechnictype', + options={'ordering': ('label',), 'verbose_name': 'Type de m\xe9thode de fouille', 'verbose_name_plural': 'Types de m\xe9thode de fouille'}, + ), + migrations.AlterModelOptions( + name='historicalcontextrecord', + options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': "historical Unit\xe9 d'Enregistrement"}, + ), + migrations.AlterModelOptions( + name='identificationtype', + options={'ordering': ('order', 'label'), 'verbose_name': "Type d'identification", 'verbose_name_plural': "Types d'identification"}, + ), + migrations.AlterModelOptions( + name='recordrelations', + options={'permissions': [('view_recordrelation', 'Can view all Context record relations')], 'verbose_name': "Relation entre Unit\xe9s d'Enregistrement", 'verbose_name_plural': "Relations entre Unit\xe9s d'Enregistrement"}, + ), + migrations.AlterModelOptions( + name='relationtype', + options={'ordering': ('order', 'label'), 'verbose_name': 'Type de relation', 'verbose_name_plural': 'Types de relation'}, + ), + migrations.AlterModelOptions( + name='unit', + options={'ordering': ('order', 'label'), 'verbose_name': "Type d'Unit\xe9 d'Enregistrement", 'verbose_name_plural': "Types d'Unit\xe9 d'Enregistrement"}, + ), + migrations.AlterField( + model_name='activitytype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='activitytype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='activitytype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='activitytype', + name='order', + field=models.IntegerField(verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='activitytype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='contextrecord', + name='activity', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_context_records.ActivityType', verbose_name='Activit\xe9'), + ), + migrations.AlterField( + model_name='contextrecord', + name='archaeological_site', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='context_records', to='archaeological_operations.ArchaeologicalSite', verbose_name='Entit\xe9 (EA)'), + ), + migrations.AlterField( + model_name='contextrecord', + name='auto_external_id', + field=models.BooleanField(default=False, verbose_name="L'identifiant est attribu\xe9 automatiquement"), + ), + migrations.AlterField( + model_name='contextrecord', + name='cached_label', + field=models.TextField(blank=True, db_index=True, null=True, verbose_name='Nom en cache'), + ), + migrations.AlterField( + model_name='contextrecord', + name='closing_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de cl\xf4ture'), + ), + migrations.AlterField( + model_name='contextrecord', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire g\xe9n\xe9ral'), + ), + migrations.AlterField( + model_name='contextrecord', + name='datings_comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire relatif aux datations'), + ), + migrations.AlterField( + model_name='contextrecord', + name='depth', + field=models.FloatField(blank=True, null=True, verbose_name='Profondeur (m)'), + ), + migrations.AlterField( + model_name='contextrecord', + name='depth_of_appearance', + field=models.FloatField(blank=True, null=True, verbose_name="Profondeur d'apparition (m)"), + ), + migrations.AlterField( + model_name='contextrecord', + name='diameter', + field=models.FloatField(blank=True, null=True, verbose_name='Diam\xe8tre (m)'), + ), + migrations.AlterField( + model_name='contextrecord', + name='excavation_technic', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_context_records.ExcavationTechnicType', verbose_name='M\xe9thode de fouille'), + ), + migrations.AlterField( + model_name='contextrecord', + name='external_id', + field=models.TextField(blank=True, null=True, verbose_name='Identifiant'), + ), + migrations.AlterField( + model_name='contextrecord', + name='filling', + field=models.TextField(blank=True, null=True, verbose_name='Remplissage'), + ), + migrations.AlterField( + model_name='contextrecord', + name='history_creator', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Cr\xe9ateur'), + ), + migrations.AlterField( + model_name='contextrecord', + name='history_modifier', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Dernier \xe9diteur'), + ), + migrations.AlterField( + model_name='contextrecord', + name='interpretation', + field=models.TextField(blank=True, null=True, verbose_name='Interpr\xe9tation'), + ), + migrations.AlterField( + model_name='contextrecord', + name='label', + field=models.CharField(max_length=200, verbose_name='Identifiant'), + ), + migrations.AlterField( + model_name='contextrecord', + name='length', + field=models.FloatField(blank=True, null=True, verbose_name='Taille (m)'), + ), + migrations.AlterField( + model_name='contextrecord', + name='location', + field=models.TextField(blank=True, help_text="Une courte description de la localisation de l'Unit\xe9 d'Enregistrement", null=True, verbose_name='Localisation'), + ), + migrations.AlterField( + model_name='contextrecord', + name='multi_polygon', + field=django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, null=True, srid=4326, verbose_name='Polygones multi-parties'), + ), + migrations.AlterField( + model_name='contextrecord', + name='opening_date', + field=models.DateField(blank=True, null=True, verbose_name="Date d'ouverture"), + ), + migrations.AlterField( + model_name='contextrecord', + name='operation', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='context_record', to='archaeological_operations.Operation', verbose_name='Op\xe9ration'), + ), + migrations.AlterField( + model_name='contextrecord', + name='parcel', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='context_record', to='archaeological_operations.Parcel', verbose_name='Parcelle'), + ), + migrations.AlterField( + model_name='contextrecord', + name='relation_image', + field=models.FileField(blank=True, null=True, upload_to=ishtar_common.models.get_image_path, verbose_name='Image des relations (SVG g\xe9n\xe9r\xe9)'), + ), + migrations.AlterField( + model_name='contextrecord', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='contextrecord', + name='taq', + field=models.IntegerField(blank=True, help_text="\xab Terminus Ante Quem \xbb. L'Unit\xe9 d'Enregistrement ne peut avoir \xe9t\xe9 cr\xe9\xe9e apr\xe8s cette date.", null=True, verbose_name='TAQ'), + ), + migrations.AlterField( + model_name='contextrecord', + name='taq_estimated', + field=models.IntegerField(blank=True, help_text="Estimation d'un \xab Terminus Ante Quem \xbb.", null=True, verbose_name='TAQ estim\xe9'), + ), + migrations.AlterField( + model_name='contextrecord', + name='thickness', + field=models.FloatField(blank=True, null=True, verbose_name='\xc9paisseur (m)'), + ), + migrations.AlterField( + model_name='contextrecord', + name='town', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='context_record', to='ishtar_common.Town', verbose_name='Commune'), + ), + migrations.AlterField( + model_name='contextrecord', + name='tpq', + field=models.IntegerField(blank=True, help_text="\xab Terminus Post Quem \xbb. L'Unit\xe9 d'Enregistrement ne peut avoir \xe9t\xe9 cr\xe9\xe9e avant cette date.", null=True, verbose_name='TPQ'), + ), + migrations.AlterField( + model_name='contextrecord', + name='tpq_estimated', + field=models.IntegerField(blank=True, help_text="Estimation d'un \xab Terminus Post Quem \xbb.", null=True, verbose_name='TPQ estim\xe9'), + ), + migrations.AlterField( + model_name='contextrecord', + name='unit', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='archaeological_context_records.Unit', verbose_name="Type d'Unit\xe9 d'Enregistrement"), + ), + migrations.AlterField( + model_name='contextrecord', + name='width', + field=models.FloatField(blank=True, null=True, verbose_name='Largeur (m)'), + ), + migrations.AlterField( + model_name='dating', + name='dating_type', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_context_records.DatingType', verbose_name='Type de datation'), + ), + migrations.AlterField( + model_name='dating', + name='end_date', + field=models.IntegerField(blank=True, null=True, verbose_name='Date de fin'), + ), + migrations.AlterField( + model_name='dating', + name='period', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_operations.Period', verbose_name='P\xe9riode'), + ), + migrations.AlterField( + model_name='dating', + name='precise_dating', + field=models.TextField(blank=True, null=True, verbose_name='Datation pr\xe9cise'), + ), + migrations.AlterField( + model_name='dating', + name='quality', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_context_records.DatingQuality', verbose_name='Qualit\xe9'), + ), + migrations.AlterField( + model_name='dating', + name='start_date', + field=models.IntegerField(blank=True, null=True, verbose_name='Date de d\xe9but'), + ), + migrations.AlterField( + model_name='datingquality', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='datingquality', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='datingquality', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='datingquality', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='datingtype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='datingtype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='datingtype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='datingtype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='documentationtype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='documentationtype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='documentationtype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='documentationtype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='excavationtechnictype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='excavationtechnictype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='excavationtechnictype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='excavationtechnictype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='auto_external_id', + field=models.BooleanField(default=False, verbose_name="L'identifiant est attribu\xe9 automatiquement"), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='cached_label', + field=models.TextField(blank=True, db_index=True, null=True, verbose_name='Nom en cache'), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='closing_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de cl\xf4ture'), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire g\xe9n\xe9ral'), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='datings_comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire relatif aux datations'), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='depth', + field=models.FloatField(blank=True, null=True, verbose_name='Profondeur (m)'), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='depth_of_appearance', + field=models.FloatField(blank=True, null=True, verbose_name="Profondeur d'apparition (m)"), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='diameter', + field=models.FloatField(blank=True, null=True, verbose_name='Diam\xe8tre (m)'), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='external_id', + field=models.TextField(blank=True, null=True, verbose_name='Identifiant'), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='filling', + field=models.TextField(blank=True, null=True, verbose_name='Remplissage'), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='interpretation', + field=models.TextField(blank=True, null=True, verbose_name='Interpr\xe9tation'), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='label', + field=models.CharField(max_length=200, verbose_name='Identifiant'), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='length', + field=models.FloatField(blank=True, null=True, verbose_name='Taille (m)'), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='location', + field=models.TextField(blank=True, help_text="Une courte description de la localisation de l'Unit\xe9 d'Enregistrement", null=True, verbose_name='Localisation'), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='multi_polygon', + field=django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, null=True, srid=4326, verbose_name='Polygones multi-parties'), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='opening_date', + field=models.DateField(blank=True, null=True, verbose_name="Date d'ouverture"), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='relation_image', + field=models.TextField(blank=True, max_length=100, null=True, verbose_name='Image des relations (SVG g\xe9n\xe9r\xe9)'), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='taq', + field=models.IntegerField(blank=True, help_text="\xab Terminus Ante Quem \xbb. L'Unit\xe9 d'Enregistrement ne peut avoir \xe9t\xe9 cr\xe9\xe9e apr\xe8s cette date.", null=True, verbose_name='TAQ'), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='taq_estimated', + field=models.IntegerField(blank=True, help_text="Estimation d'un \xab Terminus Ante Quem \xbb.", null=True, verbose_name='TAQ estim\xe9'), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='thickness', + field=models.FloatField(blank=True, null=True, verbose_name='\xc9paisseur (m)'), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='tpq', + field=models.IntegerField(blank=True, help_text="\xab Terminus Post Quem \xbb. L'Unit\xe9 d'Enregistrement ne peut avoir \xe9t\xe9 cr\xe9\xe9e avant cette date.", null=True, verbose_name='TPQ'), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='tpq_estimated', + field=models.IntegerField(blank=True, help_text="Estimation d'un \xab Terminus Post Quem \xbb.", null=True, verbose_name='TPQ estim\xe9'), + ), + migrations.AlterField( + model_name='historicalcontextrecord', + name='width', + field=models.FloatField(blank=True, null=True, verbose_name='Largeur (m)'), + ), + migrations.AlterField( + model_name='identificationtype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='identificationtype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='identificationtype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='identificationtype', + name='order', + field=models.IntegerField(verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='identificationtype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='relationtype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='relationtype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='relationtype', + name='inverse_relation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_context_records.RelationType', verbose_name='Relation inverse'), + ), + migrations.AlterField( + model_name='relationtype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='relationtype', + name='logical_relation', + field=models.CharField(blank=True, choices=[(b'above', 'Au-dessus'), (b'bellow', 'En dessous'), (b'equal', '\xc9gal')], max_length=10, null=True, verbose_name='Relation logique'), + ), + migrations.AlterField( + model_name='relationtype', + name='order', + field=models.IntegerField(default=1, verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='relationtype', + name='symmetrical', + field=models.BooleanField(verbose_name='Sym\xe9trique'), + ), + migrations.AlterField( + model_name='relationtype', + name='tiny_label', + field=models.CharField(blank=True, max_length=50, null=True, verbose_name='D\xe9nomination courte'), + ), + migrations.AlterField( + model_name='relationtype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='unit', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='unit', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='unit', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='unit', + name='order', + field=models.IntegerField(verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='unit', + name='parent', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_context_records.Unit', verbose_name="Type d'UE parent"), + ), + migrations.AlterField( + model_name='unit', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + ] diff --git a/archaeological_context_records/models.py b/archaeological_context_records/models.py index 89f3edee4..d7d7a618d 100644 --- a/archaeological_context_records/models.py +++ b/archaeological_context_records/models.py @@ -84,6 +84,23 @@ class Dating(models.Model): return unicode(self.period) return u"%s (%s-%s)" % (self.period, start_date, end_date) + @classmethod + def is_identical(cls, dating_1, dating_2): + """ + Compare two dating attribute by attribute and return True if all + attribute is identical + """ + for attr in ["period", "start_date", "end_date", "dating_type", + "quality", "precise_dating"]: + value1 = getattr(dating_1, attr) + value2 = getattr(dating_2, attr) + if attr == "precise_dating": + value1 = value1.strip() + value2 = value2.strip() + if value1 != value2: + return False + return True + def context_records_lbl(self): return u" - ".join( [cr.cached_label for cr in self.context_records.all()] @@ -521,6 +538,9 @@ class ContextRecord(BulkUpdatedItem, BaseHistorizedItem, def get_query_owns(cls, ishtaruser): q = cls._construct_query_own( 'operation__', Operation._get_query_owns_dicts(ishtaruser) + ) | cls._construct_query_own( + 'base_finds__find__basket__', + [{"shared_with": ishtaruser, "shared_write_with": ishtaruser}] ) | cls._construct_query_own('', [ {'history_creator': ishtaruser.user_ptr}, {'operation__end_date__isnull': True} diff --git a/archaeological_context_records/templates/ishtar/forms/qa_operation_contextrecord.html b/archaeological_context_records/templates/ishtar/forms/qa_operation_contextrecord.html new file mode 100644 index 000000000..c782832ff --- /dev/null +++ b/archaeological_context_records/templates/ishtar/forms/qa_operation_contextrecord.html @@ -0,0 +1,28 @@ +{% extends "ishtar/forms/qa_base.html" %} +{% load i18n inline_formset table_form %} + +{% block main_form %} +{% if form.non_field_errors %} +<div class="alert alert-danger" role="alert"> + {{form.non_field_errors}} +</div> +{% endif %} + +<h4>{% trans "Quick add context record" %}</h4> + +{% for hidden in form.hidden_fields %}{{hidden}} +{% if hidden.errors %}<div class="invalid-feedback"> + {{ hidden.errors }} +</div>{% endif %} +{% endfor %} +{% with force_large_col=True %}{% for field in form %} +<div class="form-row"> + {% include "blocks/bs_field_snippet.html" %} +</div> +{% endfor %}{% endwith %} + +<div class="alert alert-info"> + {% trans "To put more information to the context record use the full form on the top menu: \"Context record > Add\"." %} +</div> +{% endblock %} + diff --git a/archaeological_context_records/templates/ishtar/sheet_contextrecord.html b/archaeological_context_records/templates/ishtar/sheet_contextrecord.html index 2ad74b7d2..af5da11dd 100644 --- a/archaeological_context_records/templates/ishtar/sheet_contextrecord.html +++ b/archaeological_context_records/templates/ishtar/sheet_contextrecord.html @@ -171,9 +171,11 @@ {% endif %} {% trans "Document from this context record" as cr_docs %} +{% if permission_view_own_document or permission_view_document %} {% if item.documents.count %} {% dynamic_table_document cr_docs 'documents' 'context_records' item.pk '' output %} {% endif %} +{% endif %} {% trans "Finds" as finds %} {% if item.base_finds.count %} @@ -181,8 +183,10 @@ {% endif %} {% trans "Documents from associated finds" as finds_docs %} +{% if permission_view_own_document or permission_view_document %} {% if item.find_docs_q.count %} {% dynamic_table_document finds_docs 'documents' 'finds__base_finds__context_record' item.pk '' output %} {% endif %} +{% endif %} {% endblock %} diff --git a/archaeological_context_records/urls.py b/archaeological_context_records/urls.py index c05cff87e..175c87482 100644 --- a/archaeological_context_records/urls.py +++ b/archaeological_context_records/urls.py @@ -82,4 +82,10 @@ urlpatterns = [ url(r'get-contextrecordrelationdetail/(?P<type>.+)?$', views.get_contextrecordrelationdetail, name='get-contextrecordrelationdetail'), + + url(r'^operation-qa-contextrecord/(?P<pks>[0-9]+)/$', + check_rights(['add_contextrecord', 'add_own_contextrecord'])( + views.QAOperationContextRecordView.as_view()), + name='operation-qa-contextrecord'), + ] diff --git a/archaeological_context_records/views.py b/archaeological_context_records/views.py index 771a2ed71..6a01a48f0 100644 --- a/archaeological_context_records/views.py +++ b/archaeological_context_records/views.py @@ -26,11 +26,15 @@ from django.shortcuts import redirect from django.utils.translation import ugettext_lazy as _ from django.views.generic import RedirectView +from ishtar_common.models import QuickAction +from archaeological_operations.models import Operation from archaeological_context_records import models + from archaeological_operations.views import site_extra_context from archaeological_context_records import forms from ishtar_common.utils import put_session_message -from ishtar_common.views import IshtarMixin, LoginRequiredMixin + +from ishtar_common.views import IshtarMixin, LoginRequiredMixin, QAItemForm from ishtar_common.views_item import display_item, get_item, show_item, \ revert_item from archaeological_context_records import wizards @@ -171,4 +175,21 @@ class GenerateRelationImage(IshtarMixin, LoginRequiredMixin, RedirectView): except models.ContextRecord.DoesNotExist: raise Http404() self.context_record.generate_relation_image() - return super(GenerateRelationImage, self).get(request, *args, **kwargs)
\ No newline at end of file + return super(GenerateRelationImage, self).get(request, *args, **kwargs) + + +class QAOperationContextRecordView(QAItemForm): + template_name = 'ishtar/forms/qa_operation_contextrecord.html' + model = Operation + form_class = forms.QAOperationCR + page_name = _(u"Context record") + + def get_quick_action(self): + return QuickAction( + url="operation-qa-contextrecord", icon_class="fa fa-plus", + text=_(u"Add context record"), target="one", + rights=['add_contextrecord', 'add_own_contextrecord']) + + def form_valid(self, form): + form.save(self.items) + return HttpResponseRedirect(reverse("success")) diff --git a/archaeological_files/ishtar_menu.py b/archaeological_files/ishtar_menu.py index 21e59a6af..bd41f3782 100644 --- a/archaeological_files/ishtar_menu.py +++ b/archaeological_files/ishtar_menu.py @@ -73,10 +73,6 @@ MENU_SECTIONS = [ _(u"Deletion"), model=AdministrativeAct, access_controls=['change_administrativeact']), - MenuItem('file_administrativeact_document', - _(u"Documents"), - model=AdministrativeAct, - access_controls=['change_administrativeact']), ],)]),), (100, SectionItem( diff --git a/archaeological_files/locale/django.pot b/archaeological_files/locale/django.pot index cb5d930f3..d223864b9 100644 --- a/archaeological_files/locale/django.pot +++ b/archaeological_files/locale/django.pot @@ -6,7 +6,6 @@ # Étienne Loks <etienne.loks@iggdrasil.net>, 2016. #zanata # Valérie-Emma Leroux <emma@iggdrasil.net>, 2017. #zanata # Valérie-Emma Leroux <emma@iggdrasil.net>, 2018. #zanata -# Étienne Loks <etienne.loks@iggdrasil.net>, 2018. #zanata msgid "" msgstr "" @@ -298,19 +297,15 @@ msgstr "" msgid "Administrative act" msgstr "" -#: ishtar_menu.py:77 models.py:321 -msgid "Documents" -msgstr "" - -#: ishtar_menu.py:83 +#: ishtar_menu.py:79 msgid "Dashboard" msgstr "" -#: ishtar_menu.py:86 +#: ishtar_menu.py:82 msgid "General informations" msgstr "" -#: ishtar_menu.py:89 models.py:339 +#: ishtar_menu.py:85 models.py:339 #: templates/ishtar/dashboards/dashboard_file.html:7 msgid "Archaeological files" msgstr "" @@ -481,6 +476,10 @@ msgstr "" msgid "Research archaeology comment" msgstr "" +#: models.py:321 +msgid "Documents" +msgstr "" + #: models.py:324 msgid "Cached name" msgstr "" diff --git a/archaeological_files/migrations/0016_auto_20181203_1442.py b/archaeological_files/migrations/0016_auto_20181203_1442.py new file mode 100644 index 000000000..08f1c01ea --- /dev/null +++ b/archaeological_files/migrations/0016_auto_20181203_1442.py @@ -0,0 +1,433 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-12-03 14:42 +from __future__ import unicode_literals + +import datetime +from django.conf import settings +import django.contrib.postgres.search +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import ishtar_common.utils +import re + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_files', '0015_auto_20181017_1854'), + ] + + operations = [ + migrations.AlterModelOptions( + name='file', + options={'ordering': ('cached_label',), 'permissions': (('view_file', 'Can view all Archaeological files'), ('view_own_file', 'Can view own Archaeological file'), ('add_own_file', 'Can add own Archaeological file'), ('change_own_file', 'Can change own Archaeological file'), ('delete_own_file', 'Can delete own Archaeological file'), ('close_file', 'Can close File')), 'verbose_name': 'Dossier', 'verbose_name_plural': 'Dossiers'}, + ), + migrations.AlterModelOptions( + name='filetype', + options={'ordering': ('label',), 'verbose_name': 'Type de dossier arch\xe9ologique', 'verbose_name_plural': 'Types de dossier arch\xe9ologique'}, + ), + migrations.AlterModelOptions( + name='historicalfile', + options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical Dossier'}, + ), + migrations.AlterModelOptions( + name='permittype', + options={'ordering': ('label',), 'verbose_name': 'Type de permis', 'verbose_name_plural': 'Types de permis'}, + ), + migrations.AlterField( + model_name='file', + name='address', + field=models.TextField(blank=True, null=True, verbose_name='Adresse des terrains'), + ), + migrations.AlterField( + model_name='file', + name='auto_external_id', + field=models.BooleanField(default=False, verbose_name="L'identifiant est attribu\xe9 automatiquement"), + ), + migrations.AlterField( + model_name='file', + name='cached_label', + field=models.TextField(blank=True, db_index=True, null=True, verbose_name='Nom en cache'), + ), + migrations.AlterField( + model_name='file', + name='classified_area', + field=models.NullBooleanField(verbose_name="Au sein d'un site class\xe9"), + ), + migrations.AlterField( + model_name='file', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='file', + name='corporation_general_contractor', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='general_contractor_files', to='ishtar_common.Organization', verbose_name="Organisation de l'am\xe9nageur"), + ), + migrations.AlterField( + model_name='file', + name='creation_date', + field=models.DateField(blank=True, default=datetime.date.today, null=True, verbose_name='Date de cr\xe9ation'), + ), + migrations.AlterField( + model_name='file', + name='departments', + field=models.ManyToManyField(blank=True, to='ishtar_common.Department', verbose_name='D\xe9partements'), + ), + migrations.AlterField( + model_name='file', + name='end_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de cl\xf4ture'), + ), + migrations.AlterField( + model_name='file', + name='external_id', + field=models.CharField(blank=True, max_length=120, null=True, verbose_name='Identifiant'), + ), + migrations.AlterField( + model_name='file', + name='file_type', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.FileType', verbose_name='Type de dossier'), + ), + migrations.AlterField( + model_name='file', + name='general_contractor', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='general_contractor_files', to='ishtar_common.Person', verbose_name='Am\xe9nageur'), + ), + migrations.AlterField( + model_name='file', + name='history_creator', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Cr\xe9ateur'), + ), + migrations.AlterField( + model_name='file', + name='history_modifier', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Dernier \xe9diteur'), + ), + migrations.AlterField( + model_name='file', + name='imported_line', + field=models.TextField(blank=True, null=True, verbose_name='Ligne import\xe9e'), + ), + migrations.AlterField( + model_name='file', + name='in_charge', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='file_responsability', to='ishtar_common.Person', verbose_name='Dossier suivi par'), + ), + migrations.AlterField( + model_name='file', + name='instruction_deadline', + field=models.DateField(blank=True, null=True, verbose_name="Date limite d'instruction"), + ), + migrations.AlterField( + model_name='file', + name='internal_reference', + field=models.CharField(blank=True, max_length=60, null=True, verbose_name='R\xe9f\xe9rence interne'), + ), + migrations.AlterField( + model_name='file', + name='locality', + field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Lieu-dit'), + ), + migrations.AlterField( + model_name='file', + name='main_town', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='file_main', to='ishtar_common.Town', verbose_name='Commune principale'), + ), + migrations.AlterField( + model_name='file', + name='name', + field=models.TextField(blank=True, null=True, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='file', + name='numeric_reference', + field=models.IntegerField(blank=True, null=True, verbose_name='R\xe9f\xe9rence num\xe9rique'), + ), + migrations.AlterField( + model_name='file', + name='organization', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='files', to='ishtar_common.Organization', verbose_name='Organisation'), + ), + migrations.AlterField( + model_name='file', + name='permit_reference', + field=models.TextField(blank=True, null=True, verbose_name='R\xe9f\xe9rence du permis'), + ), + migrations.AlterField( + model_name='file', + name='permit_type', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.PermitType', verbose_name='Type de permis'), + ), + migrations.AlterField( + model_name='file', + name='planning_service', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='planning_service_files', to='ishtar_common.Organization', verbose_name='Service instructeur'), + ), + migrations.AlterField( + model_name='file', + name='postal_code', + field=models.CharField(blank=True, max_length=10, null=True, verbose_name='Adresse des terrains - code postal'), + ), + migrations.AlterField( + model_name='file', + name='protected_area', + field=models.NullBooleanField(verbose_name="Au sein d'un secteur sauvegard\xe9"), + ), + migrations.AlterField( + model_name='file', + name='raw_general_contractor', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Am\xe9nageur (brut)'), + ), + migrations.AlterField( + model_name='file', + name='raw_town_planning_service', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Service instructeur (brut)'), + ), + migrations.AlterField( + model_name='file', + name='reception_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de r\xe9ception'), + ), + migrations.AlterField( + model_name='file', + name='related_file', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.File', verbose_name='Dossier li\xe9 \xe0'), + ), + migrations.AlterField( + model_name='file', + name='requested_operation_type', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='ishtar_common.OperationType', verbose_name="Type d'op\xe9ration demand\xe9e"), + ), + migrations.AlterField( + model_name='file', + name='research_comment', + field=models.TextField(blank=True, null=True, verbose_name="Commentaire relatif \xe0 l'arch\xe9ologie programm\xe9e"), + ), + migrations.AlterField( + model_name='file', + name='responsible_town_planning_service', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='responsible_town_planning_service_files', to='ishtar_common.Person', verbose_name='Responsable pour le service instructeur'), + ), + migrations.AlterField( + model_name='file', + name='scientist', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='scientist', to='ishtar_common.Person', verbose_name='Responsable scientifique'), + ), + migrations.AlterField( + model_name='file', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='file', + name='total_developed_surface', + field=models.FloatField(blank=True, null=True, verbose_name='Surface totale am\xe9nag\xe9e (m2)'), + ), + migrations.AlterField( + model_name='file', + name='total_surface', + field=models.FloatField(blank=True, null=True, verbose_name='Surface totale des terrains (m2)'), + ), + migrations.AlterField( + model_name='file', + name='towns', + field=models.ManyToManyField(blank=True, related_name='file', to='ishtar_common.Town', verbose_name='Communes'), + ), + migrations.AlterField( + model_name='file', + name='year', + field=models.IntegerField(default=ishtar_common.utils.get_current_year, verbose_name='Ann\xe9e'), + ), + migrations.AlterField( + model_name='filetype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='filetype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='filetype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='filetype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='historicalfile', + name='address', + field=models.TextField(blank=True, null=True, verbose_name='Adresse des terrains'), + ), + migrations.AlterField( + model_name='historicalfile', + name='auto_external_id', + field=models.BooleanField(default=False, verbose_name="L'identifiant est attribu\xe9 automatiquement"), + ), + migrations.AlterField( + model_name='historicalfile', + name='cached_label', + field=models.TextField(blank=True, db_index=True, null=True, verbose_name='Nom en cache'), + ), + migrations.AlterField( + model_name='historicalfile', + name='classified_area', + field=models.NullBooleanField(verbose_name="Au sein d'un site class\xe9"), + ), + migrations.AlterField( + model_name='historicalfile', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='historicalfile', + name='creation_date', + field=models.DateField(blank=True, default=datetime.date.today, null=True, verbose_name='Date de cr\xe9ation'), + ), + migrations.AlterField( + model_name='historicalfile', + name='end_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de cl\xf4ture'), + ), + migrations.AlterField( + model_name='historicalfile', + name='external_id', + field=models.CharField(blank=True, max_length=120, null=True, verbose_name='Identifiant'), + ), + migrations.AlterField( + model_name='historicalfile', + name='imported_line', + field=models.TextField(blank=True, null=True, verbose_name='Ligne import\xe9e'), + ), + migrations.AlterField( + model_name='historicalfile', + name='instruction_deadline', + field=models.DateField(blank=True, null=True, verbose_name="Date limite d'instruction"), + ), + migrations.AlterField( + model_name='historicalfile', + name='internal_reference', + field=models.CharField(blank=True, max_length=60, null=True, verbose_name='R\xe9f\xe9rence interne'), + ), + migrations.AlterField( + model_name='historicalfile', + name='locality', + field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Lieu-dit'), + ), + migrations.AlterField( + model_name='historicalfile', + name='name', + field=models.TextField(blank=True, null=True, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='historicalfile', + name='numeric_reference', + field=models.IntegerField(blank=True, null=True, verbose_name='R\xe9f\xe9rence num\xe9rique'), + ), + migrations.AlterField( + model_name='historicalfile', + name='permit_reference', + field=models.TextField(blank=True, null=True, verbose_name='R\xe9f\xe9rence du permis'), + ), + migrations.AlterField( + model_name='historicalfile', + name='postal_code', + field=models.CharField(blank=True, max_length=10, null=True, verbose_name='Adresse des terrains - code postal'), + ), + migrations.AlterField( + model_name='historicalfile', + name='protected_area', + field=models.NullBooleanField(verbose_name="Au sein d'un secteur sauvegard\xe9"), + ), + migrations.AlterField( + model_name='historicalfile', + name='raw_general_contractor', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Am\xe9nageur (brut)'), + ), + migrations.AlterField( + model_name='historicalfile', + name='raw_town_planning_service', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Service instructeur (brut)'), + ), + migrations.AlterField( + model_name='historicalfile', + name='reception_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de r\xe9ception'), + ), + migrations.AlterField( + model_name='historicalfile', + name='research_comment', + field=models.TextField(blank=True, null=True, verbose_name="Commentaire relatif \xe0 l'arch\xe9ologie programm\xe9e"), + ), + migrations.AlterField( + model_name='historicalfile', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='historicalfile', + name='total_developed_surface', + field=models.FloatField(blank=True, null=True, verbose_name='Surface totale am\xe9nag\xe9e (m2)'), + ), + migrations.AlterField( + model_name='historicalfile', + name='total_surface', + field=models.FloatField(blank=True, null=True, verbose_name='Surface totale des terrains (m2)'), + ), + migrations.AlterField( + model_name='historicalfile', + name='year', + field=models.IntegerField(default=ishtar_common.utils.get_current_year, verbose_name='Ann\xe9e'), + ), + migrations.AlterField( + model_name='permittype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='permittype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='permittype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='permittype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='saisinetype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='saisinetype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='saisinetype', + name='delay', + field=models.IntegerField(default=30, verbose_name='D\xe9lai (en jours)'), + ), + migrations.AlterField( + model_name='saisinetype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='saisinetype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + ] diff --git a/archaeological_files/wizards.py b/archaeological_files/wizards.py index 106008192..c9b1ba9c2 100644 --- a/archaeological_files/wizards.py +++ b/archaeological_files/wizards.py @@ -43,8 +43,8 @@ class FileWizard(OperationWizard): town_step_keys = ['towns-'] wizard_done_window = reverse_lazy('show-file') - def get_extra_model(self, dct, form_list): - dct = super(FileWizard, self).get_extra_model(dct, form_list) + def get_extra_model(self, dct, m2m, form_list): + dct = super(FileWizard, self).get_extra_model(dct, m2m, form_list) if not dct.get('numeric_reference'): current_ref = models.File.objects.filter(year=dct['year'])\ .aggregate(Max('numeric_reference'))["numeric_reference__max"] diff --git a/archaeological_finds/admin.py b/archaeological_finds/admin.py index 1513c7eeb..45050eb2e 100644 --- a/archaeological_finds/admin.py +++ b/archaeological_finds/admin.py @@ -156,8 +156,13 @@ admin_site.register(models.CommunicabilityType, HierarchicalTypeAdmin) class TreatmentTypeAdmin(GeneralTypeAdmin): - list_display = HierarchicalTypeAdmin.list_display + [ - 'order', 'virtual', 'upstream_is_many', 'downstream_is_many'] + list_display = HierarchicalTypeAdmin.list_display[:-1] + ['order'] + \ + [HierarchicalTypeAdmin.list_display[-1]] + list_filter = [ + 'virtual', 'destructive', 'create_new_find', 'upstream_is_many', + 'downstream_is_many', 'destructive', 'change_reference_location', + 'change_current_location', 'restore_reference_location' + ] model = models.TreatmentType @@ -177,10 +182,19 @@ class ConservatoryStateAdmin(GeneralTypeAdmin): list_display = GeneralTypeAdmin.list_display + ['order'] +@admin.register(models.TreatmentFileType, site=admin_site) +class TreatmentFileType(GeneralTypeAdmin): + list_display = GeneralTypeAdmin.list_display + ["treatment_type"] + + +@admin.register(models.TreatmentState, site=admin_site) +class TreatmentState(GeneralTypeAdmin): + list_display = GeneralTypeAdmin.list_display[:-1] + ["order", "executed"] + + general_models = [ models.RemarkabilityType, models.IntegrityType, - models.TreatmentFileType, models.TreatmentState, models.BatchType, models.AlterationCauseType, models.AlterationType, models.TreatmentEmergencyType, models.ObjectTypeQualityType, models.MaterialTypeQualityType diff --git a/archaeological_finds/fixtures/initial_data-fr.json b/archaeological_finds/fixtures/initial_data-fr.json index a346da9ab..3125ab8da 100644 --- a/archaeological_finds/fixtures/initial_data-fr.json +++ b/archaeological_finds/fixtures/initial_data-fr.json @@ -890,6 +890,38 @@ } }, { + "model": "archaeological_finds.treatmenttype", + "fields": { + "label": "Pr\u00eat", + "txt_idx": "loan", + "comment": "Un pr\u00eat est un changement temporaire de contenant pour du mobilier.", + "available": true, + "parent": null, + "order": 10, + "virtual": false, + "destructive": false, + "create_new_find": false, + "upstream_is_many": false, + "downstream_is_many": false + } +}, +{ + "model": "archaeological_finds.treatmenttype", + "fields": { + "label": "Retour de pr\u00eat", + "txt_idx": "loan-return", + "comment": "Retour de mobilier dans son contenant de r\u00e9f\u00e9rence.", + "available": true, + "parent": null, + "order": 10, + "virtual": false, + "destructive": false, + "create_new_find": false, + "upstream_is_many": false, + "downstream_is_many": false + } +}, +{ "model": "archaeological_finds.treatmentstate", "fields": { "label": "Pr\u00e9vu", diff --git a/archaeological_finds/forms.py b/archaeological_finds/forms.py index 5ca8618d5..ae592d013 100644 --- a/archaeological_finds/forms.py +++ b/archaeological_finds/forms.py @@ -43,8 +43,8 @@ from archaeological_finds.forms_treatments import TreatmentSelect, \ AdministrativeActTreatmentFileForm, \ AdministrativeActTreatmentFileFormSelection, \ AdministrativeActTreatmentFileModifForm, \ - DashboardForm as DashboardTreatmentForm, \ - DashboardTreatmentFileForm, QAFindTreatmentForm + DashboardForm as DashboardTreatmentForm, N1TreatmentForm,\ + DashboardTreatmentFileForm, QAFindTreatmentForm, OneNTreatmentForm from archaeological_operations.models import Period, ArchaeologicalSite, \ RelationType as OpeRelationType from archaeological_operations.widgets import OAWidget @@ -53,10 +53,11 @@ from bootstrap_datepicker.widgets import DatePicker from ishtar_common import widgets from ishtar_common.forms import CustomForm, CustomFormSearch, FormSet, \ FloatField, reverse_lazy, TableSelect, get_now, FinalForm, \ - ManageOldType, FieldType, IshtarForm, FormHeader, QAForm, HistorySelect + ManageOldType, FieldType, IshtarForm, FormHeader, QAForm, HistorySelect, \ + PkWizardSearch from ishtar_common.forms_common import get_town_field from ishtar_common.models import valid_id, valid_ids, get_current_profile, \ - SpatialReferenceSystem, Area, OperationType + SpatialReferenceSystem, Area, OperationType, IshtarUser from ishtar_common.utils import convert_coordinates_to_point __all__ = [ @@ -71,17 +72,21 @@ __all__ = [ 'AdministrativeActTreatmentFormSelection', 'AdministrativeActTreatmentFileModifForm', 'DashboardTreatmentForm', 'DashboardTreatmentFileForm', - 'RecordFormSelection', 'FindForm', 'DateForm', 'DatingFormSet', - 'PreservationForm', 'FindBasketFormSelection', 'FindBasketForm', - 'FindSelect', 'FindFormSelection', 'FindFormSelectionWarehouseModule', - 'MultipleFindFormSelection', 'MultipleFindFormSelectionWarehouseModule', - 'FindMultipleFormSelection', 'check_form', 'check_exist', 'check_not_exist', + 'RecordFormSelection', 'FindForm', 'SimpleFindForm', 'DateForm', + 'DatingFormSet', 'PreservationForm', 'FindBasketFormSelection', + 'FindBasketForWriteFormSelection', + 'FindBasketForm', 'FindSelect', 'FindFormSelection', + 'FindFormSelectionWarehouseModule', 'MultipleFindFormSelection', + 'MultipleFindFormSelectionWarehouseModule', 'FindMultipleFormSelection', + 'check_form', 'check_exist', 'check_not_exist', 'check_value', 'check_type_field', 'check_type_not_field', 'check_treatment', 'ResultFindForm', 'ResultFindFormSet', 'FindDeletionForm', 'UpstreamFindFormSelection', 'NewFindBasketForm', - 'SelectFindBasketForm', 'DeleteFindBasketForm', 'FindBasketAddItemForm', + 'SelectFindBasketForm', 'FindBasketAddItemForm', 'QAFindFormSingle', 'QAFindFormMulti', 'QAFindBasketForm', - 'QAFindTreatmentForm' + 'QAFindTreatmentForm', 'QAFindbasketDuplicateForm', + 'N1TreatmentForm', 'OneNTreatmentForm', 'ResultingFindForm', + 'ResultingFindsForm', 'SingleUpstreamFindFormSelection' ] logger = logging.getLogger(__name__) @@ -121,23 +126,33 @@ class RecordFormSelection(CustomForm, forms.Form): cr.operation.pk) -class FindForm(CustomForm, ManageOldType): +class BaseFindForm(CustomForm, ManageOldType): + """ + Base find form with no field related to base_find + """ file_upload = True form_label = _("Find") - form_admin_name = _(u"Find - 020 - General") - form_slug = "find-020-general" - base_models = ['get_first_base_find', 'object_type', 'material_type', - 'communicabilitie'] + form_admin_name = _(u"Simple find - 020 - General") + form_slug = "simplefind-020-general" + base_models = ['object_type', 'material_type', 'communicabilitie'] associated_models = { 'material_type': models.MaterialType, 'object_type': models.ObjectType, 'communicabilitie': models.CommunicabilityType, - 'get_first_base_find__batch': models.BatchType, - 'get_first_base_find__spatial_reference_system': SpatialReferenceSystem, 'material_type_quality': models.MaterialTypeQualityType, 'object_type_quality': models.ObjectTypeQualityType, 'checked_type': models.CheckedType, } + field_order = [ + 'label', 'denomination', 'previous_id', 'museum_id', 'seal_number', + 'mark', 'description', 'is_complete', 'material_type', + 'material_type_quality', 'object_type', 'object_type_quality', + 'find_number', 'min_number_of_individuals', 'inscription', + 'manufacturing_place', 'communicabilitie', 'comment', 'dating_comment', + 'length', 'width', 'height', 'thickness', 'diameter', 'circumference', + 'volume', 'weight', 'clutter_long_side', 'clutter_short_side', + 'clutter_height', 'dimensions_comment', 'checked_type', 'check_date' + ] HEADERS = {} HEADERS['label'] = FormHeader(_(u"Identification")) @@ -146,8 +161,6 @@ class FindForm(CustomForm, ManageOldType): validators=[validators.MaxLengthValidator(60)]) denomination = forms.CharField(label=_(u"Denomination"), required=False) previous_id = forms.CharField(label=_("Previous ID"), required=False) - get_first_base_find__excavation_id = forms.CharField( - label=_(u"Excavation ID"), required=False) museum_id = forms.CharField(label=_(u"Museum ID"), required=False) seal_number = forms.CharField(label=_(u"Seal number"), required=False) mark = forms.CharField(label=_(u"Mark"), required=False) @@ -155,14 +168,6 @@ class FindForm(CustomForm, ManageOldType): HEADERS['description'] = FormHeader(_(u"Description")) description = forms.CharField(label=_(u"Description"), widget=forms.Textarea, required=False) - get_first_base_find__discovery_date = forms.DateField( - label=_(u"Discovery date (exact or TPQ)"), widget=DatePicker, - required=False) - get_first_base_find__discovery_date_taq = forms.DateField( - label=_(u"Discovery date (TAQ)"), widget=DatePicker, required=False) - get_first_base_find__batch = forms.ChoiceField( - label=_(u"Batch/object"), choices=[], - required=False) is_complete = forms.NullBooleanField(label=_(u"Is complete?"), required=False) material_type = widgets.Select2MultipleField( @@ -194,24 +199,115 @@ class FindForm(CustomForm, ManageOldType): label=_(u"Comment on dating"), required=False, widget=forms.Textarea) HEADERS['length'] = FormHeader(_(u"Dimensions")) - length = FloatField(label=_(u"Length (cm)"), required=False) - width = FloatField(label=_(u"Width (cm)"), required=False) - height = FloatField(label=_(u"Height (cm)"), required=False) - diameter = FloatField(label=_(u"Diameter (cm)"), required=False) - thickness = FloatField(label=_(u"Thickness (cm)"), required=False) + length = FloatField(label=_(u"Length (cm)"), + widget=widgets.CentimeterMeterWidget, required=False) + width = FloatField(label=_(u"Width (cm)"), required=False, + widget=widgets.CentimeterMeterWidget) + height = FloatField(label=_(u"Height (cm)"), + widget=widgets.CentimeterMeterWidget, required=False) + thickness = FloatField(label=_(u"Thickness (cm)"), + widget=widgets.CentimeterMeterWidget, required=False) + diameter = FloatField(label=_(u"Diameter (cm)"), + widget=widgets.CentimeterMeterWidget, required=False) + circumference = FloatField( + label=_(u"Circumference (cm)"), widget=widgets.CentimeterMeterWidget, + required=False) volume = FloatField(label=_(u"Volume (l)"), required=False) - weight = FloatField(label=_(u"Weight (g)"), required=False) + weight = FloatField(label=_(u"Weight (g)"), + widget=widgets.GramKilogramWidget, required=False) clutter_long_side = FloatField( - label=_(u"Clutter long side (cm)"), required=False) + label=_(u"Clutter long side (cm)"), + widget=widgets.CentimeterMeterWidget, required=False) clutter_short_side = FloatField( - label=_(u"Clutter short side (cm)"), required=False) + label=_(u"Clutter short side (cm)"), + widget=widgets.CentimeterMeterWidget, required=False) clutter_height = FloatField( - label=_(u"Clutter height (cm)"), required=False) + label=_(u"Clutter height (cm)"), + widget=widgets.CentimeterMeterWidget, required=False) dimensions_comment = forms.CharField( label=_(u"Dimensions comment"), required=False, widget=forms.Textarea) - HEADERS['get_first_base_find__x'] = FormHeader( - _(u"Coordinates")) + HEADERS['checked_type'] = FormHeader(_(u"Sheet")) + checked_type = forms.ChoiceField(label=_(u"Check"), required=False) + check_date = forms.DateField( + initial=get_now, label=_(u"Check date"), widget=DatePicker) + + TYPES = [ + FieldType('material_type', models.MaterialType, is_multiple=True), + FieldType('material_type_quality', models.MaterialTypeQualityType), + FieldType('object_type', models.ObjectType, is_multiple=True), + FieldType('object_type_quality', models.ObjectTypeQualityType), + FieldType('communicabilitie', models.CommunicabilityType, + is_multiple=True), + FieldType('checked_type', models.CheckedType, is_multiple=True), + ] + + def __init__(self, *args, **kwargs): + context_record = kwargs.pop('context_record') + super(BaseFindForm, self).__init__(*args, **kwargs) + if not context_record or \ + not context_record.operation.operation_type.judiciary: + self.fields.pop('seal_number') + + def clean(self): + clutter_long_side = self.cleaned_data.get('clutter_long_side', None) + clutter_short_side = self.cleaned_data.get('clutter_short_side', None) + + if clutter_long_side and clutter_short_side and \ + clutter_short_side > clutter_long_side: + raise forms.ValidationError( + unicode(_( + u"Clutter: short side cannot be bigger than the long side." + )) + ) + return self.cleaned_data + + +class FindForm(BaseFindForm): + file_upload = True + form_label = _("Find") + form_admin_name = _(u"Find - 020 - General") + form_slug = "find-020-general" + base_models = ['get_first_base_find'] + BaseFindForm.base_models + associated_models = BaseFindForm.associated_models.copy() + associated_models.update({ + 'get_first_base_find__batch': models.BatchType, + 'get_first_base_find__spatial_reference_system': SpatialReferenceSystem, + }) + field_order = [ + 'label', 'denomination', 'previous_id', + 'get_first_base_find__excavation_id', 'museum_id', 'seal_number', + 'mark', 'description', 'get_first_base_find__discovery_date', + 'get_first_base_find__discovery_date_taq', 'get_first_base_find__batch', + 'is_complete', 'material_type', 'material_type_quality', 'object_type', + 'object_type_quality', 'find_number', 'min_number_of_individuals', + 'inscription', 'manufacturing_place', 'communicabilitie', 'comment', + 'dating_comment', 'length', 'width', 'height', 'thickness', 'diameter', + 'circumference', + 'volume', 'weight', 'clutter_long_side', 'clutter_short_side', + 'clutter_height', 'dimensions_comment', 'get_first_base_find__x', + 'get_first_base_find__estimated_error_x', 'get_first_base_find__y', + 'get_first_base_find__estimated_error_y', 'get_first_base_find__z', + 'get_first_base_find__estimated_error_z', + 'get_first_base_find__spatial_reference_system', + 'get_first_base_find__topographic_localisation', 'checked_type', + 'check_date', + ] + + HEADERS = BaseFindForm.HEADERS.copy() + get_first_base_find__excavation_id = forms.CharField( + label=_(u"Excavation ID"), required=False) + + get_first_base_find__discovery_date = forms.DateField( + label=_(u"Discovery date (exact or TPQ)"), widget=DatePicker, + required=False) + get_first_base_find__discovery_date_taq = forms.DateField( + label=_(u"Discovery date (TAQ)"), widget=DatePicker, required=False) + get_first_base_find__batch = forms.ChoiceField( + label=_(u"Batch/object"), choices=[], + required=False) + + HEADERS['get_first_base_find__x'] = FormHeader(_(u"Coordinates")) get_first_base_find__x = forms.FloatField(label=_(u"X"), required=False) get_first_base_find__estimated_error_x = \ forms.FloatField(label=_(u"Estimated error for X"), required=False) @@ -229,22 +325,10 @@ class FindForm(CustomForm, ManageOldType): required=False, max_length=120 ) - HEADERS['checked_type'] = FormHeader(_(u"Sheet")) - checked_type = forms.ChoiceField(label=_(u"Check"), required=False) - check_date = forms.DateField( - initial=get_now, label=_(u"Check date"), widget=DatePicker) - - TYPES = [ - FieldType('material_type', models.MaterialType, is_multiple=True), - FieldType('material_type_quality', models.MaterialTypeQualityType), - FieldType('object_type', models.ObjectType, is_multiple=True), - FieldType('object_type_quality', models.ObjectTypeQualityType), - FieldType('communicabilitie', models.CommunicabilityType, - is_multiple=True), + TYPES = BaseFindForm.TYPES + [ FieldType('get_first_base_find__batch', models.BatchType), FieldType('get_first_base_find__spatial_reference_system', SpatialReferenceSystem), - FieldType('checked_type', models.CheckedType, is_multiple=True), ] PROFILE_FILTER = { 'mapping': [ @@ -256,14 +340,8 @@ class FindForm(CustomForm, ManageOldType): ], } - def __init__(self, *args, **kwargs): - context_record = kwargs.pop('context_record') - super(FindForm, self).__init__(*args, **kwargs) - if not context_record or \ - not context_record.operation.operation_type.judiciary: - self.fields.pop('seal_number') - def clean(self): + self.cleaned_data = super(FindForm, self).clean() taq = self.cleaned_data.get('get_first_base_find__discovery_date_taq', None) tpq = self.cleaned_data.get('get_first_base_find__discovery_date', @@ -280,17 +358,6 @@ class FindForm(CustomForm, ManageOldType): unicode(_(u"Discovery date: TAQ date must be older than TPQ " u"date."))) - clutter_long_side = self.cleaned_data.get('clutter_long_side', None) - clutter_short_side = self.cleaned_data.get('clutter_short_side', None) - - if clutter_long_side and clutter_short_side and \ - clutter_short_side > clutter_long_side: - raise forms.ValidationError( - unicode(_( - u"Clutter: short side cannot be bigger than the long side." - )) - ) - if not get_current_profile().mapping: return self.cleaned_data x = self.cleaned_data.get('get_first_base_find__x', None) @@ -318,6 +385,154 @@ class FindForm(CustomForm, ManageOldType): return self.cleaned_data +class SimpleFindForm(BaseFindForm): + def __init__(self, *args, **kwargs): + self.base_finds = kwargs.pop('base_finds') + super(SimpleFindForm, self).__init__(*args, **kwargs) + + +class ResultingFindForm(CustomForm, ManageOldType): + file_upload = True + form_label = _("Resulting find") + form_admin_name = _(u"Treatment n-1 - 030 - Resulting find") + form_slug = "treatmentn1-030-resulting-find" + + associated_models = { + 'resulting_material_type': models.MaterialType, + 'resulting_object_type': models.ObjectType, + 'resulting_communicabilitie': models.CommunicabilityType, + 'resulting_material_type_quality': models.MaterialTypeQualityType, + 'resulting_object_type_quality': models.ObjectTypeQualityType, + 'resulting_checked_type': models.CheckedType, + } + HEADERS = {} + HEADERS['resulting_label'] = FormHeader(_(u"Identification")) + + resulting_label = forms.CharField( + label=_(u"Free ID"), + validators=[validators.MaxLengthValidator(60)]) + resulting_denomination = forms.CharField(label=_(u"Denomination"), + required=False) + + HEADERS['resulting_description'] = FormHeader(_(u"Description")) + resulting_description = forms.CharField( + label=_(u"Description"), widget=forms.Textarea, required=False) + resulting_is_complete = forms.NullBooleanField( + label=_(u"Is complete?"), required=False) + resulting_material_type = widgets.Select2MultipleField( + label=_(u"Material types"), required=False + ) + resulting_material_type_quality = forms.ChoiceField( + label=_(u"Material type quality"), required=False, choices=[]) + resulting_object_type = widgets.Select2MultipleField( + label=_(u"Object types"), required=False, + ) + resulting_object_type_quality = forms.ChoiceField( + label=_(u"Object type quality"), required=False, choices=[]) + resulting_find_number = forms.IntegerField( + label=_(u"Find number"), required=False) + resulting_min_number_of_individuals = forms.IntegerField( + label=_(u"Minimum number of individuals (MNI)"), required=False) + + resulting_decoration = forms.CharField( + label=_(u"Decoration"), widget=forms.Textarea, required=False) + resulting_inscription = forms.CharField( + label=_(u"Inscription"), widget=forms.Textarea, required=False) + resulting_manufacturing_place = forms.CharField( + label=_(u"Manufacturing place"), required=False) + resulting_communicabilitie = widgets.Select2MultipleField( + label=_(u"Communicability"), required=False + ) + resulting_comment = forms.CharField(label=_(u"Comment"), required=False, + widget=forms.Textarea) + resulting_dating_comment = forms.CharField( + label=_(u"Comment on dating"), required=False, widget=forms.Textarea) + + HEADERS['resulting_length'] = FormHeader(_(u"Dimensions")) + resulting_length = FloatField(label=_(u"Length (cm)"), required=False) + resulting_width = FloatField(label=_(u"Width (cm)"), required=False) + resulting_height = FloatField(label=_(u"Height (cm)"), required=False) + resulting_diameter = FloatField(label=_(u"Diameter (cm)"), required=False) + resulting_circumference = FloatField(label=_(u"Circumference (cm)"), + required=False) + resulting_thickness = FloatField(label=_(u"Thickness (cm)"), required=False) + resulting_volume = FloatField(label=_(u"Volume (l)"), required=False) + resulting_weight = FloatField(label=_(u"Weight (g)"), required=False) + resulting_clutter_long_side = FloatField( + label=_(u"Clutter long side (cm)"), required=False) + resulting_clutter_short_side = FloatField( + label=_(u"Clutter short side (cm)"), required=False) + resulting_clutter_height = FloatField( + label=_(u"Clutter height (cm)"), required=False) + resulting_dimensions_comment = forms.CharField( + label=_(u"Dimensions comment"), required=False, widget=forms.Textarea) + + HEADERS['resulting_checked_type'] = FormHeader(_(u"Sheet")) + resulting_checked_type = forms.ChoiceField(label=_(u"Check"), + required=False) + resulting_check_date = forms.DateField( + initial=get_now, label=_(u"Check date"), widget=DatePicker) + + TYPES = [ + FieldType('resulting_material_type', models.MaterialType, + is_multiple=True), + FieldType('resulting_material_type_quality', + models.MaterialTypeQualityType), + FieldType('resulting_object_type', models.ObjectType, + is_multiple=True), + FieldType('resulting_object_type_quality', + models.ObjectTypeQualityType), + FieldType('resulting_communicabilitie', models.CommunicabilityType, + is_multiple=True), + FieldType('resulting_checked_type', models.CheckedType, + is_multiple=True), + ] + + +class ResultingFindsForm(CustomForm, ManageOldType): + form_label = _("Resulting finds") + form_admin_name = _(u"Treatment 1-n - 030 - Resulting finds") + form_slug = "treatment1n-030-resulting-finds" + associated_models = {} + + resultings_number = forms.IntegerField( + label=_(u"Number of resulting finds"), + min_value=1 + ) + resultings_label = forms.CharField( + label=_(u"Prefix label for resulting finds"), + validators=[validators.MaxLengthValidator(200)], + help_text=_( + u'E.g.: with a prefix "item-", each resulting item will be named ' + u'"item-1", "item-2", "item-3"') + ) + resultings_start_number = forms.IntegerField( + label=_(u"Numbering starting from"), initial=1, min_value=0 + ) + resultings_basket_name = forms.CharField( + label=_(u"Name of the new basket containing the resulting items"), + max_length=200 + ) + + def __init__(self, *args, **kwargs): + self.user = None + if 'user' in kwargs: + self.user = kwargs.pop('user') + if hasattr(self.user, 'ishtaruser'): + self.user = self.user.ishtaruser + super(ResultingFindsForm, self).__init__(*args, **kwargs) + if not self.user: + return + + def clean(self): + q = models.FindBasket.objects.filter( + user=self.user, label=self.cleaned_data['resultings_basket_name']) + if q.count(): + raise forms.ValidationError(_(u"A basket with this label already " + u"exists.")) + return self.cleaned_data + + class QAFindFormMulti(QAForm): form_admin_name = _(u"Find - Quick action - Modify") form_slug = "find-quickaction-modify" @@ -333,19 +548,20 @@ class QAFindFormMulti(QAForm): MULTI = True REPLACE_FIELDS = [ - 'qa_ue', 'qa_manufacturing_place', 'qa_checked_type', 'qa_check_date' + 'qa_denomination', 'qa_ue', 'qa_manufacturing_place', 'qa_checked_type', + 'qa_check_date' ] HEADERS = { 'qa_ue': FormHeader(_(u"Context record")), - 'qa_label': FormHeader(_(u"Identification")), + 'qa_denomination': FormHeader(_(u"Identification")), 'qa_description': FormHeader(_(u"Description")), 'qa_checked_type': FormHeader(_(u"Sheet")), 'qa_period': FormHeader(_(u"Datation")), } SINGLE_FIELDS = [ - 'qa_label', 'qa_denomination', 'qa_previous_id', + 'qa_label', 'qa_previous_id', 'qa_get_first_base_find__excavation_id', 'qa_museum_id', 'qa_seal_number', 'qa_mark' ] @@ -494,6 +710,35 @@ class QAFindBasketForm(IshtarForm): basket.items.add(item) +class QAFindbasketDuplicateForm(IshtarForm): + label = forms.CharField(label="", max_length=None, required=True) + + def __init__(self, *args, **kwargs): + self.user = None + if 'user' in kwargs: + self.user = kwargs.pop('user') + if hasattr(self.user, 'ishtaruser'): + self.user = self.user.ishtaruser + self.basket = kwargs.pop('items')[0] + super(QAFindbasketDuplicateForm, self).__init__(*args, **kwargs) + self.fields['label'].initial = self.basket.label + unicode( + _(u" - duplicate")) + + def clean(self): + label = self.cleaned_data['label'].strip() + if not label: + raise forms.ValidationError(_(u"A label is required.")) + if models.FindBasket.objects.filter(user=self.user, + label=label).count(): + raise forms.ValidationError(_(u"A basket with this label already " + u"exists.")) + return self.cleaned_data + + def save(self): + self.basket.duplicate(label=self.cleaned_data['label'], + ishtaruser=self.user) + + class PreservationForm(CustomForm, ManageOldType): form_label = _("Preservation") form_admin_name = _(u"Find - 030 - Preservation") @@ -654,6 +899,10 @@ class FindSelect(HistorySelect): label=_(u"Batch/object"), choices=[]) checked_type = forms.ChoiceField(label=_("Check")) documents__image__isnull = forms.NullBooleanField(label=_(u"Has an image?")) + loan = forms.NullBooleanField(label=_(u"Loan?")) + treatments_file_end_date = forms.DateField( + label=_(u"Treatment file end date before"), widget=DatePicker + ) TYPES = [ FieldType('datings__period', Period), @@ -683,7 +932,8 @@ class FindSelect(HistorySelect): if self.current_user: self.fields['basket'].choices += [ (b.pk, b.label) for b in models.FindBasket.objects.filter( - user=self.current_user).all()] + models.FindBasket.get_query_owns(self.current_user) + ).all()] def get_input_ids(self): ids = super(FindSelect, self).get_input_ids() @@ -699,20 +949,36 @@ class FindSelect(HistorySelect): class FindSelectWarehouseModule(FindSelect): + container_ref__location = forms.IntegerField( + label=_(u"Reference container - Warehouse (location)"), + widget=widgets.JQueryAutoComplete( + reverse_lazy('autocomplete-warehouse'), + associated_model=Warehouse), + validators=[valid_id(Warehouse)]) + container_ref__responsible = forms.IntegerField( + label=_(u"Reference container - Warehouse (responsible)"), + widget=widgets.JQueryAutoComplete( + reverse_lazy('autocomplete-warehouse'), + associated_model=Warehouse), + validators=[valid_id(Warehouse)]) + container_ref__index = forms.IntegerField( + label=_(u"Reference container ID")) + container_ref__reference = forms.CharField( + label=_(u"Reference container ref.")) container__location = forms.IntegerField( - label=_(u"Warehouse (location)"), + label=_(u"Current container - Warehouse (location)"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-warehouse'), associated_model=Warehouse), validators=[valid_id(Warehouse)]) container__responsible = forms.IntegerField( - label=_(u"Warehouse (responsible)"), + label=_(u"Current container - Warehouse (responsible)"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-warehouse'), associated_model=Warehouse), validators=[valid_id(Warehouse)]) - container__index = forms.IntegerField(label=_(u"Container ID")) - container__reference = forms.CharField(label=_(u"Container ref.")) + container__index = forms.IntegerField(label=_(u"Current container ID")) + container__reference = forms.CharField(label=_(u"Current container ref.")) class FindFormSelection(CustomFormSearch): @@ -725,7 +991,7 @@ class FindFormSelection(CustomFormSearch): label="", required=False, widget=widgets.DataTable( reverse_lazy('get-find'), - FindSelect, models.Find, + FindSelect, models.Find, source_full=reverse_lazy('get-find-full')), validators=[valid_id(models.Find)]) @@ -910,8 +1176,19 @@ class FindDeletionForm(FinalForm): confirm_end_msg = _(u"Would you like to delete this find?") -class UpstreamFindFormSelection(FindFormSelection): - form_label = _(u"Upstream find") +class UpstreamFindFormSelection(PkWizardSearch, FindFormSelection): + form_label = _(u"Upstream finds") + current_model = models.Find + pk_key = 'resulting_pk' + + pk = forms.CharField( + label="", required=False, + widget=widgets.DataTable( + reverse_lazy('get-find'), + FindSelect, current_model, + multiple_select=True, + source_full=reverse_lazy('get-find-full')), + validators=[valid_ids(current_model)]) def __init__(self, *args, **kwargs): super(UpstreamFindFormSelection, self).__init__(*args, **kwargs) @@ -919,6 +1196,17 @@ class UpstreamFindFormSelection(FindFormSelection): self.fields['resulting_pk'] = self.fields.pop('pk') +class SingleUpstreamFindFormSelection(UpstreamFindFormSelection): + current_model = models.Find + pk = forms.CharField( + label="", required=False, + widget=widgets.DataTable( + reverse_lazy('get-find'), + FindSelect, current_model, + source_full=reverse_lazy('get-find-full')), + validators=[valid_ids(current_model)]) + + class FindBasketSelect(CustomForm, TableSelect): _model = models.FindBasket @@ -947,19 +1235,57 @@ class FindBasketFormSelection(CustomFormSearch): validators=[valid_id(models.FindBasket)]) +class FindBasketForWriteFormSelection(CustomFormSearch): + SEARCH_AND_SELECT = True + form_label = _("Basket search") + associated_models = {'pk': models.FindBasket} + currents = {'pk': models.FindBasket} + + pk = forms.IntegerField( + label="", required=False, + widget=widgets.DataTable( + reverse_lazy('get-findbasket-write'), + FindBasketSelect, models.FindBasket, + ), + validators=[valid_id(models.FindBasket)]) + + class FindBasketForm(IshtarForm): form_label = _(u"Find basket") + associated_models = {"shared_with": IshtarUser, + "shared_write_with": IshtarUser} label = forms.CharField( label=_(u"Label"), validators=[validators.MaxLengthValidator(1000)]) comment = forms.CharField(label=_(u"Comment"), widget=forms.Textarea, required=False) + shared_with = widgets.Select2MultipleField( + model=IshtarUser, remote=True, + label=_(u"Shared (read) with"), + required=False, long_widget=True + ) + shared_write_with = widgets.Select2MultipleField( + model=IshtarUser, remote=True, + label=_(u"Shared (read/edit) with"), + required=False, long_widget=True + ) -class NewFindBasketForm(forms.ModelForm): +class NewFindBasketForm(forms.ModelForm, IshtarForm): + shared_with = widgets.Select2MultipleField( + model=IshtarUser, remote=True, + label=_(u"Shared (read) with"), + required=False, long_widget=True + ) + shared_write_with = widgets.Select2MultipleField( + model=IshtarUser, remote=True, + label=_(u"Shared (read/edit) with"), + required=False, long_widget=True + ) + class Meta: model = models.FindBasket - fields = ('label', 'comment') + fields = ('label', 'comment', 'shared_with', 'shared_write_with') def __init__(self, *args, **kwargs): self.user = kwargs.pop('user') @@ -995,22 +1321,15 @@ class SelectFindBasketForm(IshtarForm): super(SelectFindBasketForm, self).__init__(*args, **kwargs) if not self.user: return - self.fields['basket'].choices = [('', '--')] + [ - (b.pk, unicode(b)) - for b in models.FindBasket.objects.filter( - Q(user=self.user) | Q(shared_with=self.user) - )] + self.fields['basket'].choices = self.get_basket_choices() - -class DeleteFindBasketForm(SelectFindBasketForm): - def save(self): - try: - models.FindBasket.objects.get(pk=self.cleaned_data['basket'], - user=self.user).delete() - except models.FindBasket.DoesNotExist: - # something strange... TODO: log it - pass - return + def get_basket_choices(self): + return [('', u'--')] + [ + (str(b.pk), unicode(b)) + for b in models.FindBasket.objects.filter( + Q(user=self.user) | Q(shared_write_with=self.user) + ) + ] class FindBasketAddItemForm(forms.Form): @@ -1020,8 +1339,8 @@ class FindBasketAddItemForm(forms.Form): def save(self, user): try: basket = models.FindBasket.objects.filter( - Q(user=user) | Q(shared_with=user) - ).get(pk=self.cleaned_data['basket_id']) + Q(user=user) | Q(shared_with=user) | Q(shared_write_with=user) + ).distinct().get(pk=self.cleaned_data['basket_id']) item = models.Find.objects.get( pk=self.cleaned_data['item_id']) except models.FindBasket.DoesNotExist or\ diff --git a/archaeological_finds/forms_treatments.py b/archaeological_finds/forms_treatments.py index 7ada0f4bc..10c4527ef 100644 --- a/archaeological_finds/forms_treatments.py +++ b/archaeological_finds/forms_treatments.py @@ -23,10 +23,9 @@ from collections import OrderedDict from django import forms from django.core import validators -from django.forms.formsets import formset_factory from django.utils.translation import ugettext_lazy as _ -import models +from archaeological_finds import models from archaeological_operations.forms import AdministrativeActForm, \ AdministrativeActOpeFormSelection, AdministrativeActModifForm from archaeological_operations.models import ActType, AdministrativeAct @@ -80,7 +79,9 @@ class TreatmentFormSelection(forms.Form): class BaseTreatmentForm(CustomForm, ManageOldType): - form_label = _(u"Base treatment") + UPSTREAM_IS_MANY = False + DOWNSTREAM_IS_MANY = False + form_label = _(u"Treatment") form_admin_name = _(u"Treatment - 020 - General") form_slug = "treatment-020-general" base_models = ['treatment_type'] @@ -94,20 +95,20 @@ class BaseTreatmentForm(CustomForm, ManageOldType): file_upload = True need_user_for_initialization = True - label = forms.CharField(label=_(u"Label"), - max_length=200, required=False) - other_reference = forms.CharField( - label=_(u"Other ref."), max_length=200, required=False) + treatment_type = widgets.Select2MultipleField( + label=_(u"Treatment type"), choices=[], + widget=widgets.CheckboxSelectMultiple) + treatment_state = forms.ChoiceField(label=_(u"State"), choices=[]) year = forms.IntegerField(label=_("Year"), initial=lambda: datetime.datetime.now().year, validators=[validators.MinValueValidator(1000), validators.MaxValueValidator(2100)]) - treatment_type = forms.MultipleChoiceField( - label=_(u"Treatment type"), choices=[], - widget=widgets.CheckboxSelectMultiple) - treatment_state = forms.ChoiceField(label=_(u"State"), - choices=[], required=False) - target_is_basket = forms.NullBooleanField(label=_(u"Target")) + location = forms.IntegerField( + label=_(u"Location"), + widget=widgets.JQueryAutoComplete( + reverse_lazy('autocomplete-warehouse'), associated_model=Warehouse, + new=True), + validators=[valid_id(Warehouse)]) person = forms.IntegerField( label=_(u"Responsible"), widget=widgets.JQueryAutoComplete( @@ -120,30 +121,29 @@ class BaseTreatmentForm(CustomForm, ManageOldType): reverse_lazy('autocomplete-organization'), associated_model=Organization, new=True), validators=[valid_id(Organization)], required=False) - location = forms.IntegerField( - label=_(u"Location"), - widget=widgets.JQueryAutoComplete( - reverse_lazy('autocomplete-warehouse'), associated_model=Warehouse, - new=True), - validators=[valid_id(Warehouse)]) + label = forms.CharField(label=_(u"Label"), + max_length=200, required=False) + other_reference = forms.CharField( + label=_(u"Other ref."), max_length=200, required=False) + # external_id = forms.CharField( + # label=_(u"External ref."), max_length=200, required=False) + start_date = forms.DateField(label=_(u"Start date"), required=False, + widget=DatePicker, initial=datetime.date.today) + end_date = forms.DateField(label=_(u"Closing date"), required=False, + widget=DatePicker) container = forms.IntegerField( - label=_(u"Container (relevant for packaging)"), + label=_(u"Destination container (relevant for treatment that change " + u"location)"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-container'), associated_model=Container, new=True), validators=[valid_id(Container)], required=False) - external_id = forms.CharField( - label=_(u"External ref."), max_length=200, required=False) goal = forms.CharField(label=_(u"Goal"), widget=forms.Textarea, required=False) description = forms.CharField(label=_(u"Description"), widget=forms.Textarea, required=False) comment = forms.CharField(label=_(u"Comment"), widget=forms.Textarea, required=False) - start_date = forms.DateField(label=_(u"Start date"), required=False, - widget=DatePicker) - end_date = forms.DateField(label=_(u"Closing date"), required=False, - widget=DatePicker) estimated_cost = forms.FloatField(label=_(u"Estimated cost ({currency})"), required=False) quoted_cost = forms.FloatField(label=_(u"Quoted cost ({currency})"), @@ -152,12 +152,15 @@ class BaseTreatmentForm(CustomForm, ManageOldType): required=False) insurance_cost = forms.FloatField(label=_(u"Insurance cost ({currency})"), required=False) + executed = forms.BooleanField(required=False, disabled=True, + widget=forms.HiddenInput) TYPES = [ - FieldType('treatment_state', models.TreatmentState), - FieldType('treatment_type', models.TreatmentType, is_multiple=True, - extra_args={'dct': {'upstream_is_many': False, - 'downstream_is_many': False}}) + FieldType('treatment_state', models.TreatmentState, True), + FieldType( + 'treatment_type', models.TreatmentType, is_multiple=True, + extra_args={'dct': {'upstream_is_many': False, + 'downstream_is_many': False}}) ] def __init__(self, *args, **kwargs): @@ -170,14 +173,20 @@ class BaseTreatmentForm(CustomForm, ManageOldType): self.fields[key].label = self.fields[key].label.format( currency=currency) + initial = kwargs.get('initial', {}) + if initial.get('executed', False): + self.fields['treatment_state'].choices = \ + models.TreatmentState.get_types(empty_first=False, + dct={'executed': True}) + q = Person.objects.filter(ishtaruser__pk=user.pk) if q.count(): person = q.all()[0] self.fields['person'].initial = person.pk if person.attached_to: self.fields['organization'].initial = person.attached_to.pk - self.fields['target_is_basket'].widget.choices = \ - ((False, _(u"Single find")), (True, _(u"Basket"))) + # self.fields['target_is_basket'].widget.choices = \ + # ((False, _(u"Single find")), (True, _(u"Basket"))) # TODO """ self.fields['basket'].required = False @@ -194,38 +203,97 @@ class BaseTreatmentForm(CustomForm, ManageOldType): def clean(self, *args, **kwargs): data = self.cleaned_data - packaging = models.TreatmentType.get_cache('packaging') - if not packaging: - logger.warning("No 'packaging' treatment type defined") - return + + try: + treatment_types = [ + models.TreatmentType.objects.get( + pk=pk, available=True, + upstream_is_many=self.UPSTREAM_IS_MANY, + downstream_is_many=self.DOWNSTREAM_IS_MANY) + for pk in data.get('treatment_type', [])] + except models.TreatmentType.DoesNotExist: + raise forms.ValidationError(_(u"Unknow treatment type")) + + + change_current_location = [ + unicode(tp) for tp in treatment_types + if tp.change_current_location + ] + restore_reference_location = [ + unicode(tp) for tp in treatment_types + if tp.restore_reference_location + ] + change_ref_location = [ + unicode(tp) for tp in treatment_types + if tp.change_reference_location + ] + + if (change_ref_location or change_current_location + ) and restore_reference_location: + if change_ref_location: + raise forms.ValidationError( + unicode( + _(u"{} is not compatible with {} " + u"treatment(s).")).format( + u' ; '.join(restore_reference_location), + u' ; '.join(change_ref_location), + ) + ) + else: + raise forms.ValidationError( + unicode( + _(u"{} is not compatible with {} " + u"treatment(s).")).format( + u' ; '.join(restore_reference_location), + u' ; '.join(change_current_location) + ) + ) + if data.get('container', None) \ - and str(packaging.pk) not in data.get('treatment_type', []): + and not change_ref_location\ + and not change_current_location: raise forms.ValidationError( - _(u"The container field is attached to the treatment. If " - u"no packaging treatment is done it is not relevant.")) - if not data.get('container', None) \ - and str(packaging.pk) in data.get('treatment_type', []): + _(u"The container field is attached to the treatment but " + u"no treatment with container change is defined.")) + if not data.get('container', None) and ( + change_ref_location or change_current_location): raise forms.ValidationError( - _(u"If a packaging treatment is done, the container field " - u"must be filled.")) + _(u"A treatment with location change is defined, the container " + u"field must be filled.")) if not data.get('person', None) and not data.get('organization', None): raise forms.ValidationError( _(u"A responsible or an organization must be defined.")) return data - # TODO - """ - for treatment_type in self.cleaned_data.get('treatment_type', []): - try: - treatment = models.TreatmentType.objects.get( - pk=treatment_type, available=True) - except models.TreatmentType.DoesNotExist: - raise forms.ValidationError(_(u"This treatment type is not " - u"available.")) - if treatment.upstream_is_many and \ - not self.cleaned_data.get('basket'): - raise forms.ValidationError(_(u"This treatment needs a " - u"basket.")) - """ + + +class N1TreatmentForm(BaseTreatmentForm): + UPSTREAM_IS_MANY = True + form_admin_name = _(u"Treatment n-1 - 020 - General") + form_slug = "treatmentn1-020-general" + + TYPES = [ + FieldType('treatment_state', models.TreatmentState, True, + extra_args={'dct': {"executed": True}}), + FieldType( + 'treatment_type', models.TreatmentType, is_multiple=True, + extra_args={'dct': {'upstream_is_many': True, + 'downstream_is_many': False}}) + ] + + +class OneNTreatmentForm(BaseTreatmentForm): + DOWNSTREAM_IS_MANY = True + form_admin_name = _(u"Treatment 1-n - 020 - General") + form_slug = "treatment1n-020-general" + + TYPES = [ + FieldType('treatment_state', models.TreatmentState, True, + extra_args={'dct': {"executed": True}}), + FieldType( + 'treatment_type', models.TreatmentType, is_multiple=True, + extra_args={'dct': {'upstream_is_many': False, + 'downstream_is_many': True}}) + ] class TreatmentModifyForm(BaseTreatmentForm): @@ -240,7 +308,7 @@ class TreatmentModifyForm(BaseTreatmentForm): fields[key] = value if key == 'year': fields['index'] = idx - fields.pop('target_is_basket') + # fields.pop('target_is_basket') self.fields = fields def clean(self, *args, **kwargs): @@ -287,6 +355,11 @@ class QAFindTreatmentForm(IshtarForm): reverse_lazy('autocomplete-container'), associated_model=Container, new=True), validators=[valid_id(Container)]) + reference_container = forms.BooleanField( + label=_(u"Change the reference container"), required=False, + widget=widgets.CheckboxInput, initial=True, + help_text=_(u"If unchecked the current container will be changed") + ) create_treatment = forms.BooleanField( label=_(u"Create a treatment"), required=False, widget=widgets.CheckboxInput @@ -344,8 +417,9 @@ class QAFindTreatmentForm(IshtarForm): container = Container.objects.get(pk=self.cleaned_data['container']) if self.cleaned_data['create_treatment']: packaging, created = models.TreatmentType.objects.get_or_create( - label=u"Conditionnement", - txt_idx='packaging' + txt_idx='packaging', + defaults={"label": _(u"Packaging"), + "change_reference_location": True} ) t = models.Treatment.objects.create( container=container, @@ -359,10 +433,13 @@ class QAFindTreatmentForm(IshtarForm): t.treatment_types.add(packaging) t.save(items=items) return + container_attr = 'container' + if self.cleaned_data.get('reference_container', False): + container_attr = 'container_ref' for find in items: - if find.container == container: + if getattr(find, container_attr) == container: continue - find.container = container + setattr(find, container_attr, container) find.save() @@ -542,7 +619,9 @@ class TreatmentFileForm(ManageOldType): base_models = ['treatment_type_type'] associated_models = { 'type': models.TreatmentFileType, 'in_charge': Person, - 'applicant': Person, 'applicant_organisation': Organization} + 'applicant': Person, 'applicant_organisation': Organization, + 'associated_basket': models.FindBasket + } need_user_for_initialization = True name = forms.CharField(label=_(u"Name"), @@ -575,6 +654,11 @@ class TreatmentFileForm(ManageOldType): reverse_lazy('autocomplete-organization'), associated_model=Organization, new=True), validators=[valid_id(Organization)], required=False) + associated_basket = forms.IntegerField( + _(u"Associated basket"), + widget=widgets.JQueryAutoComplete( + reverse_lazy('autocomplete-findbasket'), + associated_model=models.FindBasket), required=False) comment = forms.CharField(label=_(u"Comment"), widget=forms.Textarea, required=False) creation_date = forms.DateField(label=_(u"Start date"), required=False, diff --git a/archaeological_finds/ishtar_menu.py b/archaeological_finds/ishtar_menu.py index afd624b74..21a582a18 100644 --- a/archaeological_finds/ishtar_menu.py +++ b/archaeological_finds/ishtar_menu.py @@ -99,23 +99,23 @@ MENU_SECTIONS = [ MenuItem('treatmentfle_search', _(u"Search"), model=models.TreatmentFile, - access_controls=['view_filetreatment', - 'view_own_filetreatment']), + access_controls=['view_treatmentfile', + 'view_own_treatmentfile']), MenuItem('treatmentfle_creation', _(u"Creation"), model=models.TreatmentFile, - access_controls=['change_filetreatment', - 'change_own_filetreatment']), + access_controls=['change_treatmentfile', + 'change_own_treatmentfile']), MenuItem('treatmentfle_modification', _(u"Modification"), model=models.TreatmentFile, - access_controls=['change_filetreatment', - 'change_own_filetreatment']), + access_controls=['change_treatmentfile', + 'change_own_treatmentfile']), MenuItem('treatmentfle_deletion', _(u"Deletion"), model=models.TreatmentFile, - access_controls=['change_filetreatment', - 'change_own_filetreatment']), + access_controls=['change_treatmentfile', + 'change_own_treatmentfile']), SectionItem( 'admin_act_fletreatments', _(u"Administrative act"), childs=[ @@ -134,10 +134,6 @@ MENU_SECTIONS = [ _(u"Deletion"), model=AdministrativeAct, access_controls=['change_administrativeact']), - MenuItem('treatmentfle_administrativeact_document', - _(u"Documents"), - model=AdministrativeAct, - access_controls=['change_administrativeact']), ] ), ] @@ -148,41 +144,47 @@ MENU_SECTIONS = [ profile_restriction='warehouse', css='menu-warehouse', childs=[ - SectionItem( - 'find_treatments', _(u"Simple treatments"), - childs=[ - MenuItem('treatment_search', - _(u"Search"), - model=models.Treatment, - access_controls=['view_treatment', - 'view_own_treatment']), - MenuItem('treatment_creation', - _(u"Creation"), - model=models.Treatment, - access_controls=['change_treatment', - 'change_own_treatment']), - MenuItem('treatment_modification', - _(u"Modification"), - model=models.Treatment, - access_controls=['change_treatment', - 'change_own_treatment']), - MenuItem('treatment_deletion', - _(u"Deletion"), - model=models.Treatment, - access_controls=['change_treatment', - 'change_own_treatment']), - ]), - SectionItem( + MenuItem('treatment_search', + _(u"Search"), + model=models.Treatment, + access_controls=['view_treatment', + 'view_own_treatment']), + MenuItem( + 'treatment_creation', + _(u"Simple treatment - creation"), + model=models.Treatment, + access_controls=['change_find', 'change_own_find']), + MenuItem( + 'treatment_creation_n1', + _(u"Treatment many to one - creation"), + model=models.Treatment, + access_controls=['change_find', 'change_own_find']), + MenuItem( + 'treatment_creation_1n', + _(u"Treatment one to many - creation"), + model=models.Treatment, + access_controls=['change_find', 'change_own_find']), + MenuItem('treatment_modification', + _(u"Modification"), + model=models.Treatment, + access_controls=['change_treatment', + 'change_own_treatment']), + MenuItem('treatment_deletion', + _(u"Deletion"), + model=models.Treatment, + access_controls=['change_treatment', + 'change_own_treatment']), + SectionItem( 'admin_act_treatments', _(u"Administrative act"), childs=[ MenuItem('treatment_admacttreatment_search', _(u"Search"), model=AdministrativeAct, - access_controls=['change_administrativeact']), + access_controls=['view_administrativeact']), MenuItem('treatment_admacttreatment', _(u"Creation"), model=AdministrativeAct, - access_controls=['change_administrativeact']), + access_controls=['add_administrativeact']), MenuItem( 'treatment_admacttreatment_modification', _(u"Modification"), model=AdministrativeAct, @@ -191,10 +193,6 @@ MENU_SECTIONS = [ _(u"Deletion"), model=AdministrativeAct, access_controls=['change_administrativeact']), - MenuItem('treatment_administrativeact_document', - _(u"Documents"), - model=AdministrativeAct, - access_controls=['change_administrativeact']), ]), ] )), diff --git a/archaeological_finds/locale/django.pot b/archaeological_finds/locale/django.pot index 4ca54a290..65b0b22ba 100644 --- a/archaeological_finds/locale/django.pot +++ b/archaeological_finds/locale/django.pot @@ -9,853 +9,961 @@ msgid "" msgstr "" -#: admin.py:39 models_finds.py:288 +#: admin.py:39 models_finds.py:303 msgid "Point (2D)" msgstr "" -#: admin.py:41 models_finds.py:290 +#: admin.py:41 models_finds.py:305 msgid "Line" msgstr "" -#: admin.py:43 models_finds.py:291 +#: admin.py:43 models_finds.py:306 msgid "Multi polygon" msgstr "" -#: forms.py:91 forms.py:97 forms.py:340 forms.py:353 forms.py:631 -#: models_finds.py:660 models_finds.py:1213 wizards.py:75 +#: forms.py:96 forms.py:102 forms.py:556 forms.py:569 forms.py:876 +#: models_finds.py:722 models_finds.py:1337 wizards.py:86 msgid "Context record" msgstr "" -#: forms.py:92 +#: forms.py:97 msgid "Find - 010 - Context record choice" msgstr "" -#: forms.py:126 ishtar_menu.py:32 models_finds.py:1089 models_finds.py:1717 -#: models_treatments.py:349 templates/ishtar/sheet_find.html:4 +#: forms.py:134 forms.py:268 ishtar_menu.py:32 models_finds.py:1192 +#: models_finds.py:1959 models_treatments.py:585 +#: templates/ishtar/sheet_find.html:4 msgid "Find" msgstr "" -#: forms.py:127 -msgid "Find - 020 - General" +#: forms.py:135 +msgid "Simple find - 020 - General" msgstr "" -#: forms.py:142 forms.py:341 templates/ishtar/sheet_find.html:40 +#: forms.py:157 forms.py:409 forms.py:557 templates/ishtar/sheet_find.html:110 msgid "Identification" msgstr "" -#: forms.py:145 forms.py:360 forms.py:600 forms.py:889 models_finds.py:253 -#: models_finds.py:968 +#: forms.py:160 forms.py:412 forms.py:576 forms.py:845 forms.py:1155 +#: models_finds.py:268 models_finds.py:1060 msgid "Free ID" msgstr "" -#: forms.py:147 forms.py:362 forms.py:601 forms.py:932 models_finds.py:969 +#: forms.py:162 forms.py:414 forms.py:578 forms.py:846 forms.py:1220 +#: models_finds.py:1061 msgid "Denomination" msgstr "" -#: forms.py:148 forms.py:363 models_finds.py:1042 +#: forms.py:163 forms.py:579 models_finds.py:1141 msgid "Previous ID" msgstr "" -#: forms.py:150 forms.py:365 models_finds.py:257 -msgid "Excavation ID" -msgstr "" - -#: forms.py:151 forms.py:366 models_finds.py:970 +#: forms.py:164 forms.py:582 models_finds.py:1062 msgid "Museum ID" msgstr "" -#: forms.py:152 forms.py:367 models_finds.py:965 +#: forms.py:165 forms.py:583 models_finds.py:1057 msgid "Seal number" msgstr "" -#: forms.py:153 forms.py:368 models_finds.py:1038 +#: forms.py:166 forms.py:584 models_finds.py:1137 msgid "Mark" msgstr "" -#: forms.py:155 forms.py:156 forms.py:342 forms.py:371 forms.py:652 -#: forms_treatments.py:139 models_finds.py:258 models_finds.py:971 -#: models_treatments.py:146 templates/ishtar/sheet_find.html:58 +#: forms.py:168 forms.py:169 forms.py:417 forms.py:419 forms.py:558 +#: forms.py:587 forms.py:897 forms_treatments.py:141 models_finds.py:273 +#: models_finds.py:1063 models_treatments.py:164 +#: templates/ishtar/sheet_find.html:128 msgid "Description" msgstr "" -#: forms.py:159 models_finds.py:265 -msgid "Discovery date (exact or TPQ)" -msgstr "" - -#: forms.py:162 models_finds.py:267 templates/ishtar/sheet_basefind.html:29 -msgid "Discovery date (TAQ)" -msgstr "" - -#: forms.py:164 forms.py:654 models_finds.py:269 -msgid "Batch/object" -msgstr "" - -#: forms.py:166 models_finds.py:1003 +#: forms.py:171 forms.py:421 models_finds.py:1100 msgid "Is complete?" msgstr "" -#: forms.py:169 forms.py:373 models_finds.py:57 models_finds.py:685 -#: models_finds.py:977 +#: forms.py:174 forms.py:423 forms.py:589 models_finds.py:57 +#: models_finds.py:748 models_finds.py:1069 msgid "Material types" msgstr "" -#: forms.py:172 models_finds.py:982 +#: forms.py:177 forms.py:426 models_finds.py:1074 msgid "Material type quality" msgstr "" -#: forms.py:174 forms.py:376 models_finds.py:152 models_finds.py:686 -#: models_finds.py:1006 +#: forms.py:179 forms.py:428 forms.py:592 models_finds.py:167 +#: models_finds.py:749 models_finds.py:1103 msgid "Object types" msgstr "" -#: forms.py:177 models_finds.py:1011 +#: forms.py:182 forms.py:431 models_finds.py:1108 msgid "Object type quality" msgstr "" -#: forms.py:178 forms.py:896 models_finds.py:989 +#: forms.py:183 forms.py:433 forms.py:1162 models_finds.py:1081 msgid "Find number" msgstr "" -#: forms.py:180 models_finds.py:1024 +#: forms.py:185 forms.py:435 models_finds.py:1121 msgid "Minimum number of individuals (MNI)" msgstr "" -#: forms.py:182 models_finds.py:972 +#: forms.py:187 forms.py:438 models_finds.py:1064 msgid "Decoration" msgstr "" -#: forms.py:184 models_finds.py:973 +#: forms.py:189 forms.py:440 models_finds.py:1065 msgid "Inscription" msgstr "" -#: forms.py:187 forms.py:379 models_finds.py:975 +#: forms.py:192 forms.py:442 forms.py:595 models_finds.py:1067 msgid "Manufacturing place" msgstr "" -#: forms.py:189 forms.py:381 models_finds.py:1021 +#: forms.py:194 forms.py:444 forms.py:597 models_finds.py:1118 msgid "Communicability" msgstr "" -#: forms.py:191 forms.py:384 forms.py:955 forms_treatments.py:141 -#: forms_treatments.py:578 models_finds.py:259 models_finds.py:1039 -#: models_treatments.py:145 models_treatments.py:609 +#: forms.py:196 forms.py:446 forms.py:600 forms.py:1260 forms_treatments.py:143 +#: forms_treatments.py:657 models_finds.py:274 models_finds.py:1138 +#: models_treatments.py:163 models_treatments.py:847 msgid "Comment" msgstr "" -#: forms.py:194 forms.py:394 models_finds.py:1040 +#: forms.py:199 forms.py:449 forms.py:610 models_finds.py:1139 msgid "Comment on dating" msgstr "" -#: forms.py:196 templates/ishtar/sheet_find.html:76 +#: forms.py:201 forms.py:451 templates/ishtar/sheet_find.html:146 msgid "Dimensions" msgstr "" -#: forms.py:197 models_finds.py:1025 +#: forms.py:202 forms.py:452 models_finds.py:1122 msgid "Length (cm)" msgstr "" -#: forms.py:198 models_finds.py:1026 +#: forms.py:204 forms.py:453 models_finds.py:1123 msgid "Width (cm)" msgstr "" -#: forms.py:199 models_finds.py:1027 +#: forms.py:206 forms.py:454 models_finds.py:1124 msgid "Height (cm)" msgstr "" -#: forms.py:200 models_finds.py:1028 +#: forms.py:208 forms.py:458 models_finds.py:1128 +msgid "Thickness (cm)" +msgstr "" + +#: forms.py:210 forms.py:455 models_finds.py:1125 msgid "Diameter (cm)" msgstr "" -#: forms.py:201 models_finds.py:1029 -msgid "Thickness (cm)" +#: forms.py:213 forms.py:456 models_finds.py:1126 +msgid "Circumference (cm)" msgstr "" -#: forms.py:202 forms.py:894 models_finds.py:985 +#: forms.py:215 forms.py:459 forms.py:1160 models_finds.py:1077 msgid "Volume (l)" msgstr "" -#: forms.py:203 forms.py:895 templates/ishtar/sheet_find.html:84 +#: forms.py:216 forms.py:460 forms.py:1161 templates/ishtar/sheet_find.html:155 msgid "Weight (g)" msgstr "" -#: forms.py:205 +#: forms.py:219 forms.py:462 msgid "Clutter long side (cm)" msgstr "" -#: forms.py:207 +#: forms.py:222 forms.py:464 msgid "Clutter short side (cm)" msgstr "" -#: forms.py:209 +#: forms.py:225 forms.py:466 msgid "Clutter height (cm)" msgstr "" -#: forms.py:211 models_finds.py:1036 +#: forms.py:228 forms.py:468 models_finds.py:1135 msgid "Dimensions comment" msgstr "" -#: forms.py:214 templates/ishtar/sheet_basefind.html:46 -#: templates/ishtar/sheet_basefind.html:50 +#: forms.py:230 forms.py:470 forms.py:559 +#: templates/ishtar/sheet_basefind.html:70 templates/ishtar/sheet_find.html:164 +msgid "Sheet" +msgstr "" + +#: forms.py:231 forms.py:471 forms.py:603 forms.py:900 models_finds.py:1143 +msgid "Check" +msgstr "" + +#: forms.py:233 forms.py:474 forms.py:605 models_finds.py:1145 +msgid "Check date" +msgstr "" + +#: forms.py:260 +msgid "Clutter: short side cannot be bigger than the long side." +msgstr "" + +#: forms.py:269 +msgid "Find - 020 - General" +msgstr "" + +#: forms.py:299 forms.py:581 models_finds.py:272 +msgid "Excavation ID" +msgstr "" + +#: forms.py:302 models_finds.py:280 +msgid "Discovery date (exact or TPQ)" +msgstr "" + +#: forms.py:305 models_finds.py:282 templates/ishtar/sheet_basefind.html:33 +msgid "Discovery date (TAQ)" +msgstr "" + +#: forms.py:307 forms.py:899 models_finds.py:284 +msgid "Batch/object" +msgstr "" + +#: forms.py:310 templates/ishtar/sheet_basefind.html:50 +#: templates/ishtar/sheet_basefind.html:54 msgid "Coordinates" msgstr "" -#: forms.py:215 models_finds.py:276 +#: forms.py:311 models_finds.py:291 msgid "X" msgstr "" -#: forms.py:217 models_finds.py:279 +#: forms.py:313 models_finds.py:294 msgid "Estimated error for X" msgstr "" -#: forms.py:218 models_finds.py:277 +#: forms.py:314 models_finds.py:292 msgid "Y" msgstr "" -#: forms.py:220 models_finds.py:281 +#: forms.py:316 models_finds.py:296 msgid "Estimated error for Y" msgstr "" -#: forms.py:221 models_finds.py:278 +#: forms.py:317 models_finds.py:293 msgid "Z" msgstr "" -#: forms.py:223 models_finds.py:283 +#: forms.py:319 models_finds.py:298 msgid "Estimated error for Z" msgstr "" -#: forms.py:225 models_finds.py:286 +#: forms.py:321 models_finds.py:301 msgid "Spatial Reference System" msgstr "" -#: forms.py:228 models_finds.py:274 +#: forms.py:324 models_finds.py:289 msgid "Point of topographic reference" msgstr "" -#: forms.py:232 forms.py:343 templates/ishtar/sheet_basefind.html:66 -#: templates/ishtar/sheet_find.html:93 -msgid "Sheet" +#: forms.py:352 +msgid "" +"Discovery date: if a TAQ date is provided a TPQ date has to be informed. If " +"you have a precise date fill only the TPQ - discovery date field." msgstr "" -#: forms.py:233 forms.py:387 forms.py:655 models_finds.py:1044 -msgid "Check" +#: forms.py:358 +msgid "Discovery date: TAQ date must be older than TPQ date." msgstr "" -#: forms.py:235 forms.py:389 models_finds.py:1046 -msgid "Check date" +#: forms.py:374 +msgid "You should at least provide X, Y and the spatial reference system used." msgstr "" -#: forms.py:274 -msgid "" -"Discovery date: if a TAQ date is provided a TPQ date has to be informed. If " -"you have a precise date fill only the TPQ - discovery date field." +#: forms.py:383 +msgid "Coordinates are not relevant for the spatial reference system used: {}." msgstr "" -#: forms.py:280 -msgid "Discovery date: TAQ date must be older than TPQ date." +#: forms.py:396 forms.py:1152 +msgid "Resulting find" msgstr "" -#: forms.py:290 -msgid "Clutter: short side cannot be bigger than the long side." +#: forms.py:397 +msgid "Treatment n-1 - 030 - Resulting find" msgstr "" -#: forms.py:307 -msgid "You should at least provide X, Y and the spatial reference system used." +#: forms.py:493 forms.py:1171 +msgid "Resulting finds" msgstr "" -#: forms.py:316 -msgid "Coordinates are not relevant for the spatial reference system used: {}." +#: forms.py:494 +msgid "Treatment 1-n - 030 - Resulting finds" msgstr "" -#: forms.py:322 +#: forms.py:499 +msgid "Number of resulting finds" +msgstr "" + +#: forms.py:503 +msgid "Prefix label for resulting finds" +msgstr "" + +#: forms.py:506 +msgid "" +"E.g.: with a prefix \"item-\", each resulting item will be named \"item-1\", " +"\"item-2\", \"item-3\"" +msgstr "" + +#: forms.py:510 +msgid "Numbering starting from" +msgstr "" + +#: forms.py:513 +msgid "Name of the new basket containing the resulting items" +msgstr "" + +#: forms.py:531 forms.py:697 forms.py:733 +msgid "A basket with this label already exists." +msgstr "" + +#: forms.py:537 msgid "Find - Quick action - Modify" msgstr "" -#: forms.py:344 +#: forms.py:560 msgid "Datation" msgstr "" -#: forms.py:392 forms.py:565 forms.py:641 templates/ishtar/sheet_find.html:123 +#: forms.py:608 forms.py:810 forms.py:886 templates/ishtar/sheet_find.html:196 msgid "Period" msgstr "" -#: forms.py:436 +#: forms.py:652 msgid "Find - Quick action - Modify single" msgstr "" -#: forms.py:449 +#: forms.py:665 msgid "Create" msgstr "" -#: forms.py:450 +#: forms.py:666 msgid "Update" msgstr "" -#: forms.py:452 forms.py:636 forms.py:982 forms.py:986 forms_treatments.py:180 -#: ishtar_menu.py:57 models_finds.py:926 -#: templates/ishtar/sheet_findbasket.html:4 views.py:646 +#: forms.py:668 forms.py:881 forms.py:1308 forms.py:1312 ishtar_menu.py:57 +#: models_finds.py:605 models_finds.py:1018 +#: templates/ishtar/sheet_findbasket.html:4 views.py:824 wizards.py:360 msgid "Basket" msgstr "" -#: forms.py:474 +#: forms.py:690 msgid "On update, you have to select a basket." msgstr "" -#: forms.py:478 +#: forms.py:694 forms.py:730 msgid "A label is required." msgstr "" -#: forms.py:481 -msgid "A basket with this label already exists." +#: forms.py:725 +msgid " - duplicate" msgstr "" -#: forms.py:498 templates/ishtar/sheet_find.html:102 +#: forms.py:743 templates/ishtar/sheet_find.html:175 msgid "Preservation" msgstr "" -#: forms.py:499 +#: forms.py:744 msgid "Find - 030 - Preservation" msgstr "" -#: forms.py:513 forms.py:648 models_finds.py:1015 +#: forms.py:758 forms.py:893 models_finds.py:1112 msgid "Integrity / interest" msgstr "" -#: forms.py:516 forms.py:650 models_finds.py:1018 +#: forms.py:761 forms.py:895 models_finds.py:1115 msgid "Remarkability" msgstr "" -#: forms.py:518 forms.py:646 models_finds.py:1056 +#: forms.py:763 forms.py:891 models_finds.py:1155 msgid "Conservatory state" msgstr "" -#: forms.py:521 models_finds.py:1065 +#: forms.py:766 models_finds.py:1164 msgid "Alteration" msgstr "" -#: forms.py:524 models_finds.py:1069 +#: forms.py:769 models_finds.py:1168 msgid "Alteration cause" msgstr "" -#: forms.py:527 models_finds.py:1062 +#: forms.py:772 models_finds.py:1161 msgid "Recommended treatments" msgstr "" -#: forms.py:529 models_finds.py:1073 +#: forms.py:774 models_finds.py:1172 msgid "Treatment emergency" msgstr "" -#: forms.py:531 models_finds.py:1048 +#: forms.py:776 models_finds.py:1147 msgid "Estimated value" msgstr "" -#: forms.py:532 models_finds.py:1076 +#: forms.py:777 models_finds.py:1175 msgid "Insurance value" msgstr "" -#: forms.py:534 models_finds.py:1078 +#: forms.py:779 models_finds.py:1177 msgid "Appraisal date" msgstr "" -#: forms.py:536 models_finds.py:1058 +#: forms.py:781 models_finds.py:1157 msgid "Conservatory comment" msgstr "" -#: forms.py:560 forms.py:584 models_finds.py:997 -#: templates/ishtar/sheet_find.html:119 +#: forms.py:805 forms.py:829 models_finds.py:1089 +#: templates/ishtar/sheet_find.html:192 msgid "Dating" msgstr "" -#: forms.py:566 forms_treatments.py:143 forms_treatments.py:370 -#: forms_treatments.py:580 models_finds.py:1722 models_treatments.py:148 -#: models_treatments.py:360 templates/ishtar/sheet_find.html:124 -#: templates/ishtar/sheet_find.html:185 templates/ishtar/sheet_find.html:223 +#: forms.py:811 forms_treatments.py:128 forms_treatments.py:442 +#: forms_treatments.py:659 models_finds.py:1964 models_treatments.py:166 +#: models_treatments.py:596 templates/ishtar/sheet_find.html:197 +#: templates/ishtar/sheet_find.html:265 templates/ishtar/sheet_find.html:302 +#: templates/ishtar/sheet_find.html:340 msgid "Start date" msgstr "" -#: forms.py:568 models_finds.py:1723 models_treatments.py:361 -#: templates/ishtar/sheet_find.html:125 templates/ishtar/sheet_find.html:186 -#: templates/ishtar/sheet_find.html:224 +#: forms.py:813 models_finds.py:1965 models_treatments.py:597 +#: templates/ishtar/sheet_find.html:198 templates/ishtar/sheet_find.html:266 +#: templates/ishtar/sheet_find.html:303 templates/ishtar/sheet_find.html:341 msgid "End date" msgstr "" -#: forms.py:569 templates/ishtar/sheet_find.html:127 +#: forms.py:814 templates/ishtar/sheet_find.html:200 msgid "Quality" msgstr "" -#: forms.py:571 templates/ishtar/sheet_find.html:126 +#: forms.py:816 templates/ishtar/sheet_find.html:199 msgid "Dating type" msgstr "" -#: forms.py:573 templates/ishtar/sheet_find.html:128 +#: forms.py:818 templates/ishtar/sheet_find.html:201 msgid "Precise dating" msgstr "" -#: forms.py:585 +#: forms.py:830 msgid "Find - 040 - Dating" msgstr "" -#: forms.py:592 +#: forms.py:837 msgid "Find - 001 - Search" msgstr "" -#: forms.py:595 forms.py:928 forms_treatments.py:50 forms_treatments.py:419 -#: forms_treatments.py:493 forms_treatments.py:686 +#: forms.py:840 forms.py:1216 forms_treatments.py:49 forms_treatments.py:491 +#: forms_treatments.py:565 forms_treatments.py:765 msgid "Full text search" msgstr "" -#: forms.py:598 models_finds.py:294 +#: forms.py:843 models_finds.py:309 msgid "Short ID" msgstr "" -#: forms.py:599 models_finds.py:297 +#: forms.py:844 models_finds.py:312 msgid "Complete ID" msgstr "" -#: forms.py:604 forms_treatments.py:56 forms_treatments.py:101 -#: forms_treatments.py:295 forms_treatments.py:423 forms_treatments.py:498 -#: forms_treatments.py:550 forms_treatments.py:690 models_treatments.py:122 -#: models_treatments.py:582 +#: forms.py:849 forms_treatments.py:55 forms_treatments.py:100 +#: forms_treatments.py:363 forms_treatments.py:495 forms_treatments.py:570 +#: forms_treatments.py:624 forms_treatments.py:769 models_treatments.py:137 +#: models_treatments.py:820 msgid "Year" msgstr "" -#: forms.py:606 +#: forms.py:851 msgid "Operation's number (index by year)" msgstr "" -#: forms.py:609 +#: forms.py:854 msgid "Code PATRIARCHE" msgstr "" -#: forms.py:613 +#: forms.py:858 msgid "Operation type" msgstr "" -#: forms.py:616 +#: forms.py:861 msgid "Areas" msgstr "" -#: forms.py:619 +#: forms.py:864 msgid "Archaeological site (attached to the operation)" msgstr "" -#: forms.py:625 +#: forms.py:870 msgid "Archaeological site (attached to the context record)" msgstr "" -#: forms.py:638 +#: forms.py:883 msgid "Search within related operations" msgstr "" -#: forms.py:640 +#: forms.py:885 msgid "Search within related context records" msgstr "" -#: forms.py:642 forms.py:893 models_finds.py:56 +#: forms.py:887 forms.py:1159 models_finds.py:56 msgid "Material type" msgstr "" -#: forms.py:643 models_finds.py:151 +#: forms.py:888 models_finds.py:166 msgid "Object type" msgstr "" -#: forms.py:645 +#: forms.py:890 msgid "Preservation type" msgstr "" -#: forms.py:656 forms_treatments.py:59 +#: forms.py:901 forms_treatments.py:58 msgid "Has an image?" msgstr "" -#: forms.py:703 -msgid "Warehouse (location)" +#: forms.py:902 +msgid "Loan?" +msgstr "" + +#: forms.py:904 +msgid "Treatment file end date before" +msgstr "" + +#: forms.py:953 +msgid "Reference container - Warehouse (location)" +msgstr "" + +#: forms.py:959 +msgid "Reference container - Warehouse (responsible)" msgstr "" -#: forms.py:709 -msgid "Warehouse (responsible)" +#: forms.py:965 +msgid "Reference container ID" msgstr "" -#: forms.py:714 -msgid "Container ID" +#: forms.py:967 +msgid "Reference container ref." msgstr "" -#: forms.py:715 -msgid "Container ref." +#: forms.py:969 +msgid "Current container - Warehouse (location)" msgstr "" -#: forms.py:720 forms.py:744 views.py:185 +#: forms.py:975 +msgid "Current container - Warehouse (responsible)" +msgstr "" + +#: forms.py:980 +msgid "Current container ID" +msgstr "" + +#: forms.py:981 +msgid "Current container ref." +msgstr "" + +#: forms.py:986 forms.py:1010 views.py:241 msgid "Find search" msgstr "" -#: forms.py:769 models_treatments.py:258 -#: templates/ishtar/sheet_treatment.html:56 +#: forms.py:1035 forms.py:1180 models_treatments.py:280 +#: templates/ishtar/sheet_treatment.html:102 msgid "Upstream finds" msgstr "" -#: forms.py:771 models_finds.py:1090 +#: forms.py:1037 models_finds.py:1193 #: templates/ishtar/forms/qa_find_treatment.html:11 +#: templates/ishtar/sheet_treatment.html:24 msgid "Finds" msgstr "" -#: forms.py:783 +#: forms.py:1049 msgid "You should at least select one archaeological find." msgstr "" -#: forms.py:886 -msgid "Resulting find" -msgstr "" - -#: forms.py:891 +#: forms.py:1157 msgid "Precise description" msgstr "" -#: forms.py:905 -msgid "Resulting finds" -msgstr "" - -#: forms.py:910 +#: forms.py:1176 msgid "Would you like to delete this find?" msgstr "" -#: forms.py:914 models_treatments.py:68 -msgid "Upstream find" -msgstr "" - -#: forms.py:925 +#: forms.py:1213 msgid "Find basket - 001 - Search" msgstr "" -#: forms.py:937 views.py:122 +#: forms.py:1225 forms.py:1240 views.py:164 msgid "Basket search" msgstr "" -#: forms.py:951 +#: forms.py:1254 msgid "Find basket" msgstr "" -#: forms.py:953 forms_treatments.py:54 forms_treatments.py:97 -#: models_treatments.py:118 templates/ishtar/sheet_find.html:179 -#: templates/ishtar/sheet_find.html:217 +#: forms.py:1258 forms_treatments.py:53 forms_treatments.py:122 +#: models_treatments.py:133 +#: templates/ishtar/forms/qa_findbasket_duplicate.html:15 +#: templates/ishtar/sheet_find.html:259 templates/ishtar/sheet_find.html:296 +#: templates/ishtar/sheet_find.html:334 msgid "Label" msgstr "" -#: forms.py:972 +#: forms.py:1264 forms.py:1277 +msgid "Shared (read) with" +msgstr "" + +#: forms.py:1269 forms.py:1282 +msgid "Shared (read/edit) with" +msgstr "" + +#: forms.py:1298 msgid "Another basket already exists with this name." msgstr "" -#: forms_treatments.py:55 forms_treatments.py:100 models_treatments.py:120 +#: forms_treatments.py:54 forms_treatments.py:125 models_treatments.py:135 msgid "Other ref." msgstr "" -#: forms_treatments.py:57 forms_treatments.py:232 forms_treatments.py:424 -#: forms_treatments.py:486 forms_treatments.py:499 forms_treatments.py:603 -#: forms_treatments.py:691 forms_treatments.py:758 models_treatments.py:123 -#: models_treatments.py:583 +#: forms_treatments.py:56 forms_treatments.py:295 forms_treatments.py:496 +#: forms_treatments.py:558 forms_treatments.py:571 forms_treatments.py:682 +#: forms_treatments.py:770 forms_treatments.py:837 models_treatments.py:138 +#: models_treatments.py:821 msgid "Index" msgstr "" -#: forms_treatments.py:58 forms_treatments.py:106 forms_treatments.py:378 -#: forms_treatments.py:440 models_finds.py:106 models_treatments.py:128 -#: models_treatments.py:359 +#: forms_treatments.py:57 forms_treatments.py:97 forms_treatments.py:450 +#: forms_treatments.py:512 models_finds.py:121 models_treatments.py:143 +#: models_treatments.py:595 msgid "Treatment type" msgstr "" -#: forms_treatments.py:71 views.py:420 +#: forms_treatments.py:70 views.py:479 msgid "Treatment search" msgstr "" -#: forms_treatments.py:83 -msgid "Base treatment" +#: forms_treatments.py:82 ishtar_menu.py:143 models_treatments.py:187 +#: models_treatments.py:587 templates/ishtar/sheet_treatment.html:4 +#: templates/ishtar/sheet_treatment.html:17 +msgid "Treatment" msgstr "" -#: forms_treatments.py:84 +#: forms_treatments.py:83 msgid "Treatment - 020 - General" msgstr "" -#: forms_treatments.py:108 models_treatments.py:70 models_treatments.py:130 -#: templates/ishtar/sheet_find.html:181 templates/ishtar/sheet_find.html:219 +#: forms_treatments.py:99 models_treatments.py:83 models_treatments.py:145 +#: templates/ishtar/sheet_find.html:261 templates/ishtar/sheet_find.html:298 +#: templates/ishtar/sheet_find.html:336 msgid "State" msgstr "" -#: forms_treatments.py:110 -msgid "Target" +#: forms_treatments.py:105 models_treatments.py:151 models_treatments.py:598 +msgid "Location" msgstr "" -#: forms_treatments.py:112 forms_treatments.py:301 forms_treatments.py:561 -#: models_treatments.py:71 models_treatments.py:138 +#: forms_treatments.py:111 forms_treatments.py:369 forms_treatments.py:635 +#: models_treatments.py:84 models_treatments.py:156 msgid "Responsible" msgstr "" -#: forms_treatments.py:118 forms_treatments.py:307 models_treatments.py:141 +#: forms_treatments.py:117 forms_treatments.py:375 models_treatments.py:159 msgid "Organization" msgstr "" -#: forms_treatments.py:124 models_treatments.py:133 models_treatments.py:362 -msgid "Location" -msgstr "" - -#: forms_treatments.py:130 -msgid "Container (relevant for packaging)" +#: forms_treatments.py:130 forms_treatments.py:442 forms_treatments.py:665 +#: forms_treatments.py:718 models_treatments.py:167 models_treatments.py:841 +msgid "Closing date" msgstr "" -#: forms_treatments.py:136 forms_treatments.py:557 -msgid "External ref." +#: forms_treatments.py:133 +msgid "Destination container (relevant for treatment that change location)" msgstr "" -#: forms_treatments.py:137 models_treatments.py:147 +#: forms_treatments.py:139 models_treatments.py:165 msgid "Goal" msgstr "" -#: forms_treatments.py:145 forms_treatments.py:370 forms_treatments.py:586 -#: forms_treatments.py:639 models_treatments.py:149 models_treatments.py:603 -msgid "Closing date" -msgstr "" - -#: forms_treatments.py:147 +#: forms_treatments.py:145 #, python-brace-format msgid "Estimated cost ({currency})" msgstr "" -#: forms_treatments.py:149 +#: forms_treatments.py:147 #, python-brace-format msgid "Quoted cost ({currency})" msgstr "" -#: forms_treatments.py:151 +#: forms_treatments.py:149 #, python-brace-format msgid "Realized cost ({currency})" msgstr "" -#: forms_treatments.py:153 +#: forms_treatments.py:151 #, python-brace-format msgid "Insurance cost ({currency})" msgstr "" -#: forms_treatments.py:180 -msgid "Single find" +#: forms_treatments.py:212 +msgid "Unknow treatment type" msgstr "" -#: forms_treatments.py:204 +#: forms_treatments.py:233 forms_treatments.py:242 +msgid "{} is not compatible with {} treatment(s)." +msgstr "" + +#: forms_treatments.py:253 msgid "" -"The container field is attached to the treatment. If no packaging treatment " -"is done it is not relevant." +"The container field is attached to the treatment but no treatment with " +"container change is defined." msgstr "" -#: forms_treatments.py:209 -msgid "If a packaging treatment is done, the container field must be filled." +#: forms_treatments.py:258 +msgid "" +"A treatment with location change is defined, the container field must be " +"filled." msgstr "" -#: forms_treatments.py:213 +#: forms_treatments.py:262 msgid "A responsible or an organization must be defined." msgstr "" -#: forms_treatments.py:256 +#: forms_treatments.py:267 +msgid "Treatment n-1 - 020 - General" +msgstr "" + +#: forms_treatments.py:281 +msgid "Treatment 1-n - 020 - General" +msgstr "" + +#: forms_treatments.py:319 msgid "Another treatment with this index exists for {}." msgstr "" -#: forms_treatments.py:262 models_treatments.py:126 +#: forms_treatments.py:325 models_treatments.py:141 msgid "Associated request" msgstr "" -#: forms_treatments.py:263 +#: forms_treatments.py:326 msgid "Treatment - 010 - Request choice" msgstr "" -#: forms_treatments.py:268 forms_treatments.py:541 ishtar_menu.py:95 -#: models_treatments.py:618 models_treatments.py:646 -#: templates/ishtar/sheet_treatmentfile.html:4 wizards.py:207 +#: forms_treatments.py:331 forms_treatments.py:613 ishtar_menu.py:95 +#: models_treatments.py:860 models_treatments.py:882 +#: templates/ishtar/sheet_treatmentfile.html:4 wizards.py:465 msgid "Treatment request" msgstr "" -#: forms_treatments.py:277 +#: forms_treatments.py:340 msgid "" "Are you sure you want to delete this treatment? All changes made to the " "associated finds since this treatment record will be lost!" msgstr "" -#: forms_treatments.py:280 +#: forms_treatments.py:343 msgid "Would you like to delete this treatment?" msgstr "" -#: forms_treatments.py:285 models_finds.py:683 models_finds.py:1000 -#: models_treatments.py:150 models_treatments.py:363 -#: templates/ishtar/sheet_find.html:184 templates/ishtar/sheet_find.html:222 +#: forms_treatments.py:348 models_finds.py:1092 models_treatments.py:169 +#: models_treatments.py:599 templates/ishtar/sheet_find.html:264 +#: templates/ishtar/sheet_find.html:301 templates/ishtar/sheet_find.html:339 msgid "Container" msgstr "" -#: forms_treatments.py:291 +#: forms_treatments.py:354 templates/ishtar/forms/qa_find_treatment.html:31 +msgid "Change the reference container" +msgstr "" + +#: forms_treatments.py:356 +msgid "If unchecked the current container will be changed" +msgstr "" + +#: forms_treatments.py:359 msgid "Create a treatment" msgstr "" -#: forms_treatments.py:298 +#: forms_treatments.py:366 msgid "Precise date" msgstr "" -#: forms_treatments.py:340 +#: forms_treatments.py:408 msgid "At least a year is required." msgstr "" -#: forms_treatments.py:369 +#: forms_treatments.py:416 models_finds.py:1022 models_finds.py:1304 +#: templates/ishtar/forms/qa_find_treatment.html:16 views.py:844 +msgid "Packaging" +msgstr "" + +#: forms_treatments.py:441 msgid "months" msgstr "" -#: forms_treatments.py:369 +#: forms_treatments.py:441 msgid "years" msgstr "" -#: forms_treatments.py:374 forms_treatments.py:643 +#: forms_treatments.py:446 forms_treatments.py:722 msgid "Slicing" msgstr "" -#: forms_treatments.py:377 forms_treatments.py:646 +#: forms_treatments.py:449 forms_treatments.py:725 msgid "Date get from" msgstr "" -#: forms_treatments.py:380 forms_treatments.py:649 +#: forms_treatments.py:452 forms_treatments.py:728 msgid "Date after" msgstr "" -#: forms_treatments.py:382 forms_treatments.py:651 +#: forms_treatments.py:454 forms_treatments.py:730 msgid "Date before" msgstr "" -#: forms_treatments.py:425 forms_treatments.py:475 forms_treatments.py:692 -#: forms_treatments.py:747 +#: forms_treatments.py:497 forms_treatments.py:547 forms_treatments.py:771 +#: forms_treatments.py:826 msgid "Act type" msgstr "" -#: forms_treatments.py:426 forms_treatments.py:693 +#: forms_treatments.py:498 forms_treatments.py:772 msgid "Indexed?" msgstr "" -#: forms_treatments.py:427 forms_treatments.py:694 +#: forms_treatments.py:499 forms_treatments.py:773 msgid "Object" msgstr "" -#: forms_treatments.py:431 forms_treatments.py:698 +#: forms_treatments.py:503 forms_treatments.py:777 msgid "Signature date after" msgstr "" -#: forms_treatments.py:433 forms_treatments.py:700 +#: forms_treatments.py:505 forms_treatments.py:779 msgid "Signature date before" msgstr "" -#: forms_treatments.py:435 +#: forms_treatments.py:507 msgid "Treatment name" msgstr "" -#: forms_treatments.py:436 +#: forms_treatments.py:508 msgid "Treatment year" msgstr "" -#: forms_treatments.py:437 +#: forms_treatments.py:509 msgid "Treatment index" msgstr "" -#: forms_treatments.py:439 +#: forms_treatments.py:511 msgid "Treatment internal reference" msgstr "" -#: forms_treatments.py:443 forms_treatments.py:714 +#: forms_treatments.py:515 forms_treatments.py:793 msgid "Modified by" msgstr "" -#: forms_treatments.py:473 +#: forms_treatments.py:545 msgid "Treatment - Administrative act - General" msgstr "" -#: forms_treatments.py:496 forms_treatments.py:548 models_treatments.py:588 +#: forms_treatments.py:568 forms_treatments.py:622 models_treatments.py:826 msgid "Name" msgstr "" -#: forms_treatments.py:497 forms_treatments.py:555 +#: forms_treatments.py:569 forms_treatments.py:629 msgid "Internal ref." msgstr "" -#: forms_treatments.py:500 forms_treatments.py:559 models_treatments.py:69 -#: templates/ishtar/sheet_find.html:180 templates/ishtar/sheet_find.html:218 +#: forms_treatments.py:572 forms_treatments.py:633 models_treatments.py:82 +#: templates/ishtar/sheet_find.html:260 templates/ishtar/sheet_find.html:297 +#: templates/ishtar/sheet_find.html:335 msgid "Type" msgstr "" -#: forms_treatments.py:503 +#: forms_treatments.py:575 msgid "In charge" msgstr "" -#: forms_treatments.py:509 forms_treatments.py:567 models_treatments.py:597 -#: templates/ishtar/sheet_treatmentfile.html:45 +#: forms_treatments.py:581 forms_treatments.py:641 models_treatments.py:835 +#: templates/ishtar/sheet_treatmentfile.html:46 msgid "Applicant" msgstr "" -#: forms_treatments.py:515 forms_treatments.py:573 models_treatments.py:601 -#: templates/ishtar/sheet_treatmentfile.html:53 +#: forms_treatments.py:587 forms_treatments.py:647 models_treatments.py:839 +#: templates/ishtar/sheet_treatmentfile.html:54 msgid "Applicant organisation" msgstr "" -#: forms_treatments.py:529 views.py:524 +#: forms_treatments.py:601 views.py:681 msgid "Treatment request search" msgstr "" -#: forms_treatments.py:584 forms_treatments.py:638 models_treatments.py:607 +#: forms_treatments.py:631 +msgid "External ref." +msgstr "" + +#: forms_treatments.py:653 +msgid "Associated basket" +msgstr "" + +#: forms_treatments.py:663 forms_treatments.py:717 models_treatments.py:845 msgid "Reception date" msgstr "" -#: forms_treatments.py:626 +#: forms_treatments.py:705 msgid "Another treatment request with this index exists for {}." msgstr "" -#: forms_treatments.py:632 +#: forms_treatments.py:711 msgid "Are you sure you want to delete this treatment request?" msgstr "" -#: forms_treatments.py:633 +#: forms_treatments.py:712 msgid "Would you like to delete this treatment request?" msgstr "" -#: forms_treatments.py:637 models_treatments.py:605 +#: forms_treatments.py:716 models_treatments.py:843 msgid "Creation date" msgstr "" -#: forms_treatments.py:647 forms_treatments.py:711 models_treatments.py:519 -#: models_treatments.py:590 +#: forms_treatments.py:726 forms_treatments.py:790 models_treatments.py:757 +#: models_treatments.py:828 msgid "Treatment request type" msgstr "" -#: forms_treatments.py:703 +#: forms_treatments.py:782 msgid "Treatment request name" msgstr "" -#: forms_treatments.py:705 +#: forms_treatments.py:784 msgid "Treatment request year" msgstr "" -#: forms_treatments.py:707 +#: forms_treatments.py:786 msgid "Treatment request index" msgstr "" -#: forms_treatments.py:709 +#: forms_treatments.py:788 msgid "Treatment request internal reference" msgstr "" -#: forms_treatments.py:745 +#: forms_treatments.py:824 msgid "Treatment request - Administrative act - General" msgstr "" #: ishtar_menu.py:37 ishtar_menu.py:60 ishtar_menu.py:100 ishtar_menu.py:123 -#: ishtar_menu.py:155 ishtar_menu.py:179 +#: ishtar_menu.py:148 ishtar_menu.py:181 msgid "Search" msgstr "" #: ishtar_menu.py:42 ishtar_menu.py:65 ishtar_menu.py:105 ishtar_menu.py:127 -#: ishtar_menu.py:160 ishtar_menu.py:183 +#: ishtar_menu.py:185 msgid "Creation" msgstr "" #: ishtar_menu.py:47 ishtar_menu.py:70 ishtar_menu.py:110 ishtar_menu.py:131 -#: ishtar_menu.py:165 ishtar_menu.py:188 +#: ishtar_menu.py:168 ishtar_menu.py:190 msgid "Modification" msgstr "" #: ishtar_menu.py:52 ishtar_menu.py:82 ishtar_menu.py:115 ishtar_menu.py:134 -#: ishtar_menu.py:170 ishtar_menu.py:191 +#: ishtar_menu.py:173 ishtar_menu.py:193 msgid "Deletion" msgstr "" @@ -863,22 +971,20 @@ msgstr "" msgid "Manage items" msgstr "" -#: ishtar_menu.py:120 ishtar_menu.py:176 models_finds.py:1719 +#: ishtar_menu.py:120 ishtar_menu.py:178 models_finds.py:1961 msgid "Administrative act" msgstr "" -#: ishtar_menu.py:138 ishtar_menu.py:195 models_finds.py:1081 -#: models_treatments.py:163 models_treatments.py:611 -msgid "Documents" +#: ishtar_menu.py:154 +msgid "Simple treatment - creation" msgstr "" -#: ishtar_menu.py:147 models_treatments.py:170 models_treatments.py:351 -#: templates/ishtar/sheet_treatment.html:4 -msgid "Treatment" +#: ishtar_menu.py:159 +msgid "Treatment many to one - creation" msgstr "" -#: ishtar_menu.py:152 -msgid "Simple treatments" +#: ishtar_menu.py:164 +msgid "Treatment one to many - creation" msgstr "" #: models_finds.py:51 @@ -889,9 +995,9 @@ msgstr "" msgid "Recommendation" msgstr "" -#: models_finds.py:66 models_finds.py:79 models_finds.py:92 models_finds.py:138 -#: models_finds.py:161 models_finds.py:218 models_finds.py:967 -#: models_treatments.py:355 +#: models_finds.py:66 models_finds.py:79 models_finds.py:92 models_finds.py:153 +#: models_finds.py:176 models_finds.py:233 models_finds.py:1059 +#: models_treatments.py:45 models_treatments.py:591 msgid "Order" msgstr "" @@ -904,12 +1010,10 @@ msgid "Material type quality types" msgstr "" #: models_finds.py:82 -#| msgid "Conservatory state" msgid "Conservatory state type" msgstr "" #: models_finds.py:83 -#| msgid "Conservatory states" msgid "Conservatory state types" msgstr "" @@ -917,573 +1021,697 @@ msgstr "" msgid "Virtual" msgstr "" -#: models_finds.py:95 -msgid "Upstream is many" +#: models_finds.py:94 +msgid "Destructive" +msgstr "" + +#: models_finds.py:96 +msgid "Create a new find" msgstr "" #: models_finds.py:97 -msgid "Check this if for this treatment from many finds you'll get one." +msgid "" +"If True when this treatment is applied a new version of the object will be " +"created." msgstr "" #: models_finds.py:100 -msgid "Downstream is many" +msgid "Upstream is many" msgstr "" #: models_finds.py:102 +msgid "Check this if for this treatment from many finds you'll get one." +msgstr "" + +#: models_finds.py:105 +msgid "Downstream is many" +msgstr "" + +#: models_finds.py:107 msgid "Check this if for this treatment from one find you'll get many." msgstr "" -#: models_finds.py:107 models_treatments.py:240 -msgid "Treatment types" +#: models_finds.py:110 +msgid "Change reference location" +msgstr "" + +#: models_finds.py:111 +msgid "The treatment change the reference location." +msgstr "" + +#: models_finds.py:113 +msgid "Change current location" +msgstr "" + +#: models_finds.py:114 +msgid "The treatment change the current location." +msgstr "" + +#: models_finds.py:116 +msgid "Restore the reference location" msgstr "" #: models_finds.py:117 +msgid "" +"The treatment change restore reference location to the current location." +msgstr "" + +#: models_finds.py:122 models_treatments.py:262 +msgid "Treatment types" +msgstr "" + +#: models_finds.py:132 msgid "Integrity / interest type" msgstr "" -#: models_finds.py:118 +#: models_finds.py:133 msgid "Integrity / interest types" msgstr "" -#: models_finds.py:128 +#: models_finds.py:143 msgid "Remarkability type" msgstr "" -#: models_finds.py:129 +#: models_finds.py:144 msgid "Remarkability types" msgstr "" -#: models_finds.py:140 +#: models_finds.py:155 msgid "Batch type" msgstr "" -#: models_finds.py:141 +#: models_finds.py:156 msgid "Batch types" msgstr "" -#: models_finds.py:164 +#: models_finds.py:179 msgid "Object type quality type" msgstr "" -#: models_finds.py:165 +#: models_finds.py:180 msgid "Object type quality types" msgstr "" -#: models_finds.py:175 +#: models_finds.py:190 msgid "Alteration type" msgstr "" -#: models_finds.py:176 +#: models_finds.py:191 msgid "Alteration types" msgstr "" -#: models_finds.py:186 +#: models_finds.py:201 msgid "Alteration cause type" msgstr "" -#: models_finds.py:187 +#: models_finds.py:202 msgid "Alteration cause types" msgstr "" -#: models_finds.py:197 +#: models_finds.py:212 msgid "Treatment emergency type" msgstr "" -#: models_finds.py:198 +#: models_finds.py:213 msgid "Treatment emergency types" msgstr "" -#: models_finds.py:208 +#: models_finds.py:223 msgid "Communicability type" msgstr "" -#: models_finds.py:209 +#: models_finds.py:224 msgid "Communicability types" msgstr "" -#: models_finds.py:221 +#: models_finds.py:236 msgid "Checked type" msgstr "" -#: models_finds.py:222 +#: models_finds.py:237 msgid "Checked types" msgstr "" -#: models_finds.py:254 models_finds.py:960 models_treatments.py:143 -#: models_treatments.py:586 +#: models_finds.py:269 models_finds.py:1052 models_treatments.py:161 +#: models_treatments.py:824 msgid "External ID" msgstr "" -#: models_finds.py:256 models_finds.py:962 +#: models_finds.py:271 models_finds.py:1054 msgid "External ID is set automatically" msgstr "" -#: models_finds.py:260 +#: models_finds.py:275 msgid "Special interest" msgstr "" -#: models_finds.py:264 +#: models_finds.py:279 msgid "Context Record" msgstr "" -#: models_finds.py:272 +#: models_finds.py:287 msgid "Material index" msgstr "" -#: models_finds.py:289 +#: models_finds.py:304 msgid "Point (3D)" msgstr "" -#: models_finds.py:295 models_finds.py:298 +#: models_finds.py:310 models_finds.py:313 msgid "Cached value - do not edit" msgstr "" -#: models_finds.py:308 models_finds.py:958 +#: models_finds.py:323 models_finds.py:1050 msgid "Base find" msgstr "" -#: models_finds.py:309 +#: models_finds.py:324 msgid "Base finds" msgstr "" -#: models_finds.py:565 +#: models_finds.py:589 msgid "g" msgstr "" -#: models_finds.py:566 +#: models_finds.py:590 msgid "kg" msgstr "" -#: models_finds.py:592 views.py:301 +#: models_finds.py:600 views.py:863 views.py:882 +msgid "Duplicate" +msgstr "" + +#: models_finds.py:626 views.py:379 msgid "Manage basket" msgstr "" -#: models_finds.py:661 +#: models_finds.py:633 models_finds.py:1299 +msgid "Add treatment" +msgstr "" + +#: models_finds.py:723 msgid "Base find - Short ID" msgstr "" -#: models_finds.py:662 +#: models_finds.py:724 msgid "Base find - Complete ID" msgstr "" -#: models_finds.py:664 +#: models_finds.py:726 msgid "Operation (code)" msgstr "" -#: models_finds.py:666 +#: models_finds.py:728 msgid "Town" msgstr "" -#: models_finds.py:668 +#: models_finds.py:730 msgid "Operation (name)" msgstr "" -#: models_finds.py:672 +#: models_finds.py:734 msgid "Parcel" msgstr "" -#: models_finds.py:673 +#: models_finds.py:735 msgid "Batch" msgstr "" -#: models_finds.py:674 +#: models_finds.py:736 msgid "Base find - Comment" msgstr "" -#: models_finds.py:675 +#: models_finds.py:737 msgid "Base find - Description" msgstr "" -#: models_finds.py:676 +#: models_finds.py:738 msgid "Base find - Topographic localisation" msgstr "" -#: models_finds.py:678 +#: models_finds.py:740 msgid "Base find - Special interest" msgstr "" -#: models_finds.py:680 +#: models_finds.py:742 msgid "Base find - Discovery date (exact or TPQ)" msgstr "" -#: models_finds.py:682 +#: models_finds.py:744 msgid "Base find - Discovery date (TAQ)" msgstr "" -#: models_finds.py:684 +#: models_finds.py:745 +msgid "Current container" +msgstr "" + +#: models_finds.py:746 models_finds.py:1097 +msgid "Reference container" +msgstr "" + +#: models_finds.py:747 msgid "Periods" msgstr "" -#: models_finds.py:760 +#: models_finds.py:823 msgctxt "key for text search" msgid "short-id" msgstr "" -#: models_finds.py:764 +#: models_finds.py:827 msgctxt "key for text search" msgid "complete-id" msgstr "" -#: models_finds.py:768 +#: models_finds.py:831 msgctxt "key for text search" msgid "free-id" msgstr "" -#: models_finds.py:772 +#: models_finds.py:835 msgctxt "key for text search" msgid "denomination" msgstr "" -#: models_finds.py:776 +#: models_finds.py:839 msgctxt "key for text search" msgid "town" msgstr "" -#: models_finds.py:780 models_treatments.py:87 models_treatments.py:551 +#: models_finds.py:843 models_treatments.py:102 models_treatments.py:789 msgctxt "key for text search" msgid "year" msgstr "" -#: models_finds.py:784 +#: models_finds.py:847 msgctxt "key for text search" msgid "operation-code" msgstr "" -#: models_finds.py:788 +#: models_finds.py:851 msgctxt "key for text search" msgid "code-patriarche" msgstr "" -#: models_finds.py:792 +#: models_finds.py:855 msgctxt "key for text search" msgid "operation-type" msgstr "" -#: models_finds.py:797 +#: models_finds.py:860 msgctxt "key for text search" msgid "area" msgstr "" -#: models_finds.py:801 +#: models_finds.py:864 msgctxt "key for text search" msgid "site" msgstr "" -#: models_finds.py:806 models_finds.py:945 +#: models_finds.py:869 models_finds.py:1037 msgctxt "key for text search" msgid "context-record-site" msgstr "" -#: models_finds.py:811 models_finds.py:939 +#: models_finds.py:874 models_finds.py:1031 msgctxt "key for text search" msgid "context-record" msgstr "" -#: models_finds.py:815 +#: models_finds.py:878 msgctxt "key for text search" msgid "operation-relation-type" msgstr "" -#: models_finds.py:819 +#: models_finds.py:882 msgctxt "key for text search" msgid "context-record-relation-type" msgstr "" -#: models_finds.py:823 +#: models_finds.py:886 msgctxt "key for text search" msgid "period" msgstr "" -#: models_finds.py:827 +#: models_finds.py:890 msgctxt "key for text search" msgid "material" msgstr "" -#: models_finds.py:831 +#: models_finds.py:894 msgctxt "key for text search" msgid "object-type" msgstr "" -#: models_finds.py:835 +#: models_finds.py:898 msgctxt "key for text search" msgid "preservation" msgstr "" -#: models_finds.py:839 +#: models_finds.py:902 msgctxt "key for text search" msgid "conservatory" msgstr "" -#: models_finds.py:843 +#: models_finds.py:906 msgctxt "key for text search" msgid "integrity" msgstr "" -#: models_finds.py:847 +#: models_finds.py:910 msgctxt "key for text search" msgid "remarkability" msgstr "" -#: models_finds.py:851 +#: models_finds.py:914 msgctxt "key for text search" msgid "description" msgstr "" -#: models_finds.py:855 +#: models_finds.py:918 msgctxt "key for text search" msgid "batch" msgstr "" -#: models_finds.py:859 +#: models_finds.py:922 msgctxt "key for text search" msgid "checked" msgstr "" -#: models_finds.py:863 models_treatments.py:95 +#: models_finds.py:926 models_treatments.py:110 msgctxt "key for text search" msgid "has-image" msgstr "" -#: models_finds.py:867 models_finds.py:942 +#: models_finds.py:930 models_finds.py:1034 msgctxt "key for text search" msgid "location" msgstr "" -#: models_finds.py:871 +#: models_finds.py:934 msgctxt "key for text search" msgid "warehouse" msgstr "" -#: models_finds.py:875 +#: models_finds.py:938 msgctxt "key for text search" msgid "container-index" msgstr "" -#: models_finds.py:879 +#: models_finds.py:942 msgctxt "key for text search" msgid "container-ref" msgstr "" -#: models_finds.py:883 +#: models_finds.py:946 +msgctxt "key for text search" +msgid "current-location" +msgstr "" + +#: models_finds.py:950 +msgctxt "key for text search" +msgid "current-warehouse" +msgstr "" + +#: models_finds.py:954 +msgctxt "key for text search" +msgid "current-container-index" +msgstr "" + +#: models_finds.py:958 +msgctxt "key for text search" +msgid "current-container-ref" +msgstr "" + +#: models_finds.py:962 wizards.py:399 msgctxt "key for text search" msgid "basket" msgstr "" -#: models_finds.py:887 models_finds.py:936 +#: models_finds.py:966 models_finds.py:1028 msgctxt "key for text search" msgid "operation" msgstr "" -#: models_finds.py:891 +#: models_finds.py:970 msgctxt "key for text search" msgid "last-modified-by" msgstr "" -#: models_finds.py:895 +#: models_finds.py:974 msgctxt "key for text search" msgid "modified-since" msgstr "" -#: models_finds.py:919 -msgid "Bulk update" +#: models_finds.py:978 +msgctxt "key for text search" +msgid "created-by" msgstr "" -#: models_finds.py:930 models_finds.py:1180 -#: templates/ishtar/forms/qa_find_treatment.html:16 views.py:666 -msgid "Packaging" +#: models_finds.py:982 +msgctxt "key for text search" +msgid "loan" msgstr "" #: models_finds.py:986 +msgctxt "key for text search" +msgid "treatment-end-date-before" +msgstr "" + +#: models_finds.py:1011 +msgid "Bulk update" +msgstr "" + +#: models_finds.py:1078 msgid "Weight" msgstr "" -#: models_finds.py:987 +#: models_finds.py:1079 msgid "Weight unit" msgstr "" -#: models_finds.py:993 templates/ishtar/sheet_find.html:174 +#: models_finds.py:1085 templates/ishtar/sheet_find.html:291 msgid "Upstream treatment" msgstr "" -#: models_finds.py:996 templates/ishtar/sheet_find.html:212 +#: models_finds.py:1088 templates/ishtar/sheet_find.html:329 msgid "Downstream treatment" msgstr "" -#: models_finds.py:1031 +#: models_finds.py:1130 msgid "Clutter - long side (cm)" msgstr "" -#: models_finds.py:1033 +#: models_finds.py:1132 msgid "Clutter - short side (cm)" msgstr "" -#: models_finds.py:1035 +#: models_finds.py:1134 msgid "Clutter - height (cm)" msgstr "" -#: models_finds.py:1051 +#: models_finds.py:1150 msgid "Collection" msgstr "" -#: models_finds.py:1083 models_treatments.py:165 models_treatments.py:613 +#: models_finds.py:1180 models_treatments.py:180 models_treatments.py:849 +#: templates/ishtar/sheet_find.html:56 templates/ishtar/sheet_treatment.html:32 +msgid "Documents" +msgstr "" + +#: models_finds.py:1183 models_treatments.py:188 +#: templates/ishtar/sheet_find.html:254 +#: templates/ishtar/sheet_treatmentfile.html:62 +msgid "Treatments" +msgstr "" + +#: models_finds.py:1185 +msgid "Related treatments when no new find is created" +msgstr "" + +#: models_finds.py:1186 models_treatments.py:182 models_treatments.py:855 msgid "Cached name" msgstr "" -#: models_finds.py:1105 +#: models_finds.py:1208 msgid "FIND" msgstr "" -#: models_finds.py:1174 +#: models_finds.py:1296 msgid "Add to basket" msgstr "" -#: models_finds.py:1222 wizards.py:74 wizards.py:219 +#: models_finds.py:1346 wizards.py:85 wizards.py:477 msgid "Operation" msgstr "" -#: models_finds.py:1544 +#: models_finds.py:1738 +msgid "No reference container have been set - the localisation cannot be set." +msgstr "" + +#: models_finds.py:1742 msgid "No container have been set - the localisation cannot be set." msgstr "" -#: models_finds.py:1550 +#: models_finds.py:1748 msgid "The division number {} have not been set for the warehouse {}." msgstr "" -#: models_finds.py:1720 +#: models_finds.py:1962 msgid "Person" msgstr "" -#: models_finds.py:1726 +#: models_finds.py:1968 msgid "Property" msgstr "" -#: models_finds.py:1727 +#: models_finds.py:1969 msgid "Properties" msgstr "" -#: models_treatments.py:42 +#: models_treatments.py:44 +msgid "Treatment is executed" +msgstr "" + +#: models_treatments.py:48 msgid "Treatment state type" msgstr "" -#: models_treatments.py:43 +#: models_treatments.py:49 msgid "Treatment state types" msgstr "" -#: models_treatments.py:67 +#: models_treatments.py:80 msgid "Downstream find" msgstr "" -#: models_treatments.py:79 +#: models_treatments.py:81 +msgid "Upstream find" +msgstr "" + +#: models_treatments.py:94 msgctxt "key for text search" msgid "label" msgstr "" -#: models_treatments.py:83 +#: models_treatments.py:98 msgctxt "key for text search" msgid "other-reference" msgstr "" -#: models_treatments.py:91 models_treatments.py:555 +#: models_treatments.py:106 models_treatments.py:793 msgctxt "key for text search" msgid "index" msgstr "" -#: models_treatments.py:99 models_treatments.py:559 +#: models_treatments.py:114 models_treatments.py:797 msgctxt "key for text search" msgid "type" msgstr "" -#: models_treatments.py:135 +#: models_treatments.py:149 +msgid "Treatment have been executed" +msgstr "" + +#: models_treatments.py:153 msgid "Location where the treatment is done. Target warehouse for a move." msgstr "" -#: models_treatments.py:152 +#: models_treatments.py:171 msgid "Estimated cost" msgstr "" -#: models_treatments.py:154 +#: models_treatments.py:173 msgid "Quoted cost" msgstr "" -#: models_treatments.py:156 +#: models_treatments.py:175 msgid "Realized cost" msgstr "" -#: models_treatments.py:158 +#: models_treatments.py:177 msgid "Insurance cost" msgstr "" -#: models_treatments.py:160 -msgid "Target a basket" +#: models_treatments.py:208 +msgid "TREATMENT" msgstr "" -#: models_treatments.py:171 templates/ishtar/sheet_find.html:171 -#: templates/ishtar/sheet_treatmentfile.html:61 -msgid "Treatments" +#: models_treatments.py:271 templates/ishtar/sheet_treatment.html:107 +msgid "Downstream finds" msgstr "" -#: models_treatments.py:190 -msgid "TREATMENT" +#: models_treatments.py:289 models_treatments.py:911 +msgid "Add associated administrative act" msgstr "" -#: models_treatments.py:249 templates/ishtar/sheet_treatment.html:61 -msgid "Downstream finds" +#: models_treatments.py:290 models_treatments.py:912 +msgid "admin. act" msgstr "" -#: models_treatments.py:364 templates/ishtar/sheet_find.html:183 -#: templates/ishtar/sheet_find.html:221 +#: models_treatments.py:600 templates/ishtar/sheet_find.html:263 +#: templates/ishtar/sheet_find.html:300 templates/ishtar/sheet_find.html:338 msgid "Doer" msgstr "" -#: models_treatments.py:365 models_treatments.py:366 +#: models_treatments.py:601 models_treatments.py:602 +#: templates/ishtar/sheet_treatment.html:97 msgid "Related finds" msgstr "" -#: models_treatments.py:508 +#: models_treatments.py:744 msgid "Is upstream" msgstr "" -#: models_treatments.py:520 +#: models_treatments.py:758 msgid "Treatment request types" msgstr "" -#: models_treatments.py:543 +#: models_treatments.py:781 msgctxt "key for text search" msgid "name" msgstr "" -#: models_treatments.py:547 +#: models_treatments.py:785 msgctxt "key for text search" msgid "reference" msgstr "" -#: models_treatments.py:563 +#: models_treatments.py:801 msgctxt "key for text search" msgid "in-charge" msgstr "" -#: models_treatments.py:567 +#: models_treatments.py:805 msgctxt "key for text search" msgid "applicant" msgstr "" -#: models_treatments.py:571 +#: models_treatments.py:809 msgctxt "key for text search" msgid "applicant-organisation" msgstr "" -#: models_treatments.py:584 +#: models_treatments.py:822 msgid "Internal reference" msgstr "" -#: models_treatments.py:593 +#: models_treatments.py:831 msgid "Person in charge" msgstr "" -#: models_treatments.py:619 +#: models_treatments.py:861 msgid "Treatment requests" msgstr "" +#: models_treatments.py:924 +msgid "Add associated treatment" +msgstr "" + +#: templates/ishtar/blocks/window_find_nav.html:9 +msgid "Baskets" +msgstr "" + #: templates/ishtar/forms/qa_find_basket.html:22 msgid "New" msgstr "" @@ -1492,49 +1720,54 @@ msgstr "" msgid "Add" msgstr "" -#: templates/ishtar/forms/qa_find_treatment.html:31 +#: templates/ishtar/forms/qa_find_treatment.html:37 msgid "Associate a treatment" msgstr "" -#: templates/ishtar/sheet_basefind.html:6 +#: templates/ishtar/forms/qa_findbasket_duplicate.html:6 +msgid "" +"Items of the basket will be attached to the new basket but not the shares." +msgstr "" + +#: templates/ishtar/sheet_basefind.html:10 msgid "Internal ID" msgstr "" -#: templates/ishtar/sheet_basefind.html:21 +#: templates/ishtar/sheet_basefind.html:25 msgid "Discovery date" msgstr "" -#: templates/ishtar/sheet_basefind.html:24 +#: templates/ishtar/sheet_basefind.html:28 msgid "Discovery year" msgstr "" -#: templates/ishtar/sheet_basefind.html:27 +#: templates/ishtar/sheet_basefind.html:31 msgid "Discovery date (TPQ)" msgstr "" -#: templates/ishtar/sheet_basefind.html:52 +#: templates/ishtar/sheet_basefind.html:56 msgid "X:" msgstr "" -#: templates/ishtar/sheet_basefind.html:53 -#: templates/ishtar/sheet_basefind.html:55 #: templates/ishtar/sheet_basefind.html:57 +#: templates/ishtar/sheet_basefind.html:59 +#: templates/ishtar/sheet_basefind.html:61 msgid "error:" msgstr "" -#: templates/ishtar/sheet_basefind.html:54 +#: templates/ishtar/sheet_basefind.html:58 msgid "Y:" msgstr "" -#: templates/ishtar/sheet_basefind.html:56 +#: templates/ishtar/sheet_basefind.html:60 msgid "Z:" msgstr "" -#: templates/ishtar/sheet_basefind.html:60 +#: templates/ishtar/sheet_basefind.html:64 msgid "SRID" msgstr "" -#: templates/ishtar/sheet_basefind.html:75 +#: templates/ishtar/sheet_basefind.html:79 msgid "Last modified by" msgstr "" @@ -1544,65 +1777,85 @@ msgid "" "the find." msgstr "" -#: templates/ishtar/sheet_find.html:29 -msgid "Associated base finds" +#: templates/ishtar/sheet_find.html:23 +msgid "Image / Base find" +msgstr "" + +#: templates/ishtar/sheet_find.html:30 +msgid "Identification / Description / Dimensions" +msgstr "" + +#: templates/ishtar/sheet_find.html:38 +msgid "Datings / Preservation" +msgstr "" + +#: templates/ishtar/sheet_find.html:47 +msgid "Warehouse / Treatments" +msgstr "" + +#: templates/ishtar/sheet_find.html:64 +msgid "Custom fields" msgstr "" -#: templates/ishtar/sheet_find.html:53 +#: templates/ishtar/sheet_find.html:123 msgid "Administrative index" msgstr "" -#: templates/ishtar/sheet_find.html:95 +#: templates/ishtar/sheet_find.html:166 msgid "Checked" msgstr "" -#: templates/ishtar/sheet_find.html:160 -msgid "Warehouse" +#: templates/ishtar/sheet_find.html:233 +msgid "Warehouse - reference container" msgstr "" -#: templates/ishtar/sheet_find.html:178 templates/ishtar/sheet_find.html:216 +#: templates/ishtar/sheet_find.html:243 +msgid "Warehouse - current container" +msgstr "" + +#: templates/ishtar/sheet_find.html:258 templates/ishtar/sheet_find.html:295 +#: templates/ishtar/sheet_find.html:333 msgid "Year - index" msgstr "" -#: templates/ishtar/sheet_find.html:182 templates/ishtar/sheet_find.html:220 +#: templates/ishtar/sheet_find.html:262 templates/ishtar/sheet_find.html:299 +#: templates/ishtar/sheet_find.html:337 msgid "Related finds (max. 15 displayed)" msgstr "" -#: templates/ishtar/sheet_find.html:208 +#: templates/ishtar/sheet_find.html:325 msgid "Export as CSV" msgstr "" -#: templates/ishtar/sheet_find.html:208 templates/ishtar/sheet_find.html:247 +#: templates/ishtar/sheet_find.html:325 templates/ishtar/sheet_find.html:364 msgid "CSV" msgstr "" -#: templates/ishtar/sheet_find.html:252 +#: templates/ishtar/sheet_find.html:371 +#: templates/ishtar/sheet_treatment.html:124 msgid "Associated documents" msgstr "" -#: templates/ishtar/sheet_findbasket.html:19 +#: templates/ishtar/sheet_findbasket.html:20 msgid "Content" msgstr "" -#: templates/ishtar/sheet_treatment.html:25 +#: templates/ishtar/sheet_treatment.html:41 +#: templates/ishtar/sheet_treatment.html:132 +#: templates/ishtar/sheet_treatmentfile.html:74 +msgid "Administrative acts" +msgstr "" + +#: templates/ishtar/sheet_treatment.html:63 msgctxt "Treatment" msgid "Closed" msgstr "" -#: templates/ishtar/sheet_treatment.html:27 +#: templates/ishtar/sheet_treatment.html:65 msgctxt "Treatment" msgid "Active" msgstr "" -#: templates/ishtar/sheet_treatment.html:66 -msgid "Related operations" -msgstr "" - -#: templates/ishtar/sheet_treatment.html:77 -#: templates/ishtar/sheet_treatmentfile.html:73 -msgid "Administrative acts" -msgstr "" - #: templates/ishtar/sheet_treatmentfile.html:24 msgctxt "Treatment request" msgid "Closed" @@ -1613,86 +1866,132 @@ msgctxt "Treatment request" msgid "Active" msgstr "" -#: views.py:132 +#: templates/ishtar/wizard/wizard_findbasket_deletion.html:8 +msgid "This basket is attached to treatments requests:" +msgstr "" + +#: templates/ishtar/wizard/wizard_findbasket_deletion.html:12 +msgid "Are you sure you want to delete this basket?" +msgstr "" + +#: templates/ishtar/wizard/wizard_findbasket_deletion.html:16 +msgid "Items inside the basket (these items will not be deleted):" +msgstr "" + +#: templates/ishtar/wizard/wizard_findbasket_deletion.html:23 +msgid "Basket informations:" +msgstr "" + +#: templates/ishtar/wizard/wizard_simplefind.html:6 +msgid "" +"This find is related to many base finds. To edit field related to base finds " +"edit the corresponding find between theses:" +msgstr "" + +#: templates/ishtar/wizard/wizard_treatement_deletion.html:8 +msgid "Are you sure you want to delete this treatment?" +msgstr "" + +#: templates/ishtar/wizard/wizard_treatement_deletion.html:10 +msgid "The following finds will be deleted and restored to a previous version." +msgstr "" + +#: templates/ishtar/wizard/wizard_treatement_deletion.html:16 +msgid "" +"All changes made to the associated finds since this treatment record will be " +"lost!" +msgstr "" + +#: templates/ishtar/wizard/wizard_treatement_deletion.html:21 +msgid "Treatment informations:" +msgstr "" + +#: views.py:175 msgid "Basket modify" msgstr "" -#: views.py:173 +#: views.py:198 +msgid "Basket deletion" +msgstr "" + +#: views.py:229 msgid "New find" msgstr "" -#: views.py:209 +#: views.py:281 msgid "Find modification" msgstr "" -#: views.py:238 +#: views.py:316 msgid "Find deletion" msgstr "" -#: views.py:251 +#: views.py:329 msgid "New basket" msgstr "" -#: views.py:280 +#: views.py:358 msgid "Manage items in basket" msgstr "" -#: views.py:389 -msgid "Delete basket" -msgstr "" - -#: views.py:441 +#: views.py:484 views.py:497 views.py:510 msgid "New treatment" msgstr "" -#: views.py:449 +#: views.py:518 msgid "Treatment modification" msgstr "" -#: views.py:466 +#: views.py:609 msgid "Treatment deletion" msgstr "" -#: views.py:473 +#: views.py:616 msgid "Treatment: search administrative act" msgstr "" -#: views.py:482 +#: views.py:625 msgid "Treatment: new administrative act" msgstr "" -#: views.py:492 +#: views.py:635 msgid "Treatment: administrative act modification" msgstr "" -#: views.py:501 +#: views.py:644 msgid "Treatment: administrative act deletion" msgstr "" -#: views.py:534 +#: views.py:691 msgid "New treatment request" msgstr "" -#: views.py:541 +#: views.py:700 msgid "Treatment request modification" msgstr "" -#: views.py:557 +#: views.py:716 msgid "Treatment request deletion" msgstr "" -#: views.py:564 +#: views.py:723 msgid "Treatment request: search administrative act" msgstr "" -#: views.py:574 +#: views.py:734 msgid "Treatment request: new administrative act" msgstr "" -#: views.py:584 +#: views.py:744 msgid "Treatment request: administrative act modification" msgstr "" -#: views.py:593 +#: views.py:753 msgid "Treatment request: administrative act deletion" msgstr "" + +#: wizards.py:394 +msgid "" +"The new basket: \"{}\" have been created with the resulting items. This " +"search have been pinned." +msgstr "" diff --git a/archaeological_finds/migrations/0039_auto_20181115_1649.py b/archaeological_finds/migrations/0039_auto_20181115_1649.py new file mode 100644 index 000000000..3752c173c --- /dev/null +++ b/archaeological_finds/migrations/0039_auto_20181115_1649.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-11-15 16:49 +from __future__ import unicode_literals + +from django.db import migrations, models +import virtualtime + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_finds', '0038_auto_20181112_1625'), + ] + + operations = [ + migrations.AddField( + model_name='historicaltreatment', + name='creation_date', + field=models.DateTimeField(default=virtualtime.virtual_datetime.now), + ), + migrations.AddField( + model_name='treatment', + name='creation_date', + field=models.DateTimeField(default=virtualtime.virtual_datetime.now), + ), + migrations.AddField( + model_name='treatment', + name='finds', + field=models.ManyToManyField(blank=True, help_text='Related finds for non-destructive treatment', related_name='treatments', to='archaeological_finds.Find', verbose_name='Finds'), + ), + migrations.AddField( + model_name='treatmenttype', + name='destructive', + field=models.BooleanField(default=False, verbose_name='Destructive'), + ), + ] diff --git a/archaeological_finds/migrations/0040_auto_20181120_1027.py b/archaeological_finds/migrations/0040_auto_20181120_1027.py new file mode 100644 index 000000000..fd649dd8f --- /dev/null +++ b/archaeological_finds/migrations/0040_auto_20181120_1027.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-11-20 10:27 +from __future__ import unicode_literals + +from django.db import migrations, models + + +def init_create_new_find(apps, schema): + TreatmentType = apps.get_model('archaeological_finds', 'TreatmentType') + for tp in TreatmentType.objects.all(): + if (tp.upstream_is_many or tp.downstream_is_many) and not tp.virtual: + tp.create_new_find = True + tp.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_finds', '0039_auto_20181115_1649'), + ] + + operations = [ + migrations.AlterModelOptions( + name='treatment', + options={'ordering': ('start_date',), 'permissions': (('view_treatment', 'Can view all Treatments'), ('view_own_treatment', 'Can view own Treatment'), ('add_own_treatment', 'Can add own Treatment'), ('change_own_treatment', 'Can change own Treatment'), ('delete_own_treatment', 'Can delete own Treatment')), 'verbose_name': 'Treatment', 'verbose_name_plural': 'Treatments'}, + ), + migrations.AddField( + model_name='treatmenttype', + name='create_new_find', + field=models.BooleanField(default=False, help_text='If True when this treatment is applied a new version of the object will be created.', verbose_name='Create a new find'), + ), + migrations.RunPython(init_create_new_find) + ] diff --git a/archaeological_finds/migrations/0041_auto_20181121_1225.py b/archaeological_finds/migrations/0041_auto_20181121_1225.py new file mode 100644 index 000000000..248dc6499 --- /dev/null +++ b/archaeological_finds/migrations/0041_auto_20181121_1225.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-11-21 12:25 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_finds', '0040_auto_20181120_1027'), + ] + + operations = [ + migrations.RemoveField( + model_name='treatment', + name='finds', + ), + migrations.AddField( + model_name='find', + name='treatments', + field=models.ManyToManyField(blank=True, help_text='Related treatments when no new find is created', related_name='finds', to='archaeological_finds.Treatment', verbose_name='Treatments'), + ), + ] diff --git a/archaeological_finds/migrations/0042_auto_20181129_1755.py b/archaeological_finds/migrations/0042_auto_20181129_1755.py new file mode 100644 index 000000000..42d732cf2 --- /dev/null +++ b/archaeological_finds/migrations/0042_auto_20181129_1755.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-11-29 17:55 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ishtar_common', '0077_auto_20181129_1755'), + ('archaeological_finds', '0041_auto_20181121_1225'), + ] + + operations = [ + migrations.AlterModelOptions( + name='treatmentfile', + options={'ordering': ('cached_label',), 'permissions': (('view_treatmentfile', 'Can view all Treatment requests'), ('view_own_treatmentfile', 'Can view own Treatment request'), ('add_own_treatmentfile', 'Can add own Treatment request'), ('change_own_treatmentfile', 'Can change own Treatment request'), ('delete_own_treatmentfile', 'Can delete own Treatment request')), 'verbose_name': 'Treatment request', 'verbose_name_plural': 'Treatment requests'}, + ), + migrations.AddField( + model_name='findbasket', + name='shared_write_with', + field=models.ManyToManyField(blank=True, related_name='shared_write_findbaskets', to='ishtar_common.IshtarUser', verbose_name='Shared (read/edit) with'), + ), + migrations.AlterField( + model_name='findbasket', + name='shared_with', + field=models.ManyToManyField(blank=True, related_name='shared_findbaskets', to='ishtar_common.IshtarUser', verbose_name='Shared (read) with'), + ), + ] diff --git a/archaeological_finds/migrations/0043_auto_20181130_1310.py b/archaeological_finds/migrations/0043_auto_20181130_1310.py new file mode 100644 index 000000000..e8881e45d --- /dev/null +++ b/archaeological_finds/migrations/0043_auto_20181130_1310.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-11-30 13:10 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_finds', '0042_auto_20181129_1755'), + ] + + operations = [ + migrations.RemoveField( + model_name='historicaltreatment', + name='target_is_basket', + ), + migrations.RemoveField( + model_name='treatment', + name='target_is_basket', + ), + migrations.AddField( + model_name='historicaltreatmentfile', + name='associated_basket', + field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='archaeological_finds.FindBasket'), + ), + migrations.AddField( + model_name='treatmentfile', + name='associated_basket', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='archaeological_finds.FindBasket'), + ), + ] diff --git a/archaeological_finds/migrations/0044_auto_20181201_1854.py b/archaeological_finds/migrations/0044_auto_20181201_1854.py new file mode 100644 index 000000000..e11a9db81 --- /dev/null +++ b/archaeological_finds/migrations/0044_auto_20181201_1854.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-12-01 18:54 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_warehouse', '0025_auto_20181112_1842'), + ('archaeological_finds', '0043_auto_20181130_1310'), + ] + + operations = [ + migrations.AlterModelOptions( + name='findbasket', + options={'permissions': (('view_find', 'Can view all Finds'), ('view_own_find', 'Can view own Find')), 'verbose_name': 'Basket'}, + ), + migrations.AddField( + model_name='find', + name='container_ref', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='finds_ref', to='archaeological_warehouse.Container', verbose_name='Reference container'), + ), + migrations.AddField( + model_name='historicalfind', + name='container_ref', + field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='archaeological_warehouse.Container'), + ), + migrations.AlterField( + model_name='treatmentfile', + name='associated_basket', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='treatment_files', to='archaeological_finds.FindBasket'), + ), + ] diff --git a/archaeological_finds/migrations/0045_migrate_current_container_to_ref_container.py b/archaeological_finds/migrations/0045_migrate_current_container_to_ref_container.py new file mode 100644 index 000000000..7639f95b7 --- /dev/null +++ b/archaeological_finds/migrations/0045_migrate_current_container_to_ref_container.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-12-01 19:17 +from __future__ import unicode_literals + +from django.db import migrations + + +def migrate_containers(apps, schema): + Find = apps.get_model('archaeological_finds', 'find') + for f in Find.objects.filter(container__isnull=False).all(): + f.skip_history_when_saving = True + f.container_ref = f.container + f.save() + TreatmentType = apps.get_model('archaeological_finds', 'TreatmentType') + TreatmentType.objects.get_or_create( + txt_idx="loan", + defaults={ + "label": u"Prêt", + "virtual": False, + "comment": u"Un prêt est un changement temporaire de contenant " + u"pour du mobilier."} + ) + TreatmentType.objects.get_or_create( + txt_idx="loan-return", + defaults={ + "label": u"Retour de prêt", + "virtual": False, + "comment": u"Retour de mobilier dans son contenant de référence."} + ) + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_finds', '0044_auto_20181201_1854'), + ] + + operations = [ + migrations.RunPython(migrate_containers) + ] diff --git a/archaeological_finds/migrations/0046_treatmentfiletype_treatment_type.py b/archaeological_finds/migrations/0046_treatmentfiletype_treatment_type.py new file mode 100644 index 000000000..867cd4545 --- /dev/null +++ b/archaeological_finds/migrations/0046_treatmentfiletype_treatment_type.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-12-02 18:31 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_finds', '0045_migrate_current_container_to_ref_container'), + ] + + operations = [ + migrations.AddField( + model_name='treatmentfiletype', + name='treatment_type', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_finds.TreatmentType'), + ), + ] diff --git a/archaeological_finds/migrations/0047_auto_20181203_1442.py b/archaeological_finds/migrations/0047_auto_20181203_1442.py new file mode 100644 index 000000000..90ed25028 --- /dev/null +++ b/archaeological_finds/migrations/0047_auto_20181203_1442.py @@ -0,0 +1,1523 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-12-03 14:42 +from __future__ import unicode_literals + +import datetime +from django.conf import settings +import django.contrib.gis.db.models.fields +import django.contrib.postgres.search +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import ishtar_common.utils +import re + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_finds', '0046_treatmentfiletype_treatment_type'), + ] + + operations = [ + migrations.AlterModelOptions( + name='alterationcausetype', + options={'ordering': ('parent__label', 'label'), 'verbose_name': "Type de cause d'alt\xe9ration", 'verbose_name_plural': "Types de cause d'alt\xe9ration"}, + ), + migrations.AlterModelOptions( + name='alterationtype', + options={'ordering': ('parent__label', 'label'), 'verbose_name': "Type d'alt\xe9ration", 'verbose_name_plural': "Types d'alt\xe9ration"}, + ), + migrations.AlterModelOptions( + name='basefind', + options={'permissions': (('view_basefind', 'Can view all Base finds'), ('view_own_basefind', 'Can view own Base find'), ('add_own_basefind', 'Can add own Base find'), ('change_own_basefind', 'Can change own Base find'), ('delete_own_basefind', 'Can delete own Base find')), 'verbose_name': "Mobilier d'origine", 'verbose_name_plural': "Mobilier d'origine"}, + ), + migrations.AlterModelOptions( + name='batchtype', + options={'ordering': ('order',), 'verbose_name': 'Type de lot', 'verbose_name_plural': 'Types de lot'}, + ), + migrations.AlterModelOptions( + name='checkedtype', + options={'ordering': ('order',), 'verbose_name': 'Type de v\xe9rification', 'verbose_name_plural': 'Types de v\xe9rification'}, + ), + migrations.AlterModelOptions( + name='communicabilitytype', + options={'ordering': ('parent__label', 'label'), 'verbose_name': 'Type de communicabilit\xe9', 'verbose_name_plural': 'Types de communicabilit\xe9'}, + ), + migrations.AlterModelOptions( + name='find', + options={'ordering': ('cached_label',), 'permissions': (('view_find', 'Can view all Finds'), ('view_own_find', 'Can view own Find'), ('add_own_find', 'Can add own Find'), ('change_own_find', 'Can change own Find'), ('delete_own_find', 'Can delete own Find')), 'verbose_name': 'Mobilier', 'verbose_name_plural': 'Mobilier'}, + ), + migrations.AlterModelOptions( + name='findbasket', + options={'permissions': (('view_find', 'Can view all Finds'), ('view_own_find', 'Can view own Find')), 'verbose_name': 'Panier'}, + ), + migrations.AlterModelOptions( + name='historicalbasefind', + options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': "historical Mobilier d'origine"}, + ), + migrations.AlterModelOptions( + name='historicalfind', + options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical Mobilier'}, + ), + migrations.AlterModelOptions( + name='historicaltreatment', + options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical Traitement'}, + ), + migrations.AlterModelOptions( + name='historicaltreatmentfile', + options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical Demande de traitement'}, + ), + migrations.AlterModelOptions( + name='integritytype', + options={'ordering': ('label',), 'verbose_name': "Type d'int\xe9grit\xe9 / int\xe9r\xeat", 'verbose_name_plural': "Types d'int\xe9grit\xe9 / int\xe9r\xeat"}, + ), + migrations.AlterModelOptions( + name='materialtype', + options={'ordering': ('label',), 'verbose_name': 'Type de mat\xe9riau', 'verbose_name_plural': 'Types de mat\xe9riau'}, + ), + migrations.AlterModelOptions( + name='materialtypequalitytype', + options={'ordering': ('order',), 'verbose_name': 'Type de qualit\xe9 du type de mat\xe9riaux', 'verbose_name_plural': 'Types de qualit\xe9 du type de mat\xe9riaux'}, + ), + migrations.AlterModelOptions( + name='objecttype', + options={'ordering': ('parent__label', 'label'), 'verbose_name': "Type d'objet", 'verbose_name_plural': "Types d'objet"}, + ), + migrations.AlterModelOptions( + name='objecttypequalitytype', + options={'ordering': ('order',), 'verbose_name': "Type de qualit\xe9 du type d'objet", 'verbose_name_plural': "Types de qualit\xe9 du type d'objet"}, + ), + migrations.AlterModelOptions( + name='property', + options={'verbose_name': 'Propri\xe9t\xe9', 'verbose_name_plural': 'Propri\xe9t\xe9s'}, + ), + migrations.AlterModelOptions( + name='remarkabilitytype', + options={'ordering': ('label',), 'verbose_name': 'Type de remarquabilit\xe9', 'verbose_name_plural': 'Types de remarquabilit\xe9'}, + ), + migrations.AlterModelOptions( + name='treatment', + options={'ordering': ('start_date',), 'permissions': (('view_treatment', 'Can view all Treatments'), ('view_own_treatment', 'Can view own Treatment'), ('add_own_treatment', 'Can add own Treatment'), ('change_own_treatment', 'Can change own Treatment'), ('delete_own_treatment', 'Can delete own Treatment')), 'verbose_name': 'Traitement', 'verbose_name_plural': 'Traitements'}, + ), + migrations.AlterModelOptions( + name='treatmentemergencytype', + options={'ordering': ('label',), 'verbose_name': "Type d'urgence de traitement", 'verbose_name_plural': "Types d'urgence du traitement"}, + ), + migrations.AlterModelOptions( + name='treatmentfile', + options={'ordering': ('cached_label',), 'permissions': (('view_treatmentfile', 'Can view all Treatment requests'), ('view_own_treatmentfile', 'Can view own Treatment request'), ('add_own_treatmentfile', 'Can add own Treatment request'), ('change_own_treatmentfile', 'Can change own Treatment request'), ('delete_own_treatmentfile', 'Can delete own Treatment request')), 'verbose_name': 'Demande de traitement', 'verbose_name_plural': 'Demandes de traitement'}, + ), + migrations.AlterModelOptions( + name='treatmentfiletype', + options={'ordering': ('label',), 'verbose_name': 'Type de demande de traitement', 'verbose_name_plural': 'Types de demande de traitement'}, + ), + migrations.AlterModelOptions( + name='treatmentstate', + options={'ordering': ('label',), 'verbose_name': "Type d'\xe9tat de traitement", 'verbose_name_plural': "Types d'\xe9tat de traitement"}, + ), + migrations.AlterModelOptions( + name='treatmenttype', + options={'ordering': ('order', 'label'), 'verbose_name': 'Type de traitement', 'verbose_name_plural': 'Types de traitement'}, + ), + migrations.AlterField( + model_name='alterationcausetype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='alterationcausetype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='alterationcausetype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='alterationcausetype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='alterationtype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='alterationtype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='alterationtype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='alterationtype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='basefind', + name='auto_external_id', + field=models.BooleanField(default=False, verbose_name="L'identifiant est attribu\xe9 automatiquement"), + ), + migrations.AlterField( + model_name='basefind', + name='batch', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_finds.BatchType', verbose_name='Lot/objet'), + ), + migrations.AlterField( + model_name='basefind', + name='cache_complete_id', + field=models.TextField(blank=True, db_index=True, help_text='Valeur en cache - ne pas \xe9diter', null=True, verbose_name='Identifiant complet'), + ), + migrations.AlterField( + model_name='basefind', + name='cache_short_id', + field=models.TextField(blank=True, db_index=True, help_text='Valeur en cache - ne pas \xe9diter', null=True, verbose_name='Identifiant court'), + ), + migrations.AlterField( + model_name='basefind', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='basefind', + name='context_record', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='base_finds', to='archaeological_context_records.ContextRecord', verbose_name="Unit\xe9 d'Enregistrement"), + ), + migrations.AlterField( + model_name='basefind', + name='discovery_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de d\xe9couverte (exacte ou TPQ)'), + ), + migrations.AlterField( + model_name='basefind', + name='discovery_date_taq', + field=models.DateField(blank=True, null=True, verbose_name='Date de d\xe9couverte (TAQ)'), + ), + migrations.AlterField( + model_name='basefind', + name='estimated_error_x', + field=models.FloatField(blank=True, null=True, verbose_name='Erreur estim\xe9e pour X'), + ), + migrations.AlterField( + model_name='basefind', + name='estimated_error_y', + field=models.FloatField(blank=True, null=True, verbose_name='Erreur estim\xe9e pour Y'), + ), + migrations.AlterField( + model_name='basefind', + name='estimated_error_z', + field=models.FloatField(blank=True, null=True, verbose_name='Erreur estim\xe9e pour Z'), + ), + migrations.AlterField( + model_name='basefind', + name='excavation_id', + field=models.TextField(blank=True, null=True, verbose_name='Identifiant fouille'), + ), + migrations.AlterField( + model_name='basefind', + name='external_id', + field=models.TextField(blank=True, null=True, verbose_name='Identifiant'), + ), + migrations.AlterField( + model_name='basefind', + name='history_creator', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Cr\xe9ateur'), + ), + migrations.AlterField( + model_name='basefind', + name='history_modifier', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Dernier \xe9diteur'), + ), + migrations.AlterField( + model_name='basefind', + name='label', + field=models.TextField(verbose_name='Identifiant libre'), + ), + migrations.AlterField( + model_name='basefind', + name='line', + field=django.contrib.gis.db.models.fields.LineStringField(blank=True, null=True, srid=4326, verbose_name='Ligne'), + ), + migrations.AlterField( + model_name='basefind', + name='material_index', + field=models.IntegerField(default=0, verbose_name='Index mat\xe9riel'), + ), + migrations.AlterField( + model_name='basefind', + name='multi_polygon', + field=django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, null=True, srid=4326, verbose_name='Polygones multi-parties'), + ), + migrations.AlterField( + model_name='basefind', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='basefind', + name='spatial_reference_system', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='ishtar_common.SpatialReferenceSystem', verbose_name='Syst\xe8me de r\xe9f\xe9rence spatiale'), + ), + migrations.AlterField( + model_name='basefind', + name='special_interest', + field=models.CharField(blank=True, max_length=120, null=True, verbose_name='Int\xe9r\xeat sp\xe9cifique'), + ), + migrations.AlterField( + model_name='basefind', + name='topographic_localisation', + field=models.CharField(blank=True, max_length=120, null=True, verbose_name='Point topographique'), + ), + migrations.AlterField( + model_name='batchtype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='batchtype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='batchtype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='batchtype', + name='order', + field=models.IntegerField(default=10, verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='batchtype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='checkedtype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='checkedtype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='checkedtype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='checkedtype', + name='order', + field=models.IntegerField(default=10, verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='checkedtype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='communicabilitytype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='communicabilitytype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='communicabilitytype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='communicabilitytype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='conservatorystate', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='conservatorystate', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='conservatorystate', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='conservatorystate', + name='order', + field=models.IntegerField(default=10, verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='conservatorystate', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='find', + name='alteration_causes', + field=models.ManyToManyField(blank=True, related_name='finds', to='archaeological_finds.AlterationCauseType', verbose_name="Cause d'alt\xe9ration"), + ), + migrations.AlterField( + model_name='find', + name='alterations', + field=models.ManyToManyField(blank=True, related_name='finds', to='archaeological_finds.AlterationType', verbose_name='Alt\xe9ration'), + ), + migrations.AlterField( + model_name='find', + name='appraisal_date', + field=models.DateField(blank=True, null=True, verbose_name="Date d'\xe9valuation"), + ), + migrations.AlterField( + model_name='find', + name='auto_external_id', + field=models.BooleanField(default=False, verbose_name="L'identifiant est attribu\xe9 automatiquement"), + ), + migrations.AlterField( + model_name='find', + name='base_finds', + field=models.ManyToManyField(related_name='find', to='archaeological_finds.BaseFind', verbose_name="Mobilier d'origine"), + ), + migrations.AlterField( + model_name='find', + name='cached_label', + field=models.TextField(blank=True, db_index=True, null=True, verbose_name='Nom en cache'), + ), + migrations.AlterField( + model_name='find', + name='check_date', + field=models.DateField(default=datetime.date.today, verbose_name='Date de v\xe9rification'), + ), + migrations.AlterField( + model_name='find', + name='checked_type', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_finds.CheckedType', verbose_name='V\xe9rification'), + ), + migrations.AlterField( + model_name='find', + name='clutter_height', + field=models.FloatField(blank=True, null=True, verbose_name='Encombrement - hauteur (cm)'), + ), + migrations.AlterField( + model_name='find', + name='clutter_long_side', + field=models.FloatField(blank=True, null=True, verbose_name='Encombrement - grand c\xf4t\xe9 (cm)'), + ), + migrations.AlterField( + model_name='find', + name='clutter_short_side', + field=models.FloatField(blank=True, null=True, verbose_name='Encombrement - petit c\xf4t\xe9 (cm)'), + ), + migrations.AlterField( + model_name='find', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='find', + name='communicabilities', + field=models.ManyToManyField(blank=True, related_name='find', to='archaeological_finds.CommunicabilityType', verbose_name='Communicabilit\xe9'), + ), + migrations.AlterField( + model_name='find', + name='conservatory_comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire relatif \xe0 la conservation'), + ), + migrations.AlterField( + model_name='find', + name='conservatory_state', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='archaeological_finds.ConservatoryState', verbose_name='\xc9tat de conservation'), + ), + migrations.AlterField( + model_name='find', + name='container', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='finds', to='archaeological_warehouse.Container', verbose_name='Contenant'), + ), + migrations.AlterField( + model_name='find', + name='dating_comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire relatif aux datations'), + ), + migrations.AlterField( + model_name='find', + name='datings', + field=models.ManyToManyField(related_name='find', to='archaeological_context_records.Dating', verbose_name='Datation'), + ), + migrations.AlterField( + model_name='find', + name='decoration', + field=models.TextField(blank=True, null=True, verbose_name='D\xe9cor'), + ), + migrations.AlterField( + model_name='find', + name='denomination', + field=models.TextField(blank=True, null=True, verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='find', + name='diameter', + field=models.FloatField(blank=True, null=True, verbose_name='Diam\xe8tre (cm)'), + ), + migrations.AlterField( + model_name='find', + name='dimensions_comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire relatif aux dimensions'), + ), + migrations.AlterField( + model_name='find', + name='downstream_treatment', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='upstream', to='archaeological_finds.Treatment', verbose_name='Traitement aval'), + ), + migrations.AlterField( + model_name='find', + name='estimated_value', + field=models.FloatField(blank=True, null=True, verbose_name='Valeur estim\xe9e'), + ), + migrations.AlterField( + model_name='find', + name='external_id', + field=models.TextField(blank=True, null=True, verbose_name='Identifiant'), + ), + migrations.AlterField( + model_name='find', + name='find_number', + field=models.IntegerField(blank=True, null=True, verbose_name='Mobilier (en nombre)'), + ), + migrations.AlterField( + model_name='find', + name='height', + field=models.FloatField(blank=True, null=True, verbose_name='Hauteur (cm)'), + ), + migrations.AlterField( + model_name='find', + name='history_creator', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Cr\xe9ateur'), + ), + migrations.AlterField( + model_name='find', + name='history_modifier', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Dernier \xe9diteur'), + ), + migrations.AlterField( + model_name='find', + name='insurance_value', + field=models.FloatField(blank=True, null=True, verbose_name="Valeur d'assurance"), + ), + migrations.AlterField( + model_name='find', + name='integrities', + field=models.ManyToManyField(blank=True, related_name='find', to='archaeological_finds.IntegrityType', verbose_name='Int\xe9grit\xe9 / int\xe9r\xeat'), + ), + migrations.AlterField( + model_name='find', + name='is_complete', + field=models.NullBooleanField(verbose_name='Est complet ?'), + ), + migrations.AlterField( + model_name='find', + name='label', + field=models.TextField(verbose_name='Identifiant libre'), + ), + migrations.AlterField( + model_name='find', + name='length', + field=models.FloatField(blank=True, null=True, verbose_name='Longueur (cm)'), + ), + migrations.AlterField( + model_name='find', + name='manufacturing_place', + field=models.TextField(blank=True, null=True, verbose_name='Lieu de fabrication'), + ), + migrations.AlterField( + model_name='find', + name='mark', + field=models.TextField(blank=True, null=True, verbose_name='Marquage'), + ), + migrations.AlterField( + model_name='find', + name='material_type_quality', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='finds', to='archaeological_finds.MaterialTypeQualityType', verbose_name='Qualit\xe9 du type de mat\xe9riaux'), + ), + migrations.AlterField( + model_name='find', + name='material_types', + field=models.ManyToManyField(blank=True, related_name='finds', to='archaeological_finds.MaterialType', verbose_name='Types de mat\xe9riau'), + ), + migrations.AlterField( + model_name='find', + name='min_number_of_individuals', + field=models.IntegerField(blank=True, null=True, verbose_name="Nombre minimum d'individus (NMI)"), + ), + migrations.AlterField( + model_name='find', + name='museum_id', + field=models.TextField(blank=True, null=True, verbose_name='Identifiant mus\xe9e'), + ), + migrations.AlterField( + model_name='find', + name='object_type_quality', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='finds', to='archaeological_finds.ObjectTypeQualityType', verbose_name="Qualit\xe9 du type d'objet"), + ), + migrations.AlterField( + model_name='find', + name='object_types', + field=models.ManyToManyField(blank=True, related_name='find', to='archaeological_finds.ObjectType', verbose_name="Types d'objet"), + ), + migrations.AlterField( + model_name='find', + name='order', + field=models.IntegerField(default=1, verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='find', + name='preservation_to_considers', + field=models.ManyToManyField(blank=True, related_name='finds_recommended', to='archaeological_finds.TreatmentType', verbose_name='Traitements recommand\xe9s'), + ), + migrations.AlterField( + model_name='find', + name='previous_id', + field=models.TextField(blank=True, null=True, verbose_name='Identifiant pr\xe9c\xe9dent'), + ), + migrations.AlterField( + model_name='find', + name='remarkabilities', + field=models.ManyToManyField(blank=True, related_name='find', to='archaeological_finds.RemarkabilityType', verbose_name='Remarquabilit\xe9'), + ), + migrations.AlterField( + model_name='find', + name='seal_number', + field=models.TextField(blank=True, null=True, verbose_name='Num\xe9ro de scell\xe9'), + ), + migrations.AlterField( + model_name='find', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='find', + name='thickness', + field=models.FloatField(blank=True, null=True, verbose_name='\xc9paisseur (cm)'), + ), + migrations.AlterField( + model_name='find', + name='treatment_emergency', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_finds.TreatmentEmergencyType', verbose_name='Urgence du traitement'), + ), + migrations.AlterField( + model_name='find', + name='treatments', + field=models.ManyToManyField(blank=True, help_text='Related treatments when no new find is created', related_name='finds', to='archaeological_finds.Treatment', verbose_name='Traitements'), + ), + migrations.AlterField( + model_name='find', + name='upstream_treatment', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='downstream', to='archaeological_finds.Treatment', verbose_name='Traitement amont'), + ), + migrations.AlterField( + model_name='find', + name='weight', + field=models.FloatField(blank=True, null=True, verbose_name='Poids'), + ), + migrations.AlterField( + model_name='find', + name='weight_unit', + field=models.CharField(blank=True, choices=[(b'g', 'g'), (b'kg', 'kg')], max_length=4, null=True, verbose_name='Unit\xe9 de poids'), + ), + migrations.AlterField( + model_name='find', + name='width', + field=models.FloatField(blank=True, null=True, verbose_name='Largeur (cm)'), + ), + migrations.AlterField( + model_name='findbasket', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='findbasket', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='findbasket', + name='label', + field=models.CharField(max_length=1000, verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='findbasket', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='findbasket', + name='user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='findbaskets', to='ishtar_common.IshtarUser', verbose_name='Propri\xe9taire'), + ), + migrations.AlterField( + model_name='historicalbasefind', + name='auto_external_id', + field=models.BooleanField(default=False, verbose_name="L'identifiant est attribu\xe9 automatiquement"), + ), + migrations.AlterField( + model_name='historicalbasefind', + name='cache_complete_id', + field=models.TextField(blank=True, db_index=True, help_text='Valeur en cache - ne pas \xe9diter', null=True, verbose_name='Identifiant complet'), + ), + migrations.AlterField( + model_name='historicalbasefind', + name='cache_short_id', + field=models.TextField(blank=True, db_index=True, help_text='Valeur en cache - ne pas \xe9diter', null=True, verbose_name='Identifiant court'), + ), + migrations.AlterField( + model_name='historicalbasefind', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='historicalbasefind', + name='discovery_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de d\xe9couverte (exacte ou TPQ)'), + ), + migrations.AlterField( + model_name='historicalbasefind', + name='discovery_date_taq', + field=models.DateField(blank=True, null=True, verbose_name='Date de d\xe9couverte (TAQ)'), + ), + migrations.AlterField( + model_name='historicalbasefind', + name='estimated_error_x', + field=models.FloatField(blank=True, null=True, verbose_name='Erreur estim\xe9e pour X'), + ), + migrations.AlterField( + model_name='historicalbasefind', + name='estimated_error_y', + field=models.FloatField(blank=True, null=True, verbose_name='Erreur estim\xe9e pour Y'), + ), + migrations.AlterField( + model_name='historicalbasefind', + name='estimated_error_z', + field=models.FloatField(blank=True, null=True, verbose_name='Erreur estim\xe9e pour Z'), + ), + migrations.AlterField( + model_name='historicalbasefind', + name='excavation_id', + field=models.TextField(blank=True, null=True, verbose_name='Identifiant fouille'), + ), + migrations.AlterField( + model_name='historicalbasefind', + name='external_id', + field=models.TextField(blank=True, null=True, verbose_name='Identifiant'), + ), + migrations.AlterField( + model_name='historicalbasefind', + name='label', + field=models.TextField(verbose_name='Identifiant libre'), + ), + migrations.AlterField( + model_name='historicalbasefind', + name='line', + field=django.contrib.gis.db.models.fields.LineStringField(blank=True, null=True, srid=4326, verbose_name='Ligne'), + ), + migrations.AlterField( + model_name='historicalbasefind', + name='material_index', + field=models.IntegerField(default=0, verbose_name='Index mat\xe9riel'), + ), + migrations.AlterField( + model_name='historicalbasefind', + name='multi_polygon', + field=django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, null=True, srid=4326, verbose_name='Polygones multi-parties'), + ), + migrations.AlterField( + model_name='historicalbasefind', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='historicalbasefind', + name='special_interest', + field=models.CharField(blank=True, max_length=120, null=True, verbose_name='Int\xe9r\xeat sp\xe9cifique'), + ), + migrations.AlterField( + model_name='historicalbasefind', + name='topographic_localisation', + field=models.CharField(blank=True, max_length=120, null=True, verbose_name='Point topographique'), + ), + migrations.AlterField( + model_name='historicalfind', + name='appraisal_date', + field=models.DateField(blank=True, null=True, verbose_name="Date d'\xe9valuation"), + ), + migrations.AlterField( + model_name='historicalfind', + name='auto_external_id', + field=models.BooleanField(default=False, verbose_name="L'identifiant est attribu\xe9 automatiquement"), + ), + migrations.AlterField( + model_name='historicalfind', + name='cached_label', + field=models.TextField(blank=True, db_index=True, null=True, verbose_name='Nom en cache'), + ), + migrations.AlterField( + model_name='historicalfind', + name='check_date', + field=models.DateField(default=datetime.date.today, verbose_name='Date de v\xe9rification'), + ), + migrations.AlterField( + model_name='historicalfind', + name='clutter_height', + field=models.FloatField(blank=True, null=True, verbose_name='Encombrement - hauteur (cm)'), + ), + migrations.AlterField( + model_name='historicalfind', + name='clutter_long_side', + field=models.FloatField(blank=True, null=True, verbose_name='Encombrement - grand c\xf4t\xe9 (cm)'), + ), + migrations.AlterField( + model_name='historicalfind', + name='clutter_short_side', + field=models.FloatField(blank=True, null=True, verbose_name='Encombrement - petit c\xf4t\xe9 (cm)'), + ), + migrations.AlterField( + model_name='historicalfind', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='historicalfind', + name='conservatory_comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire relatif \xe0 la conservation'), + ), + migrations.AlterField( + model_name='historicalfind', + name='dating_comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire relatif aux datations'), + ), + migrations.AlterField( + model_name='historicalfind', + name='decoration', + field=models.TextField(blank=True, null=True, verbose_name='D\xe9cor'), + ), + migrations.AlterField( + model_name='historicalfind', + name='denomination', + field=models.TextField(blank=True, null=True, verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='historicalfind', + name='diameter', + field=models.FloatField(blank=True, null=True, verbose_name='Diam\xe8tre (cm)'), + ), + migrations.AlterField( + model_name='historicalfind', + name='dimensions_comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire relatif aux dimensions'), + ), + migrations.AlterField( + model_name='historicalfind', + name='estimated_value', + field=models.FloatField(blank=True, null=True, verbose_name='Valeur estim\xe9e'), + ), + migrations.AlterField( + model_name='historicalfind', + name='external_id', + field=models.TextField(blank=True, null=True, verbose_name='Identifiant'), + ), + migrations.AlterField( + model_name='historicalfind', + name='find_number', + field=models.IntegerField(blank=True, null=True, verbose_name='Mobilier (en nombre)'), + ), + migrations.AlterField( + model_name='historicalfind', + name='height', + field=models.FloatField(blank=True, null=True, verbose_name='Hauteur (cm)'), + ), + migrations.AlterField( + model_name='historicalfind', + name='insurance_value', + field=models.FloatField(blank=True, null=True, verbose_name="Valeur d'assurance"), + ), + migrations.AlterField( + model_name='historicalfind', + name='is_complete', + field=models.NullBooleanField(verbose_name='Est complet ?'), + ), + migrations.AlterField( + model_name='historicalfind', + name='label', + field=models.TextField(verbose_name='Identifiant libre'), + ), + migrations.AlterField( + model_name='historicalfind', + name='length', + field=models.FloatField(blank=True, null=True, verbose_name='Longueur (cm)'), + ), + migrations.AlterField( + model_name='historicalfind', + name='manufacturing_place', + field=models.TextField(blank=True, null=True, verbose_name='Lieu de fabrication'), + ), + migrations.AlterField( + model_name='historicalfind', + name='mark', + field=models.TextField(blank=True, null=True, verbose_name='Marquage'), + ), + migrations.AlterField( + model_name='historicalfind', + name='min_number_of_individuals', + field=models.IntegerField(blank=True, null=True, verbose_name="Nombre minimum d'individus (NMI)"), + ), + migrations.AlterField( + model_name='historicalfind', + name='museum_id', + field=models.TextField(blank=True, null=True, verbose_name='Identifiant mus\xe9e'), + ), + migrations.AlterField( + model_name='historicalfind', + name='order', + field=models.IntegerField(default=1, verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='historicalfind', + name='previous_id', + field=models.TextField(blank=True, null=True, verbose_name='Identifiant pr\xe9c\xe9dent'), + ), + migrations.AlterField( + model_name='historicalfind', + name='seal_number', + field=models.TextField(blank=True, null=True, verbose_name='Num\xe9ro de scell\xe9'), + ), + migrations.AlterField( + model_name='historicalfind', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='historicalfind', + name='thickness', + field=models.FloatField(blank=True, null=True, verbose_name='\xc9paisseur (cm)'), + ), + migrations.AlterField( + model_name='historicalfind', + name='weight', + field=models.FloatField(blank=True, null=True, verbose_name='Poids'), + ), + migrations.AlterField( + model_name='historicalfind', + name='weight_unit', + field=models.CharField(blank=True, choices=[(b'g', 'g'), (b'kg', 'kg')], max_length=4, null=True, verbose_name='Unit\xe9 de poids'), + ), + migrations.AlterField( + model_name='historicalfind', + name='width', + field=models.FloatField(blank=True, null=True, verbose_name='Largeur (cm)'), + ), + migrations.AlterField( + model_name='historicaltreatment', + name='cached_label', + field=models.TextField(blank=True, db_index=True, null=True, verbose_name='Nom en cache'), + ), + migrations.AlterField( + model_name='historicaltreatment', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='historicaltreatment', + name='end_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de cl\xf4ture'), + ), + migrations.AlterField( + model_name='historicaltreatment', + name='estimated_cost', + field=models.FloatField(blank=True, null=True, verbose_name='Co\xfbt estim\xe9'), + ), + migrations.AlterField( + model_name='historicaltreatment', + name='external_id', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Identifiant'), + ), + migrations.AlterField( + model_name='historicaltreatment', + name='goal', + field=models.TextField(blank=True, null=True, verbose_name='But'), + ), + migrations.AlterField( + model_name='historicaltreatment', + name='insurance_cost', + field=models.FloatField(blank=True, null=True, verbose_name="Co\xfbt d'assurance"), + ), + migrations.AlterField( + model_name='historicaltreatment', + name='label', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='historicaltreatment', + name='other_reference', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Autre r\xe9f.'), + ), + migrations.AlterField( + model_name='historicaltreatment', + name='quoted_cost', + field=models.FloatField(blank=True, null=True, verbose_name='Co\xfbt devis\xe9'), + ), + migrations.AlterField( + model_name='historicaltreatment', + name='realized_cost', + field=models.FloatField(blank=True, null=True, verbose_name='Co\xfbt r\xe9alis\xe9'), + ), + migrations.AlterField( + model_name='historicaltreatment', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='historicaltreatment', + name='start_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de d\xe9but'), + ), + migrations.AlterField( + model_name='historicaltreatment', + name='year', + field=models.IntegerField(default=ishtar_common.utils.get_current_year, verbose_name='Ann\xe9e'), + ), + migrations.AlterField( + model_name='historicaltreatmentfile', + name='cached_label', + field=models.TextField(blank=True, db_index=True, null=True, verbose_name='Nom en cache'), + ), + migrations.AlterField( + model_name='historicaltreatmentfile', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='historicaltreatmentfile', + name='creation_date', + field=models.DateField(blank=True, default=datetime.date.today, null=True, verbose_name='Date de cr\xe9ation'), + ), + migrations.AlterField( + model_name='historicaltreatmentfile', + name='end_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de cl\xf4ture'), + ), + migrations.AlterField( + model_name='historicaltreatmentfile', + name='external_id', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Identifiant'), + ), + migrations.AlterField( + model_name='historicaltreatmentfile', + name='internal_reference', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='R\xe9f\xe9rence interne'), + ), + migrations.AlterField( + model_name='historicaltreatmentfile', + name='name', + field=models.TextField(blank=True, null=True, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='historicaltreatmentfile', + name='reception_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de r\xe9ception'), + ), + migrations.AlterField( + model_name='historicaltreatmentfile', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='historicaltreatmentfile', + name='year', + field=models.IntegerField(default=ishtar_common.utils.get_current_year, verbose_name='Ann\xe9e'), + ), + migrations.AlterField( + model_name='integritytype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='integritytype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='integritytype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='integritytype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='materialtype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='materialtype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='materialtype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='materialtype', + name='recommendation', + field=models.TextField(blank=True, null=True, verbose_name='Recommandation'), + ), + migrations.AlterField( + model_name='materialtype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='materialtypequalitytype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='materialtypequalitytype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='materialtypequalitytype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='materialtypequalitytype', + name='order', + field=models.IntegerField(default=10, verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='materialtypequalitytype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='objecttype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='objecttype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='objecttype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='objecttype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='objecttypequalitytype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='objecttypequalitytype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='objecttypequalitytype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='objecttypequalitytype', + name='order', + field=models.IntegerField(default=10, verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='objecttypequalitytype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='property', + name='administrative_act', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_operations.AdministrativeAct', verbose_name='Acte administratif'), + ), + migrations.AlterField( + model_name='property', + name='end_date', + field=models.DateField(verbose_name='Date de fin'), + ), + migrations.AlterField( + model_name='property', + name='find', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_finds.Find', verbose_name='Mobilier'), + ), + migrations.AlterField( + model_name='property', + name='history_creator', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Cr\xe9ateur'), + ), + migrations.AlterField( + model_name='property', + name='history_modifier', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Dernier \xe9diteur'), + ), + migrations.AlterField( + model_name='property', + name='person', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='properties', to='ishtar_common.Person', verbose_name='Personne'), + ), + migrations.AlterField( + model_name='property', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='property', + name='start_date', + field=models.DateField(verbose_name='Date de d\xe9but'), + ), + migrations.AlterField( + model_name='remarkabilitytype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='remarkabilitytype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='remarkabilitytype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='remarkabilitytype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='treatment', + name='cached_label', + field=models.TextField(blank=True, db_index=True, null=True, verbose_name='Nom en cache'), + ), + migrations.AlterField( + model_name='treatment', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='treatment', + name='container', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_warehouse.Container', verbose_name='Contenant'), + ), + migrations.AlterField( + model_name='treatment', + name='end_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de cl\xf4ture'), + ), + migrations.AlterField( + model_name='treatment', + name='estimated_cost', + field=models.FloatField(blank=True, null=True, verbose_name='Co\xfbt estim\xe9'), + ), + migrations.AlterField( + model_name='treatment', + name='external_id', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Identifiant'), + ), + migrations.AlterField( + model_name='treatment', + name='file', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='treatments', to='archaeological_finds.TreatmentFile', verbose_name='Demande associ\xe9e'), + ), + migrations.AlterField( + model_name='treatment', + name='goal', + field=models.TextField(blank=True, null=True, verbose_name='But'), + ), + migrations.AlterField( + model_name='treatment', + name='history_creator', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Cr\xe9ateur'), + ), + migrations.AlterField( + model_name='treatment', + name='history_modifier', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Dernier \xe9diteur'), + ), + migrations.AlterField( + model_name='treatment', + name='insurance_cost', + field=models.FloatField(blank=True, null=True, verbose_name="Co\xfbt d'assurance"), + ), + migrations.AlterField( + model_name='treatment', + name='label', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='treatment', + name='location', + field=models.ForeignKey(blank=True, help_text='Endroit o\xf9 le traitement est r\xe9alis\xe9. Renseignez le lieu de conservation de destination pour un d\xe9placement.', null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_warehouse.Warehouse', verbose_name='Localisation'), + ), + migrations.AlterField( + model_name='treatment', + name='organization', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='treatments', to='ishtar_common.Organization', verbose_name='Organisation'), + ), + migrations.AlterField( + model_name='treatment', + name='other_reference', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Autre r\xe9f.'), + ), + migrations.AlterField( + model_name='treatment', + name='person', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='treatments', to='ishtar_common.Person', verbose_name='Responsable'), + ), + migrations.AlterField( + model_name='treatment', + name='quoted_cost', + field=models.FloatField(blank=True, null=True, verbose_name='Co\xfbt devis\xe9'), + ), + migrations.AlterField( + model_name='treatment', + name='realized_cost', + field=models.FloatField(blank=True, null=True, verbose_name='Co\xfbt r\xe9alis\xe9'), + ), + migrations.AlterField( + model_name='treatment', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='treatment', + name='start_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de d\xe9but'), + ), + migrations.AlterField( + model_name='treatment', + name='treatment_state', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_finds.TreatmentState', verbose_name='\xc9tat'), + ), + migrations.AlterField( + model_name='treatment', + name='treatment_types', + field=models.ManyToManyField(to='archaeological_finds.TreatmentType', verbose_name='Type de traitement'), + ), + migrations.AlterField( + model_name='treatment', + name='year', + field=models.IntegerField(default=ishtar_common.utils.get_current_year, verbose_name='Ann\xe9e'), + ), + migrations.AlterField( + model_name='treatmentemergencytype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='treatmentemergencytype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='treatmentemergencytype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='treatmentemergencytype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='treatmentfile', + name='applicant', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='treatmentfile_applicant', to='ishtar_common.Person', verbose_name='Demandeur'), + ), + migrations.AlterField( + model_name='treatmentfile', + name='applicant_organisation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='treatmentfile_applicant', to='ishtar_common.Organization', verbose_name='Organisation du demandeur'), + ), + migrations.AlterField( + model_name='treatmentfile', + name='cached_label', + field=models.TextField(blank=True, db_index=True, null=True, verbose_name='Nom en cache'), + ), + migrations.AlterField( + model_name='treatmentfile', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='treatmentfile', + name='creation_date', + field=models.DateField(blank=True, default=datetime.date.today, null=True, verbose_name='Date de cr\xe9ation'), + ), + migrations.AlterField( + model_name='treatmentfile', + name='end_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de cl\xf4ture'), + ), + migrations.AlterField( + model_name='treatmentfile', + name='external_id', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Identifiant'), + ), + migrations.AlterField( + model_name='treatmentfile', + name='history_creator', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Cr\xe9ateur'), + ), + migrations.AlterField( + model_name='treatmentfile', + name='history_modifier', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Dernier \xe9diteur'), + ), + migrations.AlterField( + model_name='treatmentfile', + name='in_charge', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='treatmentfile_responsability', to='ishtar_common.Person', verbose_name='Dossier suivi par'), + ), + migrations.AlterField( + model_name='treatmentfile', + name='internal_reference', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='R\xe9f\xe9rence interne'), + ), + migrations.AlterField( + model_name='treatmentfile', + name='name', + field=models.TextField(blank=True, null=True, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='treatmentfile', + name='reception_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de r\xe9ception'), + ), + migrations.AlterField( + model_name='treatmentfile', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='treatmentfile', + name='type', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_finds.TreatmentFileType', verbose_name='Type de demande de traitement'), + ), + migrations.AlterField( + model_name='treatmentfile', + name='year', + field=models.IntegerField(default=ishtar_common.utils.get_current_year, verbose_name='Ann\xe9e'), + ), + migrations.AlterField( + model_name='treatmentfiletype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='treatmentfiletype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='treatmentfiletype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='treatmentfiletype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='treatmentstate', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='treatmentstate', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='treatmentstate', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='treatmentstate', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='treatmenttype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='treatmenttype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='treatmenttype', + name='downstream_is_many', + field=models.BooleanField(default=False, help_text="Cochez cela si, pour ce traitement, \xe0 partir d'un seul \xe9l\xe9ment vous en obtenez plusieurs.", verbose_name='Les \xe9l\xe9ments aval sont multiples'), + ), + migrations.AlterField( + model_name='treatmenttype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='treatmenttype', + name='order', + field=models.IntegerField(default=10, verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='treatmenttype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='treatmenttype', + name='upstream_is_many', + field=models.BooleanField(default=False, help_text='Cochez cela si, pour ce traitement, \xe0 partir de plusieurs \xe9l\xe9ments vous en obtenez un seul.', verbose_name='Les \xe9l\xe9ments amont sont multiples'), + ), + migrations.AlterField( + model_name='treatmenttype', + name='virtual', + field=models.BooleanField(verbose_name='Virtuel'), + ), + ] diff --git a/archaeological_finds/migrations/0048_auto_20181203_1746.py b/archaeological_finds/migrations/0048_auto_20181203_1746.py new file mode 100644 index 000000000..567832d72 --- /dev/null +++ b/archaeological_finds/migrations/0048_auto_20181203_1746.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-12-03 17:46 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_finds', '0047_auto_20181203_1442'), + ] + + operations = [ + migrations.AddField( + model_name='find', + name='circumference', + field=models.FloatField(blank=True, null=True, verbose_name='Circumference (cm)'), + ), + migrations.AddField( + model_name='historicalfind', + name='circumference', + field=models.FloatField(blank=True, null=True, verbose_name='Circumference (cm)'), + ), + ] diff --git a/archaeological_finds/migrations/0049_auto_20181210_1518.py b/archaeological_finds/migrations/0049_auto_20181210_1518.py new file mode 100644 index 000000000..28f790ab0 --- /dev/null +++ b/archaeological_finds/migrations/0049_auto_20181210_1518.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-12-10 15:18 +from __future__ import unicode_literals + +from django.db import migrations, models + + +def migrate_treatment_types(apps, schema): + TreatmentType = apps.get_model('archaeological_finds', 'TreatmentType') + q = TreatmentType.objects.filter(txt_idx="loan") + if q.count(): + loan = q.all()[0] + loan.change_current_location = True + loan.save() + q = TreatmentType.objects.filter(txt_idx="loan-return") + if q.count(): + loan_r = q.all()[0] + loan_r.restore_reference_location = True + loan_r.save() + q = TreatmentType.objects.filter(txt_idx="packaging") + if q.count(): + packaging = q.all()[0] + packaging.change_reference_location = True + packaging.change_current_location = True + packaging.save() + q = TreatmentType.objects.filter(txt_idx="virtual-reassembly") + if q.count(): + v = q.all()[0] + v.upstream_is_many = False + v.save() + q = TreatmentType.objects.filter(txt_idx="virtual_group") + if q.count(): + v = q.all()[0] + v.upstream_is_many = False + v.save() + for t in TreatmentType.objects.all(): + t.txt_idx = t.txt_idx.replace("_", "-") + t.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_finds', '0048_auto_20181203_1746'), + ] + + operations = [ + migrations.AddField( + model_name='treatmenttype', + name='change_current_location', + field=models.BooleanField(default=False, help_text='The treatment change the current location.', verbose_name='Change current location'), + ), + migrations.AddField( + model_name='treatmenttype', + name='change_reference_location', + field=models.BooleanField(default=False, help_text='The treatment change the reference location.', verbose_name='Change reference location'), + ), + migrations.AddField( + model_name='treatmenttype', + name='restore_reference_location', + field=models.BooleanField(default=False, help_text='The treatment change restore reference location to the current location.', verbose_name='Restore the reference location'), + ), + migrations.RunPython(migrate_treatment_types) + ] diff --git a/archaeological_finds/migrations/0050_auto_20181211_1509.py b/archaeological_finds/migrations/0050_auto_20181211_1509.py new file mode 100644 index 000000000..c9928d617 --- /dev/null +++ b/archaeological_finds/migrations/0050_auto_20181211_1509.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-12-11 15:09 +from __future__ import unicode_literals + +from django.db import migrations, models + + +def migrate_treatment_states(apps, schema): + TreatmentState = apps.get_model('archaeological_finds', 'TreatmentState') + q = TreatmentState.objects.filter(txt_idx="completed") + if q.count(): + t = q.all()[0] + t.executed = True + t.save() + for t in TreatmentState.objects.all(): + t.txt_idx = t.txt_idx.replace("_", "-") + t.save() + orders = [(10, "planned"), (20, "to-be-confirmed"), (30, "in-progress"), + (40, "completed"), (50, "cancelled"), (60, "unknown"),] + for order, txt_idx in orders: + q = TreatmentState.objects.filter(txt_idx=txt_idx) + if not q.count(): + continue + t = q.all()[0] + t.order = order + t.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_finds', '0049_auto_20181210_1518'), + ] + + operations = [ + migrations.AlterModelOptions( + name='treatmentstate', + options={'ordering': ('order', 'label'), 'verbose_name': "Type d'\xe9tat de traitement", 'verbose_name_plural': "Types d'\xe9tat de traitement"}, + ), + migrations.AddField( + model_name='treatmentstate', + name='executed', + field=models.BooleanField(default=False, verbose_name='Treatment is executed'), + ), + migrations.AddField( + model_name='treatmentstate', + name='order', + field=models.IntegerField(default=10, verbose_name='Ordre'), + ), + migrations.RunPython(migrate_treatment_states) + ] diff --git a/archaeological_finds/migrations/0051_auto_20181211_1530.py b/archaeological_finds/migrations/0051_auto_20181211_1530.py new file mode 100644 index 000000000..9bcdb60a7 --- /dev/null +++ b/archaeological_finds/migrations/0051_auto_20181211_1530.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-12-11 15:30 +from __future__ import unicode_literals + +import archaeological_finds.models_treatments +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_finds', '0050_auto_20181211_1509'), + ] + + operations = [ + migrations.AlterField( + model_name='treatment', + name='treatment_state', + field=models.ForeignKey(default=archaeological_finds.models_treatments.TreatmentState.get_default, on_delete=django.db.models.deletion.CASCADE, to='archaeological_finds.TreatmentState', verbose_name='\xc9tat'), + ), + ] diff --git a/archaeological_finds/migrations/0052_auto_20181211_1558.py b/archaeological_finds/migrations/0052_auto_20181211_1558.py new file mode 100644 index 000000000..5c0f63d7c --- /dev/null +++ b/archaeological_finds/migrations/0052_auto_20181211_1558.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-12-11 15:58 +from __future__ import unicode_literals + +from django.db import migrations, models + + +def migrate_treatment_states(apps, schema): + Treatment = apps.get_model('archaeological_finds', 'Treatment') + for t in Treatment.objects.all(): + t.executed = True + t.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_finds', '0051_auto_20181211_1530'), + ] + + operations = [ + migrations.AddField( + model_name='historicaltreatment', + name='executed', + field=models.BooleanField(default=False, verbose_name='Treatment have been executed'), + ), + migrations.AddField( + model_name='treatment', + name='executed', + field=models.BooleanField(default=False, verbose_name='Treatment have been executed'), + ), + migrations.RunPython(migrate_treatment_states) + ] diff --git a/archaeological_finds/models_finds.py b/archaeological_finds/models_finds.py index e53ad6e6d..393583749 100644 --- a/archaeological_finds/models_finds.py +++ b/archaeological_finds/models_finds.py @@ -23,7 +23,7 @@ from django.conf import settings from django.contrib.gis.db import models from django.core.urlresolvers import reverse from django.db import connection -from django.db.models import Max, Q +from django.db.models import Max, Q, F from django.db.models.signals import m2m_changed, post_save, post_delete, \ pre_delete from django.core.exceptions import ObjectDoesNotExist @@ -91,6 +91,11 @@ post_delete.connect(post_save_cache, sender=ConservatoryState) class TreatmentType(HierarchicalType): order = models.IntegerField(_(u"Order"), default=10) virtual = models.BooleanField(_(u"Virtual")) + destructive = models.BooleanField(_(u"Destructive"), default=False) + create_new_find = models.BooleanField( + _(u"Create a new find"), default=False, + help_text=_(u"If True when this treatment is applied a new version " + u"of the object will be created.")) upstream_is_many = models.BooleanField( _(u"Upstream is many"), default=False, help_text=_( @@ -101,6 +106,16 @@ class TreatmentType(HierarchicalType): help_text=_( u"Check this if for this treatment from one find you'll get " u"many.")) + change_reference_location = models.BooleanField( + _(u"Change reference location"), default=False, + help_text=_(u"The treatment change the reference location.")) + change_current_location = models.BooleanField( + _(u"Change current location"), default=False, + help_text=_(u"The treatment change the current location.")) + restore_reference_location = models.BooleanField( + _(u"Restore the reference location"), default=False, + help_text=_(u"The treatment change restore reference location to the " + u"current location.")) class Meta: verbose_name = _(u"Treatment type") @@ -326,6 +341,15 @@ class BaseFind(BulkUpdatedItem, BaseHistorizedItem, OwnPerms): finds = self.find.filter().order_by("-order").all() return finds and finds[0] + def get_main_find(self): + """ + Get the last find which is not related to many base_find + """ + for find in self.find.order_by('-pk'): + if find.base_finds.count() == 1: + return find + return + def generate_index(self): """ Generate index based on operation or context record (based on @@ -566,31 +590,54 @@ WEIGHT_UNIT = (('g', _(u"g")), ('kg', _(u"kg")),) -class FindBasket(Basket, OwnPerms): +class FindBasket(Basket, MainItem): + SHOW_URL = 'show-findbasket' items = models.ManyToManyField('Find', blank=True, related_name='basket') + QUICK_ACTIONS = [ + QuickAction( + url="findbasket-qa-duplicate", icon_class="fa fa-clone", + text=_(u"Duplicate"), target="one", + rights=['view_find', 'view_own_find']), + ] + class Meta: + verbose_name = _(u"Basket") permissions = ( ("view_find", u"Can view all Finds"), ("view_own_find", u"Can view own Find"), ) - @classmethod - def get_query_owns(cls, ishtaruser): - return Q(user=ishtaruser) - def get_extra_actions(self, request): """ For sheet template: return "Manage basket" action """ # url, base_text, icon, extra_text, extra css class, is a quick action - # no particular rights: if you can view an itm you can add it to your - # own basket - actions = [ - (reverse("select_itemsinbasket", args=[self.pk]), - _(u"Manage basket"), - "fa fa-shopping-basket", "", "", False), + if not request.user or not request.user.ishtaruser: + return [] + + ishtaruser = request.user.ishtaruser + actions = [] + if self.user == ishtaruser or ishtaruser.pk in [ + user.pk for user in self.shared_write_with.all()]: + actions = [ + (reverse("select_itemsinbasket", args=[self.pk]), + _(u"Manage basket"), + "fa fa-shopping-basket", "", "", False), + ] + can_edit_find = self.can_do(request, 'change_find') + if can_edit_find: + actions += [ + (reverse('findbasket-add-treatment', args=[self.pk]), + _(u"Add treatment"), "fa fa-exchange", "", "", False), + ] + + duplicate = self.QUICK_ACTIONS[0] + actions += [ + (reverse(duplicate.url, args=[self.pk]), + duplicate.text, duplicate.icon_class, + "", "", True), ] return actions @@ -631,6 +678,20 @@ class FBulkView(object): """ +def query_loan(is_true=True): + """ + Query to get loan find + + :return: (filter, exclude, extra) + """ + if is_true: + return Q(container_ref__isnull=False, container__isnull=False), \ + Q(container_ref=F('container')), None + else: + return Q(container_ref__isnull=False, container__isnull=False, + container_ref=F('container')), None, None + + class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, MainItem): EXTERNAL_ID_KEY = 'find_external_id' @@ -642,7 +703,8 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, 'base_finds__context_record__label', 'material_types__label', 'object_types__label', 'datings__period__label', - 'container__cached_label', ] + 'container__cached_label', + 'container_ref__cached_label'] if settings.COUNTRY == 'fr': TABLE_COLS.insert( 3, 'base_finds__context_record__operation__code_patriarche') @@ -652,7 +714,7 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, 'previous_id', 'label', 'material_types__label', 'datings__period__label', 'find_number', 'object_types__label', 'container__cached_label', - 'container__cached_location', + 'container_ref__cached_label', 'description', 'base_finds__context_record__town__name', 'base_finds__context_record__parcel', ] @@ -670,7 +732,7 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, 'base_finds__context_record__archaeological_site__name': IshtarSiteProfile.get_default_site_label, 'base_finds__context_record__parcel': _(u"Parcel"), - 'base_finds__batch':_(u"Batch"), + 'base_finds__batch': _(u"Batch"), 'base_finds__comment': _(u"Base find - Comment"), 'base_finds__description': _(u"Base find - Description"), 'base_finds__topographic_localisation': _(u"Base find - " @@ -680,7 +742,8 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, u"Base find - Discovery date (exact or TPQ)"), 'base_finds__discovery_date_taq': _( u"Base find - Discovery date (TAQ)"), - 'container__cached_label': _(u"Container"), + 'container__cached_label': _(u"Current container"), + 'container_ref__cached_label': _(u"Reference container"), 'datings__period__label': _(u"Periods"), 'material_types__label': _(u"Material types"), 'object_types__label': _(u"Object types"), @@ -706,7 +769,7 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, 'base_finds__context_record__', } - DATED_FIELDS = ['last_modified__gte'] + DATED_FIELDS = ['last_modified__gte', 'treatments__file__end_date__lte'] BASE_REQUEST = {'downstream_treatment__isnull': True} EXTRA_REQUEST_KEYS = { 'base_finds__context_record': @@ -863,20 +926,36 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, pgettext_lazy("key for text search", u"has-image"), 'documents__image__isnull', ), - 'container__location': ( + 'container_ref__location': ( pgettext_lazy("key for text search", u"location"), + 'container_ref__location__name__iexact', + ), + 'container_ref__responsible': ( + pgettext_lazy("key for text search", u"warehouse"), + 'container_ref__responsible__name__iexact', + ), + 'container_ref__index': ( + pgettext_lazy("key for text search", u"container-index"), + 'container_ref__index', + ), + 'container_ref__reference': ( + pgettext_lazy("key for text search", u"container-ref"), + 'container_ref__reference__iexact', + ), + 'container__location': ( + pgettext_lazy("key for text search", u"current-location"), 'container__location__name__iexact', ), 'container__responsible': ( - pgettext_lazy("key for text search", u"warehouse"), + pgettext_lazy("key for text search", u"current-warehouse"), 'container__responsible__name__iexact', ), 'container__index': ( - pgettext_lazy("key for text search", u"container-index"), + pgettext_lazy("key for text search", u"current-container-index"), 'container__index', ), 'container__reference': ( - pgettext_lazy("key for text search", u"container-ref"), + pgettext_lazy("key for text search", u"current-container-ref"), 'container__reference__iexact', ), 'basket': ( @@ -899,6 +978,14 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, pgettext_lazy("key for text search", u"created-by"), 'history_creator__ishtaruser__person__cached_label__iexact' ), + 'loan': ( + pgettext_lazy("key for text search", u"loan"), + query_loan + ), + 'treatments_file_end_date': ( + pgettext_lazy("key for text search", u"treatment-end-date-before"), + 'treatments__file__end_date__lte' + ) } for v in ALT_NAMES.values(): for language_code, language_lbl in settings.LANGUAGES: @@ -906,6 +993,8 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, EXTRA_REQUEST_KEYS[unicode(v[0])] = v[1] deactivate() + EXTRA_REQUEST_FUNC = {""} + PARENT_SEARCH_VECTORS = ['base_finds'] BASE_SEARCH_VECTORS = [ "cached_label", "label", "description", "container__location__name", @@ -1003,6 +1092,11 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, "archaeological_warehouse.Container", verbose_name=_(u"Container"), blank=True, null=True, related_name='finds', on_delete=models.SET_NULL) + container_ref = models.ForeignKey( + "archaeological_warehouse.Container", + verbose_name=_(u"Reference container"), + blank=True, null=True, + related_name='finds_ref', on_delete=models.SET_NULL) is_complete = models.NullBooleanField(_(u"Is complete?"), blank=True, null=True) object_types = models.ManyToManyField( @@ -1029,6 +1123,8 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, width = models.FloatField(_(u"Width (cm)"), blank=True, null=True) height = models.FloatField(_(u"Height (cm)"), blank=True, null=True) diameter = models.FloatField(_(u"Diameter (cm)"), blank=True, null=True) + circumference = models.FloatField(_(u"Circumference (cm)"), blank=True, + null=True) thickness = models.FloatField(_(u"Thickness (cm)"), blank=True, null=True) clutter_long_side = models.FloatField( _(u"Clutter - long side (cm)"), blank=True, null=True) @@ -1083,6 +1179,10 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, documents = models.ManyToManyField( Document, related_name='finds', verbose_name=_(u"Documents"), blank=True) + treatments = models.ManyToManyField( + "Treatment", verbose_name=_(u"Treatments"), + related_name='finds', blank=True, + help_text=_(u"Related treatments when no new find is created")) cached_label = models.TextField(_(u"Cached name"), null=True, blank=True, db_index=True) history = HistoricalRecords() @@ -1156,6 +1256,22 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, return return self.base_finds.order_by('-pk').all()[0] + def get_values(self, prefix=''): + values = super(Find, self).get_values(prefix=prefix) + return values + # TODO + bf = self.get_first_base_find() + if not bf: + return values + operation = bf.context_record.operation + values[prefix + "operation"] = [ + { + "common_name": operation.common_name, + "code_patriarche": operation.code_patriarche, + "address": operation.address + } + ] + @property def reference(self): bf = self.get_first_base_find() @@ -1179,6 +1295,8 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, (reverse("find-qa-basket", args=[self.pk]), _(u"Add to basket"), "fa fa-shopping-basket", "", "", True), + (reverse('find-add-treatment', args=[self.pk]), + _(u"Add treatment"), "fa fa-exchange", "", "", False), ] if get_current_profile().warehouse: actions.append( @@ -1338,7 +1456,7 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, q = q.filter(**fltr) return q.filter(downstream_treatment__isnull=True).count() - def duplicate(self, user): + def duplicate(self, user, copy_datings=True): model = self.__class__ new = model.objects.get(pk=self.pk) @@ -1356,12 +1474,22 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, m2m = [field.name for field in model._meta.many_to_many if field.name not in PRIVATE_FIELDS] for field in m2m: - if field == 'images': - for doc in Document.objects.filter(finds__pk=self.pk).all(): - doc.finds.add(new.pk) + if field == 'datings' and copy_datings: + for dating in self.datings.all(): + is_present = False + for current_dating in new.datings.all(): + if Dating.is_identical(current_dating, dating): + is_present = True + break + if is_present: + continue + dating.pk = None + dating.save() + new.datings.add(dating) else: for val in getattr(self, field).all(): - getattr(new, field).add(val) + if val not in getattr(new, field).all(): + getattr(new, field).add(val) return new @classmethod @@ -1375,6 +1503,9 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, ) | cls._construct_query_own( 'base_finds__context_record__operation__', Operation._get_query_owns_dicts(ishtaruser) + ) | cls._construct_query_own( + 'basket__', + [{"shared_with": ishtaruser, "shared_write_with": ishtaruser}] ) | cls._construct_query_own('', [ {'history_creator': ishtaruser.user_ptr}, {'base_finds__context_record__operation__end_date__isnull': True} @@ -1493,21 +1624,62 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, with connection.cursor() as c: c.execute(sql, args) - def get_localisation(self, place): + def get_localisation(self, place, is_ref=False): """ Get localisation reference in the warehouse :param place: number of the localisation starting with 0 + :param is_ref: if true - reference container else current container :return: reference - empty string if not available """ - if not self.container: + if is_ref: + container = self.container_ref + else: + container = self.container + if not container: return "" - locas = self.container.get_localisations() + locas = container.get_localisations() if len(locas) < (place + 1): return "" return locas[place] @property + def reference_localisation_1(self): + return self.get_localisation(0, is_ref=True) + + @property + def reference_localisation_2(self): + return self.get_localisation(1, is_ref=True) + + @property + def reference_localisation_3(self): + return self.get_localisation(2, is_ref=True) + + @property + def reference_localisation_4(self): + return self.get_localisation(3, is_ref=True) + + @property + def reference_localisation_5(self): + return self.get_localisation(4, is_ref=True) + + @property + def reference_localisation_6(self): + return self.get_localisation(5, is_ref=True) + + @property + def reference_localisation_7(self): + return self.get_localisation(6, is_ref=True) + + @property + def reference_localisation_8(self): + return self.get_localisation(7, is_ref=True) + + @property + def reference_localisation_9(self): + return self.get_localisation(8, is_ref=True) + + @property def localisation_1(self): return self.get_localisation(0) @@ -1543,19 +1715,75 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, def localisation_9(self): return self.get_localisation(8) - def set_localisation(self, place, context, value): - if not self.container: + def set_localisation(self, place, context, value, is_ref=False): + """ + Get localisation reference in the warehouse + + :param place: number of the localisation starting with 0 + :param context: context of the request - not used + :param value: localisation value + :param is_ref: if true - reference container else current container + :return: None + """ + if is_ref: + container = self.container_ref + else: + container = self.container + + if not container: if not value: return - raise ImporterError(_(u"No container have been set - the " - u"localisation cannot be set.")) + if is_ref: + raise ImporterError( + _(u"No reference container have been set - the " + u"localisation cannot be set.")) + else: + raise ImporterError( + _(u"No container have been set - the localisation cannot " + u"be set.")) - localisation = self.container.set_localisation(place, value) + localisation = container.set_localisation(place, value) if value and value != '-' and not localisation: raise ImporterError( unicode(_(u"The division number {} have not been set " u"for the warehouse {}.")).format( - place + 1, self.container.location)) + place + 1, container.location)) + + @post_importer_action + def set_reference_localisation_1(self, context, value): + return self.set_localisation(0, context, value, is_ref=True) + + @post_importer_action + def set_reference_localisation_2(self, context, value): + return self.set_localisation(1, context, value, is_ref=True) + + @post_importer_action + def set_reference_localisation_3(self, context, value): + return self.set_localisation(2, context, value, is_ref=True) + + @post_importer_action + def set_reference_localisation_4(self, context, value): + return self.set_localisation(3, context, value, is_ref=True) + + @post_importer_action + def set_reference_localisation_5(self, context, value): + return self.set_localisation(4, context, value, is_ref=True) + + @post_importer_action + def set_reference_localisation_6(self, context, value): + return self.set_localisation(5, context, value, is_ref=True) + + @post_importer_action + def set_reference_localisation_7(self, context, value): + return self.set_localisation(6, context, value, is_ref=True) + + @post_importer_action + def set_reference_localisation_8(self, context, value): + return self.set_localisation(7, context, value, is_ref=True) + + @post_importer_action + def set_reference_localisation_9(self, context, value): + return self.set_localisation(8, context, value, is_ref=True) @post_importer_action def set_localisation_1(self, context, value): @@ -1634,6 +1862,9 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, super(Find, self).save(*args, **kwargs) self.skip_history_when_saving = True + if self.container_ref and not self.container: + self.container = self.container_ref + updated = self.update_external_id(save=False) if updated: self._cached_label_checked = False @@ -1649,6 +1880,9 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, for base_find in self.base_finds.filter( context_record__operation__pk__isnull=False).all(): modified = False + if self.label and not base_find.label: + base_find.label = self.label + modified = True if not base_find.index: modified = base_find.generate_index() short_id = base_find.short_id() @@ -1659,6 +1893,8 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms, if base_find.cache_complete_id != complete_id: base_find.cache_complete_id = complete_id modified = True + if base_find.update_external_id(): + modified = True if modified: base_find.skip_history_when_saving = True base_find._cached_label_checked = False diff --git a/archaeological_finds/models_treatments.py b/archaeological_finds/models_treatments.py index 6a57a77f5..06f61068b 100644 --- a/archaeological_finds/models_treatments.py +++ b/archaeological_finds/models_treatments.py @@ -21,6 +21,7 @@ import datetime from django.conf import settings from django.contrib.gis.db import models +from django.core.urlresolvers import reverse from django.db.models import Max, Q from django.db.models.signals import post_save, post_delete, pre_delete from django.template.defaultfilters import slugify @@ -29,19 +30,31 @@ from django.utils.translation import ugettext_lazy as _, pgettext_lazy, \ from archaeological_finds.models_finds import Find, FindBasket, TreatmentType from archaeological_operations.models import ClosedItem, Operation +from archaeological_context_records.models import Dating from archaeological_warehouse.models import Warehouse, Container from ishtar_common.models import Document, GeneralType, \ ImageModel, BaseHistorizedItem, OwnPerms, HistoricalRecords, Person, \ Organization, ValueGetter, post_save_cache, ShortMenuItem, \ DashboardFormItem, ExternalIdManager -from ishtar_common.utils import cached_label_changed, get_current_year +from ishtar_common.utils import cached_label_changed, get_current_year, \ + update_data class TreatmentState(GeneralType): + executed = models.BooleanField(_(u"Treatment is executed"), default=False) + order = models.IntegerField(verbose_name=_(u"Order"), default=10) + class Meta: verbose_name = _(u"Treatment state type") verbose_name_plural = _(u"Treatment state types") - ordering = ('label',) + ordering = ('order', 'label',) + + @classmethod + def get_default(cls): + q = cls.objects.filter(executed=True) + if not q.count(): + return None + return q.all()[0].pk post_save.connect(post_save_cache, sender=TreatmentState) @@ -68,10 +81,12 @@ class Treatment(DashboardFormItem, ValueGetter, BaseHistorizedItem, "upstream_cached_label": _(u"Upstream find"), "treatment_types__label": _(u"Type"), "treatment_state__label": _(u"State"), - 'person__cached_label': _(u"Responsible"), + "person__cached_label": _(u"Responsible"), } # extra keys than can be passed to save method - EXTRA_SAVED_KEYS = ('items', 'user') + EXTRA_SAVED_KEYS = ('items', 'user', 'resulting_find', 'upstream_items', + 'resulting_finds', 'upstream_item', + 'treatment_type_list') # alternative names of fields for searches ALT_NAMES = { @@ -127,8 +142,11 @@ class Treatment(DashboardFormItem, ValueGetter, BaseHistorizedItem, treatment_types = models.ManyToManyField( TreatmentType, verbose_name=_(u"Treatment type")) treatment_state = models.ForeignKey( - TreatmentState, verbose_name=_(u"State"), blank=True, null=True, + TreatmentState, verbose_name=_(u"State"), + default=TreatmentState.get_default ) + executed = models.BooleanField( + _(u"Treatment have been executed"), default=False) location = models.ForeignKey( Warehouse, verbose_name=_(u"Location"), blank=True, null=True, help_text=_( @@ -147,6 +165,7 @@ class Treatment(DashboardFormItem, ValueGetter, BaseHistorizedItem, goal = models.TextField(_(u"Goal"), blank=True, null=True) start_date = models.DateField(_(u"Start date"), blank=True, null=True) end_date = models.DateField(_(u"Closing date"), blank=True, null=True) + creation_date = models.DateTimeField(default=datetime.datetime.now) container = models.ForeignKey(Container, verbose_name=_(u"Container"), blank=True, null=True) estimated_cost = models.FloatField(_(u"Estimated cost"), @@ -157,8 +176,6 @@ class Treatment(DashboardFormItem, ValueGetter, BaseHistorizedItem, blank=True, null=True) insurance_cost = models.FloatField(_(u"Insurance cost"), blank=True, null=True) - target_is_basket = models.BooleanField(_(u"Target a basket"), - default=False) documents = models.ManyToManyField( Document, related_name='treatments', verbose_name=_(u"Documents"), blank=True) @@ -177,6 +194,7 @@ class Treatment(DashboardFormItem, ValueGetter, BaseHistorizedItem, ("change_own_treatment", u"Can change own Treatment"), ("delete_own_treatment", u"Can delete own Treatment"), ) + ordering = ("start_date", ) def __unicode__(self): if self.cached_label: @@ -189,6 +207,10 @@ class Treatment(DashboardFormItem, ValueGetter, BaseHistorizedItem, def short_class_name(self): return _(u"TREATMENT") + @property + def limited_finds(self): + return self.finds.all()[:15] + def natural_key(self): return (self.external_id, ) @@ -258,6 +280,17 @@ class Treatment(DashboardFormItem, ValueGetter, BaseHistorizedItem, upstream_lbl.short_description = _(u"Upstream finds") upstream_lbl.admin_order_field = 'upstream__cached_label' + def get_extra_actions(self, request): + # url, base_text, icon, extra_text, extra css class, is a quick action + actions = [] + if self.can_do(request, 'add_administrativeact'): + actions += [ + (reverse('treatment-add-adminact', args=[self.pk]), + _(u"Add associated administrative act"), "fa fa-plus", + _(u"admin. act"), "", False), + ] + return actions + def get_values(self, prefix=''): values = super(Treatment, self).get_values(prefix=prefix) values[prefix + "upstream_finds"] = u" ; ".join( @@ -283,41 +316,243 @@ class Treatment(DashboardFormItem, ValueGetter, BaseHistorizedItem, if q.count(): self.index = q.all().aggregate(Max('index'))['index__max'] + 1 + def _create_n_1_resulting_find(self, resulting_find, upstream_items, + treatment_types): + """ + Manage creation of n<->1 treatment + """ + m2m = {} + base_fields = [f.name for f in Find._meta.get_fields()] + for k in resulting_find.keys(): + # if not in base fields should be a m2m + if k not in base_fields: + values = resulting_find.pop(k) + if values: + m2m[k + "s"] = values + + resulting_find['history_modifier'] = self.history_modifier + new_find = Find.objects.create(**resulting_find) + + for k in m2m: + m2m_field = getattr(new_find, k) + try: + for value in m2m[k]: + m2m_field.add(value) + except TypeError: + m2m_field.add(m2m[k]) + + create_new_find = bool([tp for tp in treatment_types + if tp.create_new_find]) + + current_base_finds = [] + current_documents = [] + for upstream_item in upstream_items: + # datings are not explicitly part of the resulting_find + # need to reassociate with no duplicate + for dating in upstream_item.datings.all(): + is_present = False + for current_dating in new_find.datings.all(): + if Dating.is_identical(current_dating, dating): + is_present = True + break + if is_present: + continue + dating.pk = None # duplicate + dating.save() + new_find.datings.add(dating) + + # associate base finds + for base_find in upstream_item.base_finds.all(): + if base_find.pk in current_base_finds: + continue + current_base_finds.append(base_find.pk) + new_find.base_finds.add(base_find) + + # documents + for document in upstream_item.documents.all(): + if document.pk in current_documents: + continue + current_documents.append(document.pk) + new_find.documents.add(document) + + # data + new_find.data = update_data(new_find.data, upstream_item.data, + merge=True) + + if create_new_find: + upstream_item.downstream_treatment = self + upstream_item.history_modifier = self.history_modifier + upstream_item.save() + else: + self.finds.add(upstream_item) + + new_find.upstream_treatment = self + new_find.skip_history_when_saving = True + new_find.save() + + def _create_1_n_resulting_find(self, resulting_finds, upstream_item, user, + treatment_types): + """ + Manage creation of 1<->n treatment + """ + new_items = [] + start_number = resulting_finds['start_number'] + for idx in range(resulting_finds['number']): + label = resulting_finds['label'] + unicode(start_number + idx) + new_find = Find.objects.get( + pk=upstream_item.pk).duplicate(user) + new_find.upstream_treatment = self + new_find.label = label + new_find.skip_history_when_saving = True + new_find.save() + new_items.append(new_find) + + create_new_find = bool([tp for tp in treatment_types + if tp.create_new_find]) + + if create_new_find: + upstream_item.downstream_treatment = self + upstream_item.skip_history_when_saving = True + upstream_item.save() + else: + self.finds.add(upstream_item) + + if getattr(user, 'ishtaruser', None): + b = FindBasket.objects.create( + label=resulting_finds['basket_name'], user=user.ishtaruser) + for item in new_items: + b.items.add(item) + def save(self, *args, **kwargs): - items, user, extra_args_for_new = [], None, [] + items, user, extra_args_for_new, resulting_find = [], None, [], None + upstream_items, upstream_item, resulting_finds = [], None, None + treatment_types = [] if "items" in kwargs: items = kwargs.pop('items') + if "resulting_find" in kwargs: + resulting_find = kwargs.pop('resulting_find') + if "resulting_finds" in kwargs: + resulting_finds = kwargs.pop('resulting_finds') + if "upstream_items" in kwargs: + upstream_items = kwargs.pop('upstream_items') + if "upstream_item" in kwargs: + upstream_item = kwargs.pop('upstream_item') if "user" in kwargs: user = kwargs.pop('user') if "extra_args_for_new" in kwargs: extra_args_for_new = kwargs.pop('extra_args_for_new') + if "treatment_type_list" in kwargs: + treatment_types = kwargs.pop('treatment_type_list') self.pre_save() super(Treatment, self).save(*args, **kwargs) + to_be_executed = not self.executed and self.treatment_state.executed + updated = [] + # baskets if hasattr(items, "items"): items = items.items.all() + if hasattr(upstream_items, "items"): + upstream_items = upstream_items.items.all() + if not items and self.finds.count(): + items = list(self.finds.all()) + if not treatment_types and self.treatment_types.count(): + treatment_types = list(self.treatment_types.all()) + + # execute the treatment + if upstream_items and resulting_find: + if not to_be_executed: + # should not happen but bad validation check... + return + self._create_n_1_resulting_find(resulting_find, upstream_items, + treatment_types) + self.executed = True + self.save() + return + + if upstream_item and resulting_finds: + if not to_be_executed: + # should not happen but bad validation check... + return + self._create_1_n_resulting_find( + resulting_finds, upstream_item, self.history_modifier, + treatment_types) + self.executed = True + self.save() + return + + create_new_find = bool([tp for tp in treatment_types + if tp.create_new_find]) + for item in items: - new = item.duplicate(user) - item.downstream_treatment = self - item.save() - new.upstream_treatment = self - for k in extra_args_for_new: - setattr(new, k, extra_args_for_new[k]) - new.save() - updated.append(new.pk) - # update baskets - for basket in \ - FindBasket.objects.filter(items__pk=item.pk).all(): - basket.items.remove(item) - basket.items.add(new) + if not create_new_find or not to_be_executed: + self.finds.add(item) + else: + self.finds.clear() + new = item.duplicate(user) + item.downstream_treatment = self + item.save() + new.upstream_treatment = self + for k in extra_args_for_new: + setattr(new, k, extra_args_for_new[k]) + new.save() + updated.append(new.pk) + # update baskets + for basket in \ + FindBasket.objects.filter(items__pk=item.pk).all(): + basket.items.remove(item) + basket.items.add(new) + + if not to_be_executed: + return + + if create_new_find: + q = Find.objects.filter(upstream_treatment=self) + else: + q = Find.objects.filter(treatments=self) + + # manage loan return + for tp in treatment_types: + if tp.restore_reference_location: + for find in q.all(): + if find.container_ref: + find.container = find.container_ref + if find.pk in updated: + # don't record twice history + find.skip_history_when_saving = True + find.save() + self.executed = True + self.save() + break + # manage containers - for find in Find.objects.filter(upstream_treatment=self).all(): - if find.container != self.container: - find.container = self.container - if find.pk in updated: - # don't record twice history - find.skip_history_when_saving = True - find.save() + if not self.container: + return + + container_attrs = [] + for tp in treatment_types: + if tp.change_current_location: + if 'container' in container_attrs: + continue + container_attrs.append('container') + if tp.change_reference_location: + if 'container_ref' in container_attrs: + continue + container_attrs.append('container_ref') + + if not container_attrs: + # non consistent treatment + return + + for find in q.all(): + for container_attr in container_attrs: + if getattr(find, container_attr) != self.container: + setattr(find, container_attr, self.container) + if find.pk in updated: + # don't record twice history + find.skip_history_when_saving = True + find.save() + self.executed = True + self.save() @property def associated_filename(self): @@ -515,6 +750,8 @@ class FindTreatments(AbsFindTreatments): class TreatmentFileType(GeneralType): + treatment_type = models.ForeignKey(TreatmentType, blank=True, null=True) + class Meta: verbose_name = _(u"Treatment request type") verbose_name_plural = _(u"Treatment request types") @@ -610,6 +847,10 @@ class TreatmentFile(DashboardFormItem, ClosedItem, BaseHistorizedItem, documents = models.ManyToManyField( Document, related_name='treatment_files', verbose_name=_(u"Documents"), blank=True) + associated_basket = models.ForeignKey( + FindBasket, null=True, blank=True, on_delete=models.SET_NULL, + related_name='treatment_files' + ) cached_label = models.TextField(_(u"Cached name"), null=True, blank=True, db_index=True) history = HistoricalRecords() @@ -619,21 +860,15 @@ class TreatmentFile(DashboardFormItem, ClosedItem, BaseHistorizedItem, verbose_name_plural = _(u"Treatment requests") unique_together = ('year', 'index') permissions = ( - ("view_filetreatment", + ("view_treatmentfile", u"Can view all Treatment requests"), - ("add_filetreatment", - u"Can add Treatment request"), - ("change_filetreatment", - u"Can change Treatment request"), - ("delete_filetreatment", - u"Can delete Treatment request"), - ("view_own_filetreatment", + ("view_own_treatmentfile", u"Can view own Treatment request"), - ("add_own_filetreatment", + ("add_own_treatmentfile", u"Can add own Treatment request"), - ("change_own_filetreatment", + ("change_own_treatmentfile", u"Can change own Treatment request"), - ("delete_own_filetreatment", + ("delete_own_treatmentfile", u"Can delete own Treatment request"), ) ordering = ('cached_label',) @@ -657,6 +892,39 @@ class TreatmentFile(DashboardFormItem, ClosedItem, BaseHistorizedItem, for attr in ('year', 'index', 'internal_reference', 'name') if getattr(self, attr)]) + def get_values(self, prefix=''): + values = super(TreatmentFile, self).get_values(prefix=prefix) + if not self.associated_basket: + return + values[prefix + "basket"] = [ + find.get_values() for find in self.associated_basket.items.all() + ] + return values + + def get_extra_actions(self, request): + # url, base_text, icon, extra_text, extra css class, is a quick action + actions = [] + if self.can_do(request, 'add_administrativeact'): + actions += [ + (reverse('treatmentfile-add-adminact', args=[self.pk]), + _(u"Add associated administrative act"), "fa fa-plus", + _(u"admin. act"), "", False), + ] + if not self.associated_basket: + return actions + if self.type.treatment_type and self.treatments.filter( + treatment_types__pk=self.type.treatment_type.pk).count(): + # a treatment of this type already exists + return actions + can_edit_find = self.can_do(request, 'change_find') + if can_edit_find: + actions += [ + (reverse('treatmentfile-add-treatment', args=[self.pk]), + _(u"Add associated treatment"), "fa fa-exchange", "", "", + False), + ] + return actions + @classmethod def get_owns(cls, user, menu_filtr=None, limit=None, values=None, get_short_menu_class=None): diff --git a/archaeological_finds/templates/ishtar/blocks/window_find_nav.html b/archaeological_finds/templates/ishtar/blocks/window_find_nav.html new file mode 100644 index 000000000..74c6858a1 --- /dev/null +++ b/archaeological_finds/templates/ishtar/blocks/window_find_nav.html @@ -0,0 +1,21 @@ +{% extends "ishtar/blocks/window_nav.html" %} +{% load i18n link_to_window %} +{% block post_pin %}{% if baskets %} +<div class="dropdown btn-secondary"> + <button class="btn btn-sm btn-secondary dropdown-toggle" type="button" + id="dropdown-post-pin-{{window_id}}" + data-toggle="dropdown"aria-haspopup="true" + aria-expanded="false"> + <i class="fa fa-shopping-basket"></i> {% trans "Baskets" %} + </button> + <div class="dropdown-menu" aria-labelledby="dropdown-post-pin-{{window_id}}"> + {% for basket_id, lbl in baskets %} + <a class="dropdown-item" href="#" + onclick="load_window('{% url 'show-findbasket' basket_id %}')"> + <i class="fa fa-info-circle display_details" aria-hidden="true"></i> + {{lbl}} + </a> + {% endfor %} + </div> +</div> +{% endif %}{% endblock %} diff --git a/archaeological_finds/templates/ishtar/forms/qa_find_treatment.html b/archaeological_finds/templates/ishtar/forms/qa_find_treatment.html index ef3906735..f20f0cb65 100644 --- a/archaeological_finds/templates/ishtar/forms/qa_find_treatment.html +++ b/archaeological_finds/templates/ishtar/forms/qa_find_treatment.html @@ -27,20 +27,26 @@ </div> <div class="form-row"> + {{ form.reference_container }} <label for="{{form.reference_container.auto_id}}"> + {% trans "Change the reference container" %} + </label> + </div> + + <div class="form-row"> {{ form.create_treatment }} <label for="{{form.create_treatment.auto_id}}"> {% trans "Associate a treatment" %} </label> </div> <div id="new-treatment"> - {% for field in form %} - {% if field.name != 'container' and field.name != 'create_treatment' %} - {% if forloop.counter0|divisibleby:2 %} + {% with force_large_col=True %}{% for field in form %} + {% if field.name != 'reference_container' and field.name != 'container' and field.name != 'create_treatment' %} + {% if forloop.counter|divisibleby:2 %} <div class="form-row">{% endif %} {% include "blocks/bs_field_snippet.html" %} {% if not forloop.counter0|divisibleby:2 %} </div>{% endif %} {% endif %} - {% endfor %} + {% endfor %}{% endwith %} </div> {% endblock %} diff --git a/archaeological_finds/templates/ishtar/forms/qa_findbasket_duplicate.html b/archaeological_finds/templates/ishtar/forms/qa_findbasket_duplicate.html new file mode 100644 index 000000000..b9ec50f22 --- /dev/null +++ b/archaeological_finds/templates/ishtar/forms/qa_findbasket_duplicate.html @@ -0,0 +1,22 @@ +{% extends "ishtar/forms/qa_base.html" %} +{% load i18n inline_formset table_form %} + +{% block main_form %} +<div class="alert alert-info"> + {% trans "Items of the basket will be attached to the new basket but not the shares." %} +</div> +{% if form.non_field_errors %} +<div class="alert alert-danger" role="alert"> + {{form.non_field_errors}} +</div> +{% endif %} +<div class="form-row"> + <div class="form-group col-lg-6 required"> + <label>{% trans "Label" %}</label> + </div> + {% with form.label as field %} + {% include "blocks/bs_field_snippet.html" %} + {% endwith %} +</div> +{% endblock %} + diff --git a/archaeological_finds/templates/ishtar/sheet_basefind.html b/archaeological_finds/templates/ishtar/sheet_basefind.html index c20ca66ee..7ea16fecb 100644 --- a/archaeological_finds/templates/ishtar/sheet_basefind.html +++ b/archaeological_finds/templates/ishtar/sheet_basefind.html @@ -1,6 +1,10 @@ {% load i18n window_field from_dict link_to_window window_tables window_header humanize %} - <p class='window-refs text-center'>{{base_find.complete_id }}</p> - <p class='window-refs text-center'>{{base_find.short_id }}</p> +<div id="{{window_id}}-base-find-{{forloop.counter}}" role="tabpanel" + class="tab-pane fade{% if forloop.first %} show active{% endif %}"> + <p class='window-refs text-center'>{{ base_find.complete_id }}</p> + {% if base_find.complete_id != base_find.short_id %} + <p class='window-refs text-center'>{{ base_find.short_id }}</p> + {% endif %} {% if base_find.external_id %} <p class='window-refs text-center external-id'> <small title="{% trans 'Internal ID' %}"> @@ -77,11 +81,5 @@ {% endwith %}{% endwith %} {% endif %} </div> - -{% if first %} - </div> </div> -<div class="subsection"> -{% endif %} -{% if forloop.counter0 %}<hr/>{% endif %} diff --git a/archaeological_finds/templates/ishtar/sheet_find.html b/archaeological_finds/templates/ishtar/sheet_find.html index 021ea5652..7171c3deb 100644 --- a/archaeological_finds/templates/ishtar/sheet_find.html +++ b/archaeological_finds/templates/ishtar/sheet_find.html @@ -1,10 +1,10 @@ {% extends "ishtar/sheet.html" %} -{% load i18n window_field from_dict link_to_window window_tables window_header humanize %} +{% load i18n ishtar_helpers window_field from_dict link_to_window window_tables window_header humanize %} {% block head_title %}<strong>{% trans "Find" %}</strong>{% if item.denomination %} - {{item.denomination|default:""}}{% endif %} - {{item.label|default:""}}{% endblock %} {% block toolbar %} -{% window_nav item window_id 'show-find' 'find_modify' 'show-historized-find' 'revert-find' previous next 1 %} +{% window_find_nav item window_id 'show-find' 'find_modify' 'show-historized-find' 'revert-find' previous next 1 baskets %} {% endblock %} {% block content %} @@ -15,243 +15,387 @@ </div> {% endif %} +{# trick to set to null non existing variable #} +{% with permission_view_document=permission_view_document %} +{% with permission_view_own_document=permission_view_own_document %} -{% with nb_image=item.images.count %} -{% if nb_image %} -<div class="clearfix"> - <div class="card float-left col-12 col-md-6 col-lg-4"> - {% include "ishtar/blocks/window_image.html" %} - <div class="card-body"> - </div> - </div> -{% endif %} +{% with display_identification=item.integrities.count|or_:item.remarkabilities.count|or_:item.conservatory_state|or_:item.conservatory_comment|or_:item.alterations.count|or_:item.alteration_causes.count|or_:item.preservation_to_considers.count|or_:item.appraisal_date|or_:item.treatment_emergency|or_:item.insurance_value|or_:item.estimated_value|or_:item.datings.count|or_:item.dating_comment %} +{% with display_warehouse_treatments=item.container|or_:item.container_ref|or_:item.upstream_treatment|or_:item.downstream_treatment|or_:item.treatments.count %} +{% with can_view_documents=permission_view_own_document|or_:permission_view_document %} +{% with display_documents=can_view_documents|and_:item.documents.count %} - <h2>{% trans "Associated base finds"%}</h2> +<ul class="nav nav-tabs" id="{{window_id}}-tabs" role="tablist"> + <li class="nav-item"> + <a class="nav-link active" id="{{window_id}}-basefind-tab" + data-toggle="tab" href="#{{window_id}}-basefind" role="tab" + aria-controls="{{window_id}}-basefind" aria-selected="true"> + {% trans "Image / Base find" %} + </a> + </li> + <li class="nav-item"> + <a class="nav-link" id="{{window_id}}-identification-tab" + data-toggle="tab" href="#{{window_id}}-identification" role="tab" + aria-controls="{{window_id}}-identification" aria-selected="false"> + {% trans "Identification / Description / Dimensions" %} + </a> + </li> + {% if display_identification %} + <li class="nav-item"> + <a class="nav-link" id="{{window_id}}-preservation-tab" + data-toggle="tab" href="#{{window_id}}-preservation" role="tab" + aria-controls="{{window_id}}-preservation" aria-selected="false"> + {% trans "Datings / Preservation" %} + </a> + </li> + {% endif %} + {% if display_warehouse_treatments %} + <li class="nav-item"> + <a class="nav-link" id="{{window_id}}-warehouse-tab" + data-toggle="tab" href="#{{window_id}}-warehouse" role="tab" + aria-controls="{{window_id}}-warehouse" aria-selected="false"> + {% trans "Warehouse / Treatments" %} + </a> + </li> + {% endif %} + {% if display_documents %} + <li class="nav-item"> + <a class="nav-link" id="{{window_id}}-documents-tab" + data-toggle="tab" href="#{{window_id}}-documents" role="tab" + aria-controls="{{window_id}}-treatments" aria-selected="false"> + {% trans "Documents" %} + </a> + </li> + {% endif %} + {% if item.data %} + <li class="nav-item"> + <a class="nav-link" id="{{window_id}}-json-tab" + data-toggle="tab" href="#{{window_id}}-json" role="tab" + aria-controls="{{window_id}}-json" aria-selected="false"> + {% trans "Custom fields" %} + </a> + </li> + {% endif %} +</ul> - <div class="subsection"> - {% for base_find in item.base_finds.all %} - {% with first=forloop.first|add:nb_image %} - {% include "ishtar/sheet_basefind.html" %} - {% endwith %} - {% endfor %} - </div> -{% endwith %} +<div class="tab-content" id="{{window_id}}-tab-content"> -<h3>{% trans "Identification" %}</h3> + <div class="tab-pane fade show active" id="{{window_id}}-basefind" + role="tabpanel" aria-labelledby="{{window_id}}-basefind-tab"> + {% with nb_image=item.images.count %} + {% if nb_image %} + <div class="clearfix"> + <div class="card float-left col-12 col-md-6 col-lg-4"> + {% include "ishtar/blocks/window_image.html" %} + <div class="card-body"> + </div> + </div> + {% endif %} -<div class='text-center'> - {% include "ishtar/blocks/sheet_external_id.html" %} -</div> + <ul class="nav nav-pills" role="tablist"> + {% for base_find in item.base_finds.all %} + <li class="nav-item"> + <a class="nav-link{% if forloop.first %} active{% endif %}" + data-toggle="tab" href="#{{window_id}}-base-find-{{forloop.counter}}" + role="tab"> + {{base_find.short_id}} + </a> + </li> + {% endfor %} + </ul> -<div class='row'> - {% field_flex "Denomination" item.denomination %} - {% field_flex "Free ID" item.label %} - {% field_flex "Previous ID" item.previous_id %} - {% field_flex "Excavation ID" item.excavation_ids %} - {% field_flex "Museum ID" item.museum_id %} - {% field_flex "Seal number" item.seal_number %} - {% trans "Administrative index" as admin_index_label %} - {% field_flex admin_index_label item.administrative_index %} - {% field_flex_full "Mark" item.mark "<pre>" "</pre>" %} -</div> + <div class="tab-content"> + {% for base_find in item.base_finds.all %} + {% with first=forloop.first|add:nb_image %} + {% include "ishtar/sheet_basefind.html" %} + {% endwith %} + {% endfor %} + </div> + {% if nb_image %} + </div> + {% endif %} + {% endwith %} + </div> -<h3>{% trans "Description" %}</h3> -<div class='row'> - {% field_flex_full "Description" item.description "<pre>" "</pre>" %} - {% field_flex "Is complete?" item.is_complete %} - {% field_flex_multiple "Material types" item.material_types %} - {% field_flex "Material type quality" item.material_type_quality %} - {% field_flex_multiple "Object types" item.object_types %} - {% field_flex "Object type quality" item.object_type_quality %} - {% field_flex "Find number" item.find_number %} - {% field_flex "Minimum number of individuals (MNI)" item.min_number_of_individuals %} - {% field_flex_full "Decoration" item.decoration "<pre>" "</pre>" %} - {% field_flex_full "Inscription" item.inscription "<pre>" "</pre>" %} - {% field_flex "Manufacturing place" item.manufacturing_place %} - {% field_flex_multiple "Communicability" item.communicabilities %} - {% field_flex_full "Comment" item.comment "<pre>" "</pre>" %} -</div> + <div class="tab-pane fade" id="{{window_id}}-identification" + role="tabpanel" aria-labelledby="{{window_id}}-identification-tab"> + <h3>{% trans "Identification" %}</h3> -{% if item.length or item.width or item.height or item.diameter or item.thickness or item.volume or item.weight_string or item.dimensions_comment or item.clutter_long_side or item.clutter_short_side or item.clutter_height %} -<h3>{% trans "Dimensions" %}</h3> -<div class='row'> - {% field_flex "Length (cm)" item.length %} - {% field_flex "Width (cm)" item.width %} - {% field_flex "Height (cm)" item.height %} - {% field_flex "Diameter (cm)" item.diameter %} - {% field_flex "Thickness (cm)" item.thickness %} - {% field_flex "Volume (l)" item.volume %} - {% trans "Weight (g)" as weight_label %} - {% field_flex weight_label item.weight_string %} - {% field_flex "Clutter long side (cm)" item.clutter_long_side %} - {% field_flex "Clutter short side (cm)" item.clutter_short_side %} - {% field_flex "Clutter height (cm)" item.clutter_height %} - {% field_flex_full "Dimensions comment" item.dimensions_comment "<pre>" "</pre>" %} -</div> -{% endif %} - -<h3>{% trans "Sheet" %}</h3> -<div class='row'> - {% trans "Checked" as checked_label %} - {% field_flex checked_label item.checked_type %} - {% field_flex "Check date" item.check_date %} - {% include "ishtar/blocks/sheet_creation_section.html" %} -</div> - -{% if item.integrities.count or item.remarkabilities.count or item.conservatory_state or item.conservatory_comment or item.alterations.count or item.alteration_causes.count or item.preservation_to_considers.count or item.appraisal_date or item.treatment_emergency or item.insurance_value or item.estimated_value %} -<h3>{% trans "Preservation" %}</h3> -<div class='row'> - {% field_flex_multiple "Integrity / interest" item.integrities %} - {% field_flex_multiple "Remarkability" item.remarkabilities %} - {% field_flex "Conservatory state" item.conservatory_state %} - {% field_flex_multiple "Alteration" item.alterations %} - {% field_flex_multiple "Alteration cause" item.alteration_causes %} - {% field_flex_multiple "Recommended treatments" item.preservation_to_considers %} - {% field_flex "Treatment emergency" item.treatment_emergency %} - {% field_flex "Estimated value" item.estimated_value|default_if_none:''|intcomma '' ' '|add:CURRENCY %} - {% field_flex "Insurance value" item.insurance_value|default_if_none:''|intcomma '' ' '|add:CURRENCY %} - {% field_flex "Appraisal date" item.appraisal_date %} - {% field_flex_full "Conservatory comment" item.conservatory_comment "<pre>" "</pre>" %} -</div> -{% endif %} + <div class='text-center'> + {% include "ishtar/blocks/sheet_external_id.html" %} + </div> -{% if item.dating or item.dating_comment %} -<h3>{% trans "Dating" %}</h3> -{% if item.datings.count %} -<table id='{{window_id}}-datings' class="table table-striped"> - <tr> - <th>{% trans "Period" %}</th> - <th>{% trans "Start date" %}</th> - <th>{% trans "End date" %}</th> - <th>{% trans "Dating type" %}</th> - <th>{% trans "Quality" %}</th> - <th>{% trans "Precise dating" %}</th> - </tr> -{% for dating in item.datings.all %} - <tr> - <td> - {{dating.period}} - </td> - <td> - {{dating.start_date|default_if_none:"-"}} - </td> - <td> - {{dating.end_date|default_if_none:"-"}} - </td> - <td> - {{dating.dating_type|default_if_none:"-"}} - </td> - <td> - {{dating.quality|default_if_none:"-"}} - </td> - <td> - {{dating.precise_dating|default_if_none:"-"}} - </td> - </tr> -{% endfor %} -</table> -{% endif %} - {% field_flex_full "Comment on dating" item.dating_comment "<pre>" "</pre>" %} -{% endif %} + <div class='row'> + {% field_flex "Denomination" item.denomination %} + {% field_flex "Free ID" item.label %} + {% field_flex "Previous ID" item.previous_id %} + {% field_flex "Excavation ID" item.excavation_ids %} + {% field_flex "Museum ID" item.museum_id %} + {% field_flex "Seal number" item.seal_number %} + {% trans "Administrative index" as admin_index_label %} + {% field_flex admin_index_label item.administrative_index %} + {% field_flex_full "Mark" item.mark "<pre>" "</pre>" %} + </div> -{% include "ishtar/blocks/sheet_json.html" %} + <h3>{% trans "Description" %}</h3> + <div class='row'> + {% field_flex_full "Description" item.description "<pre>" "</pre>" %} + {% field_flex "Is complete?" item.is_complete %} + {% field_flex_multiple "Material types" item.material_types %} + {% field_flex "Material type quality" item.material_type_quality %} + {% field_flex_multiple "Object types" item.object_types %} + {% field_flex "Object type quality" item.object_type_quality %} + {% field_flex "Find number" item.find_number %} + {% field_flex "Minimum number of individuals (MNI)" item.min_number_of_individuals %} + {% field_flex_full "Decoration" item.decoration "<pre>" "</pre>" %} + {% field_flex_full "Inscription" item.inscription "<pre>" "</pre>" %} + {% field_flex "Manufacturing place" item.manufacturing_place %} + {% field_flex_multiple "Communicability" item.communicabilities %} + {% field_flex_full "Comment" item.comment "<pre>" "</pre>" %} + </div> -{% if item.container %} -<h3>{% trans "Warehouse"%}</h3> -<div class='row'> - {% field_flex_detail "Container" item.container %} - {% field_flex "Container ID" item.container.cached_location %} - {% field_flex_detail "Responsible warehouse" item.container.responsible %} - {% field_flex_detail "Location (warehouse)" item.container.location %} - {% field_flex "Precise localisation" item.container.cached_division %} -</div> -{% endif %} + {% if item.length or item.width or item.height or item.diameter or item.thickness or item.volume or item.weight_string or item.dimensions_comment or item.clutter_long_side or item.clutter_short_side or item.clutter_height %} + <h3>{% trans "Dimensions" %}</h3> + <div class='row'> + {% field_flex "Length (cm)" item.length %} + {% field_flex "Width (cm)" item.width %} + {% field_flex "Height (cm)" item.height %} + {% field_flex "Thickness (cm)" item.thickness %} + {% field_flex "Diameter (cm)" item.diameter %} + {% field_flex "Circumference (cm)" item.circumference %} + {% field_flex "Volume (l)" item.volume %} + {% trans "Weight (g)" as weight_label %} + {% field_flex weight_label item.weight_string %} + {% field_flex "Clutter long side (cm)" item.clutter_long_side %} + {% field_flex "Clutter short side (cm)" item.clutter_short_side %} + {% field_flex "Clutter height (cm)" item.clutter_height %} + {% field_flex_full "Dimensions comment" item.dimensions_comment "<pre>" "</pre>" %} + </div> + {% endif %} -{% if item.upstream_treatment or item.downstream_treatment %} -<h3>{% trans "Treatments"%}</h3> + <h3>{% trans "Sheet" %}</h3> + <div class='row'> + {% trans "Checked" as checked_label %} + {% field_flex checked_label item.checked_type %} + {% field_flex "Check date" item.check_date %} + {% include "ishtar/blocks/sheet_creation_section.html" %} + </div> + </div> + {% if display_identification %} + <div class="tab-pane fade" id="{{window_id}}-preservation" + role="tabpanel" aria-labelledby="{{window_id}}-preservation-tab"> + {% if item.integrities.count or item.remarkabilities.count or item.conservatory_state or item.conservatory_comment or item.alterations.count or item.alteration_causes.count or item.preservation_to_considers.count or item.appraisal_date or item.treatment_emergency or item.insurance_value or item.estimated_value %} + <h3>{% trans "Preservation" %}</h3> + <div class='row'> + {% field_flex_multiple "Integrity / interest" item.integrities %} + {% field_flex_multiple "Remarkability" item.remarkabilities %} + {% field_flex "Conservatory state" item.conservatory_state %} + {% field_flex_multiple "Alteration" item.alterations %} + {% field_flex_multiple "Alteration cause" item.alteration_causes %} + {% field_flex_multiple "Recommended treatments" item.preservation_to_considers %} + {% field_flex "Treatment emergency" item.treatment_emergency %} + {% field_flex "Estimated value" item.estimated_value|default_if_none:''|intcomma '' ' '|add:CURRENCY %} + {% field_flex "Insurance value" item.insurance_value|default_if_none:''|intcomma '' ' '|add:CURRENCY %} + {% field_flex "Appraisal date" item.appraisal_date %} + {% field_flex_full "Conservatory comment" item.conservatory_comment "<pre>" "</pre>" %} + </div> + {% endif %} -{% if item.upstream_treatment %} -<h3>{% trans "Upstream treatment" %}</h3> -<table id='{{window_id}}-upstream' class="table table-striped"> - <tr> - <th> </th> - <th>{% trans "Year - index" %}</th> - <th>{% trans "Label" %}</th> - <th>{% trans "Type" %}</th> - <th>{% trans "State" %}</th> - <th>{% trans "Related finds (max. 15 displayed)" %}</th> - <th>{% trans "Doer" %}</th> - <th>{% trans "Container" %}</th> - <th>{% trans "Start date" %}</th> - <th>{% trans "End date" %}</th> - </tr> - {% for items, treatment in item.limited_upstream_treatments %} - <tr> - <td> - <a class="display_details" href="#" - onclick="load_window('{% url 'show-treatment' treatment.id %}/');"> - <i class="fa fa-info-circle" aria-hidden="true"></i> - </a> - </td> - <td class='string'>{{ treatment.year }} - {{treatment.index}}</td> - <td class='string'>{{ treatment.label|default_if_none:"-" }}</td> - <td class='string'>{{ treatment.treatment_types_lbl }}</td> - <td class='string'>{{ treatment.treatment_state|default_if_none:"-" }}</td> - <td class='item-list'>{% for item in items %}<span>{{item}} {{ item|link_to_window}}</span>{% endfor %}</td> - <td class='string'>{{ treatment.person|default_if_none:"-" }}</td> - <td class='string'>{{ treatment.container|default_if_none:"-" }}</td> - <td class='string'>{{ treatment.start_date|default_if_none:"-" }}</td> - <td class='string'>{{ treatment.end_date|default_if_none:"-" }}</td> - </tr> - {% endfor %} -</table> -<p class='tool'><a class='badge' href="{% url 'get-upstreamtreatment' 'csv' %}?submited=1&find_id={{item.pk}}" target="_blank" title='{% trans "Export as CSV"%}'>{% trans "CSV" %}</a> ({{ENCODING}})</p> -{% endif %} + {% if item.datings.count or item.dating_comment %} + <h3>{% trans "Dating" %}</h3> + {% if item.datings.count %} + <table id='{{window_id}}-datings' class="table table-striped"> + <tr> + <th>{% trans "Period" %}</th> + <th>{% trans "Start date" %}</th> + <th>{% trans "End date" %}</th> + <th>{% trans "Dating type" %}</th> + <th>{% trans "Quality" %}</th> + <th>{% trans "Precise dating" %}</th> + </tr> + {% for dating in item.datings.all %} + <tr> + <td> + {{dating.period}} + </td> + <td> + {{dating.start_date|default_if_none:"-"}} + </td> + <td> + {{dating.end_date|default_if_none:"-"}} + </td> + <td> + {{dating.dating_type|default_if_none:"-"}} + </td> + <td> + {{dating.quality|default_if_none:"-"}} + </td> + <td> + {{dating.precise_dating|default_if_none:"-"}} + </td> + </tr> + {% endfor %} + </table> + {% endif %} + {% field_flex_full "Comment on dating" item.dating_comment "<pre>" "</pre>" %} + {% endif %} + </div> + {% endif %} + {% if display_warehouse_treatments %} + <div class="tab-pane fade" id="{{window_id}}-warehouse" + role="tabpanel" aria-labelledby="{{window_id}}-warehouse-tab"> + {% if item.container_ref %} + <h3>{% trans "Warehouse - reference container"%}</h3> + <div class='row'> + {% field_flex_detail "Container" item.container_ref %} + {% field_flex "Container ID" item.container_ref.cached_location %} + {% field_flex_detail "Responsible warehouse" item.container_ref.responsible %} + {% field_flex_detail "Location (warehouse)" item.container_ref.location %} + {% field_flex "Precise localisation" item.container_ref.cached_division %} + </div> + {% endif %} + {% if item.container and item.container_ref.pk != item.container.pk %} + <h3>{% trans "Warehouse - current container"%}</h3> + <div class='row'> + {% field_flex_detail "Container" item.container %} + {% field_flex "Container ID" item.container.cached_location %} + {% field_flex_detail "Responsible warehouse" item.container.responsible %} + {% field_flex_detail "Location (warehouse)" item.container.location %} + {% field_flex "Precise localisation" item.container.cached_division %} + </div> + {% endif %} + {% if item.upstream_treatment or item.downstream_treatment or item.treatments.count %} + {% if item.treatments.all %} + <h3>{% trans "Treatments"%}</h3> + <table id='{{window_id}}-treatments' class="table table-striped"> + <tr> + <th> </th> + <th>{% trans "Year - index" %}</th> + <th>{% trans "Label" %}</th> + <th>{% trans "Type" %}</th> + <th>{% trans "State" %}</th> + <th>{% trans "Related finds (max. 15 displayed)" %}</th> + <th>{% trans "Doer" %}</th> + <th>{% trans "Container" %}</th> + <th>{% trans "Start date" %}</th> + <th>{% trans "End date" %}</th> + </tr> + {% for treatment in item.treatments.all %} + <tr> + <td> + <a class="display_details" href="#" + onclick="load_window('{% url 'show-treatment' treatment.id %}/');"> + <i class="fa fa-info-circle" aria-hidden="true"></i> + </a> + </td> + <td class='string'>{{ treatment.year }} - {{treatment.index}}</td> + <td class='string'>{{ treatment.label|default_if_none:"-" }}</td> + <td class='string'>{{ treatment.treatment_types_lbl }}</td> + <td class='string'>{{ treatment.treatment_state|default_if_none:"-" }}</td> + <td class='item-list'>{% for it in treatment.limited_finds %}<span>{{it}} {{it|link_to_window}}</span>{% endfor %}</td> + <td class='string'>{{ treatment.person|default_if_none:"-" }}</td> + <td class='string'>{{ treatment.container|default_if_none:"-" }}</td> + <td class='string'>{{ treatment.start_date|default_if_none:"-" }}</td> + <td class='string'>{{ treatment.end_date|default_if_none:"-" }}</td> + </tr> + {% endfor %} + </table> + {% endif %} -{% if item.downstream_treatment %} -<h3>{% trans "Downstream treatment" %}</h3> -<table id='{{window_id}}-downstream' class="table table-striped"> - <tr> - <th> </th> - <th>{% trans "Year - index" %}</th> - <th>{% trans "Label" %}</th> - <th>{% trans "Type" %}</th> - <th>{% trans "State" %}</th> - <th>{% trans "Related finds (max. 15 displayed)" %}</th> - <th>{% trans "Doer" %}</th> - <th>{% trans "Container" %}</th> - <th>{% trans "Start date" %}</th> - <th>{% trans "End date" %}</th> - </tr> - {% for items, treatment in item.limited_downstream_treatments %} - <tr> - <td> - <a class="display_details" href="#" - onclick="load_window('{% url 'show-treatment' treatment.id %}/');"> - <i class="fa fa-info-circle" aria-hidden="true"></i> - </a> - </td> - <td class='string'>{{ treatment.year }} - {{treatment.index}}</td> - <td class='string'>{{ treatment.label|default_if_none:"-" }}</td> - <td class='string'>{{ treatment.treatment_types_lbl }}</td> - <td class='string'>{{ treatment.treatment_state|default_if_none:"-" }}</td> - <td class='item-list'>{% for item in items %}<span>{{item}} {{ item|link_to_window}}</span>{% endfor %}</td> - <td class='string'>{{ treatment.person|default_if_none:"" }}</td> - <td class='string'>{{ treatment.container|default_if_none:"-" }}</td> - <td class='string'>{{ treatment.start_date|default_if_none:"" }}</td> - <td class='string'>{{ treatment.end_date|default_if_none:"" }}</td> - </tr> - {% endfor %} -</table> + {% if item.upstream_treatment %} + <h3>{% trans "Upstream treatment" %}</h3> + <table id='{{window_id}}-upstream' class="table table-striped"> + <tr> + <th> </th> + <th>{% trans "Year - index" %}</th> + <th>{% trans "Label" %}</th> + <th>{% trans "Type" %}</th> + <th>{% trans "State" %}</th> + <th>{% trans "Related finds (max. 15 displayed)" %}</th> + <th>{% trans "Doer" %}</th> + <th>{% trans "Container" %}</th> + <th>{% trans "Start date" %}</th> + <th>{% trans "End date" %}</th> + </tr> + {% for items, treatment in item.limited_upstream_treatments %} + <tr> + <td> + <a class="display_details" href="#" + onclick="load_window('{% url 'show-treatment' treatment.id %}/');"> + <i class="fa fa-info-circle" aria-hidden="true"></i> + </a> + </td> + <td class='string'>{{ treatment.year }} - {{treatment.index}}</td> + <td class='string'>{{ treatment.label|default_if_none:"-" }}</td> + <td class='string'>{{ treatment.treatment_types_lbl }}</td> + <td class='string'>{{ treatment.treatment_state|default_if_none:"-" }}</td> + <td class='item-list'>{% for it in items %}<span>{{it}} {{it|link_to_window}}</span>{% endfor %}</td> + <td class='string'>{{ treatment.person|default_if_none:"-" }}</td> + <td class='string'>{{ treatment.container|default_if_none:"-" }}</td> + <td class='string'>{{ treatment.start_date|default_if_none:"-" }}</td> + <td class='string'>{{ treatment.end_date|default_if_none:"-" }}</td> + </tr> + {% endfor %} + </table> + <p class='tool'><a class='badge' href="{% url 'get-upstreamtreatment' 'csv' %}?submited=1&find_id={{item.pk}}" target="_blank" title='{% trans "Export as CSV"%}'>{% trans "CSV" %}</a> ({{ENCODING}})</p> + {% endif %} -<p class='tool'><a class='badge' href="{% url 'get-downstreamtreatment' 'csv' %}?submited=1&find_id={{item.pk}}" target="_blank">{% trans "CSV" %}</a> ({{ENCODING}})</p> -{% endif %} + {% if item.downstream_treatment %} + <h3>{% trans "Downstream treatment" %}</h3> + <table id='{{window_id}}-downstream' class="table table-striped"> + <tr> + <th> </th> + <th>{% trans "Year - index" %}</th> + <th>{% trans "Label" %}</th> + <th>{% trans "Type" %}</th> + <th>{% trans "State" %}</th> + <th>{% trans "Related finds (max. 15 displayed)" %}</th> + <th>{% trans "Doer" %}</th> + <th>{% trans "Container" %}</th> + <th>{% trans "Start date" %}</th> + <th>{% trans "End date" %}</th> + </tr> + {% for items, treatment in item.limited_downstream_treatments %} + <tr> + <td> + <a class="display_details" href="#" + onclick="load_window('{% url 'show-treatment' treatment.id %}/');"> + <i class="fa fa-info-circle" aria-hidden="true"></i> + </a> + </td> + <td class='string'>{{ treatment.year }} - {{treatment.index}}</td> + <td class='string'>{{ treatment.label|default_if_none:"-" }}</td> + <td class='string'>{{ treatment.treatment_types_lbl }}</td> + <td class='string'>{{ treatment.treatment_state|default_if_none:"-" }}</td> + <td class='item-list'>{% for it in items %}<span>{{it}} {{ it|link_to_window}}</span>{% endfor %}</td> + <td class='string'>{{ treatment.person|default_if_none:"" }}</td> + <td class='string'>{{ treatment.container|default_if_none:"-" }}</td> + <td class='string'>{{ treatment.start_date|default_if_none:"" }}</td> + <td class='string'>{{ treatment.end_date|default_if_none:"" }}</td> + </tr> + {% endfor %} + </table> -{% endif %} + <p class='tool'><a class='badge' href="{% url 'get-downstreamtreatment' 'csv' %}?submited=1&find_id={{item.pk}}" target="_blank">{% trans "CSV" %}</a> ({{ENCODING}})</p> + {% endif %} + {% endif %} + </div> + {% endif %} + {% if display_documents %} + <div class="tab-pane fade" id="{{window_id}}-documents" + role="tabpanel" aria-labelledby="{{window_id}}-documents-tab"> + {% trans "Associated documents" as finds_docs %} + {% dynamic_table_document finds_docs 'documents' 'finds' item.pk '' output %} + </div> + {% endif %} + {% if item.data %} + <div class="tab-pane fade" id="{{window_id}}-json" + role="tabpanel" aria-labelledby="{{window_id}}-json-tab"> + {% include "ishtar/blocks/sheet_json.html" %} + </div> + {% endif %} +</div> -{% trans "Associated documents" as finds_docs %} -{% if item.documents.count %} -{% dynamic_table_document finds_docs 'documents' 'finds' item.pk '' output %} -{% endif %} +{% endwith %}{% endwith %}{% endwith %}{% endwith %}{% endwith %}{% endwith %} {% endblock %} + diff --git a/archaeological_finds/templates/ishtar/sheet_findbasket.html b/archaeological_finds/templates/ishtar/sheet_findbasket.html index 3c3ca1d3f..4a101d8f2 100644 --- a/archaeological_finds/templates/ishtar/sheet_findbasket.html +++ b/archaeological_finds/templates/ishtar/sheet_findbasket.html @@ -12,8 +12,9 @@ <div class='row'> {% field_flex "Label" item.label %} {% field_flex_detail "Owned by" item.user.person %} - {% field_flex_multiple "Shared_with" item.shared_with %} {% field_flex "Comment" item.comment %} + {% field_flex_multiple_full "Shared (read) with" item.shared_with %} + {% field_flex_multiple_full "Shared (read/edit) with" item.shared_write_with %} </div> <h3>{% trans "Content" %}</h3> diff --git a/archaeological_finds/templates/ishtar/sheet_treatment.html b/archaeological_finds/templates/ishtar/sheet_treatment.html index 1a3bb931f..78460d002 100644 --- a/archaeological_finds/templates/ishtar/sheet_treatment.html +++ b/archaeological_finds/templates/ishtar/sheet_treatment.html @@ -1,7 +1,7 @@ {% extends "ishtar/sheet.html" %} {% load i18n window_field from_dict link_to_window window_tables window_ope_tables window_header humanize %} -{% block head_title %}<strong>{% trans "Treatment" %}</strong> - {{ item.label|default:"" }}{% endblock %} +{% block head_title %}<strong>{% trans "Treatment" %}</strong> - {{ item|default:"" }}{% endblock %} {% block toolbar %} {% window_nav item window_id 'show-treatment' 'treatment_modify' 'show-historized-treatment' 'revert-treatment' previous next 1 %} @@ -9,73 +9,130 @@ {% block content %} -<div class="row"> - <div class="offset-lg-4 col-lg-4 offset-md-3 col-md-6 offset-sm-1 col-sm-10 col-12"> - <div class="card"> - {% include "ishtar/blocks/window_image.html" %} - <div class="card-body"> - <p class="card-text"> - <p class="window-refs">{{ item.label|default:"" }}</p> - {% if item.other_reference %} - <p class="window-refs">{{ item.other_reference }}</p>{% endif %} - <p class="window-refs">{{ item.year }} - {{ item.index }}</p> - {% if item.external_id %} - <p class="window-refs">{{ item.external_id }}</p>{% endif %} - {% if item.end_date %} - <p class="window-refs">{% trans "Closed" context "Treatment" %} ({{item.end_date}})</p> - {% else %} - <p class="window-refs">{% trans "Active" context "Treatment" %}</p> - {% endif %} - </p> +<ul class="nav nav-tabs" id="{{window_id}}-tabs" role="tablist"> + <li class="nav-item"> + <a class="nav-link active" id="{{window_id}}-treatment-tab" + data-toggle="tab" href="#{{window_id}}-treatment" role="tab" + aria-controls="{{window_id}}-treatment" aria-selected="true"> + {% trans "Treatment" %} + </a> + </li> + <li class="nav-item"> + <a class="nav-link" id="{{window_id}}-find-tab" + data-toggle="tab" href="#{{window_id}}-find" role="tab" + aria-controls="{{window_id}}-find" aria-selected="true"> + {% trans "Finds" %} + </a> + </li> + {% if item.documents.count %} + <li class="nav-item"> + <a class="nav-link" id="{{window_id}}-documents-tab" + data-toggle="tab" href="#{{window_id}}-documents" role="tab" + aria-controls="{{window_id}}-documents" aria-selected="true"> + {% trans "Documents" %} + </a> + </li> + {% endif %} + {% if item.administrative_act.count %} + <li class="nav-item"> + <a class="nav-link" id="{{window_id}}-admin-tab" + data-toggle="tab" href="#{{window_id}}-admin" role="tab" + aria-controls="{{window_id}}-admin" aria-selected="true"> + {% trans "Administrative acts" %} + </a> + </li> + {% endif %} +</ul> + +<div class="tab-content" id="{{window_id}}-tab-content"> + <div class="tab-pane fade show active" id="{{window_id}}-treatment" + role="tabpanel" aria-labelledby="{{window_id}}-treatment-tab"> + <div class="row"> + <div class="offset-lg-4 col-lg-4 offset-md-3 col-md-6 offset-sm-1 col-sm-10 col-12"> + <div class="card"> + {% include "ishtar/blocks/window_image.html" %} + <div class="card-body"> + <p class="card-text"> + <p class="window-refs">{{ item.label|default:"" }}</p> + {% if item.other_reference %} + <p class="window-refs">{{ item.other_reference }}</p>{% endif %} + <p class="window-refs">{{ item.year }} - {{ item.index }}</p> + {% if item.external_id %} + <p class="window-refs">{{ item.external_id }}</p>{% endif %} + {% if item.end_date %} + <p class="window-refs">{% trans "Closed" context "Treatment" %} ({{item.end_date}})</p> + {% else %} + <p class="window-refs">{% trans "Active" context "Treatment" %}</p> + {% endif %} + </p> + </div> + </div> </div> </div> + + <div class="row"> + {% field_flex_multiple "Treatment type" item.treatment_types %} + {% field_flex "State" item.treatment_state %} + {% field_flex_detail "Associated request" item.file %} + {% field_flex "Location" item.location %} + {% field_flex "Container" item.container %} + {% field_flex "Responsible" item.person %} + {% field_flex "Organization" item.organization %} + {% field_flex "Start date" item.start_date %} + {% field_flex "Closing date" item.end_date %} + {% field_flex "Estimated cost" item.estimated_cost|intcomma '' " "|add:CURRENCY %} + {% field_flex "Quoted cost" item.quoted_cost|intcomma '' " "|add:CURRENCY %} + {% field_flex "Realized cost" item.realized_cost|intcomma '' " "|add:CURRENCY %} + {% field_flex "Insurance cost" item.insurance_cost|intcomma '' " "|add:CURRENCY %} + {% field_flex_full "Comment" item.comment "<pre>" "</pre>" %} + {% field_flex_full "Description" item.description "<pre>" "</pre>" %} + {% field_flex_full "Goal" item.goal "<pre>" "</pre>" %} + + {% include "ishtar/blocks/sheet_json.html" %} + </div> </div> -</div> -<div class="row"> - {% field_flex_multiple "Treatment type" item.treatment_types %} - {% field_flex "State" item.treatment_state %} - {% field_flex_detail "Associated request" item.file %} - {% field_flex "Location" item.location %} - {% field_flex "Container" item.container %} - {% field_flex "Responsible" item.person %} - {% field_flex "Organization" item.organization %} - {% field_flex "Start date" item.start_date %} - {% field_flex "Closing date" item.end_date %} - {% field_flex "Estimated cost" item.estimated_cost|intcomma '' " "|add:CURRENCY %} - {% field_flex "Quoted cost" item.quoted_cost|intcomma '' " "|add:CURRENCY %} - {% field_flex "Realized cost" item.realized_cost|intcomma '' " "|add:CURRENCY %} - {% field_flex "Insurance cost" item.insurance_cost|intcomma '' " "|add:CURRENCY %} - {% field_flex_full "Comment" item.comment "<pre>" "</pre>" %} - {% field_flex_full "Description" item.description "<pre>" "</pre>" %} - {% field_flex_full "Goal" item.goal "<pre>" "</pre>" %} - - {% include "ishtar/blocks/sheet_json.html" %} -</div> + <div class="tab-pane fade" id="{{window_id}}-find" + role="tabpanel" aria-labelledby="{{window_id}}-find-tab"> + {% trans "Related finds" as finds %} + {% if item.finds.count %} + {% dynamic_table_document finds 'finds_for_treatment' 'treatments' item.pk 'TABLE_COLS_FOR_OPE' output %} + {% endif %} -{% trans "Upstream finds" as finds %} -{% if item.upstream.count %} -{% dynamic_table_document finds 'finds_for_treatment' 'downstream_treatment' item.pk 'TABLE_COLS_FOR_OPE' output %} -{% endif %} + {% trans "Upstream finds" as finds %} + {% if item.upstream.count %} + {% dynamic_table_document finds 'finds_for_treatment' 'downstream_treatment' item.pk 'TABLE_COLS_FOR_OPE' output %} + {% endif %} -{% trans "Downstream finds" as finds %} -{% if item.downstream.count %} -{% dynamic_table_document finds 'finds_for_treatment' 'upstream_treatment' item.pk 'TABLE_COLS_FOR_OPE' output %} -{% endif %} + {% trans "Downstream finds" as finds %} + {% if item.downstream.count %} + {% dynamic_table_document finds 'finds_for_treatment' 'upstream_treatment' item.pk 'TABLE_COLS_FOR_OPE' output %} + {% endif %} -{% trans "Related operations" as related_operations %} -{% dynamic_table_document related_operations 'operations' 'related_treatment' item.pk 'TABLE_COLS' output %} + {% comment %} + {% trans "Related operations" as related_operations %} + {% dynamic_table_document related_operations 'operations' 'related_treatment' item.pk 'TABLE_COLS' output %} + {% endcomment %} -{% comment %} -{% if item.source.count %} -{% trans "Associated documents" as associated_docs %} -{% dynamic_table_document associated_docs 'treatments_docs' 'treatment' item.pk '' output %} -{% endif %} -{% endcomment %} -{% if item.administrative_act.count %} -{% trans "Administrative acts" as admact_lbl %} -{% table_administrativact admact_lbl item.administrative_act.all %} -{% endif %} + </div> + {% if item.documents.count %} + <div class="tab-pane fade" id="{{window_id}}-documents" + role="tabpanel" aria-labelledby="{{window_id}}-documents-tab"> + {% trans "Associated documents" as treat_docs %} + {% dynamic_table_document treat_docs 'documents' 'treatments' item.pk '' output %} + </div> + {% endif %} + + {% if item.administrative_act.count %} + <div class="tab-pane fade" id="{{window_id}}-admin" + role="tabpanel" aria-labelledby="{{window_id}}-admin-tab"> + {% trans "Administrative acts" as admact_lbl %} + {% table_administrativact admact_lbl item.administrative_act.all %} + </div> + {% endif %} + + +</div> {% endblock %} diff --git a/archaeological_finds/templates/ishtar/sheet_treatmentfile.html b/archaeological_finds/templates/ishtar/sheet_treatmentfile.html index 08398a6c2..072285262 100644 --- a/archaeological_finds/templates/ishtar/sheet_treatmentfile.html +++ b/archaeological_finds/templates/ishtar/sheet_treatmentfile.html @@ -34,6 +34,7 @@ <div class="row"> {% field_flex "Type" item.type %} {% field_flex_detail "Responsible" item.in_charge %} + {% field_flex_detail "Associated basket" item.associated_basket %} {% field_flex "Creation date" item.creation_date %} {% field_flex "Reception date" item.reception_date %} {% field_flex "Closing date" item.end_date %} diff --git a/archaeological_finds/templates/ishtar/wizard/wizard_findbasket_deletion.html b/archaeological_finds/templates/ishtar/wizard/wizard_findbasket_deletion.html new file mode 100644 index 000000000..ffd5f0398 --- /dev/null +++ b/archaeological_finds/templates/ishtar/wizard/wizard_findbasket_deletion.html @@ -0,0 +1,25 @@ +{% extends "ishtar/wizard/confirm_wizard.html" %} +{% load i18n link_to_window %} + +{% block "warning_message" %} +{% if current_object.treatment_files.count %} +<div class="alert alert-{% if has_downstream %}danger{% else %}warning{% endif%}"> + <i class="fa fa-exclamation-triangle" aria-hidden="true"></i> + {% trans "This basket is attached to treatments requests:" %} + <ul>{% for tf in current_object.treatment_files.all %} + <li>{{ tf }} {{tf|link_to_window}}</li> + {% endfor %}</ul> + {% trans "Are you sure you want to delete this basket?" %} +</div> +{% endif %} +<div class="alert alert-info"> + {% trans "Items inside the basket (these items will not be deleted):" %} +</div> +<ul>{% for item in current_object.items.all %} + <li>{{item}} {{item|link_to_window}}</li> +{% endfor %}</ul> + +<div class="alert alert-info"> + {% trans "Basket informations:" %} +</div> +{% endblock %} diff --git a/archaeological_finds/templates/ishtar/wizard/wizard_simplefind.html b/archaeological_finds/templates/ishtar/wizard/wizard_simplefind.html new file mode 100644 index 000000000..b1d77ba81 --- /dev/null +++ b/archaeological_finds/templates/ishtar/wizard/wizard_simplefind.html @@ -0,0 +1,13 @@ +{% extends "ishtar/wizard/default_wizard.html" %} +{% load i18n %} +{% block form_head %} +<div class="alert alert-warning"> + <i class="fa fa-exclamation-triangle"></i> + {% trans 'This find is related to many base finds. To edit field related to base finds edit the corresponding find between theses:' %} + <ul>{% for base_find in wizard.form.base_finds %} + {% with find=base_find.get_main_find %}<li> + {{find.short_label }} + <a href="{% url 'find_modify' find.pk %}"><i class="fa fa-pencil"></i></a> + </li>{% endwith %}{% endfor %}</ul> +</div> +{% endblock %} diff --git a/archaeological_finds/templates/ishtar/wizard/wizard_treatement_deletion.html b/archaeological_finds/templates/ishtar/wizard/wizard_treatement_deletion.html new file mode 100644 index 000000000..be46bfd05 --- /dev/null +++ b/archaeological_finds/templates/ishtar/wizard/wizard_treatement_deletion.html @@ -0,0 +1,27 @@ +{% extends "ishtar/wizard/confirm_wizard.html" %} +{% load i18n link_to_window %} + +{% block "warning_message" %} +{% with has_downstream=current_object.downstream.count %} +<div class="alert alert-{% if has_downstream %}danger{% else %}warning{% endif%}"> + <i class="fa fa-exclamation-triangle" aria-hidden="true"></i> + {% trans "Are you sure you want to delete this treatment?" %} +{% if has_downstream %} + {% trans "The following finds will be deleted and restored to a previous version."%} + <ul>{% for item in current_object.downstream.all %} + <li> + {{item}} {{item|link_to_window}} + </li> + {% endfor %}</ul> + {% trans "All changes made to the associated finds since this treatment record will be lost!" %} +{% endif %} +</div> + +<div class="alert alert-info"> + {% trans "Treatment informations:" %} +</div> + + + +{% endwith %} +{% endblock %} diff --git a/archaeological_finds/tests.py b/archaeological_finds/tests.py index a55e075b7..ae03b2ba4 100644 --- a/archaeological_finds/tests.py +++ b/archaeological_finds/tests.py @@ -215,8 +215,7 @@ class TreatmentWizardCreationTest(WizardTest, FindInit, TestCase): 'treatment_type': None, 'person': 1, # doer 'location': 1, # associated warehouse - 'year': 2016, - 'target_is_basket': False + 'year': 2016 }, 'selecfind': { 'pk': 1, @@ -243,6 +242,13 @@ class TreatmentWizardCreationTest(WizardTest, FindInit, TestCase): trt_type = models.TreatmentType.objects.get(txt_idx='moving') self.form_datas[0].set('basetreatment', 'treatment_type', trt_type.pk) + completed, created = models.TreatmentState.objects.get_or_create( + txt_idx='completed', defaults={"executed": True, "label": u"Done"} + ) + completed.executed = True + completed.save() + + self.form_datas[0].set('basetreatment', 'treatment_state', completed.pk) self.find, base_find = self.get_default_find(force=True) self.form_datas[0].form_datas['selecfind'][ @@ -258,9 +264,10 @@ class TreatmentWizardCreationTest(WizardTest, FindInit, TestCase): treat = models.Treatment.objects.order_by('-pk').all()[0] self.find = models.Find.objects.get(pk=self.find.pk) self.assertEqual(models.Find.objects.filter( - upstream_treatment=treat).count(), 1) - self.assertEqual(self.find.downstream_treatment, - treat) + treatments=treat).count(), 1) + # TODO: test treatment with new find creation + # self.assertEqual(self.find.downstream_treatment, + # treat) class ImportFindTest(ImportTest, TestCase): @@ -796,7 +803,8 @@ class FindQATest(FindInit, TestCase): reverse('find-qa-bulk-update-confirm', args=[pks]), {'qa_period': period, 'qa_description': extra_desc} ) - self.assertRedirects(response, '/success/') + if response.status_code != 200: + self.assertRedirects(response, '/success/') self.assertIn(period, [dating.period.pk for dating in find_0.datings.all()]) self.assertIn(period, @@ -807,7 +815,7 @@ class FindQATest(FindInit, TestCase): base_desc_1 + u"\n" + extra_desc) -class PackagingTest(FindInit, TestCase): +class TreatmentTest(FindInit, TestCase): fixtures = FIND_FIXTURES model = models.Find @@ -832,18 +840,33 @@ class PackagingTest(FindInit, TestCase): self.basket.items.add(find) self.other_basket.items.add(find) - def testPackaging(self): + def test_packaging_with_new_find_creation(self): treatment_type = models.TreatmentType.objects.get(txt_idx='packaging') + # make packaging a treatment with a new version of the find created + treatment_type.create_new_find = True + treatment_type.save() + treatment = models.Treatment() items_nb = models.Find.objects.count() first_find = self.finds[0] - treatment.save(user=self.get_default_user(), items=self.basket) + completed, created = models.TreatmentState.objects.get_or_create( + txt_idx='completed', defaults={"executed": True, "label": u"Done"} + ) + completed.executed = True + completed.save() + + treatment.treatment_state = completed + treatment.save( + user=self.get_default_user(), items=self.basket, + treatment_type_list=[treatment_type], + ) + treatment.treatment_types.add(treatment_type) + self.assertEqual(items_nb + self.basket.items.count(), models.Find.objects.count(), msg="Packaging doesn't generate enough new finds") - treatment.treatment_types.add(treatment_type) resulting_find = models.Find.objects.get( upstream_treatment__upstream=first_find, @@ -866,15 +889,69 @@ class PackagingTest(FindInit, TestCase): item, self.finds, msg="Other basket have not been upgraded after packaging") - def test_delete(self): - # manage treatment deletion + def test_simple_delete(self): treatment_type = models.TreatmentType.objects.get(txt_idx='packaging') + treatment_type.create_new_find = False + treatment_type.save() + + nb_find = models.Find.objects.count() + treatment = models.Treatment() initial_find = self.finds[0] - treatment.save(user=self.get_default_user(), items=self.basket) + completed, created = models.TreatmentState.objects.get_or_create( + txt_idx='completed', defaults={"executed": True, "label": u"Done"} + ) + completed.executed = True + completed.save() + + treatment.treatment_state = completed + treatment.save( + user=self.get_default_user(), items=self.basket, + treatment_type_list=[treatment_type], + ) treatment.treatment_types.add(treatment_type) + self.assertEqual(nb_find, models.Find.objects.count()) + + treatment.delete() + self.assertEqual( + models.Treatment.objects.filter(pk=treatment.pk).count(), 0) + + q = models.Find.objects.filter(pk=initial_find.pk) + # initial find not deleted + self.assertEqual(q.count(), 1) + initial_find = q.all()[0] + self.assertEqual(initial_find.upstream_treatment, None) + + def test_upstream_find_delete(self): + treatment_type = models.TreatmentType.objects.get(txt_idx='packaging') + # make packaging a treatment with a new version of the find created + treatment_type.create_new_find = True + treatment_type.save() + + nb_find = models.Find.objects.count() + + treatment = models.Treatment() + + initial_find = self.finds[0] + completed, created = models.TreatmentState.objects.get_or_create( + txt_idx='completed', defaults={"executed": True, "label": u"Done"} + ) + completed.executed = True + completed.save() + + treatment.treatment_state = completed + treatment.save( + user=self.get_default_user(), items=self.basket, + treatment_type_list=[treatment_type], + ) + treatment.treatment_types.add(treatment_type) + + nb_b = self.basket.items.count() + self.assertEqual( + nb_find + nb_b, models.Find.objects.count()) + resulting_find = models.Find.objects.get( upstream_treatment__upstream=initial_find, base_finds__pk=initial_find.base_finds.all()[0].pk @@ -888,3 +965,42 @@ class PackagingTest(FindInit, TestCase): self.assertEqual(q.count(), 1) initial_find = q.all()[0] self.assertEqual(initial_find.upstream_treatment, None) + + def test_treatment_delete(self): + treatment_type = models.TreatmentType.objects.get(txt_idx='packaging') + treatment_type.create_new_find = True + treatment_type.save() + + nb_find = models.Find.objects.count() + + treatment = models.Treatment() + + initial_find = self.finds[0] + completed, created = models.TreatmentState.objects.get_or_create( + txt_idx='completed', defaults={"executed": True, "label": u"Done"} + ) + completed.executed = True + completed.save() + + treatment.treatment_state = completed + treatment.save( + user=self.get_default_user(), items=self.basket, + treatment_type_list=[treatment_type], + ) + treatment.treatment_types.add(treatment_type) + + nb_b = self.basket.items.count() + self.assertEqual( + nb_find + nb_b, models.Find.objects.count()) + + treatment.delete() + + self.assertEqual(nb_find, models.Find.objects.count()) + + self.assertEqual( + models.Treatment.objects.filter(pk=treatment.pk).count(), 0) + q = models.Find.objects.filter(pk=initial_find.pk) + # initial find not deleted + self.assertEqual(q.count(), 1) + initial_find = q.all()[0] + self.assertEqual(initial_find.upstream_treatment, None) diff --git a/archaeological_finds/urls.py b/archaeological_finds/urls.py index 588c8d520..fe7b2acd2 100644 --- a/archaeological_finds/urls.py +++ b/archaeological_finds/urls.py @@ -45,6 +45,8 @@ urlpatterns = [ views.find_modify, name='find_modify'), url(r'get-findbasket/$', views.get_find_basket, name='get-findbasket'), + url(r'get-findbasket-write/$', views.get_find_basket_for_write, + name='get-findbasket-write'), url(r'find_basket_search/(?P<step>.+)?$', check_rights(['view_find', 'view_own_find'])( views.basket_search_wizard), name='find_basket_search'), @@ -78,9 +80,36 @@ urlpatterns = [ check_rights(['view_find', 'view_own_find'])( views.FindBasketListView.as_view()), name='list_iteminbasket'), - url(r'^find_basket_deletion/$', + url(r'^find_basket_deletion/(?P<step>.+)?$', check_rights(['view_find', 'view_own_find'])( - views.DeleteFindBasketView.as_view()), name='delete_findbasket'), + views.basket_delete_wizard), + name='find_basket_deletion'), + url(r'^findbasket-qa-duplicate/(?P<pks>[0-9-]+)?/$', + check_rights(['view_find', 'view_own_find'])( + views.QAFindbasketDuplicateFormView.as_view()), + name='findbasket-qa-duplicate'), + + url(r'^findbasket-add-treatment/(?P<pk>[0-9-]+)/$', + check_rights(['change_find', 'change_own_find'])( + views.findbasket_treatment_add), + name='findbasket-add-treatment'), + url(r'^find-add-treatment/(?P<pk>[0-9-]+)/$', + check_rights(['change_find', 'change_own_find'])( + views.find_treatment_add), + name='find-add-treatment'), + url(r'^treatmentfile-add-treatment/(?P<pk>[0-9-]+)/$', + check_rights(['change_find', 'change_own_find'])( + views.treatmentfile_treatment_add), + name='treatmentfile-add-treatment'), + url(r'^treatment-add-adminact/(?P<pk>[0-9-]+)/$', + check_rights(['add_administrativeact'])( + views.treatment_adminact_add), + name='treatment-add-adminact'), + + url(r'^treatmentfile-add-adminact/(?P<pk>[0-9-]+)/$', + check_rights(['add_administrativeact'])( + views.treatmentfile_adminact_add), + name='treatmentfile-add-adminact'), url(r'^find-qa-bulk-update/(?P<pks>[0-9-]+)?/$', check_rights(['change_find', 'change_own_find'])( @@ -100,10 +129,16 @@ urlpatterns = [ views.QAFindTreatmentFormView.as_view()), name='find-qa-packaging'), - url(r'^treatment_creation/(?P<step>.+)?$', check_rights(['change_find', 'change_own_find'])( views.treatment_creation_wizard), name='treatment_creation'), + url(r'^treatment_creation_n1/(?P<step>.+)?$', + check_rights(['change_find', 'change_own_find'])( + views.treatment_creation_n1_wizard), name='treatment_creation_n1'), + url(r'^treatment_creation_1n/(?P<step>.+)?$', + check_rights(['change_find', 'change_own_find'])( + views.treatment_creation_1n_wizard), name='treatment_creation_1n'), + url(r'^treatment_modification/(?P<step>.+)?$', check_rights(['change_find', 'change_own_find'])( views.treatment_modification_wizard), @@ -248,6 +283,10 @@ urlpatterns = [ administrativeactfile_document, name='treatmentfle-administrativeact-document', kwargs={'treatment_file': True}), + url(r'autocomplete-findbasket/$', + check_rights(['change_find', 'change_own_find'])( + views.autocomplete_findbasket), + name='autocomplete-findbasket'), ] urlpatterns += get_urls_for_model(models.Find, views, own=True, diff --git a/archaeological_finds/views.py b/archaeological_finds/views.py index c340639c5..fb5cdc11e 100644 --- a/archaeological_finds/views.py +++ b/archaeological_finds/views.py @@ -19,6 +19,7 @@ import json +from django.core.exceptions import PermissionDenied from django.core.urlresolvers import reverse from django.db.models import Q from django.http import HttpResponseRedirect, HttpResponse, Http404 @@ -27,18 +28,24 @@ from django.utils.translation import ugettext_lazy as _ from django.views.generic import TemplateView from django.views.generic.edit import CreateView, FormView + +from ishtar_common.models import IshtarUser, get_current_profile +from archaeological_operations.models import AdministrativeAct +from archaeological_finds import models + +from ishtar_common.forms import FinalForm from archaeological_context_records.forms \ import RecordFormSelection as RecordFormSelectionTable from archaeological_operations.forms import FinalAdministrativeActDeleteForm -from archaeological_operations.wizards import AdministrativeActDeletionWizard -from forms import * -from ishtar_common.forms import FinalForm -from ishtar_common.models import IshtarUser, get_current_profile +from archaeological_finds import forms + from ishtar_common.views import get_autocomplete_generic, IshtarMixin, \ LoginRequiredMixin, QAItemEditForm, QAItemForm from ishtar_common.views_item import display_item, get_item, show_item, \ - revert_item, get_autocomplete_item -from wizards import * + revert_item, get_autocomplete_item, get_autocomplete_query + +from archaeological_operations.wizards import AdministrativeActDeletionWizard +from archaeological_finds import wizards get_find = get_item(models.Find, 'get_find', 'find') @@ -105,30 +112,66 @@ def autocomplete_treatmentfile(request): return HttpResponse(data, content_type='text/plain') -show_find = show_item(models.Find, 'find') +def show_find_extra(request, find): + if not request.user or not request.user.ishtaruser: + return {} + user = request.user.ishtaruser + q = models.FindBasket.objects.filter(items__pk=find.pk).filter( + Q(user=user) | Q(shared_with__pk=user.pk) | + Q(shared_write_with__pk=user.pk) + ) + return {"baskets": [(basket.pk, basket.full_label) for basket in q.all()]} + + +show_find = show_item(models.Find, 'find', extra_dct=show_find_extra) display_find = display_item(models.Find) revert_find = revert_item(models.Find) -show_findbasket = show_item(models.FindBasket, 'findbasket') +show_findbasket = show_item(models.FindBasket, 'findbasket', + model_for_perms=models.Find) display_findbasket = display_item(models.FindBasket, show_url='show-find/basket-') + +def autocomplete_findbasket(request, current_right=None): + if not request.GET.get('term'): + return HttpResponse(content_type='text/plain') + + query = get_autocomplete_query(request, ['label']) + limit = 20 + query = query & models.FindBasket.get_write_query_owns( + request.user.ishtaruser) + items = models.FindBasket.objects.filter(query).order_by('label')[:limit] + data = json.dumps( + [{'id': item.pk, + 'value': u"{} - {}".format(item.label, item.user)[:60]} + for item in items] + ) + return HttpResponse(data, content_type='text/plain') + get_find_basket = get_item( models.FindBasket, 'get_findbasket', 'findbasket', + model_for_perms=models.Find ) -basket_search_wizard = FindBasketSearch.as_view( - [('selec-find_basket_search', FindBasketFormSelection)], +get_find_basket_for_write = get_item( + models.FindBasket, 'get_findbasket', 'findbasket', + model_for_perms=models.Find, alt_query_own='get_write_query_owns' +) + +basket_search_wizard = wizards.FindBasketSearch.as_view( + [('selec-find_basket_search', forms.FindBasketFormSelection)], label=_(u"Basket search"), url_name='find_basket_search', ) -basket_modify_wizard = FindBasketEditWizard.as_view( +basket_modify_wizard = wizards.FindBasketEditWizard.as_view( [ - ('selec-find_basket_modification', FindBasketFormSelection), - ('basket-find_basket_modification', FindBasketForm), + ('selec-find_basket_modification', + forms.FindBasketForWriteFormSelection), + ('basket-find_basket_modification', forms.FindBasketForm), ('final-find_basket_modification', FinalForm) - ], + ], label=_(u"Basket modify"), url_name='find_basket_modification', ) @@ -137,13 +180,26 @@ basket_modify_wizard = FindBasketEditWizard.as_view( def find_basket_modify(request, pk): basket_modify_wizard(request) key = 'selec-find_basket_modification' - FindBasketEditWizard.session_set_value( + wizards.FindBasketEditWizard.session_set_value( request, key, 'pk', pk, reset=True) return redirect( reverse('find_basket_modification', kwargs={'step': 'basket-find_basket_modification'})) +findbasket_deletion_steps = [ + ('selec-find_basket_deletion', forms.FindBasketForWriteFormSelection), + ('final-find_basket_deletion', FinalForm) +] + + +basket_delete_wizard = wizards.FindBasketDeletionWizard.as_view( + findbasket_deletion_steps, + label=_(u"Basket deletion"), + url_name='find_basket_deletion', +) + + def check_preservation_module(self): return get_current_profile().preservation @@ -158,9 +214,9 @@ def check_not_warehouse_module(self): find_creation_steps = [ ('selecrecord-find_creation', RecordFormSelectionTable), - ('find-find_creation', FindForm), - ('preservation-find_creation', PreservationForm), - ('dating-find_creation', DatingFormSet), + ('find-find_creation', forms.FindForm), + ('preservation-find_creation', forms.PreservationForm), + ('dating-find_creation', forms.DatingFormSet), ('final-find_creation', FinalForm) ] @@ -168,7 +224,7 @@ find_creation_condition_dict = { 'preservation-find_creation': check_preservation_module, } -find_creation_wizard = FindWizard.as_view( +find_creation_wizard = wizards.FindWizard.as_view( find_creation_steps, label=_(u"New find"), condition_dict=find_creation_condition_dict, @@ -179,31 +235,47 @@ find_search_condition_dict = { 'generalwarehouse-find_search': check_warehouse_module, } -find_search_wizard = FindSearch.as_view([ - ('general-find_search', FindFormSelection), - ('generalwarehouse-find_search', FindFormSelectionWarehouseModule)], +find_search_wizard = wizards.FindSearch.as_view([ + ('general-find_search', forms.FindFormSelection), + ('generalwarehouse-find_search', forms.FindFormSelectionWarehouseModule)], label=_(u"Find search"), url_name='find_search', condition_dict=find_search_condition_dict ) + +def has_many_base_find(wizard): + find = wizard.get_current_object() + if not find: + return False + return find.base_finds.count() > 1 + + +def has_only_one_base_find(wizard): + return not has_many_base_find(wizard) + + find_modification_condition_dict = { 'selec-find_modification': check_not_warehouse_module, 'selecw-find_modification': check_warehouse_module, 'preservation-find_modification': check_preservation_module, + 'selecrecord-find_modification': has_only_one_base_find, + 'find-find_modification': has_only_one_base_find, + 'simplefind-find_modification': has_many_base_find, } find_modification_steps = [ - ('selec-find_modification', FindFormSelection), - ('selecw-find_modification', FindFormSelectionWarehouseModule), - ('selecrecord-find_modification', RecordFormSelection), - ('find-find_modification', FindForm), - ('preservation-find_modification', PreservationForm), - ('dating-find_modification', DatingFormSet), + ('selec-find_modification', forms.FindFormSelection), + ('selecw-find_modification', forms.FindFormSelectionWarehouseModule), + ('selecrecord-find_modification', forms.RecordFormSelection), + ('find-find_modification', forms.FindForm), + ('simplefind-find_modification', forms.SimpleFindForm), + ('preservation-find_modification', forms.PreservationForm), + ('dating-find_modification', forms.DatingFormSet), ('final-find_modification', FinalForm) ] -find_modification_wizard = FindModificationWizard.as_view( +find_modification_wizard = wizards.FindModificationWizard.as_view( find_modification_steps, condition_dict=find_modification_condition_dict, label=_(u"Find modification"), @@ -216,11 +288,18 @@ def find_modify(request, pk): key = 'selec-find_modification' if get_current_profile().warehouse: key = 'selecw-find_modification' - FindModificationWizard.session_set_value( + wizards.FindModificationWizard.session_set_value( request, key, 'pk', pk, reset=True) + q = models.Find.objects.filter(pk=pk) + if not q.count(): + raise Http404() + step = 'find-find_modification' + find = q.all()[0] + if find.base_finds.count() > 1: + step = 'simplefind-find_modification' + return redirect( - reverse('find_modification', - kwargs={'step': 'selecrecord-find_modification'})) + reverse('find_modification', kwargs={'step': step})) find_deletion_condition_dict = { 'selec-find_deletion': check_not_warehouse_module, @@ -228,11 +307,11 @@ find_deletion_condition_dict = { } find_deletion_steps = [ - ('selec-find_deletion', FindFormSelection), - ('selecw-find_deletion', FindFormSelectionWarehouseModule), - ('final-find_deletion', FindDeletionForm)] + ('selec-find_deletion', forms.FindFormSelection), + ('selecw-find_deletion', forms.FindFormSelectionWarehouseModule), + ('final-find_deletion', forms.FindDeletionForm)] -find_deletion_wizard = FindDeletionWizard.as_view( +find_deletion_wizard = wizards.FindDeletionWizard.as_view( find_deletion_steps, condition_dict=find_deletion_condition_dict, label=_(u"Find deletion"), @@ -247,7 +326,7 @@ autocomplete_integritytype = get_autocomplete_generic(models.IntegrityType) class NewFindBasketView(IshtarMixin, LoginRequiredMixin, CreateView): template_name = 'ishtar/form.html' model = models.FindBasket - form_class = NewFindBasketForm + form_class = forms.NewFindBasketForm page_name = _(u"New basket") def get_form_kwargs(self): @@ -268,15 +347,15 @@ class OwnBasket(object): def get_basket(self, user, pk): try: return models.FindBasket.objects.filter( - Q(user=user) | Q(shared_with=user) - ).get(pk=pk) + Q(user=user) | Q(shared_with=user) | Q(shared_write_with=user) + ).distinct().get(pk=pk) except models.FindBasket.DoesNotExist: raise PermissionDenied class SelectBasketForManagement(IshtarMixin, LoginRequiredMixin, FormView): template_name = 'ishtar/form.html' - form_class = SelectFindBasketForm + form_class = forms.SelectFindBasketForm page_name = _(u"Manage items in basket") def get_form_kwargs(self): @@ -309,9 +388,9 @@ class SelectItemsInBasket(OwnBasket, IshtarMixin, LoginRequiredMixin, ) context['basket'] = self.basket if get_current_profile().warehouse: - context['form'] = MultipleFindFormSelectionWarehouseModule() + context['form'] = forms.MultipleFindFormSelectionWarehouseModule() else: - context['form'] = MultipleFindFormSelection() + context['form'] = forms.MultipleFindFormSelection() context['add_url'] = reverse('add_iteminbasket') context['list_url'] = reverse('list_iteminbasket', kwargs={'pk': self.basket.pk}) @@ -323,7 +402,7 @@ class SelectItemsInBasket(OwnBasket, IshtarMixin, LoginRequiredMixin, class FindBasketAddItemView(IshtarMixin, LoginRequiredMixin, FormView): template_name = 'ishtar/simple_form.html' - form_class = FindBasketAddItemForm + form_class = forms.FindBasketAddItemForm def get_success_url(self, basket): return reverse('list_iteminbasket', kwargs={'pk': basket.pk}) @@ -381,22 +460,6 @@ class FindBasketDeleteItemView(OwnBasket, IshtarMixin, LoginRequiredMixin, basket.items.remove(find) return HttpResponseRedirect(self.get_success_url(basket)) - -class DeleteFindBasketView(IshtarMixin, LoginRequiredMixin, FormView): - template_name = 'ishtar/form_delete.html' - form_class = DeleteFindBasketForm - success_url = '/' - page_name = _(u"Delete basket") - - def get_form_kwargs(self): - kwargs = super(DeleteFindBasketView, self).get_form_kwargs() - kwargs['user'] = IshtarUser.objects.get(pk=self.request.user.pk) - return kwargs - - def form_valid(self, form): - form.save() - return HttpResponseRedirect(self.get_success_url()) - get_upstreamtreatment = get_item( models.FindUpstreamTreatments, 'get_upstreamtreatment', 'uptreatment') @@ -405,46 +468,53 @@ get_downstreamtreatment = get_item( 'downtreatment') treatment_wizard_steps = [ - ('file-treatment_creation', TreatmentFormFileChoice), - ('basetreatment-treatment_creation', BaseTreatmentForm), - ('selecfind-treatment_creation', UpstreamFindFormSelection), - ('selecbasket-treatment_creation', SelectFindBasketForm), - # ('resultfind-treatment_creation', ResultFindForm), - # ('resultfinds-treatment_creation', ResultFindFormSet), + ('selecfind-treatment_creation', forms.UpstreamFindFormSelection), + ('file-treatment_creation', forms.TreatmentFormFileChoice), + ('basetreatment-treatment_creation', forms.BaseTreatmentForm), ('final-treatment_creation', FinalForm) ] -treatment_search_wizard = TreatmentSearch.as_view([ - ('general-treatment_search', TreatmentFormSelection)], +treatment_search_wizard = wizards.TreatmentSearch.as_view([ + ('general-treatment_search', forms.TreatmentFormSelection)], label=_(u"Treatment search"), url_name='treatment_search',) -treatment_creation_wizard = TreatmentWizard.as_view( +treatment_creation_wizard = wizards.TreatmentWizard.as_view( treatment_wizard_steps, - condition_dict={ - 'selecfind-treatment_creation': - check_value('basetreatment-treatment_creation', - 'target_is_basket', False), - 'selecbasket-treatment_creation': - check_value('basetreatment-treatment_creation', - 'target_is_basket', True), - # 'resultfinds-treatment_creation': - # check_type_field('basetreatment-treatment_creation', - # 'treatment_type', models.TreatmentType, - # 'downstream_is_many'), - # 'resultfind-treatment_creation': - # check_type_field('basetreatment-treatment_creation', - # 'treatment_type', models.TreatmentType, - # 'upstream_is_many') - }, label=_(u"New treatment"), url_name='treatment_creation',) -treatment_modification_wizard = TreatmentModificationWizard.as_view( - [('selec-treatment_modification', TreatmentFormSelection), - ('file-treatment_modification', TreatmentFormFileChoice), - ('basetreatment-treatment_modification', TreatmentModifyForm), +treatment_n1_wizard_steps = [ + ('selecfind-treatment_creation_n1', forms.UpstreamFindFormSelection), + ('file-treatment_creation_n1', forms.TreatmentFormFileChoice), + ('basetreatment-treatment_creation_n1', forms.N1TreatmentForm), + ('resultingfind-treatment_creation_n1', forms.ResultingFindForm), + ('final-treatment_creation_n1', FinalForm) +] + +treatment_creation_n1_wizard = wizards.TreatmentN1Wizard.as_view( + treatment_n1_wizard_steps, + label=_(u"New treatment"), + url_name='treatment_creation_n1',) + +treatment_1n_wizard_steps = [ + ('selecfind-treatment_creation_1n', forms.SingleUpstreamFindFormSelection), + ('file-treatment_creation_1n', forms.TreatmentFormFileChoice), + ('basetreatment-treatment_creation_1n', forms.OneNTreatmentForm), + ('resultingfinds-treatment_creation_1n', forms.ResultingFindsForm), + ('final-treatment_creation_1n', FinalForm) +] + +treatment_creation_1n_wizard = wizards.Treatment1NWizard.as_view( + treatment_1n_wizard_steps, + label=_(u"New treatment"), + url_name='treatment_creation_1n',) + +treatment_modification_wizard = wizards.TreatmentModificationWizard.as_view( + [('selec-treatment_modification', forms.TreatmentFormSelection), + ('file-treatment_modification', forms.TreatmentFormFileChoice), + ('basetreatment-treatment_modification', forms.TreatmentModifyForm), ('final-treatment_modification', FinalForm)], label=_(u"Treatment modification"), url_name='treatment_modification', @@ -453,41 +523,116 @@ treatment_modification_wizard = TreatmentModificationWizard.as_view( def treatment_modify(request, pk): treatment_modification_wizard(request) - TreatmentModificationWizard.session_set_value( + wizards.TreatmentModificationWizard.session_set_value( request, 'selec-treatment_modification', 'pk', pk, reset=True) return redirect(reverse( 'treatment_modification', - kwargs={'step': 'basetreatment-treatment_modification'})) - - -treatment_deletion_wizard = TreatmentDeletionWizard.as_view([ - ('selec-treatment_deletion', TreatmentFormSelection), - ('final-treatment_deletion', TreatmentDeletionForm)], + kwargs={'step': 'file-treatment_modification'})) + + +def treatment_add(request, pks, treatment_file=None): + treatment_creation_wizard(request) + wizards.TreatmentWizard.session_set_value( + request, 'selecfind-treatment_creation', + 'resulting_pk', pks, reset=True) + if treatment_file: + wizards.TreatmentWizard.session_set_value( + request, 'file-treatment_creation', 'file', treatment_file.pk) + else: + wizards.TreatmentWizard.session_set_value( + request, 'file-treatment_creation', 'file', '') + if treatment_file: + in_charge = treatment_file.in_charge + if not in_charge: + in_charge = request.user.ishtaruser.person + dct = { + "treatment_type": treatment_file.type.treatment_type.pk + if treatment_file.type and treatment_file.type.treatment_type + else "", + "year": treatment_file.year, + "person": in_charge.pk, + } + locas = list( + set([str(f.container.location.pk) + for f in treatment_file.associated_basket.items.all() + if f.container and f.container.location]) + ) + if len(locas) == 1: # one and only one location for all finds + dct["location"] = locas[0] + for k in dct: + wizards.TreatmentWizard.session_set_value( + request, 'basetreatment-treatment_creation', k, dct[k]) + return redirect(reverse( + 'treatment_creation', + kwargs={'step': 'basetreatment-treatment_creation'})) + + +def find_treatment_add(request, pk, current_right=None): + if not models.Find.objects.filter(pk=pk).count(): + raise Http404() + return treatment_add(request, str(pk)) + + +def findbasket_treatment_add(request, pk, current_right=None): + try: + basket = models.FindBasket.objects.get(pk=pk) + except models.FindBasket.DoesNotExist: + raise Http404() + return treatment_add( + request, ",".join([str(f.pk) for f in basket.items.all()])) + + +def container_treatment_add(request, pk, current_right=None): + try: + basket = models.FindBasket.objects.get(pk=pk) + except models.FindBasket.DoesNotExist: + raise Http404() + return treatment_add(request, + ",".join([str(f.pk) for f in basket.items.all()])) + + +def treatmentfile_treatment_add(request, pk, current_right=None): + try: + tf = models.TreatmentFile.objects.get(pk=pk) + except models.TreatmentFile.DoesNotExist: + raise Http404() + if not tf.associated_basket: + raise Http404() + basket = tf.associated_basket + return treatment_add( + request, ",".join([str(f.pk) for f in basket.items.all()]), + treatment_file=tf + ) + + +treatment_deletion_wizard = wizards.TreatmentDeletionWizard.as_view([ + ('selec-treatment_deletion', forms.TreatmentFormSelection), + ('final-treatment_deletion', forms.TreatmentDeletionForm)], label=_(u"Treatment deletion"), url_name='treatment_deletion',) treatment_administrativeact_search_wizard = \ - SearchWizard.as_view([ + wizards.SearchWizard.as_view([ ('selec-treatment_admacttreatment_search', - AdministrativeActTreatmentFormSelection)], + forms.AdministrativeActTreatmentFormSelection)], label=_(u"Treatment: search administrative act"), url_name='treatment_admacttreatment_search',) treatment_administrativeact_wizard = \ - TreatmentAdministrativeActWizard.as_view([ - ('selec-treatment_admacttreatment', TreatmentFormSelection), + wizards.TreatmentAdministrativeActWizard.as_view([ + ('selec-treatment_admacttreatment', forms.TreatmentFormSelection), ('administrativeact-treatment_admacttreatment', - AdministrativeActTreatmentForm), + forms.AdministrativeActTreatmentForm), ('final-treatment_admacttreatment', FinalForm)], label=_(u"Treatment: new administrative act"), url_name='treatment_admacttreatment',) treatment_administrativeact_modification_wizard = \ - TreatmentEditAdministrativeActWizard.as_view([ + wizards.TreatmentEditAdministrativeActWizard.as_view([ ('selec-treatment_admacttreatment_modification', - AdministrativeActTreatmentFormSelection), + forms.AdministrativeActTreatmentFormSelection), ('administrativeact-treatment_admacttreatment_modification', - AdministrativeActTreatmentModifForm), + forms.AdministrativeActTreatmentModifForm), ('final-treatment_admacttreatment_modification', FinalForm)], label=_(u"Treatment: administrative act modification"), url_name='treatment_admacttreatment_modification',) @@ -495,7 +640,7 @@ treatment_administrativeact_modification_wizard = \ treatment_admacttreatment_deletion_wizard = \ AdministrativeActDeletionWizard.as_view([ ('selec-treatment_admacttreatment_deletion', - AdministrativeActTreatmentFormSelection), + forms.AdministrativeActTreatmentFormSelection), ('final-treatment_admacttreatment_deletion', FinalAdministrativeActDeleteForm)], label=_(u"Treatment: administrative act deletion"), @@ -504,7 +649,7 @@ treatment_admacttreatment_deletion_wizard = \ def treatment_administrativeacttreatment_modify(request, pk): treatment_administrativeact_modification_wizard(request) - TreatmentEditAdministrativeActWizard.session_set_value( + wizards.TreatmentEditAdministrativeActWizard.session_set_value( request, 'selec-treatment_admacttreatment_modification', 'pk', pk, reset=True) @@ -517,69 +662,86 @@ def treatment_administrativeacttreatment_modify(request, pk): })) +def treatment_adminact_add(request, pk, current_right=None): + try: + models.Treatment.objects.get(pk=pk) + except models.Treatment.DoesNotExist: + raise Http404() + treatment_administrativeact_wizard(request) + + wizards.TreatmentAdministrativeActWizard.session_set_value( + request, 'selec-treatment_admacttreatment', 'pk', pk, reset=True) + return redirect(reverse( + 'treatment_admacttreatment', + kwargs={'step': 'administrativeact-treatment_admacttreatment'})) + + # treatment request -treatmentfile_search_wizard = TreatmentFileSearch.as_view([ - ('general-treatmentfile_search', TreatmentFileFormSelection)], +treatmentfile_search_wizard = wizards.TreatmentFileSearch.as_view([ + ('general-treatmentfile_search', forms.TreatmentFileFormSelection)], label=_(u"Treatment request search"), url_name='treatmentfile_search',) treatmentfile_wizard_steps = [ - ('treatmentfile-treatmentfile_creation', TreatmentFileForm), + ('treatmentfile-treatmentfile_creation', forms.TreatmentFileForm), ('final-treatmentfile_creation', FinalForm)] -treatmentfile_creation_wizard = TreatmentFileWizard.as_view( +treatmentfile_creation_wizard = wizards.TreatmentFileWizard.as_view( treatmentfile_wizard_steps, label=_(u"New treatment request"), url_name='treatmentfile_creation',) -treatmentfile_modification_wizard = TreatmentFileModificationWizard.as_view( - [('selec-treatmentfile_modification', TreatmentFileFormSelection), - ('treatmentfile-treatmentfile_modification', TreatmentFileModifyForm), - ('final-treatmentfile_modification', FinalForm)], - label=_(u"Treatment request modification"), - url_name='treatmentfile_modification', -) +treatmentfile_modification_wizard = \ + wizards.TreatmentFileModificationWizard.as_view( + [('selec-treatmentfile_modification', forms.TreatmentFileFormSelection), + ('treatmentfile-treatmentfile_modification', + forms.TreatmentFileModifyForm), + ('final-treatmentfile_modification', FinalForm)], + label=_(u"Treatment request modification"), + url_name='treatmentfile_modification', + ) def treatmentfile_modify(request, pk): treatmentfile_modification_wizard(request) - TreatmentFileModificationWizard.session_set_value( + wizards.TreatmentFileModificationWizard.session_set_value( request, 'selec-treatmentfile_modification', 'pk', pk, reset=True) return redirect(reverse( 'treatmentfile_modification', kwargs={'step': 'treatmentfile-treatmentfile_modification'})) -treatmentfile_deletion_wizard = TreatmentFileDeletionWizard.as_view([ - ('selec-treatmentfile_deletion', TreatmentFileFormSelection), - ('final-treatmentfile_deletion', TreatmentFileDeletionForm)], +treatmentfile_deletion_wizard = wizards.TreatmentFileDeletionWizard.as_view([ + ('selec-treatmentfile_deletion', forms.TreatmentFileFormSelection), + ('final-treatmentfile_deletion', forms.TreatmentFileDeletionForm)], label=_(u"Treatment request deletion"), url_name='treatmentfile_deletion',) treatmentfile_admacttreatmentfile_search_wizard = \ - SearchWizard.as_view([ + wizards.SearchWizard.as_view([ ('selec-treatmentfle_admacttreatmentfle_search', - AdministrativeActTreatmentFileFormSelection)], + forms.AdministrativeActTreatmentFileFormSelection)], label=_(u"Treatment request: search administrative act"), url_name='treatmentfle_admacttreatmentfle_search',) treatmentfile_admacttreatmentfile_wizard = \ - TreatmentFileAdministrativeActWizard.as_view([ - ('selec-treatmentfle_admacttreatmentfle', TreatmentFileFormSelection), + wizards.TreatmentFileAdministrativeActWizard.as_view([ + ('selec-treatmentfle_admacttreatmentfle', + forms.TreatmentFileFormSelection), ('admact-treatmentfle_admacttreatmentfle', - AdministrativeActTreatmentFileForm), + forms.AdministrativeActTreatmentFileForm), ('final-treatmentfle_admacttreatmentfle', FinalForm)], label=_(u"Treatment request: new administrative act"), url_name='treatmentfle_admacttreatmentfle',) treatmentfile_admacttreatmentfile_modification_wizard = \ - TreatmentFileEditAdministrativeActWizard.as_view([ + wizards.TreatmentFileEditAdministrativeActWizard.as_view([ ('selec-treatmentfle_admacttreatmentfle_modification', - AdministrativeActTreatmentFileFormSelection), + forms.AdministrativeActTreatmentFileFormSelection), ('admact-treatmentfle_admacttreatmentfle_modification', - AdministrativeActTreatmentFileModifForm), + forms.AdministrativeActTreatmentFileModifForm), ('final-treatmentfle_admacttreatmentfle_modification', FinalForm)], label=_(u"Treatment request: administrative act modification"), url_name='treatmentfle_admacttreatmentfle_modification',) @@ -587,7 +749,7 @@ treatmentfile_admacttreatmentfile_modification_wizard = \ treatmentfile_admacttreatmentfile_deletion_wizard = \ AdministrativeActDeletionWizard.as_view([ ('selec-treatmentfle_admacttreatmentfle_deletion', - AdministrativeActTreatmentFileFormSelection), + forms.AdministrativeActTreatmentFileFormSelection), ('final-treatmentfle_admacttreatmentfle_deletion', FinalAdministrativeActDeleteForm)], label=_(u"Treatment request: administrative act deletion"), @@ -596,7 +758,7 @@ treatmentfile_admacttreatmentfile_deletion_wizard = \ def treatmentfile_administrativeacttreatmentfile_modify(request, pk): treatmentfile_admacttreatmentfile_modification_wizard(request) - TreatmentFileEditAdministrativeActWizard.session_set_value( + wizards.TreatmentFileEditAdministrativeActWizard.session_set_value( request, 'selec-treatmentfle_admacttreatmentfle_modification', 'pk', pk, reset=True) @@ -609,24 +771,42 @@ def treatmentfile_administrativeacttreatmentfile_modify(request, pk): })) +def treatmentfile_adminact_add(request, pk, current_right=None): + try: + models.TreatmentFile.objects.get(pk=pk) + except models.TreatmentFile.DoesNotExist: + raise Http404() + treatmentfile_admacttreatmentfile_wizard(request) + + wizards.TreatmentFileAdministrativeActWizard.session_set_value( + request, 'selec-treatmentfle_admacttreatmentfle', 'pk', pk, reset=True) + return redirect(reverse( + 'treatmentfle_admacttreatmentfle', + kwargs={'step': 'admact-treatmentfle_admacttreatmentfle'})) + + def reset_wizards(request): for wizard_class, url_name in ( - (FindWizard, 'find_creation'), - (FindModificationWizard, 'find_modification'), - (FindDeletionWizard, 'find_deletion'), - (TreatmentWizard, 'treatement_creation'), - (TreatmentModificationWizard, 'treatment_modification'), - (TreatmentDeletionWizard, 'treatment_deletion'), - (TreatmentAdministrativeActWizard, 'treatment_admacttreatment'), - (TreatmentEditAdministrativeActWizard, + (wizards.FindWizard, 'find_creation'), + (wizards.FindModificationWizard, 'find_modification'), + (wizards.FindDeletionWizard, 'find_deletion'), + (wizards.TreatmentWizard, 'treatement_creation'), + (wizards.TreatmentModificationWizard, 'treatment_modification'), + (wizards.TreatmentDeletionWizard, 'treatment_deletion'), + (wizards.TreatmentAdministrativeActWizard, + 'treatment_admacttreatment'), + (wizards.TreatmentEditAdministrativeActWizard, 'treatment_admacttreatment_modification'), - (TreatmentDeletionWizard, 'treatment_admacttreatment_deletion'), - (TreatmentFileWizard, 'treatmentfile_creation'), - (TreatmentFileModificationWizard, 'treatmentfile_modification'), - (TreatmentFileDeletionWizard, 'treatmentfile_deletion'), - (TreatmentFileAdministrativeActWizard, + (wizards.TreatmentDeletionWizard, + 'treatment_admacttreatment_deletion'), + (wizards.TreatmentFileWizard, + 'treatmentfile_creation'), + (wizards.TreatmentFileModificationWizard, + 'treatmentfile_modification'), + (wizards.TreatmentFileDeletionWizard, 'treatmentfile_deletion'), + (wizards.TreatmentFileAdministrativeActWizard, 'treatmentfle_admacttreatmentfle'), - (TreatmentFileEditAdministrativeActWizard, + (wizards.TreatmentFileEditAdministrativeActWizard, 'treatmentfle_admacttreatmentfle_modification'), (AdministrativeActDeletionWizard, 'treatmentfle_admacttreatmentfle_deletion'), @@ -636,13 +816,13 @@ def reset_wizards(request): class QAFindForm(QAItemEditForm): model = models.Find - form_class = QAFindFormMulti + form_class = forms.QAFindFormMulti class QAFindBasketFormView(QAItemForm): template_name = 'ishtar/forms/qa_find_basket.html' model = models.Find - form_class = QAFindBasketForm + form_class = forms.QAFindBasketForm page_name = _(u"Basket") modal_size = "small" @@ -662,7 +842,7 @@ class QAFindBasketFormView(QAItemForm): class QAFindTreatmentFormView(QAItemForm): template_name = 'ishtar/forms/qa_find_treatment.html' model = models.Find - form_class = QAFindTreatmentForm + form_class = forms.QAFindTreatmentForm page_name = _(u"Packaging") def get_quick_action(self): @@ -677,3 +857,29 @@ class QAFindTreatmentFormView(QAItemForm): def form_valid(self, form): form.save(self.items, self.request.user) return HttpResponseRedirect(reverse("success")) + + +class QAFindbasketDuplicateFormView(QAItemForm): + template_name = 'ishtar/forms/qa_findbasket_duplicate.html' + model = models.FindBasket + page_name = _(u"Duplicate") + modal_size = "small" + form_class = forms.QAFindbasketDuplicateForm + + def get_quick_action(self): + return models.FindBasket.QUICK_ACTIONS[0] + + def get_form_kwargs(self): + kwargs = super(QAFindbasketDuplicateFormView, self).get_form_kwargs() + kwargs['user'] = self.request.user + return kwargs + + def form_valid(self, form): + form.save() + return HttpResponseRedirect(reverse("success")) + + def get_context_data(self, **kwargs): + data = super(QAFindbasketDuplicateFormView, self).get_context_data( + **kwargs) + data['action_name'] = _(u"Duplicate") + return data diff --git a/archaeological_finds/wizards.py b/archaeological_finds/wizards.py index 0e0fe80e1..7f4e1b498 100644 --- a/archaeological_finds/wizards.py +++ b/archaeological_finds/wizards.py @@ -17,8 +17,9 @@ # See the file COPYING for details. +from django.contrib import messages from django.core.exceptions import ObjectDoesNotExist, PermissionDenied -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext_lazy as _, pgettext from ishtar_common.forms import reverse_lazy from ishtar_common.wizards import Wizard, DeletionWizard, SearchWizard @@ -55,11 +56,21 @@ class FindWizard(Wizard): if base_finds: return base_finds[0].context_record + def get_current_basefinds(self): + find = self.get_current_object() + if not find: + return [] + return find.base_finds.all() + def get_form_kwargs(self, step=None): kwargs = super(FindWizard, self).get_form_kwargs(step) - if step not in ('find-find_creation', 'find-find_modification'): + if step not in ( + 'find-find_creation', 'find-find_modification', + 'simplefind-find_modification',): return kwargs kwargs['context_record'] = self.get_current_contextrecord() + if step == 'simplefind-find_modification': + kwargs['base_finds'] = self.get_current_basefinds() return kwargs def get_context_data(self, form, **kwargs): @@ -75,8 +86,8 @@ class FindWizard(Wizard): (_(u"Context record"), unicode(current_cr))) return context - def get_extra_model(self, dct, form_list): - dct = super(FindWizard, self).get_extra_model(dct, form_list) + def get_extra_model(self, dct, m2m, form_list): + dct = super(FindWizard, self).get_extra_model(dct, m2m, form_list) dct['order'] = 1 if 'pk' in dct and type(dct['pk']) == ContextRecord: dct['base_finds__context_record'] = dct.pop('pk') @@ -90,6 +101,10 @@ class FindModificationWizard(FindWizard): 'selec-find_modification': ['pk'], 'selecw-find_modification': ['pk'], } + wizard_templates = { + 'simplefind-find_modification': + 'ishtar/wizard/wizard_simplefind.html', + } class FindDeletionWizard(DeletionWizard): @@ -106,11 +121,59 @@ class TreatmentSearch(SearchWizard): model = models.Treatment -class TreatmentWizard(Wizard): +class TreatmentBase(Wizard): model = models.Treatment wizard_done_window = reverse_lazy('show-treatment') + base_url = "" + saved_args = {"treatment_type_list": []} + + def get_current_finds(self): + step = self.steps.current + if not step: + return + find_form_key = 'selecfind-' + self.base_url + find_ids = self.session_get_value(find_form_key, "resulting_pk") + try: + return [ + models.Find.objects.get(pk=int(find_id.strip())) + for find_id in find_ids.split(u',') + ] + except(TypeError, ValueError, AttributeError, ObjectDoesNotExist): + pass + + def get_form_initial(self, step, data=None): + initial = super(TreatmentBase, self).get_form_initial(step) + base_step = 'basetreatment-' + self.base_url + if step != base_step: + return initial + finds = self.get_current_finds() + if not finds: + return initial + locations = [find.container.location.pk for find in finds + if find.container] + # no location or multiple locations + if not locations or len(set(locations)) != 1: + return initial + if not initial: + initial = {} + initial['location'] = locations[0] + return initial + + def get_extra_model(self, dct, m2m, form_list): + dct = super(TreatmentBase, self).get_extra_model(dct, m2m, form_list) + dct['treatment_type_list'] = [] + for k, v in m2m: + if k == 'treatment_type': + if type(v) not in (list, tuple): + v = [v] + dct['treatment_type_list'] += v + return dct + + +class TreatmentWizard(TreatmentBase): basket_step = 'basetreatment-treatment_creation' - saved_args = {"items": []} + saved_args = {"items": [], "treatment_type_list": []} + base_url = 'treatment_creation' def get_form_kwargs(self, step, **kwargs): kwargs = super(TreatmentWizard, self).get_form_kwargs(step, **kwargs) @@ -119,25 +182,31 @@ class TreatmentWizard(Wizard): kwargs['user'] = self.request.user return kwargs - def get_extra_model(self, dct, form_list): + def get_extra_model(self, dct, m2m, form_list): """ Get items concerned by the treatment """ - dct = super(TreatmentWizard, self).get_extra_model(dct, form_list) + dct = super(TreatmentWizard, self).get_extra_model(dct, m2m, form_list) if 'resulting_pk' in dct: - try: - find = models.Find.objects.get(pk=dct.pop('resulting_pk')) - if 'own' in self.current_right \ - and not find.is_own(dct['history_modifier']): + dct['items'] = [] + pks = dct.pop('resulting_pk').split(u',') + for pk in pks: + try: + find = models.Find.objects.get(pk=pk) + dct['items'].append(find) + except models.Find.DoesNotExist: raise PermissionDenied - dct['items'] = [find] - except models.Find.DoesNotExist: - raise PermissionDenied if 'basket' in dct: basket = dct.pop('basket') if basket.user.pk != dct['history_modifier'].pk: raise PermissionDenied dct['items'] = list(basket.items.all()) + + if 'items' in dct: + for find in dct['items']: + if 'own' in self.current_right \ + and not find.is_own(dct['history_modifier']): + raise PermissionDenied return dct @@ -145,7 +214,196 @@ class TreatmentModificationWizard(TreatmentWizard): modification = True +class TreatmentN1Wizard(TreatmentBase): + saved_args = {"upstream_items": [], "resulting_find": None, + "treatment_type_list": []} + base_url = 'treatment_creation_n1' + + def _update_simple_initial_from_finds(self, initial, find, k): + r_k = "resulting_" + k + if getattr(find, k) and r_k in initial: + # pop k when value is inconsistent between finds + if initial[r_k] and initial[r_k] != getattr(find, k).pk: + initial.pop(r_k) + else: + initial[r_k] = getattr(find, k).pk + return initial + + def _update_multi_initial_from_finds(self, initial, find, k): + r_k = "resulting_" + k + for value in getattr(find, k + 's').all(): + if value.pk not in initial[r_k]: + initial[r_k].append(value.pk) + return initial + + def _update_num_initial_from_finds(self, initial, find, k): + r_k = "resulting_" + k + if not getattr(find, k): + return initial + if initial[r_k] is None: + initial[r_k] = 0 + initial[r_k] += getattr(find, k) + return initial + + def _update_char_initial_from_finds(self, initial, find, k, sep=' ; '): + r_k = "resulting_" + k + value = getattr(find, k) + if not value: + return initial + value = value.strip() + if not initial[r_k]: + initial[r_k] = value + else: + # new value is entirely inside the current value + if value == initial[r_k] or (value + sep) in initial[r_k] or \ + (sep + value) in initial[r_k]: + return initial + initial[r_k] += sep + value + return initial + + def get_form_initial(self, step, data=None): + initial = super(TreatmentN1Wizard, self).get_form_initial(step) + if step != 'resultingfind-treatment_creation_n1': + return initial + finds = self.get_current_finds() + if not finds: + return initial + simple_key = ['material_type_quality'] + multi_key = ['material_type', 'object_type', 'communicabilitie'] + numeric_key = ['find_number', 'min_number_of_individuals'] + desc_key = ['decoration', 'inscription', 'comment', 'dating_comment'] + char_key = ['manufacturing_place'] + + for k in simple_key + numeric_key + desc_key + char_key: + initial["resulting_" + k] = None + for k in multi_key: + initial["resulting_" + k] = [] + + for find in finds: + for k in simple_key: + initial = self._update_simple_initial_from_finds( + initial, find, k) + for k in multi_key: + initial = self._update_multi_initial_from_finds( + initial, find, k) + for k in numeric_key: + initial = self._update_num_initial_from_finds( + initial, find, k) + for k in char_key: + initial = self._update_char_initial_from_finds( + initial, find, k, sep=' ; ') + for k in desc_key: + initial = self._update_char_initial_from_finds( + initial, find, k, sep='\n') + + for k in initial.keys(): + if initial[k] is None: + initial.pop(k) + return initial + + def get_extra_model(self, dct, m2m, form_list): + """ + Get items concerned by the treatment + """ + dct = super(TreatmentN1Wizard, self).get_extra_model( + dct, m2m, form_list) + if 'resulting_pk' not in dct: + return dct + + dct['upstream_items'] = [] + # manage upstream items + pks = dct.pop('resulting_pk') + if hasattr(pks, 'split'): + pks = pks.split(u',') # unicode or string + for pk in pks: + try: + find = models.Find.objects.get(pk=pk) + dct['upstream_items'].append(find) + except models.Find.DoesNotExist: + raise PermissionDenied + + for find in dct['upstream_items']: + if 'own' in self.current_right \ + and not find.is_own(dct['history_modifier']): + raise PermissionDenied + + # extract data of the new find + dct['resulting_find'] = {} + for k in dct.keys(): + if k.startswith('resulting_') and k != "resulting_find": + dct['resulting_find'][ + k[len('resulting_'):] + ] = dct.pop(k) + return dct + + +class Treatment1NWizard(TreatmentBase): + saved_args = {"upstream_item": None, "resulting_finds": None, + "treatment_type_list": []} + base_url = 'treatment_creation_1n' + + def get_form_kwargs(self, step, **kwargs): + kwargs = super(Treatment1NWizard, self).get_form_kwargs(step, **kwargs) + if step != 'resultingfind-treatment_creation_1n': + return kwargs + kwargs['user'] = self.request.user + return kwargs + + def get_form_initial(self, step, data=None): + initial = super(Treatment1NWizard, self).get_form_initial(step) + if step != 'resultingfinds-treatment_creation_1n': + return initial + finds = self.get_current_finds() + if not finds: + return initial + lbl = finds[0].label + initial['resultings_basket_name'] = unicode(_(u"Basket")) + u" - " + lbl + initial['resultings_label'] = lbl + u"-" + return initial + + def get_extra_model(self, dct, m2m, form_list): + """ + Get items concerned by the treatment + """ + dct = super(Treatment1NWizard, self).get_extra_model( + dct, m2m, form_list) + if 'resulting_pk' not in dct: + return dct + + # manage upstream item + pk = dct.pop('resulting_pk') + try: + find = models.Find.objects.get(pk=pk) + dct['upstream_item'] = find + except models.Find.DoesNotExist: + raise PermissionDenied + + if 'own' in self.current_right \ + and not find.is_own(dct['history_modifier']): + raise PermissionDenied + + # extract attributes to generate the new find + dct['resulting_finds'] = {} + for k in dct.keys(): + if k.startswith('resultings_'): + dct['resulting_finds'][ + k[len('resultings_'):] + ] = dct.pop(k) + messages.add_message( + self.request, messages.INFO, + unicode(_(u"The new basket: \"{}\" have been created with the " + u"resulting items. This search have been pinned.") + ).format(dct["resulting_finds"]["basket_name"]) + ) + self.request.session["pin-search-find"] = u'{}="{}"'.format( + unicode(pgettext("key for text search", u"basket")), + dct["resulting_finds"]["basket_name"]) + self.request.session['find'] = '' + return dct + + class TreatmentDeletionWizard(DeletionWizard): + wizard_confirm = 'ishtar/wizard/wizard_treatement_deletion.html' model = models.Treatment fields = ['label', 'other_reference', 'year', 'index', 'treatment_types', 'location', 'person', 'organization', @@ -243,3 +501,9 @@ class FindBasketWizard(Wizard): class FindBasketEditWizard(FindBasketWizard): edit = True + alt_is_own_method = 'get_write_query_owns' + + +class FindBasketDeletionWizard(DeletionWizard): + wizard_confirm = 'ishtar/wizard/wizard_findbasket_deletion.html' + model = models.FindBasket diff --git a/archaeological_operations/forms.py b/archaeological_operations/forms.py index 4942d9f05..3103990c9 100644 --- a/archaeological_operations/forms.py +++ b/archaeological_operations/forms.py @@ -479,11 +479,12 @@ class OperationSelect(TableSelect): 'archaeological-operations', 'operation')) year = forms.IntegerField(label=_("Year")) operation_code = forms.IntegerField(label=_(u"Numeric reference")) - if settings.COUNTRY == 'fr': - code_patriarche = forms.CharField( + code_patriarche = forms.CharField( max_length=500, widget=OAWidget, label="Code PATRIARCHE") + drassm_code = forms.CharField( + label=_(u"DRASSM code"), required=False, max_length=100) towns = get_town_field() parcel = forms.CharField(label=_(u"Parcel")) if settings.ISHTAR_DPTS: @@ -577,13 +578,16 @@ class OperationSelect(TableSelect): def __init__(self, *args, **kwargs): super(OperationSelect, self).__init__(*args, **kwargs) - if not get_current_profile().warehouse: + profile = get_current_profile() + if not profile.warehouse: self.fields.pop('documentation_deadline_before') self.fields.pop('documentation_deadline_after') self.fields.pop('documentation_received') self.fields.pop('finds_deadline_before') self.fields.pop('finds_deadline_after') self.fields.pop('finds_received') + if not profile.underwater: + self.fields.pop('drassm_code') if settings.ISHTAR_DPTS: k = 'towns__numero_insee__startswith' self.fields[k].choices = [ @@ -749,11 +753,12 @@ class OperationFormGeneral(CustomForm, ManageOldType): 'report_processing': models.ReportState } pk = forms.IntegerField(required=False, widget=forms.HiddenInput) - if settings.COUNTRY == 'fr': - code_patriarche = forms.CharField(label=u"Code PATRIARCHE", - max_length=500, - widget=OAWidget, - required=False) + code_patriarche = forms.CharField(label=u"Code PATRIARCHE", + max_length=500, + widget=OAWidget, + required=False) + drassm_code = forms.CharField( + label=_(u"DRASSM code"), required=False, max_length=100) operation_type = forms.ChoiceField(label=_(u"Operation type"), choices=[]) common_name = forms.CharField(label=_(u"Generic name"), required=False, @@ -873,9 +878,11 @@ class OperationFormGeneral(CustomForm, ManageOldType): if not profile.files: for key in self.FILE_FIELDS: self.remove_field(key) - if not profile.warehouse: - for key in self.WAREHOUSE_FIELDS: - self.remove_field(key) + if not profile.warehouse: + for key in self.WAREHOUSE_FIELDS: + self.remove_field(key) + if not profile.underwater: + self.fields.pop('drassm_code') def clean(self): cleaned_data = self.cleaned_data @@ -1262,6 +1269,11 @@ class SiteSelect(TableSelect): locality_cadastral = forms.CharField( label=_(u"Cadastral locality"), max_length=200, required=False) + + affmar_number = forms.CharField( + label=_(u"AffMar number"), required=False, max_length=100) + drassm_number = forms.CharField( + label=_(u"DRASSM number"), required=False, max_length=100) shipwreck_name = forms.CharField( label=_(u"Shipwreck name"), max_length=200, required=False) @@ -1288,6 +1300,8 @@ class SiteSelect(TableSelect): self.fields.pop('shipwreck_code') self.fields.pop('sinking_date') self.fields.pop('discovery_area') + self.fields.pop('affmar_number') + self.fields.pop('drassm_number') class SiteFormSelection(IshtarForm): @@ -1378,6 +1392,10 @@ class SiteUnderwaterForm(CustomForm, ManageOldType): form_admin_name = _(u"Archaeological site - 030 - Underwater") form_slug = u"archaeological_site-030-underwater" + affmar_number = forms.CharField( + label=_(u"AffMar number"), required=False, max_length=100) + drassm_number = forms.CharField( + label=_(u"DRASSM number"), required=False, max_length=100) shipwreck_name = forms.CharField( label=_(u"Shipwreck name"), required=False) shipwreck_code = forms.CharField( diff --git a/archaeological_operations/ishtar_menu.py b/archaeological_operations/ishtar_menu.py index 4baf14295..bfc027573 100644 --- a/archaeological_operations/ishtar_menu.py +++ b/archaeological_operations/ishtar_menu.py @@ -82,11 +82,6 @@ MENU_SECTIONS = [ _(u"Deletion"), model=models.AdministrativeAct, access_controls=['change_administrativeact']), - MenuItem( - 'operation_administrativeact_document', - _(u"Documents"), - model=models.AdministrativeAct, - access_controls=['change_administrativeact']), ],), ]), ), diff --git a/archaeological_operations/locale/django.pot b/archaeological_operations/locale/django.pot index 83373847b..2c2124db3 100644 --- a/archaeological_operations/locale/django.pot +++ b/archaeological_operations/locale/django.pot @@ -9,21 +9,21 @@ msgid "" msgstr "" -#: admin.py:91 models.py:244 models.py:836 +#: admin.py:91 models.py:263 models.py:880 msgid "Point" msgstr "" -#: admin.py:93 models.py:245 models.py:837 +#: admin.py:93 models.py:264 models.py:881 msgid "Multi polygon" msgstr "" -#: forms.py:64 forms.py:1061 forms.py:1077 forms.py:1083 models.py:1931 +#: forms.py:64 forms.py:1068 forms.py:1084 forms.py:1090 models.py:2014 #: templates/ishtar/blocks/window_tables/parcels.html:9 -#: templates/ishtar/sheet_operation.html:250 +#: templates/ishtar/sheet_operation.html:257 msgid "Parcels" msgstr "" -#: forms.py:67 forms.py:200 forms.py:1036 models.py:1915 +#: forms.py:67 forms.py:200 forms.py:1043 models.py:1998 #: templates/ishtar/blocks/window_tables/parcels.html:6 #: templates/ishtar/dashboards/dashboard_operation.html:432 #: templates/ishtar/dashboards/dashboard_operation.html:446 @@ -32,22 +32,22 @@ msgstr "" msgid "Town" msgstr "" -#: forms.py:69 forms.py:480 forms.py:763 forms.py:1400 models.py:734 -#: models.py:1489 models.py:1696 models.py:1913 +#: forms.py:69 forms.py:480 forms.py:768 forms.py:1426 models.py:774 +#: models.py:1562 models.py:1769 models.py:1996 #: templates/ishtar/blocks/window_tables/parcels.html:7 msgid "Year" msgstr "" -#: forms.py:72 models.py:1916 +#: forms.py:72 models.py:1999 #: templates/ishtar/blocks/window_tables/parcels.html:8 msgid "Section" msgstr "" -#: forms.py:75 models.py:1918 +#: forms.py:75 models.py:2001 msgid "Parcel number" msgstr "" -#: forms.py:77 models.py:1920 models.py:1939 models.py:2000 +#: forms.py:77 models.py:2003 models.py:2022 models.py:2083 msgid "Public domain" msgstr "" @@ -83,8 +83,8 @@ msgstr "" msgid "Relation type" msgstr "" -#: forms.py:373 forms.py:1254 ishtar_menu.py:32 models.py:842 models.py:1394 -#: models.py:1405 models.py:1491 models.py:1678 models.py:1912 +#: forms.py:373 forms.py:1261 ishtar_menu.py:32 models.py:886 models.py:1466 +#: models.py:1477 models.py:1564 models.py:1751 models.py:1995 #: templates/ishtar/sheet_operation.html:4 wizards.py:320 wizards.py:331 msgid "Operation" msgstr "" @@ -93,7 +93,7 @@ msgstr "" msgid ":" msgstr "" -#: forms.py:404 forms.py:608 +#: forms.py:404 forms.py:612 msgid "You should select an operation." msgstr "" @@ -113,7 +113,7 @@ msgstr "" msgid "Deleted relations" msgstr "" -#: forms.py:469 templates/ishtar/sheet_operation.html:169 +#: forms.py:469 templates/ishtar/sheet_operation.html:170 msgid "Relations" msgstr "" @@ -121,19 +121,23 @@ msgstr "" msgid "Operation - 080 - Relations" msgstr "" -#: forms.py:478 forms.py:1237 forms.py:1396 +#: forms.py:478 forms.py:1244 forms.py:1422 msgid "Full text search" msgstr "" -#: forms.py:481 models.py:735 +#: forms.py:481 models.py:775 msgid "Numeric reference" msgstr "" -#: forms.py:488 forms.py:1064 forms.py:1412 models.py:1930 models.py:2142 +#: forms.py:487 forms.py:761 models.py:870 +msgid "DRASSM code" +msgstr "" + +#: forms.py:489 forms.py:1071 forms.py:1438 models.py:2013 models.py:2225 msgid "Parcel" msgstr "" -#: forms.py:491 forms.py:1415 models.py:1395 +#: forms.py:492 forms.py:1441 models.py:1467 #: templates/ishtar/dashboards/dashboard_operation.html:390 #: templates/ishtar/dashboards/dashboard_operation.html:411 #: templates/ishtar/dashboards/dashboard_operation.html:643 @@ -142,558 +146,566 @@ msgstr "" msgid "Department" msgstr "" -#: forms.py:492 forms.py:1148 forms.py:1241 forms.py:1325 models.py:213 +#: forms.py:493 forms.py:1155 forms.py:1248 forms.py:1340 models.py:224 #: templates/ishtar/blocks/window_tables/archaeologicalsites.html:7 #: templates/ishtar/sheet_operation.html:29 msgid "Name" msgstr "" -#: forms.py:493 forms.py:761 models.py:797 +#: forms.py:494 forms.py:766 models.py:838 msgid "Address / Locality" msgstr "" -#: forms.py:494 forms.py:678 forms.py:757 models.py:742 +#: forms.py:495 forms.py:682 forms.py:762 models.py:782 msgid "Operation type" msgstr "" -#: forms.py:495 +#: forms.py:496 msgid "Is open?" msgstr "" -#: forms.py:503 forms.py:793 models.py:727 +#: forms.py:504 forms.py:798 models.py:767 msgid "In charge" msgstr "" -#: forms.py:510 models.py:1672 +#: forms.py:511 models.py:1745 msgid "Scientist in charge" msgstr "" -#: forms.py:512 forms.py:680 forms.py:783 models.py:725 +#: forms.py:513 forms.py:684 forms.py:788 models.py:765 msgid "Operator" msgstr "" -#: forms.py:521 forms.py:1153 forms.py:1243 forms.py:1330 models.py:217 -#: models.py:744 +#: forms.py:522 forms.py:1160 forms.py:1250 forms.py:1345 models.py:228 +#: models.py:784 #: templates/ishtar/blocks/window_tables/archaeologicalsites.html:9 msgid "Remains" msgstr "" -#: forms.py:522 forms.py:1131 forms.py:1150 forms.py:1242 forms.py:1327 -#: models.py:215 models.py:750 +#: forms.py:523 forms.py:1138 forms.py:1157 forms.py:1249 forms.py:1342 +#: models.py:226 models.py:790 #: templates/ishtar/blocks/window_tables/archaeologicalsites.html:8 msgid "Periods" msgstr "" -#: forms.py:523 +#: forms.py:524 msgid "Started before" msgstr "" -#: forms.py:524 +#: forms.py:525 msgid "Started after" msgstr "" -#: forms.py:525 +#: forms.py:526 msgid "Ended before" msgstr "" -#: forms.py:526 +#: forms.py:527 msgid "Ended after" msgstr "" -#: forms.py:528 +#: forms.py:529 msgid "Search within relations" msgstr "" -#: forms.py:529 forms.py:841 forms.py:1245 forms.py:1340 models.py:221 -#: models.py:798 +#: forms.py:530 forms.py:846 forms.py:1252 forms.py:1357 models.py:232 +#: models.py:839 msgid "Comment" msgstr "" -#: forms.py:530 +#: forms.py:531 msgid "Abstract (full text search)" msgstr "" -#: forms.py:532 forms.py:844 models.py:800 +#: forms.py:533 forms.py:849 models.py:841 msgid "Comment about scientific documentation" msgstr "" -#: forms.py:533 forms.py:846 models.py:815 +#: forms.py:534 forms.py:851 models.py:856 msgid "Record quality" msgstr "" -#: forms.py:534 forms.py:812 models.py:762 +#: forms.py:535 forms.py:817 models.py:802 msgid "Report processing" msgstr "" -#: forms.py:536 forms.py:849 models.py:810 +#: forms.py:537 forms.py:854 models.py:851 msgid "Virtual operation" msgstr "" -#: forms.py:538 forms.py:1188 forms.py:1192 models.py:257 +#: forms.py:539 forms.py:1195 forms.py:1199 models.py:276 msgid "Archaeological site" msgstr "" -#: forms.py:544 forms.py:1419 +#: forms.py:545 forms.py:1445 msgid "Created by" msgstr "" -#: forms.py:550 forms.py:1425 +#: forms.py:551 forms.py:1451 msgid "Modified by" msgstr "" -#: forms.py:557 forms.py:834 models.py:822 +#: forms.py:558 forms.py:839 models.py:863 msgid "Documentation received" msgstr "" -#: forms.py:559 +#: forms.py:560 msgid "Documentation deadline before" msgstr "" -#: forms.py:561 +#: forms.py:562 msgid "Documentation deadline after" msgstr "" -#: forms.py:563 forms.py:839 models.py:826 +#: forms.py:564 forms.py:844 models.py:867 msgid "Finds received" msgstr "" -#: forms.py:565 +#: forms.py:566 msgid "Finds deadline before" msgstr "" -#: forms.py:567 +#: forms.py:568 msgid "Finds deadline after" msgstr "" -#: forms.py:595 views.py:182 +#: forms.py:599 views.py:183 msgid "Operation search" msgstr "" -#: forms.py:639 +#: forms.py:643 msgid "Associated file" msgstr "" -#: forms.py:643 forms.py:937 models.py:1023 models.py:1404 models.py:1490 -#: models.py:1683 wizards.py:83 +#: forms.py:647 forms.py:944 models.py:1083 models.py:1476 models.py:1563 +#: models.py:1756 wizards.py:83 msgid "Archaeological file" msgstr "" -#: forms.py:650 forms.py:654 models.py:817 +#: forms.py:654 forms.py:658 models.py:858 msgid "Abstract" msgstr "" -#: forms.py:651 +#: forms.py:655 msgid "Operation - 090 - Abstract" msgstr "" -#: forms.py:658 +#: forms.py:662 msgid "months" msgstr "" -#: forms.py:658 +#: forms.py:662 msgid "years" msgstr "" -#: forms.py:660 models.py:711 +#: forms.py:664 models.py:751 msgid "Creation date" msgstr "" -#: forms.py:661 +#: forms.py:665 msgid "Start of field work" msgstr "" -#: forms.py:663 +#: forms.py:667 msgid "All" msgstr "" -#: forms.py:664 +#: forms.py:668 msgid "Preventive" msgstr "" -#: forms.py:665 +#: forms.py:669 msgid "Research" msgstr "" -#: forms.py:669 +#: forms.py:673 msgid "Slicing" msgstr "" -#: forms.py:672 +#: forms.py:676 msgid "Department detail" msgstr "" -#: forms.py:674 +#: forms.py:678 msgid "Date get from" msgstr "" -#: forms.py:676 +#: forms.py:680 msgid "Preventive/Research" msgstr "" -#: forms.py:682 +#: forms.py:686 msgid "Date after" msgstr "" -#: forms.py:683 +#: forms.py:687 msgid "Date before" msgstr "" -#: forms.py:684 +#: forms.py:688 msgid "With reports" msgstr "" -#: forms.py:685 +#: forms.py:689 msgid "With finds" msgstr "" -#: forms.py:737 forms.py:1317 forms.py:1466 +#: forms.py:741 forms.py:1331 forms.py:1492 #: templates/ishtar/sheet_administrativeact.html:23 #: templates/ishtar/sheet_operation.html:12 templates/ishtar/sheet_site.html:33 msgid "General" msgstr "" -#: forms.py:738 +#: forms.py:742 msgid "Operation - 010 - General" msgstr "" -#: forms.py:759 models.py:796 +#: forms.py:764 models.py:837 msgid "Generic name" msgstr "" -#: forms.py:768 models.py:764 +#: forms.py:773 models.py:804 msgid "Old code" msgstr "" -#: forms.py:771 +#: forms.py:776 msgid "Head scientist" msgstr "" -#: forms.py:790 models.py:795 +#: forms.py:795 models.py:836 msgid "Operator reference" msgstr "" -#: forms.py:804 +#: forms.py:809 msgid "Total surface (m2)" msgstr "" -#: forms.py:807 models.py:57 models.py:714 models.py:2144 +#: forms.py:812 models.py:57 models.py:754 models.py:2227 msgid "Start date" msgstr "" -#: forms.py:808 models.py:716 +#: forms.py:813 models.py:756 msgid "Excavation end date" msgstr "" -#: forms.py:810 models.py:717 +#: forms.py:815 models.py:757 msgid "Report delivery date" msgstr "" -#: forms.py:831 models.py:819 +#: forms.py:836 models.py:860 msgid "Deadline for submission of the documentation" msgstr "" -#: forms.py:836 models.py:824 +#: forms.py:841 models.py:865 msgid "Deadline for submission of the finds" msgstr "" -#: forms.py:888 +#: forms.py:895 msgid "" "If you want to set an excavation end date you have to provide a start date." msgstr "" -#: forms.py:893 +#: forms.py:900 msgid "The excavation end date cannot be before the start date." msgstr "" -#: forms.py:923 +#: forms.py:930 #, python-format msgid "" "Operation code already exists for year: %(year)d - use a value bigger than " "%(last_val)d" msgstr "" -#: forms.py:927 +#: forms.py:934 msgid "Bad operation code" msgstr "" -#: forms.py:933 models.py:1038 +#: forms.py:940 models.py:1098 msgid "Operation code" msgstr "" -#: forms.py:968 templates/ishtar/sheet_operation.html:149 +#: forms.py:975 templates/ishtar/sheet_operation.html:150 msgid "Court-ordered seizure" msgstr "" -#: forms.py:969 +#: forms.py:976 msgid "Operation - 015 - Court-ordered seizure" msgstr "" -#: forms.py:973 models.py:829 +#: forms.py:980 models.py:873 msgid "Seizure name" msgstr "" -#: forms.py:976 models.py:830 +#: forms.py:983 models.py:874 msgid "Official report number" msgstr "" -#: forms.py:979 models.py:832 +#: forms.py:986 models.py:876 msgid "Name of the protagonist" msgstr "" -#: forms.py:984 forms.py:991 models.py:731 +#: forms.py:991 forms.py:998 forms.py:1356 models.py:243 models.py:771 msgid "Collaborators" msgstr "" -#: forms.py:985 +#: forms.py:992 msgid "Operation - 020 - Collaborators" msgstr "" -#: forms.py:1000 +#: forms.py:1007 msgid "Preventive informations - excavation" msgstr "" -#: forms.py:1001 +#: forms.py:1008 msgid "Operation - 033 - Preventive - Excavation" msgstr "" -#: forms.py:1004 models.py:748 +#: forms.py:1011 models.py:788 #: templates/ishtar/dashboards/dashboard_operation.html:701 msgid "Cost (euros)" msgstr "" -#: forms.py:1005 models.py:753 +#: forms.py:1012 models.py:793 msgid "Scheduled man-days" msgstr "" -#: forms.py:1007 models.py:756 +#: forms.py:1014 models.py:796 msgid "Optional man-days" msgstr "" -#: forms.py:1009 models.py:759 +#: forms.py:1016 models.py:799 msgid "Effective man-days" msgstr "" -#: forms.py:1019 +#: forms.py:1026 msgid "Preventive informations - diagnostic" msgstr "" -#: forms.py:1020 +#: forms.py:1027 msgid "Operation - 037 - Preventive - Diagnostic" msgstr "" -#: forms.py:1025 models.py:779 +#: forms.py:1032 models.py:819 msgid "Prescription on zoning" msgstr "" -#: forms.py:1027 models.py:782 +#: forms.py:1034 models.py:822 msgid "Prescription on large area" msgstr "" -#: forms.py:1030 models.py:784 +#: forms.py:1037 models.py:824 msgid "Prescription on geoarchaeological context" msgstr "" -#: forms.py:1034 forms.py:1050 forms.py:1055 forms.py:1359 models.py:128 -#: models.py:219 models.py:506 models.py:746 models.py:1706 +#: forms.py:1041 forms.py:1057 forms.py:1062 forms.py:1381 models.py:131 +#: models.py:230 models.py:541 models.py:786 models.py:1779 msgid "Towns" msgstr "" -#: forms.py:1051 +#: forms.py:1058 msgid "Operation - 040 - Towns" msgstr "" -#: forms.py:1056 +#: forms.py:1063 msgid "Operation - 040 - Towns (2)" msgstr "" -#: forms.py:1078 +#: forms.py:1085 msgid "Operation - 050 - Parcels" msgstr "" -#: forms.py:1085 +#: forms.py:1092 msgid "Operation - 050 - Parcels (2)" msgstr "" -#: forms.py:1115 models.py:47 +#: forms.py:1122 models.py:47 msgid "Remain types" msgstr "" -#: forms.py:1116 +#: forms.py:1123 msgid "Operation - 060 - Remains" msgstr "" -#: forms.py:1122 models.py:46 +#: forms.py:1129 models.py:46 msgid "Remain type" msgstr "" -#: forms.py:1132 +#: forms.py:1139 msgid "Operation - 070 - Periods" msgstr "" -#: forms.py:1138 templates/ishtar/sheet_operation.html:273 -#: templates/ishtar/sheet_operation.html:310 +#: forms.py:1145 templates/ishtar/sheet_operation.html:280 +#: templates/ishtar/sheet_operation.html:317 msgid "Period" msgstr "" -#: forms.py:1147 forms.py:1239 forms.py:1324 models.py:212 +#: forms.py:1154 forms.py:1246 forms.py:1339 models.py:223 msgid "Reference" msgstr "" -#: forms.py:1171 forms.py:1353 +#: forms.py:1178 forms.py:1375 msgid "This reference already exists." msgstr "" -#: forms.py:1203 models.py:258 models.py:807 -#: templates/ishtar/sheet_operation.html:194 +#: forms.py:1210 models.py:277 models.py:848 +#: templates/ishtar/sheet_operation.html:195 msgid "Archaeological sites" msgstr "" -#: forms.py:1205 +#: forms.py:1212 msgid "Operation - 030 - Archaeological sites" msgstr "" -#: forms.py:1210 +#: forms.py:1217 msgid "Associated archaeological sites" msgstr "" -#: forms.py:1216 ishtar_menu.py:36 ishtar_menu.py:66 ishtar_menu.py:113 +#: forms.py:1223 ishtar_menu.py:36 ishtar_menu.py:66 ishtar_menu.py:108 msgid "Search" msgstr "" -#: forms.py:1221 +#: forms.py:1228 msgid "Would you like to close this operation?" msgstr "" -#: forms.py:1226 +#: forms.py:1233 msgid "Would you like to delete this operation?" msgstr "" -#: forms.py:1248 models.py:223 +#: forms.py:1255 models.py:234 msgid "Top operation" msgstr "" -#: forms.py:1260 forms.py:1333 models.py:226 +#: forms.py:1267 forms.py:1348 models.py:237 msgid "National Geographic Institute locality" msgstr "" -#: forms.py:1263 forms.py:1337 models.py:229 +#: forms.py:1270 forms.py:1352 models.py:240 msgid "Cadastral locality" msgstr "" -#: forms.py:1266 forms.py:1374 models.py:233 +#: forms.py:1274 forms.py:1396 models.py:257 +msgid "AffMar number" +msgstr "" + +#: forms.py:1276 forms.py:1398 models.py:259 +msgid "DRASSM number" +msgstr "" + +#: forms.py:1278 forms.py:1400 models.py:248 msgid "Shipwreck name" msgstr "" -#: forms.py:1269 forms.py:1382 models.py:235 +#: forms.py:1281 forms.py:1408 models.py:250 msgid "Oceanographic service localisation" msgstr "" -#: forms.py:1272 forms.py:1376 models.py:237 +#: forms.py:1284 forms.py:1402 models.py:252 msgid "Shipwreck code" msgstr "" -#: forms.py:1274 forms.py:1378 models.py:239 +#: forms.py:1286 forms.py:1404 models.py:254 msgid "Sinking date" msgstr "" -#: forms.py:1276 forms.py:1380 models.py:241 +#: forms.py:1288 forms.py:1406 models.py:256 msgid "Discovery area" msgstr "" -#: forms.py:1312 +#: forms.py:1326 msgid "You should select an item." msgstr "" -#: forms.py:1318 +#: forms.py:1332 msgid "Archaeological site - 010 - General" msgstr "" -#: forms.py:1360 +#: forms.py:1382 msgid "Archaeological site - 020 - Towns" msgstr "" -#: forms.py:1369 templates/ishtar/sheet_site.html:52 +#: forms.py:1391 templates/ishtar/sheet_site.html:53 msgid "Underwater" msgstr "" -#: forms.py:1370 +#: forms.py:1392 msgid "Archaeological site - 030 - Underwater" msgstr "" -#: forms.py:1401 forms.py:1535 models.py:1663 +#: forms.py:1427 forms.py:1561 models.py:1736 msgid "Index" msgstr "" -#: forms.py:1409 forms.py:1469 models.py:1418 models.py:1657 +#: forms.py:1435 forms.py:1495 models.py:1490 models.py:1730 msgid "Act type" msgstr "" -#: forms.py:1410 forms.py:1605 +#: forms.py:1436 forms.py:1631 msgid "Indexed?" msgstr "" -#: forms.py:1416 forms.py:1474 models.py:1697 +#: forms.py:1442 forms.py:1500 models.py:1770 #: templates/ishtar/blocks/window_tables/administrativacts.html:9 msgid "Object" msgstr "" -#: forms.py:1446 views.py:412 +#: forms.py:1472 views.py:413 msgid "Administrative act search" msgstr "" -#: forms.py:1461 forms.py:1563 forms.py:1630 +#: forms.py:1487 forms.py:1589 forms.py:1656 msgid "You should select an administrative act." msgstr "" -#: forms.py:1477 models.py:1694 +#: forms.py:1503 models.py:1767 msgid "Signature date" msgstr "" -#: forms.py:1489 +#: forms.py:1515 msgid "Operation - Administrative act - General" msgstr "" -#: forms.py:1523 +#: forms.py:1549 #, python-format msgid "" "This index already exists for year: %(year)d - use a value bigger than " "%(last_val)d" msgstr "" -#: forms.py:1527 +#: forms.py:1553 msgid "Bad index" msgstr "" -#: forms.py:1540 +#: forms.py:1566 msgid "Would you like to delete this administrative act?" msgstr "" -#: forms.py:1545 +#: forms.py:1571 msgid "Template" msgstr "" -#: forms.py:1569 forms.py:1573 +#: forms.py:1595 forms.py:1599 msgid "This document is not intended for this type of act." msgstr "" -#: forms.py:1591 +#: forms.py:1617 msgid "Doc generation" msgstr "" -#: forms.py:1593 +#: forms.py:1619 msgid "Generate the associated doc?" msgstr "" -#: forms.py:1614 ishtar_menu.py:101 views.py:465 +#: forms.py:1640 ishtar_menu.py:96 views.py:466 msgctxt "admin act register" msgid "Register" msgstr "" -#: ishtar_menu.py:41 ishtar_menu.py:72 ishtar_menu.py:118 +#: ishtar_menu.py:41 ishtar_menu.py:72 ishtar_menu.py:113 msgid "Creation" msgstr "" -#: ishtar_menu.py:46 ishtar_menu.py:77 ishtar_menu.py:123 +#: ishtar_menu.py:46 ishtar_menu.py:77 ishtar_menu.py:118 msgid "Modification" msgstr "" @@ -701,42 +713,38 @@ msgstr "" msgid "Closing" msgstr "" -#: ishtar_menu.py:55 ishtar_menu.py:82 ishtar_menu.py:128 +#: ishtar_menu.py:55 ishtar_menu.py:82 ishtar_menu.py:123 msgid "Deletion" msgstr "" -#: ishtar_menu.py:61 models.py:1713 +#: ishtar_menu.py:61 models.py:1786 #: templates/ishtar/sheet_administrativeact.html:4 msgid "Administrative act" msgstr "" -#: ishtar_menu.py:87 models.py:249 models.py:802 -msgid "Documents" -msgstr "" - -#: ishtar_menu.py:95 +#: ishtar_menu.py:90 msgid "Administrative Act" msgstr "" -#: ishtar_menu.py:135 +#: ishtar_menu.py:130 msgid "Dashboard" msgstr "" -#: ishtar_menu.py:139 +#: ishtar_menu.py:134 msgid "General informations" msgstr "" -#: ishtar_menu.py:143 models.py:843 +#: ishtar_menu.py:138 models.py:887 #: templates/ishtar/dashboards/dashboard_operation.html:8 -#: templates/ishtar/sheet_site.html:65 +#: templates/ishtar/sheet_site.html:68 msgid "Operations" msgstr "" -#: models.py:56 models.py:76 models.py:94 models.py:2622 +#: models.py:56 models.py:76 models.py:94 models.py:2705 msgid "Order" msgstr "" -#: models.py:58 models.py:2145 +#: models.py:58 models.py:2228 msgid "End date" msgstr "" @@ -768,665 +776,692 @@ msgstr "" msgid "Types of record quality" msgstr "" -#: models.py:135 +#: models.py:138 msgctxt "key for text search" msgid "reference" msgstr "" -#: models.py:139 models.py:569 +#: models.py:142 models.py:605 msgctxt "key for text search" msgid "name" msgstr "" -#: models.py:143 models.py:601 tests.py:1625 +#: models.py:146 models.py:637 tests.py:1625 msgctxt "key for text search" msgid "period" msgstr "" -#: models.py:147 models.py:597 tests.py:1656 +#: models.py:150 models.py:633 tests.py:1656 msgctxt "key for text search" msgid "remain" msgstr "" -#: models.py:151 models.py:557 tests.py:1633 +#: models.py:154 models.py:593 tests.py:1633 msgctxt "key for text search" msgid "town" msgstr "" -#: models.py:155 models.py:625 +#: models.py:158 models.py:661 msgctxt "key for text search" msgid "comment" msgstr "" -#: models.py:159 +#: models.py:162 msgctxt "key for text search" msgid "locality-ngi" msgstr "" -#: models.py:163 +#: models.py:166 msgctxt "key for text search" msgid "locality-cadastral" msgstr "" -#: models.py:167 +#: models.py:170 msgctxt "key for text search" msgid "shipwreck-name" msgstr "" -#: models.py:172 +#: models.py:175 msgctxt "key for text search" msgid "oceanographic-service-localisation" msgstr "" -#: models.py:176 +#: models.py:179 msgctxt "key for text search" msgid "shipwreck-code" msgstr "" -#: models.py:180 +#: models.py:183 msgctxt "key for text search" msgid "sinking-date" msgstr "" -#: models.py:184 +#: models.py:187 msgctxt "key for text search" msgid "discovery-area" msgstr "" -#: models.py:188 models.py:203 +#: models.py:191 models.py:214 msgctxt "key for text search" msgid "operation" msgstr "" -#: models.py:192 +#: models.py:195 msgctxt "key for text search" msgid "top-operation" msgstr "" -#: models.py:251 models.py:804 models.py:1926 +#: models.py:199 +msgctxt "key for text search" +msgid "numero-drassm" +msgstr "" + +#: models.py:203 +msgctxt "key for text search" +msgid "numero-affmar" +msgstr "" + +#: models.py:268 models.py:843 +msgid "Documents" +msgstr "" + +#: models.py:270 models.py:845 models.py:2009 msgid "Cached name" msgstr "" -#: models.py:280 +#: models.py:299 msgid "SITE" msgstr "" -#: models.py:345 +#: models.py:380 msgid "Unknown" msgstr "" -#: models.py:348 +#: models.py:383 msgid "Virtual operation of site: {}" msgstr "" -#: models.py:488 +#: models.py:523 msgid "Associated file (label)" msgstr "" -#: models.py:489 +#: models.py:524 msgid "Operator name" msgstr "" -#: models.py:490 +#: models.py:525 msgid "Scientist (full name)" msgstr "" -#: models.py:491 +#: models.py:526 msgid "Associated file (external ID)" msgstr "" -#: models.py:492 +#: models.py:527 msgid "Scientist (title)" msgstr "" -#: models.py:493 +#: models.py:528 msgid "Scientist (surname)" msgstr "" -#: models.py:494 +#: models.py:529 msgid "Scientist (name)" msgstr "" -#: models.py:495 +#: models.py:530 msgid "Scientist - Organization (name)" msgstr "" -#: models.py:496 +#: models.py:531 msgid "In charge (title)" msgstr "" -#: models.py:497 +#: models.py:532 msgid "In charge (surname)" msgstr "" -#: models.py:498 +#: models.py:533 msgid "In charge (name)" msgstr "" -#: models.py:499 +#: models.py:534 msgid "In charge - Organization (name)" msgstr "" -#: models.py:504 +#: models.py:539 msgid "Archaeological sites (reference)" msgstr "" -#: models.py:545 models.py:1502 tests.py:1628 tests.py:1673 +#: models.py:581 models.py:1575 tests.py:1628 tests.py:1673 msgctxt "key for text search" msgid "year" msgstr "" -#: models.py:549 +#: models.py:585 msgctxt "key for text search" msgid "operation-code" msgstr "" -#: models.py:553 models.py:1514 +#: models.py:589 models.py:1587 msgctxt "key for text search" msgid "patriarche" msgstr "" -#: models.py:561 models.py:1534 +#: models.py:597 models.py:1607 msgctxt "key for text search" msgid "parcel" msgstr "" -#: models.py:565 +#: models.py:601 msgctxt "key for text search" msgid "department" msgstr "" -#: models.py:573 +#: models.py:609 msgctxt "key for text search" msgid "address" msgstr "" -#: models.py:577 models.py:1518 +#: models.py:613 models.py:1591 msgctxt "key for text search" msgid "type" msgstr "" -#: models.py:581 tests.py:1661 +#: models.py:617 tests.py:1661 msgctxt "key for text search" msgid "is-open" msgstr "" -#: models.py:585 +#: models.py:621 msgctxt "key for text search" msgid "in-charge" msgstr "" -#: models.py:589 +#: models.py:625 msgctxt "key for text search" msgid "scientist" msgstr "" -#: models.py:593 +#: models.py:629 msgctxt "key for text search" msgid "operator" msgstr "" -#: models.py:605 +#: models.py:641 msgctxt "key for text search" msgid "start-before" msgstr "" -#: models.py:609 +#: models.py:645 msgctxt "key for text search" msgid "start-after" msgstr "" -#: models.py:613 +#: models.py:649 msgctxt "key for text search" msgid "end-before" msgstr "" -#: models.py:617 +#: models.py:653 msgctxt "key for text search" msgid "end-after" msgstr "" -#: models.py:621 +#: models.py:657 msgctxt "key for text search" msgid "relation-types" msgstr "" -#: models.py:629 +#: models.py:665 msgctxt "key for text search" msgid "abstract" msgstr "" -#: models.py:634 +#: models.py:670 msgctxt "key for text search" msgid "scientific-documentation-comment" msgstr "" -#: models.py:638 +#: models.py:674 msgctxt "key for text search" msgid "record-quality" msgstr "" -#: models.py:643 +#: models.py:679 msgctxt "key for text search" msgid "report-processing" msgstr "" -#: models.py:648 +#: models.py:684 msgctxt "key for text search" msgid "virtual-operation" msgstr "" -#: models.py:653 models.py:696 +#: models.py:689 models.py:736 msgctxt "key for text search" msgid "site" msgstr "" -#: models.py:657 models.py:1552 +#: models.py:693 models.py:1625 msgctxt "key for text search" msgid "created-by" msgstr "" -#: models.py:661 models.py:1556 +#: models.py:697 models.py:1629 msgctxt "key for text search" msgid "modified-by" msgstr "" -#: models.py:665 +#: models.py:701 msgctxt "key for text search" msgid "documentation-received" msgstr "" -#: models.py:669 +#: models.py:705 msgctxt "key for text search" msgid "documentation-deadline-before" msgstr "" -#: models.py:673 +#: models.py:709 msgctxt "key for text search" msgid "documentation-deadline-after" msgstr "" -#: models.py:677 +#: models.py:713 msgctxt "key for text search" msgid "finds-received" msgstr "" -#: models.py:681 +#: models.py:717 msgctxt "key for text search" msgid "finds-deadline-before" msgstr "" -#: models.py:685 +#: models.py:721 msgctxt "key for text search" msgid "finds-deadline-after" msgstr "" -#: models.py:698 +#: models.py:725 +msgctxt "key for text search" +msgid "code-drassm" +msgstr "" + +#: models.py:738 msgctxt "key for text search" msgid "file" msgstr "" -#: models.py:713 templates/ishtar/sheet_operation.html:60 +#: models.py:753 templates/ishtar/sheet_operation.html:61 msgid "Closing date" msgstr "" -#: models.py:720 +#: models.py:760 msgid "In charge scientist" msgstr "" -#: models.py:739 models.py:1908 +#: models.py:779 models.py:1991 msgid "File" msgstr "" -#: models.py:743 +#: models.py:783 msgid "Surface (m2)" msgstr "" -#: models.py:812 +#: models.py:853 msgid "" "If checked, it means that this operation have not been officialy registered." msgstr "" -#: models.py:891 +#: models.py:935 msgid "OPE" msgstr "" -#: models.py:988 +#: models.py:1032 msgid "Intercommunal" msgstr "" -#: models.py:1024 +#: models.py:1078 +msgid "Add context record" +msgstr "" + +#: models.py:1079 +msgid "context record" +msgstr "" + +#: models.py:1084 msgid "Code patriarche" msgstr "" -#: models.py:1066 +#: models.py:1126 msgid "This operation code already exists for this year" msgstr "" -#: models.py:1111 +#: models.py:1183 msgid "Number of parcels" msgstr "" -#: models.py:1121 +#: models.py:1193 msgid "Number of administrative acts" msgstr "" -#: models.py:1129 +#: models.py:1201 msgid "Number of indexed administrative acts" msgstr "" -#: models.py:1137 +#: models.py:1209 msgid "Number of context records" msgstr "" -#: models.py:1173 +#: models.py:1245 msgid "Number of finds" msgstr "" -#: models.py:1218 +#: models.py:1290 msgid "No type" msgstr "" -#: models.py:1249 +#: models.py:1321 msgid "Number of sources" msgstr "" -#: models.py:1287 templates/ishtar/dashboards/dashboard_operation.html:309 +#: models.py:1359 templates/ishtar/dashboards/dashboard_operation.html:309 #: templates/ishtar/dashboards/dashboard_operation.html:575 #: templates/ishtar/dashboards/dashboard_operation.html:611 msgid "Mean" msgstr "" -#: models.py:1349 +#: models.py:1421 msgid "Operation relation type" msgstr "" -#: models.py:1350 +#: models.py:1422 msgid "Operation relation types" msgstr "" -#: models.py:1363 +#: models.py:1435 msgid "Operation record relation" msgstr "" -#: models.py:1364 +#: models.py:1436 msgid "Operation record relations" msgstr "" -#: models.py:1406 models.py:1688 +#: models.py:1478 models.py:1761 msgid "Treatment request" msgstr "" -#: models.py:1407 models.py:1693 +#: models.py:1479 models.py:1766 msgid "Treatment" msgstr "" -#: models.py:1409 +#: models.py:1481 msgid "Intended to" msgstr "" -#: models.py:1411 +#: models.py:1483 msgid "Code" msgstr "" -#: models.py:1414 +#: models.py:1486 msgid "Associated template" msgstr "" -#: models.py:1415 +#: models.py:1487 msgid "Indexed" msgstr "" -#: models.py:1419 +#: models.py:1491 msgid "Act types" msgstr "" -#: models.py:1489 models.py:1734 +#: models.py:1562 models.py:1807 #: templates/ishtar/blocks/window_tables/administrativacts.html:6 #: templates/ishtar/blocks/window_tables/archaeologicalsites.html:6 msgid "Ref." msgstr "" -#: models.py:1506 +#: models.py:1579 msgctxt "key for text search" msgid "index" msgstr "" -#: models.py:1510 +#: models.py:1583 msgctxt "key for text search" msgid "other-ref" msgstr "" -#: models.py:1522 +#: models.py:1595 msgctxt "key for text search" msgid "indexed" msgstr "" -#: models.py:1526 +#: models.py:1599 msgctxt "key for text search" msgid "operation-town" msgstr "" -#: models.py:1530 +#: models.py:1603 msgctxt "key for text search" msgid "file-town" msgstr "" -#: models.py:1540 +#: models.py:1613 msgctxt "key for text search" msgid "operation-department" msgstr "" -#: models.py:1544 +#: models.py:1617 msgctxt "key for text search" msgid "file-department" msgstr "" -#: models.py:1548 +#: models.py:1621 msgctxt "key for text search" msgid "object" msgstr "" -#: models.py:1560 +#: models.py:1633 msgctxt "key for text search" msgid "signature-before" msgstr "" -#: models.py:1564 +#: models.py:1637 msgctxt "key for text search" msgid "signature-after" msgstr "" -#: models.py:1568 +#: models.py:1641 msgctxt "key for text search" msgid "file-name" msgstr "" -#: models.py:1572 +#: models.py:1645 msgctxt "key for text search" msgid "general-contractor" msgstr "" -#: models.py:1577 +#: models.py:1650 msgctxt "key for text search" msgid "general-contractor-organization" msgstr "" -#: models.py:1582 +#: models.py:1655 msgctxt "key for text search" msgid "file-reference" msgstr "" -#: models.py:1586 +#: models.py:1659 msgctxt "key for text search" msgid "file-year" msgstr "" -#: models.py:1590 +#: models.py:1663 msgctxt "key for text search" msgid "file-other-reference" msgstr "" -#: models.py:1594 +#: models.py:1667 msgctxt "key for text search" msgid "file-in-charge" msgstr "" -#: models.py:1598 +#: models.py:1671 msgctxt "key for text search" msgid "file-permit-reference" msgstr "" -#: models.py:1602 +#: models.py:1675 msgctxt "key for text search" msgid "treatment-name" msgstr "" -#: models.py:1606 +#: models.py:1679 msgctxt "key for text search" msgid "treatment-reference" msgstr "" -#: models.py:1610 +#: models.py:1683 msgctxt "key for text search" msgid "treatment-year" msgstr "" -#: models.py:1614 +#: models.py:1687 msgctxt "key for text search" msgid "treatment-index" msgstr "" -#: models.py:1618 +#: models.py:1691 msgctxt "key for text search" msgid "treatment-type" msgstr "" -#: models.py:1622 +#: models.py:1695 msgctxt "key for text search" msgid "treatment-file-name" msgstr "" -#: models.py:1626 +#: models.py:1699 msgctxt "key for text search" msgid "treatment-file-reference" msgstr "" -#: models.py:1630 +#: models.py:1703 msgctxt "key for text search" msgid "treatment-file-year" msgstr "" -#: models.py:1634 +#: models.py:1707 msgctxt "key for text search" msgid "treatment-file-index" msgstr "" -#: models.py:1638 +#: models.py:1711 msgctxt "key for text search" msgid "treatment-file-type" msgstr "" -#: models.py:1661 +#: models.py:1734 msgid "Person in charge of the operation" msgstr "" -#: models.py:1667 +#: models.py:1740 msgid "Archaeological preventive operator" msgstr "" -#: models.py:1675 +#: models.py:1748 msgid "Signatory" msgstr "" -#: models.py:1703 +#: models.py:1776 msgid "Departments" msgstr "" -#: models.py:1704 +#: models.py:1777 msgid "Cached values get from associated departments" msgstr "" -#: models.py:1707 +#: models.py:1780 msgid "Cached values get from associated towns" msgstr "" -#: models.py:1714 templates/ishtar/sheet_operation.html:202 -#: templates/ishtar/sheet_operation.html:244 +#: models.py:1787 templates/ishtar/sheet_operation.html:205 +#: templates/ishtar/sheet_operation.html:251 msgid "Administrative acts" msgstr "" -#: models.py:1837 +#: models.py:1920 msgid "This index already exists for this year" msgstr "" -#: models.py:1921 +#: models.py:2004 msgid "External ID" msgstr "" -#: models.py:1924 +#: models.py:2007 msgid "External ID is set automatically" msgstr "" -#: models.py:1925 +#: models.py:2008 msgid "Address - Locality" msgstr "" -#: models.py:2140 +#: models.py:2223 msgid "Owner" msgstr "" -#: models.py:2148 +#: models.py:2231 msgid "Parcel owner" msgstr "" -#: models.py:2149 +#: models.py:2232 msgid "Parcel owners" msgstr "" -#: models.py:2183 +#: models.py:2266 msgid "Recorded" msgstr "" -#: models.py:2184 +#: models.py:2267 msgid "Effective" msgstr "" -#: models.py:2185 +#: models.py:2268 msgid "Active" msgstr "" -#: models.py:2186 +#: models.py:2269 msgid "Field completed" msgstr "" -#: models.py:2187 +#: models.py:2270 msgid "Associated report" msgstr "" -#: models.py:2188 +#: models.py:2271 msgid "Closed" msgstr "" -#: models.py:2189 +#: models.py:2272 msgid "Documented and closed" msgstr "" -#: models.py:2623 +#: models.py:2706 msgid "Is preventive" msgstr "" -#: models.py:2626 +#: models.py:2709 msgid "Operation type old" msgstr "" -#: models.py:2627 +#: models.py:2710 msgid "Operation types old" msgstr "" #: templates/ishtar/blocks/window_tables/administrativacts.html:7 -#: templates/ishtar/sheet_operation.html:263 -#: templates/ishtar/sheet_operation.html:327 +#: templates/ishtar/sheet_operation.html:270 +#: templates/ishtar/sheet_operation.html:334 msgid "Type" msgstr "" @@ -1470,12 +1505,12 @@ msgstr "" #: templates/ishtar/dashboards/dashboard_operation.html:432 #: templates/ishtar/dashboards/dashboard_operation.html:463 #: templates/ishtar/dashboards/dashboard_operation.html:687 -#: templates/ishtar/sheet_operation.html:263 -#: templates/ishtar/sheet_operation.html:273 -#: templates/ishtar/sheet_operation.html:290 -#: templates/ishtar/sheet_operation.html:300 -#: templates/ishtar/sheet_operation.html:310 -#: templates/ishtar/sheet_operation.html:327 +#: templates/ishtar/sheet_operation.html:270 +#: templates/ishtar/sheet_operation.html:280 +#: templates/ishtar/sheet_operation.html:297 +#: templates/ishtar/sheet_operation.html:307 +#: templates/ishtar/sheet_operation.html:317 +#: templates/ishtar/sheet_operation.html:334 msgid "Number" msgstr "" @@ -1501,7 +1536,7 @@ msgstr "" #: templates/ishtar/dashboards/dashboard_operation.html:479 #: templates/ishtar/dashboards/dashboard_operation.html:499 #: templates/ishtar/dashboards/dashboard_operation.html:623 -#: templates/ishtar/sheet_operation.html:52 +#: templates/ishtar/sheet_operation.html:53 msgid "State" msgstr "" @@ -1664,7 +1699,7 @@ msgid "area by organization by realisation year" msgstr "" #: templates/ishtar/dashboards/dashboard_operation.html:670 -#: templates/ishtar/sheet_operation.html:77 +#: templates/ishtar/sheet_operation.html:78 msgid "Cost" msgstr "" @@ -1677,7 +1712,7 @@ msgid "main towns by cost" msgstr "" #: templates/ishtar/sheet_administrativeact.html:40 -#: templates/ishtar/sheet_operation.html:69 +#: templates/ishtar/sheet_operation.html:70 msgid "Surface" msgstr "" @@ -1685,103 +1720,103 @@ msgstr "" msgid "Address" msgstr "" -#: templates/ishtar/sheet_operation.html:37 +#: templates/ishtar/sheet_operation.html:38 msgid "Begining date" msgstr "" -#: templates/ishtar/sheet_operation.html:54 +#: templates/ishtar/sheet_operation.html:55 msgid "Active file" msgstr "" -#: templates/ishtar/sheet_operation.html:55 +#: templates/ishtar/sheet_operation.html:56 msgid "Closed operation" msgstr "" -#: templates/ishtar/sheet_operation.html:62 +#: templates/ishtar/sheet_operation.html:63 msgid "by" msgstr "" -#: templates/ishtar/sheet_operation.html:85 +#: templates/ishtar/sheet_operation.html:86 msgid "Duration" msgstr "" -#: templates/ishtar/sheet_operation.html:87 +#: templates/ishtar/sheet_operation.html:88 msgid "days" msgstr "" -#: templates/ishtar/sheet_operation.html:129 +#: templates/ishtar/sheet_operation.html:130 msgid "Sheet" msgstr "" -#: templates/ishtar/sheet_operation.html:138 +#: templates/ishtar/sheet_operation.html:139 msgid "This operation is virtual." msgstr "" -#: templates/ishtar/sheet_operation.html:144 +#: templates/ishtar/sheet_operation.html:145 msgid "Patriarche OA code not yet recorded!" msgstr "" -#: templates/ishtar/sheet_operation.html:159 -#: templates/ishtar/sheet_site.html:43 +#: templates/ishtar/sheet_operation.html:160 +#: templates/ishtar/sheet_site.html:44 msgid "Localisation" msgstr "" -#: templates/ishtar/sheet_operation.html:198 +#: templates/ishtar/sheet_operation.html:200 msgid "Associated parcels" msgstr "" -#: templates/ishtar/sheet_operation.html:206 +#: templates/ishtar/sheet_operation.html:209 msgid "Document from this operation" msgstr "" -#: templates/ishtar/sheet_operation.html:212 -#: templates/ishtar/sheet_operation.html:255 +#: templates/ishtar/sheet_operation.html:216 +#: templates/ishtar/sheet_operation.html:262 msgid "Context records" msgstr "" -#: templates/ishtar/sheet_operation.html:217 +#: templates/ishtar/sheet_operation.html:221 msgid "Context record relations" msgstr "" -#: templates/ishtar/sheet_operation.html:222 +#: templates/ishtar/sheet_operation.html:226 msgid "Documents from associated context records" msgstr "" -#: templates/ishtar/sheet_operation.html:227 -#: templates/ishtar/sheet_operation.html:282 -#: templates/ishtar/sheet_site.html:70 +#: templates/ishtar/sheet_operation.html:232 +#: templates/ishtar/sheet_operation.html:289 +#: templates/ishtar/sheet_site.html:73 msgid "Finds" msgstr "" -#: templates/ishtar/sheet_operation.html:232 +#: templates/ishtar/sheet_operation.html:237 msgid "Documents from associated finds" msgstr "" -#: templates/ishtar/sheet_operation.html:237 +#: templates/ishtar/sheet_operation.html:243 msgid "Associated containers" msgstr "" -#: templates/ishtar/sheet_operation.html:241 +#: templates/ishtar/sheet_operation.html:248 msgid "Statistics" msgstr "" -#: templates/ishtar/sheet_operation.html:242 +#: templates/ishtar/sheet_operation.html:249 msgid "These numbers are updated hourly" msgstr "" -#: templates/ishtar/sheet_operation.html:290 +#: templates/ishtar/sheet_operation.html:297 msgid "Material type" msgstr "" -#: templates/ishtar/sheet_operation.html:300 +#: templates/ishtar/sheet_operation.html:307 msgid "Object type" msgstr "" -#: templates/ishtar/sheet_operation.html:319 +#: templates/ishtar/sheet_operation.html:326 msgid "Sources" msgstr "" -#: templates/ishtar/sheet_operation.html:337 +#: templates/ishtar/sheet_operation.html:344 msgid "Finds by context records" msgstr "" @@ -1802,43 +1837,43 @@ msgid "" "The following error(s) has been encountered while parsing the source file:" msgstr "" -#: views.py:244 +#: views.py:245 msgid "New operation" msgstr "" -#: views.py:293 +#: views.py:294 msgid "Operation modification" msgstr "" -#: views.py:304 +#: views.py:305 msgid "You don't have sufficient permissions to do this action." msgstr "" -#: views.py:329 +#: views.py:330 msgid "Operation closing" msgstr "" -#: views.py:340 +#: views.py:341 msgid "Operation deletion" msgstr "" -#: views.py:406 +#: views.py:407 msgid "Site deletion" msgstr "" -#: views.py:425 +#: views.py:426 msgid "Operation: new administrative act" msgstr "" -#: views.py:435 +#: views.py:436 msgid "Operation: administrative act modification" msgstr "" -#: views.py:459 +#: views.py:460 msgid "Operation: administrative act deletion" msgstr "" -#: views.py:552 +#: views.py:530 msgid "" "Syntax error on the source template \"{}\" - contact your administrator and " "ask him to check the syntax of this document." diff --git a/archaeological_operations/migrations/0041_auto_20181203_1442.py b/archaeological_operations/migrations/0041_auto_20181203_1442.py new file mode 100644 index 000000000..5b6b9f7db --- /dev/null +++ b/archaeological_operations/migrations/0041_auto_20181203_1442.py @@ -0,0 +1,1117 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-12-03 14:42 +from __future__ import unicode_literals + +import datetime +from django.conf import settings +import django.contrib.gis.db.models.fields +import django.contrib.postgres.search +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import ishtar_common.models +import re + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_operations', '0040_archaeologicalsite_collaborators'), + ] + + operations = [ + migrations.AlterModelOptions( + name='acttype', + options={'ordering': ('label',), 'verbose_name': "Type d'acte", 'verbose_name_plural': "Types d'acte"}, + ), + migrations.AlterModelOptions( + name='administrativeact', + options={'ordering': ('year', 'signature_date', 'index', 'act_type'), 'permissions': (('view_administrativeact', 'Can view all Administrative acts'), ('view_own_administrativeact', 'Can view own Administrative act'), ('add_own_administrativeact', 'Can add own Administrative act'), ('change_own_administrativeact', 'Can change own Administrative act'), ('delete_own_administrativeact', 'Can delete own Administrative act')), 'verbose_name': 'Acte administratif', 'verbose_name_plural': 'Actes administratifs'}, + ), + migrations.AlterModelOptions( + name='archaeologicalsite', + options={'permissions': (('view_archaeologicalsite', 'Can view all Archaeological sites'), ('view_own_archaeologicalsite', 'Can view own Archaeological site'), ('add_own_archaeologicalsite', 'Can add own Archaeological site'), ('change_own_archaeologicalsite', 'Can change own Archaeological site'), ('delete_own_archaeologicalsite', 'Can delete own Archaeological site')), 'verbose_name': 'Entit\xe9 (EA)', 'verbose_name_plural': 'Entit\xe9s arch\xe9ologiques'}, + ), + migrations.AlterModelOptions( + name='historicaladministrativeact', + options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical Acte administratif'}, + ), + migrations.AlterModelOptions( + name='historicalarchaeologicalsite', + options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical Entit\xe9 (EA)'}, + ), + migrations.AlterModelOptions( + name='historicaloperation', + options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical Op\xe9ration'}, + ), + migrations.AlterModelOptions( + name='operation', + options={'ordering': ('cached_label',), 'permissions': (('view_operation', 'Can view all Operations'), ('view_own_operation', 'Can view own Operation'), ('add_own_operation', 'Can add own Operation'), ('change_own_operation', 'Can change own Operation'), ('delete_own_operation', 'Can delete own Operation'), ('close_operation', 'Can close Operation')), 'verbose_name': 'Op\xe9ration', 'verbose_name_plural': 'Op\xe9rations'}, + ), + migrations.AlterModelOptions( + name='operationtypeold', + options={'ordering': ['-preventive', 'order', 'label'], 'verbose_name': "Type d'op\xe9ration - ancien", 'verbose_name_plural': "Types d'op\xe9ration - ancien"}, + ), + migrations.AlterModelOptions( + name='parcel', + options={'ordering': ('year', 'section', 'parcel_number'), 'verbose_name': 'Parcelle', 'verbose_name_plural': 'Parcelles'}, + ), + migrations.AlterModelOptions( + name='parcelowner', + options={'verbose_name': 'Propri\xe9taire de parcelle', 'verbose_name_plural': 'Propri\xe9taires de parcelle'}, + ), + migrations.AlterModelOptions( + name='period', + options={'ordering': ('order',), 'verbose_name': 'Type de p\xe9riode', 'verbose_name_plural': 'Types de p\xe9riode'}, + ), + migrations.AlterModelOptions( + name='recordqualitytype', + options={'ordering': ('order',), 'verbose_name': "Type de qualit\xe9 d'enregistrement", 'verbose_name_plural': "Types de qualit\xe9 d'enregistrement"}, + ), + migrations.AlterModelOptions( + name='recordrelations', + options={'ordering': ('left_record', 'relation_type'), 'permissions': [('view_operationrelation', 'Can view all Operation relations')], 'verbose_name': 'Relation entre op\xe9rations', 'verbose_name_plural': 'Relations entre op\xe9rations'}, + ), + migrations.AlterModelOptions( + name='relationtype', + options={'ordering': ('order', 'label'), 'verbose_name': 'Type de relation entre op\xe9rations', 'verbose_name_plural': 'Types de relation entre op\xe9rations'}, + ), + migrations.AlterModelOptions( + name='remaintype', + options={'ordering': ('label',), 'verbose_name': 'Type de vestige', 'verbose_name_plural': 'Types de vestige'}, + ), + migrations.AlterModelOptions( + name='reportstate', + options={'ordering': ('order',), 'verbose_name': "Type d'\xe9tat de rapport", 'verbose_name_plural': "Types d'\xe9tat de rapport"}, + ), + migrations.AddField( + model_name='archaeologicalsite', + name='affmar_number', + field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Num\xe9ro AffMar'), + ), + migrations.AddField( + model_name='archaeologicalsite', + name='drassm_number', + field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Num\xe9ro DRASSM'), + ), + migrations.AddField( + model_name='historicalarchaeologicalsite', + name='affmar_number', + field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Num\xe9ro AffMar'), + ), + migrations.AddField( + model_name='historicalarchaeologicalsite', + name='drassm_number', + field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Num\xe9ro DRASSM'), + ), + migrations.AddField( + model_name='historicaloperation', + name='drassm_code', + field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Code DRASSM'), + ), + migrations.AddField( + model_name='operation', + name='drassm_code', + field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Code DRASSM'), + ), + migrations.AlterField( + model_name='acttype', + name='associated_template', + field=models.ManyToManyField(blank=True, related_name='acttypes', to='ishtar_common.DocumentTemplate', verbose_name='Patron associ\xe9'), + ), + migrations.AlterField( + model_name='acttype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='acttype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='acttype', + name='indexed', + field=models.BooleanField(default=False, verbose_name='Index\xe9'), + ), + migrations.AlterField( + model_name='acttype', + name='intented_to', + field=models.CharField(choices=[(b'F', 'Dossier'), (b'O', 'Op\xe9ration'), (b'TF', 'Demande de traitement'), (b'T', 'Traitement')], max_length=2, verbose_name='Destin\xe9 \xe0'), + ), + migrations.AlterField( + model_name='acttype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='acttype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='administrativeact', + name='act_object', + field=models.TextField(blank=True, max_length=300, null=True, verbose_name='Objet'), + ), + migrations.AlterField( + model_name='administrativeact', + name='act_type', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_operations.ActType', verbose_name="Type d'acte"), + ), + migrations.AlterField( + model_name='administrativeact', + name='associated_file', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='administrative_act', to='archaeological_files.File', verbose_name='Dossier'), + ), + migrations.AlterField( + model_name='administrativeact', + name='departments_label', + field=models.TextField(blank=True, help_text='Valeur en cache des d\xe9partements associ\xe9s', null=True, verbose_name='D\xe9partements'), + ), + migrations.AlterField( + model_name='administrativeact', + name='history_creator', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Cr\xe9ateur'), + ), + migrations.AlterField( + model_name='administrativeact', + name='history_modifier', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Dernier \xe9diteur'), + ), + migrations.AlterField( + model_name='administrativeact', + name='in_charge', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='adminact_operation_in_charge', to='ishtar_common.Person', verbose_name="Responsable d'op\xe9ration"), + ), + migrations.AlterField( + model_name='administrativeact', + name='operation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='administrative_act', to='archaeological_operations.Operation', verbose_name='Op\xe9ration'), + ), + migrations.AlterField( + model_name='administrativeact', + name='operator', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='adminact_operator', to='ishtar_common.Organization', verbose_name="Op\xe9rateur d'arch\xe9ologie pr\xe9ventive"), + ), + migrations.AlterField( + model_name='administrativeact', + name='scientist', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='adminact_scientist', to='ishtar_common.Person', verbose_name='Responsable scientifique'), + ), + migrations.AlterField( + model_name='administrativeact', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='administrativeact', + name='signatory', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='signatory', to='ishtar_common.Person', verbose_name='Signataire'), + ), + migrations.AlterField( + model_name='administrativeact', + name='signature_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de signature'), + ), + migrations.AlterField( + model_name='administrativeact', + name='towns_label', + field=models.TextField(blank=True, help_text='Valeur en cache des communes associ\xe9es', null=True, verbose_name='Communes'), + ), + migrations.AlterField( + model_name='administrativeact', + name='treatment', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='administrative_act', to='archaeological_finds.Treatment', verbose_name='Traitement'), + ), + migrations.AlterField( + model_name='administrativeact', + name='treatment_file', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='administrative_act', to='archaeological_finds.TreatmentFile', verbose_name='Demande de traitement'), + ), + migrations.AlterField( + model_name='administrativeact', + name='year', + field=models.IntegerField(blank=True, null=True, verbose_name='Ann\xe9e'), + ), + migrations.AlterField( + model_name='archaeologicalsite', + name='cached_label', + field=models.TextField(blank=True, db_index=True, null=True, verbose_name='Nom en cache'), + ), + migrations.AlterField( + model_name='archaeologicalsite', + name='collaborators', + field=models.ManyToManyField(blank=True, related_name='site_collaborator', to='ishtar_common.Person', verbose_name='Collaborateurs'), + ), + migrations.AlterField( + model_name='archaeologicalsite', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='archaeologicalsite', + name='discovery_area', + field=models.TextField(blank=True, null=True, verbose_name='Zone de d\xe9couverte'), + ), + migrations.AlterField( + model_name='archaeologicalsite', + name='history_creator', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Cr\xe9ateur'), + ), + migrations.AlterField( + model_name='archaeologicalsite', + name='history_modifier', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Dernier \xe9diteur'), + ), + migrations.AlterField( + model_name='archaeologicalsite', + name='locality_cadastral', + field=models.TextField(blank=True, null=True, verbose_name='Lieu-dit cadastre'), + ), + migrations.AlterField( + model_name='archaeologicalsite', + name='locality_ngi', + field=models.TextField(blank=True, null=True, verbose_name='Lieu-dit IGN'), + ), + migrations.AlterField( + model_name='archaeologicalsite', + name='multi_polygon', + field=django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, null=True, srid=4326, verbose_name='Polygones multi-parties'), + ), + migrations.AlterField( + model_name='archaeologicalsite', + name='name', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='archaeologicalsite', + name='oceanographic_service_localisation', + field=models.TextField(blank=True, null=True, verbose_name='Localisation SHOM'), + ), + migrations.AlterField( + model_name='archaeologicalsite', + name='periods', + field=models.ManyToManyField(blank=True, to='archaeological_operations.Period', verbose_name='P\xe9riodes'), + ), + migrations.AlterField( + model_name='archaeologicalsite', + name='reference', + field=models.CharField(max_length=200, unique=True, verbose_name='R\xe9f\xe9rence'), + ), + migrations.AlterField( + model_name='archaeologicalsite', + name='remains', + field=models.ManyToManyField(blank=True, to='archaeological_operations.RemainType', verbose_name='Vestiges'), + ), + migrations.AlterField( + model_name='archaeologicalsite', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='archaeologicalsite', + name='shipwreck_code', + field=models.TextField(blank=True, null=True, verbose_name='Code \xe9pave'), + ), + migrations.AlterField( + model_name='archaeologicalsite', + name='shipwreck_name', + field=models.TextField(blank=True, null=True, verbose_name="Nom de l'\xe9pave"), + ), + migrations.AlterField( + model_name='archaeologicalsite', + name='sinking_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de naufrage'), + ), + migrations.AlterField( + model_name='archaeologicalsite', + name='top_operation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='archaeological_operations.Operation', verbose_name='Op\xe9ration chapeau'), + ), + migrations.AlterField( + model_name='archaeologicalsite', + name='towns', + field=models.ManyToManyField(blank=True, related_name='sites', to='ishtar_common.Town', verbose_name='Communes'), + ), + migrations.AlterField( + model_name='historicaladministrativeact', + name='act_object', + field=models.TextField(blank=True, max_length=300, null=True, verbose_name='Objet'), + ), + migrations.AlterField( + model_name='historicaladministrativeact', + name='departments_label', + field=models.TextField(blank=True, help_text='Valeur en cache des d\xe9partements associ\xe9s', null=True, verbose_name='D\xe9partements'), + ), + migrations.AlterField( + model_name='historicaladministrativeact', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='historicaladministrativeact', + name='signature_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de signature'), + ), + migrations.AlterField( + model_name='historicaladministrativeact', + name='towns_label', + field=models.TextField(blank=True, help_text='Valeur en cache des communes associ\xe9es', null=True, verbose_name='Communes'), + ), + migrations.AlterField( + model_name='historicaladministrativeact', + name='year', + field=models.IntegerField(blank=True, null=True, verbose_name='Ann\xe9e'), + ), + migrations.AlterField( + model_name='historicalarchaeologicalsite', + name='cached_label', + field=models.TextField(blank=True, db_index=True, null=True, verbose_name='Nom en cache'), + ), + migrations.AlterField( + model_name='historicalarchaeologicalsite', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='historicalarchaeologicalsite', + name='discovery_area', + field=models.TextField(blank=True, null=True, verbose_name='Zone de d\xe9couverte'), + ), + migrations.AlterField( + model_name='historicalarchaeologicalsite', + name='locality_cadastral', + field=models.TextField(blank=True, null=True, verbose_name='Lieu-dit cadastre'), + ), + migrations.AlterField( + model_name='historicalarchaeologicalsite', + name='locality_ngi', + field=models.TextField(blank=True, null=True, verbose_name='Lieu-dit IGN'), + ), + migrations.AlterField( + model_name='historicalarchaeologicalsite', + name='multi_polygon', + field=django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, null=True, srid=4326, verbose_name='Polygones multi-parties'), + ), + migrations.AlterField( + model_name='historicalarchaeologicalsite', + name='name', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='historicalarchaeologicalsite', + name='oceanographic_service_localisation', + field=models.TextField(blank=True, null=True, verbose_name='Localisation SHOM'), + ), + migrations.AlterField( + model_name='historicalarchaeologicalsite', + name='reference', + field=models.CharField(db_index=True, max_length=200, verbose_name='R\xe9f\xe9rence'), + ), + migrations.AlterField( + model_name='historicalarchaeologicalsite', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='historicalarchaeologicalsite', + name='shipwreck_code', + field=models.TextField(blank=True, null=True, verbose_name='Code \xe9pave'), + ), + migrations.AlterField( + model_name='historicalarchaeologicalsite', + name='shipwreck_name', + field=models.TextField(blank=True, null=True, verbose_name="Nom de l'\xe9pave"), + ), + migrations.AlterField( + model_name='historicalarchaeologicalsite', + name='sinking_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de naufrage'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='abstract', + field=models.TextField(blank=True, null=True, verbose_name='R\xe9sum\xe9'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='address', + field=models.TextField(blank=True, null=True, verbose_name='Adresse / Lieu-dit'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='cached_label', + field=models.CharField(blank=True, db_index=True, max_length=500, null=True, verbose_name='Nom en cache'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='common_name', + field=models.TextField(blank=True, null=True, verbose_name='Nom g\xe9n\xe9rique'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='cost', + field=models.IntegerField(blank=True, null=True, verbose_name='Co\xfbt (euros)'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='creation_date', + field=models.DateField(default=datetime.date.today, verbose_name='Date de cr\xe9ation'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='documentation_deadline', + field=models.DateField(blank=True, null=True, verbose_name='Date limite de versement de la documentation'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='documentation_received', + field=models.NullBooleanField(verbose_name='Documentation re\xe7ue'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='effective_man_days', + field=models.IntegerField(blank=True, null=True, verbose_name='Jours-hommes effectifs'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='end_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de cl\xf4ture'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='excavation_end_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de fin de chantier'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='finds_deadline', + field=models.DateField(blank=True, null=True, verbose_name='Date limite de versement du mobilier'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='finds_received', + field=models.NullBooleanField(verbose_name='Mobilier re\xe7u'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='geoarchaeological_context_prescription', + field=models.NullBooleanField(verbose_name='Prescription sur un contexte g\xe9oarch\xe9ologique'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='large_area_prescription', + field=models.NullBooleanField(verbose_name='Prescription sur une vaste surface'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='multi_polygon', + field=django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, null=True, srid=4326, verbose_name='Polygones multi-parties'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='name_of_the_protagonist', + field=models.TextField(blank=True, null=True, verbose_name='Nom du protagoniste'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='official_report_number', + field=models.TextField(blank=True, null=True, verbose_name='Num\xe9ro de proc\xe8s-verbal'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='old_code', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Ancien code'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='operation_code', + field=models.IntegerField(blank=True, null=True, verbose_name='R\xe9f\xe9rence num\xe9rique'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='operator_reference', + field=models.CharField(blank=True, max_length=20, null=True, verbose_name="R\xe9f\xe9rence de l'op\xe9rateur"), + ), + migrations.AlterField( + model_name='historicaloperation', + name='optional_man_days', + field=models.IntegerField(blank=True, null=True, verbose_name='Jours-hommes optionnels'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='relation_image', + field=models.TextField(blank=True, max_length=100, null=True, verbose_name='Image des relations (SVG g\xe9n\xe9r\xe9)'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='report_delivery_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de livraison du rapport'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='scheduled_man_days', + field=models.IntegerField(blank=True, null=True, verbose_name='Jours-hommes pr\xe9vus'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='scientific_documentation_comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire relatif \xe0 la documentation scientifique'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='seizure_name', + field=models.TextField(blank=True, null=True, verbose_name='Nom de la saisie'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='start_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de d\xe9but'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='virtual_operation', + field=models.BooleanField(default=False, help_text="Si coch\xe9, cela signifie que cette op\xe9ration n'a pas \xe9t\xe9 officiellement enregistr\xe9e.", verbose_name='Op\xe9ration virtuelle'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='year', + field=models.IntegerField(blank=True, null=True, verbose_name='Ann\xe9e'), + ), + migrations.AlterField( + model_name='historicaloperation', + name='zoning_prescription', + field=models.NullBooleanField(verbose_name='Prescription sur zonage'), + ), + migrations.AlterField( + model_name='operation', + name='abstract', + field=models.TextField(blank=True, null=True, verbose_name='R\xe9sum\xe9'), + ), + migrations.AlterField( + model_name='operation', + name='address', + field=models.TextField(blank=True, null=True, verbose_name='Adresse / Lieu-dit'), + ), + migrations.AlterField( + model_name='operation', + name='archaeological_sites', + field=models.ManyToManyField(blank=True, related_name='operations', to='archaeological_operations.ArchaeologicalSite', verbose_name='Entit\xe9s arch\xe9ologiques'), + ), + migrations.AlterField( + model_name='operation', + name='associated_file', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='operations', to='archaeological_files.File', verbose_name='Dossier'), + ), + migrations.AlterField( + model_name='operation', + name='cached_label', + field=models.CharField(blank=True, db_index=True, max_length=500, null=True, verbose_name='Nom en cache'), + ), + migrations.AlterField( + model_name='operation', + name='collaborators', + field=models.ManyToManyField(blank=True, related_name='operation_collaborator', to='ishtar_common.Person', verbose_name='Collaborateurs'), + ), + migrations.AlterField( + model_name='operation', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='operation', + name='common_name', + field=models.TextField(blank=True, null=True, verbose_name='Nom g\xe9n\xe9rique'), + ), + migrations.AlterField( + model_name='operation', + name='cost', + field=models.IntegerField(blank=True, null=True, verbose_name='Co\xfbt (euros)'), + ), + migrations.AlterField( + model_name='operation', + name='creation_date', + field=models.DateField(default=datetime.date.today, verbose_name='Date de cr\xe9ation'), + ), + migrations.AlterField( + model_name='operation', + name='documentation_deadline', + field=models.DateField(blank=True, null=True, verbose_name='Date limite de versement de la documentation'), + ), + migrations.AlterField( + model_name='operation', + name='documentation_received', + field=models.NullBooleanField(verbose_name='Documentation re\xe7ue'), + ), + migrations.AlterField( + model_name='operation', + name='effective_man_days', + field=models.IntegerField(blank=True, null=True, verbose_name='Jours-hommes effectifs'), + ), + migrations.AlterField( + model_name='operation', + name='end_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de cl\xf4ture'), + ), + migrations.AlterField( + model_name='operation', + name='excavation_end_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de fin de chantier'), + ), + migrations.AlterField( + model_name='operation', + name='finds_deadline', + field=models.DateField(blank=True, null=True, verbose_name='Date limite de versement du mobilier'), + ), + migrations.AlterField( + model_name='operation', + name='finds_received', + field=models.NullBooleanField(verbose_name='Mobilier re\xe7u'), + ), + migrations.AlterField( + model_name='operation', + name='geoarchaeological_context_prescription', + field=models.NullBooleanField(verbose_name='Prescription sur un contexte g\xe9oarch\xe9ologique'), + ), + migrations.AlterField( + model_name='operation', + name='history_creator', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Cr\xe9ateur'), + ), + migrations.AlterField( + model_name='operation', + name='history_modifier', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Dernier \xe9diteur'), + ), + migrations.AlterField( + model_name='operation', + name='in_charge', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='operation_responsability', to='ishtar_common.Person', verbose_name='Responsable'), + ), + migrations.AlterField( + model_name='operation', + name='large_area_prescription', + field=models.NullBooleanField(verbose_name='Prescription sur une vaste surface'), + ), + migrations.AlterField( + model_name='operation', + name='multi_polygon', + field=django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, null=True, srid=4326, verbose_name='Polygones multi-parties'), + ), + migrations.AlterField( + model_name='operation', + name='name_of_the_protagonist', + field=models.TextField(blank=True, null=True, verbose_name='Nom du protagoniste'), + ), + migrations.AlterField( + model_name='operation', + name='official_report_number', + field=models.TextField(blank=True, null=True, verbose_name='Num\xe9ro de proc\xe8s-verbal'), + ), + migrations.AlterField( + model_name='operation', + name='old_code', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Ancien code'), + ), + migrations.AlterField( + model_name='operation', + name='operation_code', + field=models.IntegerField(blank=True, null=True, verbose_name='R\xe9f\xe9rence num\xe9rique'), + ), + migrations.AlterField( + model_name='operation', + name='operation_type', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='ishtar_common.OperationType', verbose_name="Type d'op\xe9ration"), + ), + migrations.AlterField( + model_name='operation', + name='operator', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='operator', to='ishtar_common.Organization', verbose_name='Op\xe9rateur'), + ), + migrations.AlterField( + model_name='operation', + name='operator_reference', + field=models.CharField(blank=True, max_length=20, null=True, verbose_name="R\xe9f\xe9rence de l'op\xe9rateur"), + ), + migrations.AlterField( + model_name='operation', + name='optional_man_days', + field=models.IntegerField(blank=True, null=True, verbose_name='Jours-hommes optionnels'), + ), + migrations.AlterField( + model_name='operation', + name='periods', + field=models.ManyToManyField(blank=True, to='archaeological_operations.Period', verbose_name='P\xe9riodes'), + ), + migrations.AlterField( + model_name='operation', + name='record_quality_type', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_operations.RecordQualityType', verbose_name="Qualit\xe9 d'enregistrement"), + ), + migrations.AlterField( + model_name='operation', + name='relation_image', + field=models.FileField(blank=True, null=True, upload_to=ishtar_common.models.get_image_path, verbose_name='Image des relations (SVG g\xe9n\xe9r\xe9)'), + ), + migrations.AlterField( + model_name='operation', + name='remains', + field=models.ManyToManyField(blank=True, to='archaeological_operations.RemainType', verbose_name='Vestiges'), + ), + migrations.AlterField( + model_name='operation', + name='report_delivery_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de livraison du rapport'), + ), + migrations.AlterField( + model_name='operation', + name='report_processing', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_operations.ReportState', verbose_name='Traitement du rapport'), + ), + migrations.AlterField( + model_name='operation', + name='scheduled_man_days', + field=models.IntegerField(blank=True, null=True, verbose_name='Jours-hommes pr\xe9vus'), + ), + migrations.AlterField( + model_name='operation', + name='scientific_documentation_comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire relatif \xe0 la documentation scientifique'), + ), + migrations.AlterField( + model_name='operation', + name='scientist', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='operation_scientist_responsability', to='ishtar_common.Person', verbose_name='Responsable du suivi scientifique'), + ), + migrations.AlterField( + model_name='operation', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='operation', + name='seizure_name', + field=models.TextField(blank=True, null=True, verbose_name='Nom de la saisie'), + ), + migrations.AlterField( + model_name='operation', + name='start_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de d\xe9but'), + ), + migrations.AlterField( + model_name='operation', + name='towns', + field=models.ManyToManyField(related_name='operations', to='ishtar_common.Town', verbose_name='Communes'), + ), + migrations.AlterField( + model_name='operation', + name='virtual_operation', + field=models.BooleanField(default=False, help_text="Si coch\xe9, cela signifie que cette op\xe9ration n'a pas \xe9t\xe9 officiellement enregistr\xe9e.", verbose_name='Op\xe9ration virtuelle'), + ), + migrations.AlterField( + model_name='operation', + name='year', + field=models.IntegerField(blank=True, null=True, verbose_name='Ann\xe9e'), + ), + migrations.AlterField( + model_name='operation', + name='zoning_prescription', + field=models.NullBooleanField(verbose_name='Prescription sur zonage'), + ), + migrations.AlterField( + model_name='operationtypeold', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='operationtypeold', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='operationtypeold', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='operationtypeold', + name='order', + field=models.IntegerField(default=1, verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='operationtypeold', + name='preventive', + field=models.BooleanField(default=True, verbose_name='Est du pr\xe9ventif'), + ), + migrations.AlterField( + model_name='operationtypeold', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='parcel', + name='address', + field=models.TextField(blank=True, null=True, verbose_name='Adresse - Lieu-dit'), + ), + migrations.AlterField( + model_name='parcel', + name='associated_file', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='parcels', to='archaeological_files.File', verbose_name='Dossier'), + ), + migrations.AlterField( + model_name='parcel', + name='auto_external_id', + field=models.BooleanField(default=False, verbose_name="L'identifiant est attribu\xe9 automatiquement"), + ), + migrations.AlterField( + model_name='parcel', + name='cached_label', + field=models.TextField(blank=True, db_index=True, null=True, verbose_name='Nom en cache'), + ), + migrations.AlterField( + model_name='parcel', + name='external_id', + field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Identifiant'), + ), + migrations.AlterField( + model_name='parcel', + name='history_creator', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Cr\xe9ateur'), + ), + migrations.AlterField( + model_name='parcel', + name='history_modifier', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Dernier \xe9diteur'), + ), + migrations.AlterField( + model_name='parcel', + name='operation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='parcels', to='archaeological_operations.Operation', verbose_name='Op\xe9ration'), + ), + migrations.AlterField( + model_name='parcel', + name='parcel_number', + field=models.CharField(blank=True, max_length=6, null=True, verbose_name='Num\xe9ro de parcelle'), + ), + migrations.AlterField( + model_name='parcel', + name='public_domain', + field=models.BooleanField(default=False, verbose_name='Domaine public'), + ), + migrations.AlterField( + model_name='parcel', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='parcel', + name='town', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='parcels', to='ishtar_common.Town', verbose_name='Commune'), + ), + migrations.AlterField( + model_name='parcel', + name='year', + field=models.IntegerField(blank=True, null=True, verbose_name='Ann\xe9e'), + ), + migrations.AlterField( + model_name='parcelowner', + name='end_date', + field=models.DateField(verbose_name='Date de fin'), + ), + migrations.AlterField( + model_name='parcelowner', + name='history_creator', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Cr\xe9ateur'), + ), + migrations.AlterField( + model_name='parcelowner', + name='history_modifier', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Dernier \xe9diteur'), + ), + migrations.AlterField( + model_name='parcelowner', + name='owner', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='parcel_owner', to='ishtar_common.Person', verbose_name='Propri\xe9taire'), + ), + migrations.AlterField( + model_name='parcelowner', + name='parcel', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='owners', to='archaeological_operations.Parcel', verbose_name='Parcelle'), + ), + migrations.AlterField( + model_name='parcelowner', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='parcelowner', + name='start_date', + field=models.DateField(verbose_name='Date de d\xe9but'), + ), + migrations.AlterField( + model_name='period', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='period', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='period', + name='end_date', + field=models.IntegerField(blank=True, null=True, verbose_name='Date de fin'), + ), + migrations.AlterField( + model_name='period', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='period', + name='order', + field=models.IntegerField(verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='period', + name='parent', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_operations.Period', verbose_name='P\xe9riode parente'), + ), + migrations.AlterField( + model_name='period', + name='start_date', + field=models.IntegerField(blank=True, null=True, verbose_name='Date de d\xe9but'), + ), + migrations.AlterField( + model_name='period', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='recordqualitytype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='recordqualitytype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='recordqualitytype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='recordqualitytype', + name='order', + field=models.IntegerField(verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='recordqualitytype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='relationtype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='relationtype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='relationtype', + name='inverse_relation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_operations.RelationType', verbose_name='Relation inverse'), + ), + migrations.AlterField( + model_name='relationtype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='relationtype', + name='logical_relation', + field=models.CharField(blank=True, choices=[(b'above', 'Au-dessus'), (b'bellow', 'En dessous'), (b'equal', '\xc9gal')], max_length=10, null=True, verbose_name='Relation logique'), + ), + migrations.AlterField( + model_name='relationtype', + name='order', + field=models.IntegerField(default=1, verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='relationtype', + name='symmetrical', + field=models.BooleanField(verbose_name='Sym\xe9trique'), + ), + migrations.AlterField( + model_name='relationtype', + name='tiny_label', + field=models.CharField(blank=True, max_length=50, null=True, verbose_name='D\xe9nomination courte'), + ), + migrations.AlterField( + model_name='relationtype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='remaintype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='remaintype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='remaintype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='remaintype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='reportstate', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='reportstate', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='reportstate', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='reportstate', + name='order', + field=models.IntegerField(verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='reportstate', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + ] diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py index 872d2bf4e..d8233ba0f 100644 --- a/archaeological_operations/models.py +++ b/archaeological_operations/models.py @@ -108,6 +108,7 @@ class ArchaeologicalSite(BaseHistorizedItem, OwnPerms, ValueGetter, SHOW_URL = 'show-site' TABLE_COLS = ['reference', 'name', 'towns_label', 'periods', 'remains'] SLUG = 'site' + LONG_SLUG = 'archaeologicalsite' BASE_SEARCH_VECTORS = [ "comment", @@ -119,6 +120,8 @@ class ArchaeologicalSite(BaseHistorizedItem, OwnPerms, ValueGetter, "reference", "shipwreck_code", "shipwreck_name", + "drassm_number", + "affmar_number", ] M2M_SEARCH_VECTORS = ["periods__label", "remains__label", "towns__name"] PARENT_SEARCH_VECTORS = ['operations'] @@ -192,6 +195,14 @@ class ArchaeologicalSite(BaseHistorizedItem, OwnPerms, ValueGetter, pgettext_lazy("key for text search", u"top-operation"), 'top_operation__cached_label__icontains' ), + 'drassm_number': ( + pgettext_lazy("key for text search", u"numero-drassm"), + 'drassm_number__iexact' + ), + 'affmar_number': ( + pgettext_lazy("key for text search", u"numero-affmar"), + 'affmar_number__iexact' + ), } for v in ALT_NAMES.values(): for language_code, language_lbl in settings.LANGUAGES: @@ -243,6 +254,10 @@ class ArchaeologicalSite(BaseHistorizedItem, OwnPerms, ValueGetter, _(u"Sinking date"), null=True, blank=True) discovery_area = models.TextField( _(u"Discovery area"), null=True, blank=True) + affmar_number = models.CharField(_(u"AffMar number"), max_length=100, + null=True, blank=True) + drassm_number = models.CharField(_(u"DRASSM number"), max_length=100, + null=True, blank=True) # gis point = models.PointField(_(u"Point"), blank=True, null=True) @@ -290,6 +305,9 @@ class ArchaeologicalSite(BaseHistorizedItem, OwnPerms, ValueGetter, 'operations__context_record__base_finds__find__container__responsible__', Warehouse._get_query_owns_dicts(ishtaruser) ) | cls._construct_query_own( + 'operations__context_record__base_finds__find__basket__', + [{"shared_with": ishtaruser, "shared_write_with": ishtaruser}] + ) | cls._construct_query_own( 'operations__context_record__base_finds__find__container__location__', Warehouse._get_query_owns_dicts(ishtaruser) ) | cls._construct_query_own( @@ -541,6 +559,7 @@ class Operation(ClosedItem, BaseHistorizedItem, OwnPerms, ValueGetter, "scientist__cached_label", "scientific_documentation_comment", "seizure_name", + "drassm_code", ] PROPERTY_SEARCH_VECTORS = [ "full_reference", "short_code_patriarche" @@ -705,6 +724,10 @@ class Operation(ClosedItem, BaseHistorizedItem, OwnPerms, ValueGetter, pgettext_lazy("key for text search", u"finds-deadline-after"), 'finds_deadline__gte' ), + 'drassm_code': ( + pgettext_lazy("key for text search", u"code-drassm"), + 'drassm_code__iexact' + ), } for v in ALT_NAMES.values(): for language_code, language_lbl in settings.LANGUAGES: @@ -783,34 +806,35 @@ class Operation(ClosedItem, BaseHistorizedItem, OwnPerms, ValueGetter, blank=True, null=True) old_code = models.CharField(_(u"Old code"), max_length=200, null=True, blank=True) - if settings.COUNTRY == 'fr': - code_patriarche = models.TextField(u"Code PATRIARCHE", null=True, - blank=True, unique=True) - TABLE_COLS = ['code_patriarche'] + TABLE_COLS - BASE_SEARCH_VECTORS = ['code_patriarche'] + BASE_SEARCH_VECTORS - # preventive - fnap_financing = models.FloatField(u"Financement FNAP (%)", - blank=True, null=True) - # preventive - fnap_cost = models.IntegerField(u"Financement FNAP (€)", - blank=True, null=True) - # preventive diag - zoning_prescription = models.NullBooleanField( - _(u"Prescription on zoning"), blank=True, null=True) - # preventive diag - large_area_prescription = models.NullBooleanField( - _(u"Prescription on large area"), blank=True, null=True) - geoarchaeological_context_prescription = models.NullBooleanField( - _(u"Prescription on geoarchaeological context"), blank=True, - null=True) # preventive diag - cira_rapporteur = models.ForeignKey( - Person, related_name='cira_rapporteur', null=True, blank=True, - on_delete=models.SET_NULL, verbose_name=u"Rapporteur CIRA") - negative_result = models.NullBooleanField( - u"Résultat considéré comme négatif", blank=True, null=True) - cira_date = models.DateField(u"Date avis CIRA", null=True, blank=True) - eas_number = models.CharField(u"Numéro de l'EA", max_length=20, - null=True, blank=True) + ## fr + code_patriarche = models.TextField(u"Code PATRIARCHE", null=True, + blank=True, unique=True) + TABLE_COLS = ['code_patriarche'] + TABLE_COLS + BASE_SEARCH_VECTORS = ['code_patriarche'] + BASE_SEARCH_VECTORS + # preventive + fnap_financing = models.FloatField(u"Financement FNAP (%)", + blank=True, null=True) + # preventive + fnap_cost = models.IntegerField(u"Financement FNAP (€)", + blank=True, null=True) + # preventive diag + zoning_prescription = models.NullBooleanField( + _(u"Prescription on zoning"), blank=True, null=True) + # preventive diag + large_area_prescription = models.NullBooleanField( + _(u"Prescription on large area"), blank=True, null=True) + geoarchaeological_context_prescription = models.NullBooleanField( + _(u"Prescription on geoarchaeological context"), blank=True, + null=True) # preventive diag + cira_rapporteur = models.ForeignKey( + Person, related_name='cira_rapporteur', null=True, blank=True, + on_delete=models.SET_NULL, verbose_name=u"Rapporteur CIRA") + negative_result = models.NullBooleanField( + u"Résultat considéré comme négatif", blank=True, null=True) + cira_date = models.DateField(u"Date avis CIRA", null=True, blank=True) + eas_number = models.CharField(u"Numéro de l'EA", max_length=20, + null=True, blank=True) + ## end fr operator_reference = models.CharField( _(u"Operator reference"), max_length=20, null=True, blank=True) common_name = models.TextField(_(u"Generic name"), null=True, blank=True) @@ -845,6 +869,9 @@ class Operation(ClosedItem, BaseHistorizedItem, OwnPerms, ValueGetter, finds_received = models.NullBooleanField( _(u"Finds received"), blank=True, null=True) + # underwater + drassm_code = models.CharField(_(u"DRASSM code"), max_length=100, + null=True, blank=True) # judiciary seizure_name = models.TextField(_(u"Seizure name"), blank=True, null=True) official_report_number = models.TextField(_(u"Official report number"), @@ -1040,6 +1067,22 @@ class Operation(ClosedItem, BaseHistorizedItem, OwnPerms, ValueGetter, finds__base_finds__context_record__operation=self ) + def get_extra_actions(self, request): + """ + For sheet template + """ + # url, base_text, icon, extra_text, extra css class, is a quick action + actions = super(Operation, self).get_extra_actions(request) + + can_add_cr = self.can_do(request, 'add_contextrecord') + if can_add_cr: + actions += [ + (reverse('operation-qa-contextrecord', args=[self.pk]), + _(u"Add context record"), "fa fa-plus", + _(u"context record"), "", True), + ] + return actions + associated_file_short_label_lbl = _(u"Archaeological file") full_code_patriarche_lbl = _(u"Code patriarche") @@ -1131,6 +1174,9 @@ class Operation(ClosedItem, BaseHistorizedItem, OwnPerms, ValueGetter, 'context_record__base_finds__find__container__location__', Warehouse._get_query_owns_dicts(ishtaruser) ) | cls._construct_query_own( + 'context_record__base_finds__find__basket__', + [{"shared_with": ishtaruser, "shared_write_with": ishtaruser}] + ) | cls._construct_query_own( '', cls._get_query_owns_dicts(ishtaruser) ) return q @@ -1461,6 +1507,7 @@ class AdministrativeAct(BaseHistorizedItem, OwnPerms, ValueGetter): 'act_object', 'signature_date', 'associated_file__cached_label', 'operation__cached_label', 'towns_label'] + SLUG = "administrativeact" TABLE_COLS_FILE = [ 'full_ref', 'year', 'index', 'act_type', 'act_object', 'associated_file', 'towns_label', @@ -1826,6 +1873,16 @@ class AdministrativeAct(BaseHistorizedItem, OwnPerms, ValueGetter): if self.treatment_file: return self.treatment_file + def get_extra_templates(self, request): + templates = [] + for template in self.act_type.associated_template.all(): + urlname = "generatedoc-administrativeactop" + templates.append( + (template.name, reverse( + urlname, args=[self.pk, template.pk])) + ) + return templates + def get_filename(self): filename = self.related_item.associated_filename filename = u"-".join(filename.split('-')[:-1]) # remove date diff --git a/archaeological_operations/templates/ishtar/sheet_operation.html b/archaeological_operations/templates/ishtar/sheet_operation.html index 6d8d475e4..8801855cd 100644 --- a/archaeological_operations/templates/ishtar/sheet_operation.html +++ b/archaeological_operations/templates/ishtar/sheet_operation.html @@ -33,6 +33,7 @@ </div> <div class="row"> + {% field_flex_2 "Code DRASSM" item.drassm_code %} {% field_flex_2 "Old code" item.old_code %} {% trans "Begining date" as begining_date_label %} {% field_flex_2 begining_date_label item.start_date|date:"DATE_FORMAT" %} @@ -195,20 +196,24 @@ {% dynamic_table_document archaeologicalsites_label 'sites' 'operations' item.pk '' output %} {% endif %} +{% if item.grouped_parcels %} {% trans "Associated parcels" as parcels_label %} {% include "ishtar/blocks/window_tables/parcels.html" %} +{% endif %} -{% if item.administrative_act %} +{% if item.administrative_act.count %} <h3>{% trans "Administrative acts" %}</h3> {% table_administrativact "" item.administrative_act.all %} {% endif %} {% trans "Document from this operation" as operation_docs %} +{% if permission_view_own_document or permission_view_document %} {% if item.documents.count %} {% dynamic_table_document operation_docs 'documents' 'operations' item.pk '' output %} {% endif %} +{% endif %} -{% if view_own_contextrecord or view_contextrecord %} +{% if permission_view_own_contextrecord or permission_view_contextrecord %} {% if item.context_record.count %} {% trans "Context records" as cr_lab %} {% dynamic_table_document cr_lab 'context_records_for_ope' 'operation_id' item.pk 'TABLE_COLS_FOR_OPE' output %} @@ -219,23 +224,28 @@ {% dynamic_table_document cr_rels 'context_records_relations_detail' 'left_record__operation' item.pk '' output %} {% endif %} +{% if permission_view_own_document or permission_view_document %} {% if item.context_record_docs_q.count %} {% trans "Documents from associated context records" as cr_docs %} {% dynamic_table_document cr_docs 'documents' 'context_records__operation' item.pk '' output %} {% endif %} {% endif %} +{% endif %} + {% if item.finds %} {% trans "Finds" as finds %} {% dynamic_table_document finds 'finds_for_ope' 'base_finds__context_record__operation' item.pk 'TABLE_COLS_FOR_OPE' output %} {% endif %} +{% if permission_view_own_document or permission_view_document %} {% if item.find_docs_q.count %} {% trans "Documents from associated finds" as finds_docs %} {% dynamic_table_document finds_docs 'documents' 'finds__base_finds__context_record__operation' item.pk '' output %} {% endif %} +{% endif %} -{% if view_own_container or view_container %} +{% if permission_view_own_container or permission_view_container %} {% if item.containers_q.count %} {% trans "Associated containers" as containers_lbl %} {% dynamic_table_document containers_lbl 'containers' 'finds__base_finds__context_record__operation' item.pk '' output %} diff --git a/archaeological_operations/templates/ishtar/sheet_site.html b/archaeological_operations/templates/ishtar/sheet_site.html index 8f8d018f6..0108d3db6 100644 --- a/archaeological_operations/templates/ishtar/sheet_site.html +++ b/archaeological_operations/templates/ishtar/sheet_site.html @@ -49,10 +49,12 @@ </div> {% endif %} -{% if item.oceanographic_service_localisation or item.shipwreck_code or item.sinking_date or item.discovery_area or item.shipwreck_name %} +{% if item.affmar_number or item.drassm_number or item.oceanographic_service_localisation or item.shipwreck_code or item.sinking_date or item.discovery_area or item.shipwreck_name %} <h3>{% trans "Underwater"%}</h3> <div class="row"> + {% field_flex "Numéro AffMar" item.affmar_number %} + {% field_flex "Numéro DRASSM" item.drassm_number %} {% field_flex "Shipwreck name" item.shipwreck_name %} {% field_flex "Shipwreck code" item.shipwreck_code %} {% field_flex "Sinking date" item.sinking_date %} diff --git a/archaeological_operations/views.py b/archaeological_operations/views.py index 48d7c4a4f..06b8b6ce9 100644 --- a/archaeological_operations/views.py +++ b/archaeological_operations/views.py @@ -52,6 +52,7 @@ from ishtar_common.forms import ClosingDateFormSelection, FinalForm, \ from ishtar_common.models import get_current_profile, IshtarSiteProfile, \ DocumentTemplate from ishtar_common.utils import put_session_message, check_rights_condition +from ishtar_common.views import gen_generate_doc from ishtar_common.views_item import get_item, show_item, revert_item, new_item from ishtar_common.wizards import SearchWizard @@ -466,30 +467,7 @@ administrativact_register_wizard = SearchWizard.as_view([ url_name='administrativact_register',) -def generatedoc_administrativeactop(request, pk, template_pk=None): - if (not request.user.has_perm( - 'ishtar_common.view_operation', models.Operation) - and not request.user.has_perm( - 'ishtar_common.view_own_operation', models.Operation)): - return HttpResponse(content_type='text/plain') - try: - act_file = models.AdministrativeAct.objects.get(pk=pk) - doc = act_file.publish(template_pk) - except models.AdministrativeAct.DoesNotExist: - doc = None - if doc: - MIMES = {'odt': 'application/vnd.oasis.opendocument.text', - 'ods': 'application/vnd.oasis.opendocument.spreadsheet'} - ext = doc.split('.')[-1] - doc_name = act_file.get_filename() + "." + ext - mimetype = 'text/csv' - if ext in MIMES: - mimetype = MIMES[ext] - response = HttpResponse(open(doc), content_type=mimetype) - response['Content-Disposition'] = 'attachment; filename=%s' % \ - doc_name - return response - return HttpResponse(content_type='text/plain') +generatedoc_administrativeactop = gen_generate_doc(models.AdministrativeAct) def administrativeactfile_document( diff --git a/archaeological_operations/wizards.py b/archaeological_operations/wizards.py index de38beb95..798e622b4 100644 --- a/archaeological_operations/wizards.py +++ b/archaeological_operations/wizards.py @@ -332,7 +332,7 @@ class OperationAdministrativeActWizard(OperationWizard): except models.AdministrativeAct.DoesNotExist: return - def get_extra_model(self, dct, form_list): + def get_extra_model(self, dct, m2m, form_list): dct['history_modifier'] = self.request.user return dct diff --git a/archaeological_warehouse/forms.py b/archaeological_warehouse/forms.py index 954c01918..2dc963ca0 100644 --- a/archaeological_warehouse/forms.py +++ b/archaeological_warehouse/forms.py @@ -18,6 +18,7 @@ # See the file COPYING for details. from collections import OrderedDict +import datetime from django import forms from django.conf import settings @@ -294,7 +295,9 @@ class BasePackagingForm(SelectFindBasketForm): associated_model=Person, new=True), validators=[valid_id(Person)]) start_date = forms.DateField( - label=_(u"Date"), required=False, widget=DatePicker) + label=_(u"Date"), required=False, widget=DatePicker, + initial=datetime.date.today + ) class FindPackagingFormSelection(FindMultipleFormSelection): diff --git a/archaeological_warehouse/ishtar_menu.py b/archaeological_warehouse/ishtar_menu.py index b697c4dd3..414b0431d 100644 --- a/archaeological_warehouse/ishtar_menu.py +++ b/archaeological_warehouse/ishtar_menu.py @@ -29,14 +29,6 @@ import models MENU_SECTIONS = [ - (70, SectionItem('treatment_management', _(u"Treatment"), - profile_restriction='warehouse', - css='menu-warehouse', - childs=[ - MenuItem('warehouse_packaging', _(u"Packaging"), - model=Treatment, - access_controls=['add_treatment', 'add_own_treatment']), - ])), (80, SectionItem('warehouse', _(u"Warehouse"), profile_restriction='warehouse', css='menu-warehouse', diff --git a/archaeological_warehouse/locale/django.pot b/archaeological_warehouse/locale/django.pot index 139895395..ac527e894 100644 --- a/archaeological_warehouse/locale/django.pot +++ b/archaeological_warehouse/locale/django.pot @@ -9,315 +9,315 @@ msgid "" msgstr "" -#: forms.py:41 forms.py:113 ishtar_menu.py:40 models.py:94 models.py:258 +#: forms.py:42 forms.py:114 ishtar_menu.py:32 models.py:95 models.py:259 #: templates/ishtar/sheet_warehouse.html:4 msgid "Warehouse" msgstr "" -#: forms.py:50 forms.py:55 models.py:622 +#: forms.py:51 forms.py:56 models.py:638 msgid "Division" msgstr "" -#: forms.py:57 models.py:286 +#: forms.py:58 models.py:287 msgid "Order" msgstr "" -#: forms.py:71 +#: forms.py:72 msgid "There are identical divisions." msgstr "" -#: forms.py:76 models.py:83 +#: forms.py:77 models.py:84 msgid "Divisions" msgstr "" -#: forms.py:77 +#: forms.py:78 msgid "Warehouse - 020 - Divisions" msgstr "" -#: forms.py:85 forms.py:254 +#: forms.py:86 forms.py:255 msgid "Full text search" msgstr "" -#: forms.py:88 forms.py:119 models.py:75 models.py:255 +#: forms.py:89 forms.py:120 models.py:76 models.py:256 msgid "Name" msgstr "" -#: forms.py:89 forms.py:121 models.py:39 models.py:77 +#: forms.py:90 forms.py:122 models.py:40 models.py:78 msgid "Warehouse type" msgstr "" -#: forms.py:101 views.py:108 +#: forms.py:102 views.py:120 msgid "Warehouse search" msgstr "" -#: forms.py:114 +#: forms.py:115 msgid "Warehouse - 010 - General" msgstr "" -#: forms.py:124 models.py:80 +#: forms.py:125 models.py:81 msgid "Person in charge" msgstr "" -#: forms.py:130 forms.py:198 models.py:81 models.py:381 +#: forms.py:131 forms.py:199 models.py:82 models.py:383 msgid "Comment" msgstr "" -#: forms.py:132 +#: forms.py:133 msgid "Address" msgstr "" -#: forms.py:134 +#: forms.py:135 msgid "Address complement" msgstr "" -#: forms.py:136 +#: forms.py:137 msgid "Postal code" msgstr "" -#: forms.py:138 +#: forms.py:139 msgid "Town" msgstr "" -#: forms.py:139 +#: forms.py:140 msgid "Country" msgstr "" -#: forms.py:141 +#: forms.py:142 msgid "Phone" msgstr "" -#: forms.py:142 +#: forms.py:143 msgid "Mobile phone" msgstr "" -#: forms.py:167 forms.py:168 +#: forms.py:168 forms.py:169 msgid "Would you like to delete this warehouse?" msgstr "" -#: forms.py:172 models.py:395 models.py:619 +#: forms.py:173 models.py:397 models.py:635 #: templates/ishtar/sheet_container.html:4 msgid "Container" msgstr "" -#: forms.py:173 +#: forms.py:174 msgid "Container - 010 - General" msgstr "" -#: forms.py:179 forms.py:261 models.py:301 +#: forms.py:180 forms.py:262 models.py:302 msgid "Ref." msgstr "" -#: forms.py:180 models.py:389 +#: forms.py:181 models.py:391 msgid "Old reference" msgstr "" -#: forms.py:182 forms.py:260 models.py:304 models.py:379 +#: forms.py:183 forms.py:261 models.py:306 models.py:381 msgid "Container type" msgstr "" -#: forms.py:184 forms.py:258 +#: forms.py:185 forms.py:259 msgid "Current location (warehouse)" msgstr "" -#: forms.py:190 forms.py:259 models.py:376 +#: forms.py:191 forms.py:260 models.py:378 msgid "Responsible warehouse" msgstr "" -#: forms.py:196 +#: forms.py:197 msgid "Image" msgstr "" -#: forms.py:223 +#: forms.py:224 msgid "ID" msgstr "" -#: forms.py:245 +#: forms.py:246 msgid "This ID already exists for this warehouse." msgstr "" -#: forms.py:272 forms.py:278 views.py:150 +#: forms.py:273 forms.py:279 views.py:162 msgid "Container search" msgstr "" -#: forms.py:274 forms.py:280 +#: forms.py:275 forms.py:281 msgid "You should select a container." msgstr "" -#: forms.py:275 +#: forms.py:276 msgid "Add a new container" msgstr "" -#: forms.py:285 ishtar_menu.py:36 views.py:103 +#: forms.py:286 views.py:115 msgid "Packaging" msgstr "" -#: forms.py:291 +#: forms.py:292 msgid "Packager" msgstr "" -#: forms.py:297 +#: forms.py:298 msgid "Date" msgstr "" -#: forms.py:301 +#: forms.py:304 msgid "Packaged finds" msgstr "" -#: forms.py:305 +#: forms.py:308 msgid "Container - 020 - Localisation" msgstr "" -#: forms.py:307 models.py:382 +#: forms.py:310 models.py:384 msgid "Localisation" msgstr "" -#: forms.py:331 forms.py:332 +#: forms.py:334 forms.py:335 msgid "Would you like to delete this container?" msgstr "" -#: ishtar_menu.py:32 -msgid "Treatment" -msgstr "" - -#: ishtar_menu.py:44 ishtar_menu.py:59 +#: ishtar_menu.py:36 ishtar_menu.py:51 msgid "Search" msgstr "" -#: ishtar_menu.py:47 ishtar_menu.py:63 +#: ishtar_menu.py:39 ishtar_menu.py:55 msgid "Creation" msgstr "" -#: ishtar_menu.py:50 ishtar_menu.py:67 +#: ishtar_menu.py:42 ishtar_menu.py:59 msgid "Modification" msgstr "" -#: ishtar_menu.py:53 ishtar_menu.py:71 +#: ishtar_menu.py:45 ishtar_menu.py:63 msgid "Deletion" msgstr "" -#: ishtar_menu.py:57 models.py:396 templates/ishtar/sheet_warehouse.html:42 +#: ishtar_menu.py:49 models.py:398 templates/ishtar/sheet_warehouse.html:42 #: templates/ishtar/sheet_warehouse.html:87 msgid "Containers" msgstr "" -#: models.py:40 +#: models.py:41 msgid "Warehouse types" msgstr "" -#: models.py:60 +#: models.py:61 msgctxt "key for text search" msgid "name" msgstr "" -#: models.py:64 models.py:356 +#: models.py:65 models.py:358 msgctxt "key for text search" msgid "type" msgstr "" -#: models.py:87 +#: models.py:88 msgid "Documents" msgstr "" -#: models.py:89 models.py:390 +#: models.py:90 models.py:392 msgid "External ID" msgstr "" -#: models.py:91 models.py:392 +#: models.py:92 models.py:394 msgid "External ID is set automatically" msgstr "" -#: models.py:95 +#: models.py:96 msgid "Warehouses" msgstr "" -#: models.py:257 +#: models.py:258 msgid "Description" msgstr "" -#: models.py:262 models.py:263 +#: models.py:263 models.py:264 msgid "Collection" msgstr "" -#: models.py:272 +#: models.py:273 msgid "Warehouse division type" msgstr "" -#: models.py:273 +#: models.py:274 msgid "Warehouse division types" msgstr "" -#: models.py:297 +#: models.py:298 msgid "Length (mm)" msgstr "" -#: models.py:298 +#: models.py:299 msgid "Width (mm)" msgstr "" -#: models.py:299 +#: models.py:300 msgid "Height (mm)" msgstr "" -#: models.py:300 +#: models.py:301 msgid "Volume (l)" msgstr "" -#: models.py:305 +#: models.py:307 msgid "Container types" msgstr "" -#: models.py:339 +#: models.py:341 msgid "Location - index" msgstr "" -#: models.py:340 +#: models.py:342 msgid "Precise localisation" msgstr "" -#: models.py:341 +#: models.py:343 msgid "Type" msgstr "" -#: models.py:348 +#: models.py:350 msgctxt "key for text search" msgid "location" msgstr "" -#: models.py:352 +#: models.py:354 msgctxt "key for text search" msgid "responsible-warehouse" msgstr "" -#: models.py:360 +#: models.py:362 msgctxt "key for text search" msgid "reference" msgstr "" -#: models.py:373 +#: models.py:375 msgid "Location (warehouse)" msgstr "" -#: models.py:380 +#: models.py:382 msgid "Container ref." msgstr "" -#: models.py:384 +#: models.py:386 msgid "Cached location" msgstr "" -#: models.py:386 +#: models.py:388 msgid "Cached division" msgstr "" -#: models.py:623 +#: models.py:584 +msgid "Add treatment" +msgstr "" + +#: models.py:639 msgid "Reference" msgstr "" -#: models.py:626 +#: models.py:642 msgid "Container localisation" msgstr "" -#: models.py:627 +#: models.py:643 msgid "Container localisations" msgstr "" @@ -378,26 +378,26 @@ msgid "" "change divisions." msgstr "" -#: views.py:120 +#: views.py:132 msgid "Warehouse creation" msgstr "" -#: views.py:129 +#: views.py:141 msgid "Warehouse modification" msgstr "" -#: views.py:145 +#: views.py:157 msgid "Warehouse deletion" msgstr "" -#: views.py:161 +#: views.py:173 msgid "Container creation" msgstr "" -#: views.py:170 +#: views.py:182 msgid "Container modification" msgstr "" -#: views.py:185 +#: views.py:197 msgid "Container deletion" msgstr "" diff --git a/archaeological_warehouse/migrations/0026_auto_20181203_1442.py b/archaeological_warehouse/migrations/0026_auto_20181203_1442.py new file mode 100644 index 000000000..141ac8d2d --- /dev/null +++ b/archaeological_warehouse/migrations/0026_auto_20181203_1442.py @@ -0,0 +1,374 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-12-03 14:42 +from __future__ import unicode_literals + +from django.conf import settings +import django.contrib.postgres.search +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import re + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_warehouse', '0025_auto_20181112_1842'), + ] + + operations = [ + migrations.AlterModelOptions( + name='container', + options={'ordering': ('cached_label',), 'permissions': (('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')), 'verbose_name': 'Contenant', 'verbose_name_plural': 'Contenants'}, + ), + migrations.AlterModelOptions( + name='containerlocalisation', + options={'ordering': ('container', 'division__order'), 'verbose_name': 'Localisation de contenant', 'verbose_name_plural': 'Localisations de contenant'}, + ), + migrations.AlterModelOptions( + name='containertype', + options={'ordering': ('label',), 'verbose_name': 'Type de contenant', 'verbose_name_plural': 'Types de contenant'}, + ), + migrations.AlterModelOptions( + name='warehouse', + options={'permissions': (('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')), 'verbose_name': 'Lieu de conservation', 'verbose_name_plural': 'Lieux de conservation'}, + ), + migrations.AlterModelOptions( + name='warehousedivision', + options={'verbose_name': 'Type de division de lieu de conservation', 'verbose_name_plural': 'Types de division de lieu de conservation'}, + ), + migrations.AlterModelOptions( + name='warehousetype', + options={'ordering': ('label',), 'verbose_name': 'Type de lieu de conservation', 'verbose_name_plural': 'Types de lieu de conservation'}, + ), + migrations.AlterField( + model_name='collection', + name='history_creator', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Cr\xe9ateur'), + ), + migrations.AlterField( + model_name='collection', + name='history_modifier', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Dernier \xe9diteur'), + ), + migrations.AlterField( + model_name='collection', + name='name', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='collection', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='collection', + name='warehouse', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='collections', to='archaeological_warehouse.Warehouse', verbose_name='Lieu de conservation'), + ), + migrations.AlterField( + model_name='container', + name='auto_external_id', + field=models.BooleanField(default=False, verbose_name="L'identifiant est attribu\xe9 automatiquement"), + ), + migrations.AlterField( + model_name='container', + name='cached_division', + field=models.TextField(blank=True, db_index=True, null=True, verbose_name='Division mise en cache'), + ), + migrations.AlterField( + model_name='container', + name='cached_location', + field=models.TextField(blank=True, db_index=True, null=True, verbose_name='Localisation - en cache'), + ), + migrations.AlterField( + model_name='container', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='container', + name='container_type', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_warehouse.ContainerType', verbose_name='Type de contenant'), + ), + migrations.AlterField( + model_name='container', + name='external_id', + field=models.TextField(blank=True, null=True, verbose_name='Identifiant'), + ), + migrations.AlterField( + model_name='container', + name='history_creator', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Cr\xe9ateur'), + ), + migrations.AlterField( + model_name='container', + name='history_modifier', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Dernier \xe9diteur'), + ), + migrations.AlterField( + model_name='container', + name='location', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='containers', to='archaeological_warehouse.Warehouse', verbose_name='Localisation (lieu de conservation)'), + ), + migrations.AlterField( + model_name='container', + name='old_reference', + field=models.TextField(blank=True, null=True, verbose_name='Ancienne r\xe9f\xe9rence'), + ), + migrations.AlterField( + model_name='container', + name='reference', + field=models.TextField(verbose_name='R\xe9f. du contenant'), + ), + migrations.AlterField( + model_name='container', + name='responsible', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='owned_containers', to='archaeological_warehouse.Warehouse', verbose_name='Lieu de conservation responsable'), + ), + migrations.AlterField( + model_name='container', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='containerlocalisation', + name='container', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='division', to='archaeological_warehouse.Container', verbose_name='Contenant'), + ), + migrations.AlterField( + model_name='containerlocalisation', + name='reference', + field=models.CharField(default=b'', max_length=200, verbose_name='R\xe9f\xe9rence'), + ), + migrations.AlterField( + model_name='containertype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='containertype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='containertype', + name='height', + field=models.IntegerField(blank=True, null=True, verbose_name='Hauteur (mm)'), + ), + migrations.AlterField( + model_name='containertype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='containertype', + name='length', + field=models.IntegerField(blank=True, null=True, verbose_name='Longueur (mm)'), + ), + migrations.AlterField( + model_name='containertype', + name='reference', + field=models.CharField(blank=True, max_length=300, null=True, verbose_name='R\xe9f.'), + ), + migrations.AlterField( + model_name='containertype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='containertype', + name='width', + field=models.IntegerField(blank=True, null=True, verbose_name='Largeur (mm)'), + ), + migrations.AlterField( + model_name='warehouse', + name='address', + field=models.TextField(blank=True, null=True, verbose_name='Adresse'), + ), + migrations.AlterField( + model_name='warehouse', + name='address_complement', + field=models.TextField(blank=True, null=True, verbose_name="Compl\xe9ment d'adresse"), + ), + migrations.AlterField( + model_name='warehouse', + name='alt_address', + field=models.TextField(blank=True, null=True, verbose_name='Autre adresse : adresse'), + ), + migrations.AlterField( + model_name='warehouse', + name='alt_address_complement', + field=models.TextField(blank=True, null=True, verbose_name="Autre adresse : compl\xe9ment d'adresse"), + ), + migrations.AlterField( + model_name='warehouse', + name='alt_address_is_prefered', + field=models.BooleanField(default=False, verbose_name="L'adresse alternative est pr\xe9f\xe9r\xe9e"), + ), + migrations.AlterField( + model_name='warehouse', + name='alt_country', + field=models.CharField(blank=True, max_length=30, null=True, verbose_name='Autre adresse : pays'), + ), + migrations.AlterField( + model_name='warehouse', + name='alt_postal_code', + field=models.CharField(blank=True, max_length=10, null=True, verbose_name='Autre adresse : code postal'), + ), + migrations.AlterField( + model_name='warehouse', + name='alt_town', + field=models.CharField(blank=True, max_length=70, null=True, verbose_name='Autre adresse : ville'), + ), + migrations.AlterField( + model_name='warehouse', + name='auto_external_id', + field=models.BooleanField(default=False, verbose_name="L'identifiant est attribu\xe9 automatiquement"), + ), + migrations.AlterField( + model_name='warehouse', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='warehouse', + name='country', + field=models.CharField(blank=True, max_length=30, null=True, verbose_name='Pays'), + ), + migrations.AlterField( + model_name='warehouse', + name='email', + field=models.EmailField(blank=True, max_length=300, null=True, verbose_name='Courriel'), + ), + migrations.AlterField( + model_name='warehouse', + name='external_id', + field=models.TextField(blank=True, null=True, verbose_name='Identifiant'), + ), + migrations.AlterField( + model_name='warehouse', + name='history_creator', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Cr\xe9ateur'), + ), + migrations.AlterField( + model_name='warehouse', + name='history_modifier', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Dernier \xe9diteur'), + ), + migrations.AlterField( + model_name='warehouse', + name='mobile_phone', + field=models.CharField(blank=True, max_length=18, null=True, verbose_name='T\xe9l\xe9phone portable'), + ), + migrations.AlterField( + model_name='warehouse', + name='name', + field=models.CharField(max_length=200, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='warehouse', + name='person_in_charge', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='warehouse_in_charge', to='ishtar_common.Person', verbose_name='Dossier suivi par'), + ), + migrations.AlterField( + model_name='warehouse', + name='phone', + field=models.CharField(blank=True, max_length=18, null=True, verbose_name='T\xe9l\xe9phone'), + ), + migrations.AlterField( + model_name='warehouse', + name='phone2', + field=models.CharField(blank=True, max_length=18, null=True, verbose_name='Type de t\xe9l\xe9phone 2'), + ), + migrations.AlterField( + model_name='warehouse', + name='phone3', + field=models.CharField(blank=True, max_length=18, null=True, verbose_name='T\xe9l\xe9phone 3'), + ), + migrations.AlterField( + model_name='warehouse', + name='phone_desc', + field=models.CharField(blank=True, max_length=300, null=True, verbose_name='Type de t\xe9l\xe9phone'), + ), + migrations.AlterField( + model_name='warehouse', + name='phone_desc2', + field=models.CharField(blank=True, max_length=300, null=True, verbose_name='Type de t\xe9l\xe9phone 2'), + ), + migrations.AlterField( + model_name='warehouse', + name='phone_desc3', + field=models.CharField(blank=True, max_length=300, null=True, verbose_name='Type de t\xe9l\xe9phone 3'), + ), + migrations.AlterField( + model_name='warehouse', + name='postal_code', + field=models.CharField(blank=True, max_length=10, null=True, verbose_name='Code postal'), + ), + migrations.AlterField( + model_name='warehouse', + name='raw_phone', + field=models.TextField(blank=True, null=True, verbose_name='T\xe9l\xe9phone brut'), + ), + migrations.AlterField( + model_name='warehouse', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='warehouse', + name='town', + field=models.CharField(blank=True, max_length=70, null=True, verbose_name='Commune'), + ), + migrations.AlterField( + model_name='warehouse', + name='warehouse_type', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_warehouse.WarehouseType', verbose_name='Type de lieu de conservation'), + ), + migrations.AlterField( + model_name='warehousedivision', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='warehousedivision', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='warehousedivision', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='warehousedivision', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='warehousedivisionlink', + name='order', + field=models.IntegerField(default=10, verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='warehousetype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='warehousetype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='warehousetype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='warehousetype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + ] diff --git a/archaeological_warehouse/models.py b/archaeological_warehouse/models.py index 5565bc504..92eaf5d2f 100644 --- a/archaeological_warehouse/models.py +++ b/archaeological_warehouse/models.py @@ -21,6 +21,7 @@ import datetime from django.conf import settings from django.contrib.gis.db import models +from django.core.urlresolvers import reverse from django.db.models import Q from django.db.models.signals import post_save, post_delete from django.template.defaultfilters import slugify @@ -311,7 +312,7 @@ post_save.connect(post_save_cache, sender=ContainerType) post_delete.connect(post_save_cache, sender=ContainerType) -class Container(LightHistorizedItem, ImageModel): +class Container(LightHistorizedItem, ImageModel, OwnPerms): TABLE_COLS = ['reference', 'container_type__label', 'cached_location', 'cached_division', 'old_reference'] IMAGE_PREFIX = 'containers/' @@ -570,6 +571,20 @@ class Container(LightHistorizedItem, ImageModel): def set_localisation_9(self, context, value): return self.set_localisation(8, value) + def get_extra_actions(self, request): + """ + extra actions for the sheet template + """ + # url, base_text, icon, extra_text, extra css class, is a quick action + actions = [] + can_edit_find = self.can_do(request, 'change_find') + if can_edit_find: + actions += [ + (reverse('container-add-treatment', args=[self.pk]), + _(u"Add treatment"), "fa fa-exchange", "", "", False), + ] + return actions + def pre_save(self): if not self.index: q = Container.objects.filter(responsible=self.responsible).order_by( diff --git a/archaeological_warehouse/urls.py b/archaeological_warehouse/urls.py index fa895b7c4..47058a352 100644 --- a/archaeological_warehouse/urls.py +++ b/archaeological_warehouse/urls.py @@ -28,8 +28,9 @@ from archaeological_warehouse import models # forms urlpatterns = [ - url(r'warehouse_packaging/(?P<step>.+)?$', - views.warehouse_packaging_wizard, name='warehouse_packaging'), + url(r'warehouse_packaging/(?P<step>.+)?$', # AFAC + check_rights(['change_find', 'change_own_find'])( + views.warehouse_packaging_wizard), name='warehouse_packaging'), url(r'new-warehouse/(?P<parent_name>.+)?/$', views.new_warehouse, name='new-warehouse'), @@ -67,6 +68,11 @@ urlpatterns = [ url(r'warehouse-modify/(?P<pk>.+)/$', views.warehouse_modify, name='warehouse_modify'), + url(r'^container-add-treatment/(?P<pk>[0-9-]+)/$', + check_rights(['change_find', 'change_own_find'])( + views.container_treatment_add), + name='container-add-treatment'), + url(r'^container_search/(?P<step>.+)?$', check_rights(['view_container', 'view_own_container'])( views.container_search_wizard), diff --git a/archaeological_warehouse/views.py b/archaeological_warehouse/views.py index 9b83fd829..83fd7f4e1 100644 --- a/archaeological_warehouse/views.py +++ b/archaeological_warehouse/views.py @@ -21,13 +21,26 @@ import json from django.core.urlresolvers import reverse from django.db.models import Q -from django.http import HttpResponse +from django.http import HttpResponse, Http404 from django.shortcuts import redirect from django.utils.translation import ugettext_lazy as _ -from forms import * +from archaeological_warehouse import models + +from archaeological_warehouse.forms import WarehouseForm, ContainerForm, \ + ContainerFormSelection, BasePackagingForm, WarehouseFormSelection, \ + SelectedDivisionFormset, WarehouseDeletionForm, \ + MainContainerFormSelection, ContainerModifyForm, LocalisationForm, \ + ContainerDeletionForm +from ishtar_common.forms import FinalForm + from ishtar_common.views_item import get_item, show_item, new_item -from wizards import * +from archaeological_finds.views import treatment_add + +from archaeological_warehouse.wizards import PackagingWizard, WarehouseSearch, \ + WarehouseWizard, WarehouseModificationWizard, WarehouseDeletionWizard, \ + ContainerSearch, ContainerWizard, ContainerModificationWizard, \ + ContainerDeletionWizard get_container = get_item(models.Container, 'get_container', 'container') show_container = show_item(models.Container, 'container') @@ -95,10 +108,9 @@ def autocomplete_container(request): for container in containers]) return HttpResponse(data, content_type='text/plain') -warehouse_packaging_wizard = PackagingWizard.as_view([ +warehouse_packaging_wizard = PackagingWizard.as_view([ # AFAC ('seleccontainer-packaging', ContainerFormSelection), ('base-packaging', BasePackagingForm), - # ('multiselecitems-packaging', FindPackagingFormSelection), ('final-packaging', FinalForm)], label=_(u"Packaging"), url_name='warehouse_packaging',) @@ -185,6 +197,15 @@ container_deletion_wizard = ContainerDeletionWizard.as_view([ label=_(u"Container deletion"), url_name='container_deletion',) + +def container_treatment_add(request, pk, current_right=None): + try: + container = models.Container.objects.get(pk=pk) + except models.Container.DoesNotExist: + raise Http404() + return treatment_add( + request, ",".join([str(f.pk) for f in container.finds.all()])) + """ warehouse_packaging_wizard = ItemSourceWizard.as_view([ ('selec-warehouse_packaging', ItemsSelection), diff --git a/archaeological_warehouse/wizards.py b/archaeological_warehouse/wizards.py index 41c5c5945..03258f1e2 100644 --- a/archaeological_warehouse/wizards.py +++ b/archaeological_warehouse/wizards.py @@ -38,9 +38,18 @@ class ContainerSearch(SearchWizard): class PackagingWizard(TreatmentWizard): basket_step = 'base-packaging' + def get_form_initial(self, step, data=None): + initial = super(PackagingWizard, self).get_form_initial(step) + user = self.request.user + if step != 'base-packaging' or not getattr(user, 'ishtaruser', None) \ + or not user.ishtaruser.person: + return initial + initial['person'] = user.ishtaruser.person.pk + return initial + def save_model(self, dct, m2m, whole_associated_models, form_list, return_object): - dct = self.get_extra_model(dct, form_list) + dct = self.get_extra_model(dct, m2m, form_list) obj = self.get_current_saved_object() dct['location'] = dct['container'].location items = None @@ -51,6 +60,8 @@ class PackagingWizard(TreatmentWizard): items = dct.pop('basket') else: dct.pop('basket') + if 'treatment_type_list' in dct: + dct.pop('treatment_type_list') treatment = Treatment(**dct) extra_args_for_new = {"container": dct['container']} treatment.save(items=items, user=self.request.user, diff --git a/docs/fr/source/_static/interface-generale.png b/docs/fr/source/_static/interface-generale.png Binary files differindex f9c9bac22..fb054a075 100644 --- a/docs/fr/source/_static/interface-generale.png +++ b/docs/fr/source/_static/interface-generale.png diff --git a/docs/fr/source/annexe-1-rattachement.rst b/docs/fr/source/annexe-1-rattachement.rst new file mode 100644 index 000000000..2a8f041b4 --- /dev/null +++ b/docs/fr/source/annexe-1-rattachement.rst @@ -0,0 +1,23 @@ +.. -*- coding: utf-8 -*- + +.. _annexe-1-rattachement: + +============================================== +Annexe 1 - Règles de rattachement aux éléments +============================================== + +:Auteur: Étienne Loks +:Date: 2018-12-04 +:Copyright: CC-BY 3.0 + +---------------------------------- + + + + - Opération + + + +.. + TODO: Penser aux zones... + diff --git a/docs/fr/source/annexe-2-permission-action.rst b/docs/fr/source/annexe-2-permission-action.rst new file mode 100644 index 000000000..134237b81 --- /dev/null +++ b/docs/fr/source/annexe-2-permission-action.rst @@ -0,0 +1,17 @@ +.. -*- coding: utf-8 -*- + +.. _annexe-2-permission-action: + +=================================================== +Annexe 2 - Permissions nécessaires pour les actions +=================================================== + +:Auteur: Étienne Loks +:Date: 2018-12-04 +:Copyright: CC-BY 3.0 + +---------------------------------- + + + - Action1.... + diff --git a/docs/fr/source/annexe-3-ex-flux-ope.rst b/docs/fr/source/annexe-3-ex-flux-ope.rst new file mode 100644 index 000000000..462b961c1 --- /dev/null +++ b/docs/fr/source/annexe-3-ex-flux-ope.rst @@ -0,0 +1,92 @@ +.. -*- coding: utf-8 -*- + +============================================================== +Annexe 3 - Exemple de flux opérationnel : prêt pour exposition +============================================================== + +:Auteur: Étienne Loks +:Date: 2018-12-04 +:Copyright: CC-BY 3.0 + +---------------------------------- + +Description +=========== + +Le flux opérationnel « Prêt pour exposition » pourrait par exemple se décomposer suivant ces différentes étapes : + + - pré-sélection du mobilier pour l'exposition par les gestionnaires de mobilier ; + - sélection du mobilier depuis cette pré-selection par la structure emprunteuse ; + - édition des documents administratifs : convention de prêt, assurance ; + - départ effectif du mobilier concerné ; + - gestion du retour du mobilier. + +Pré-requis : + + - les patrons des actes administratifs associés à la demande de prêt ont été créés, + - la personne en charge du prêt a un compte Ishtar qui dispose au minimum : + + - de droits de lecture et modification sur le mobilier éventuellement concerné par la sélection, + - d'un droit de création de demande de traitement, + - d'un droit de création d'acte administratif. + - les gestionnaires de mobilier concernés ont un compte sur Ishtar qui disposent au minimum de droits de lecture sur le mobilier éventuellement concerné par la sélection. + - la structure emprunteuse dispose d'un compte Ishtar avec droit de lecture sur le mobilier rattaché. + + +Pré-sélection du mobilier pour l'exposition par les gestionnaires de mobilier +----------------------------------------------------------------------------- + +1. Un des responsables de mobilier créé un panier depuis l'action rapide « Panier » sur les listes de mobilier (par exemple sur *Mobilier › Recherche*) ou depuis *Mobilier › Panier › Ajout*. +2. Il ajoute quelques éléments à ce panier via l'action rapide « Panier » ou *Mobilier › Panier › Gestion des éléments*. +3. Ce responsable partage ce panier en lecture/édition avec les autres gestionnaires de mobilier via *Mobilier › Panier › Modification*. +4. Les autres gestionnaires peuvent de la même manière ajouter, enlever des éléments à ce panier via l'action rapide « Panier » ou *Mobilier › Panier › Gestion des éléments*. +5. Fin d'étape : tous les gestionnaires ont signifié (oralement, par courriel, etc.) que la pré-sélection actuelle convenait. + + +Sélection du mobilier depuis cette pré-selection par la structure emprunteuse +----------------------------------------------------------------------------- + +1. Si l'on souhaite conserver cette pré-sélection avant partage et modification, elle peut être dupliquée depuis la fiche associée au panier (ouverte par exemple depuis : *Mobilier › Panier › Recherche* ou depuis l'icône « Paniers » sur une des fiches mobilier concernée par ce panier) avec l'icône « Dupliquer ». +2. Le responsable du prêt partage le panier en lecture/édition avec la structure emprunteuse via *Mobilier › Panier › Modification* et l'informe que la pré-selection est disponible (via courriel, téléphone). + +.. note:: Un lien direct peut être donné à la structure emprunteuse pour quelle gère son panier, il suffit d'aller sur le panneau de gestion des éléments du panier concerné (*Mobilier › Panier › Gestion des éléments*) et de recopier l'adresse dans la barre d'adresse. La structure emprunteuse devra préalablement s'identifier avant d'accéder à ce lien. + +.. warning:: Si le droit de lecture de mobilier de la structure emprunteuse est basé sur le mobilier rattaché via ce panier, enlever un élément du panier lui retire le droit de consulter cet élément. Une astuce peut être de partager le panier dupliqué : une fois en lecture seule, une fois en lecture/édition, ainsi même si un élément est retiré du panier en lecture/édition, il reste « rattaché » à la structure emprunteuse par le panier en lecture seule. Le panier en lecture simple peut aussi recevoir des éléments disponibles pour prêt mais pas forcément retenu dans la sélection proposée. + +3. La structure emprunteuse retire du panier les éléments qui ne l'intéresse pas. +4. Fin d'étape : la structure emprunteuse a fini sa sélection et confirme son intérêt pour un prêt (par courriel, ...). + + +Édition des documents administratifs +------------------------------------ + +1. Le responsable du prêt enleve le partage en modification du panier (*Mobilier › Panier › Modification*). +2. Le responsable du prêt crée une demande de traitement « Demande de prêt pour exposition » depuis *Demande de traitement › Ajout*. Il est important de bien renseigner les différents champs pour que la génération des documents se passe bien. Le panier concerné doit être associé à cette demande de traitement. +3. Le responsable du prêt crée les actes administratifs correspondant aux documents administratifs attendus, via l'icône « + acte admin. » de la fiche de demande de traitement ou via *Demande de traitement › Acte administratif › Ajout*. +4. Un document est généré pour chaque acte administratif depuis *Demande de traitement › Acte administratif › Documents*. Ceux-ci peuvent alors être transmis à la structure demandeuse. +5. Fin d'étape : les documents ont été retournés signés. Ils sont éventuellement numérisés et ajoutés en tant que documents à la demande de traitement. + + +Départ effectif du mobilier concerné +------------------------------------ + +1. Le responsable du prêt crée un traitement « Prêt » depuis la fiche de demande de traitement correspondante avec le bouton « Ajouter le traitement associé ». Un contenant correspondant au lieu d'emprunt doit être spécifié. + +.. note:: Le traitement peut être ajouté depuis la fiche panier ou via *Traitement › Traitement simple - Création* mais cela demande de re-sélectionner des éléments du panier ou de la demande de traitement associée. Passer par la fiche de demande de traitement correspondante est moins source d'erreur. + +2. Une alerte spécique est créée depuis le listing mobilier pour surveiller le retour du mobilier avec une chaîne de ce type : :: + + panier="Exposition Sein 2018" pret="Oui" fin-de-traitement-avant="aujourdhui+30" + +3. Avec cette requête, 30 jours avant la date de retour attendue, l'alerte sera affichée. +4. Fin d'étape : le mobilier a été retourné. + + +Gestion du retour du mobilier +----------------------------- + +1. Sur la fiche panier correspondante, sur les fiches contenants correspondants ou sur chaque fiche mobilier par mobilier, un traitement « Retour de prêt » est fait. + +.. note:: Il sera possible d'accéder rapidement aux fiches mobilier ou contenant via le QR-code. + +2. Depuis ces fiches, une demande de traitement « Constat d'état » pourra être ajoutée depuis le bouton « Ajouter une demande de traitement ». diff --git a/docs/fr/source/index.rst b/docs/fr/source/index.rst index 91ef3e740..a22a62ce0 100644 --- a/docs/fr/source/index.rst +++ b/docs/fr/source/index.rst @@ -15,3 +15,6 @@ Contents: interface-utilisateur interface-administrateur installation + annexe-1-rattachement + annexe-2-permission-action + annexe-3-ex-flux-ope diff --git a/docs/fr/source/interface-administrateur.rst b/docs/fr/source/interface-administrateur.rst index 8e8506b6d..651111826 100644 --- a/docs/fr/source/interface-administrateur.rst +++ b/docs/fr/source/interface-administrateur.rst @@ -1,17 +1,251 @@ .. -*- coding: utf-8 -*- -======================== -Interface administrateur -======================== +================================== +Configuration de l'instance Ishtar +================================== :Auteur: Étienne Loks -:Date: 2018-10-02 +:Date: 2018-12-04 :Copyright: CC-BY 3.0 +---------------------------------- + +La configuration d'Ishtar se fait essentiellement par le biais de « l'interface d'administration ». Cette interface propose une vue brute des tables en base de données. Même si cette interface propose une ergonomie simple et pratique, utiliser cette interface peut nécessiter d'avoir connaissance de notions de base d'une base de données pour pouvoir opérer des choix pertinents. + +L'interface d'administration nécessite d'avoir un compte administrateur pour y accéder. Les utilisateurs disposant de ce droit ont une icône « roue dentée » sur la barre de menu à l'extrémité droite. Sauf configuration spécifique, cette interface est aussi disponible via l'adresse « https://monsite-ishtar.net/admin/ » (ajouter `/admin/` à l'adresse de base). + +L'interface d'administration présente la liste des différentes tables par ordre alphabétique regroupées par application. + +.. warning:: Pour des questions de performance, Ishtar utilise intensément un système de cache. Il arrive parfois que celui-ci tarde à se mettre à jour. Il peut arriver que des modifications en administration prennent plusieurs minutes à être prises en compte. + +Listes de types +--------------- + +Ishtar fournit par défaut des données pour chaque liste de choix. Chacune de ces listes est paramétrable en administration. + +Dans les pages d'administration, les listes de types se retrouvent sous les dénominations « Types de ... », rangées par application : + +- **Ishtar - Commun** : contient les listes de types transversales utilisées par plusieurs types d'éléments ; +- **Ishtar - Opération** : contient les listes de types concernant les opérations et les entités archéologiques/sites ; +- **Ishtar - Unités d'enregistrement** : contient les listes de types relatives aux Unités d'enregistrement et aux datations ; +- **Ishtar - Mobilier** : contient les listes de types relatives au mobilier et aux traitements ; +- **Ishtar - Lieu de conservation** : contient les listes de types relatives aux lieux de conservation et aux contenants ; +- **Ishtar - Dossier** : contient les listes de types relatives aux dossiers administratifs. + +Dans Ishtar, chaque type est défini au minimum par les champs suivants : + +- **Dénomination** +- **Identifiant textuel** : L'identifiant textuel est une version standardisée du nom. Il ne contient que des lettres en minuscule non accentuées, des nombres et des tirets (-). Chaque identifiant textuel doit être unique dans la liste de types. Ces identifiants sont des clés permettant les échanges entre bases de données et pour des traductions. Ces identifiants peuvent être utilisés dans le code source de l'application. Une fois créés il ne faut a priori pas changer ces identifiants textuels. +- **Commentaire** : Le contenu du commentaire est affiché dans l'aide en ligne sur les formulaires. +- **Disponibilité** : Décocher ce champ rend indisponible ce type dans les formulaires, sans détruire l'information pour ce qui est déjà présent en base ; l'information est toujours visible dans les fiches. +- **Ordre** : Dans les listes les champs sont ordonnés par ce numéro d'ordre et en cas d'égalité par ordre alphabétique. + +Certains types permettent de mettre en place une hiérarchie. Pour cela le champ **parent** est disponible. Pour chaque type enfant, ce champ est renseigné avec le type parent adéquat. + +Certains types disposent aussi d'autres champs spécifiques ; ceux-ci sont explicites ou disposent d'une aide en ligne. + +.. note:: Pour travailler sur ces listes de types ou les transmettre à des tiers, la possibilité est offerte d'exporter ces listes de types via l'interface d'administration. On sélectionne les éléments à exporter (ou tous les éléments) puis on utilise l'action « Exporter les éléments sélectionnés en fichier CSV ». Le fichier peut alors être édité dans un tableur. Pour une mise à jour, il est important de ne pas modifier les identifiants textuels qui sont la clé de rapprochement pour le ré-import. L'action d'import est disponible en haut à droite : « Import depuis un CSV ». + + +Champs personnalisés +-------------------- + +Ishtar propose un certain nombre de champs standards et génériques permettant de disposer dès le départ d'une base solide et aussi pour assurer un certain degré d'inter-opérabilité entre les différentes installations d'Ishtar. Néanmoins nul ne peut prétendre à l'exhaustivité et, notamment dans le cadre d'une utilisation d'Ishtar axée recherche, le besoin se fera probablement sentir d'ajouter des champs. + +Dans Ishtar ces champs sont appelés : **Champs personnalisés**. Le format JSON étant utilisé pour stocker ces données, le nom **Données JSON** est aussi utilisé. + +Ajouter un champ personnalisé se fait via l'interface d'administration au niveau de la rubrique : *Ishtar - Commun › Données JSON - Champs*. + +Les différentes données à rentrer sont : + +* **Nom** : Ce nom sera repris dans les formulaires et la fiche. +* **Type de contenu** : Le type d'objet auquel sera rattaché le champ - Opération, Site, Unité d'Enregistrement, Mobilier, ... +* **Clé** : Valeur de la clé dans le format JSON. Cette clé ne doit impérativement comporter que des lettres minuscules, sans accent et des tirets bas « _ » (ne pas commencer la clé par le tiret bas et ne pas mettre plusieurs tirets bas d'affilée dans la clé de base). On peut structurer les données personnalisée de manière hiérarchique. Pour les clés hiérarchiques on utilise « __ » entre les sections. Par exemple pour la clé « ma_sousclef » dans la catégorie « ma_categorie », la clé sera notée : *ma_categorie__ma_sousclef*. +* **Type** : Les types de données disponibles sont les suivants : + + * Texte, + * Texte long : le composant de saisie sera une zone de texte, + * Entier : nombre entier positif ou négatif, + * Nombre à virgule, + * Booléen : case à cocher - Vrai ou Faux, + * Date : un composant permettant le choix de date depuis un calendrier est proposé, + * Choix : un composant en autocomplétion sur les valeurs existantes est proposé. L'utilisateur a la possibilité de rentrer librement de nouvelles valeurs. + +* **Ordre** : Le numéro saisie permet d'ordonner par défaut ce champ par rapport aux autres champs. +* **Section** : La section correspond à un titre de section pour présenter ce champ sur la fiche et permettre des regroupements. +* **Utiliser dans les index de recherche** : Si cette case est cochée, la recherche libre indexera le contenu de ce champ. +* **Afficher** : Si cette case n'est pas cochée, ce champ ne sera pas affiché sur la fiche. + +Sauf si un champ personnalisé est uniquement destiné à des données importées et à un affichage sur la fiche, un champ personnalisé sera dans la plupart des cas intégré à un :ref:`formulaire personnalisé <formulaire-personnalise>`. + +.. _formulaire-personnalise: + +Formulaires personnalisés +------------------------- + +La plupart des formulaires peuvent être personnalisés dans Ishtar, notamment tous les formulaires de création/modification ainsi que les formulaires de recherche. À ce jour, il n'est pas encore possible d'ajouter de nouveaux formulaires. + +Les formulaires personnalisés permettent deux choses : soustraire de l'affichage du formulaire les champs disponibles par défaut et ajouter des champs JSON dans le formulaire. Chaque formulaire personnalisé peut être mis à disposition pour tous ou seulement certains utilisateurs. + +La configuration de ces champs se fait en administration via : *Ishtar - Commun › Formulaires personnalisés*. + +La création se fait en deux temps, d'abord un paramétrage des champs de base puis une définition des champs à exclure et des champs JSON à ajouter. + +Le paramétrage de base demande les champs suivants : + + * **Nom** : le nom correspondant au formulaire personnalisé. Ce nom ne sera visible qu'en administration mais pour s'y retrouver, il doit à la fois reprendre le nom du formulaire ainsi que le contexte pour lequel il a été défini. Par exemple : « Mobilier - 020 - Général - Tout utilisateur » ou « Mobilier - 030 - Conservation - Saisie terrain ». +* **Formulaire** : le formulaire à personnaliser. Le nom utilisé permet d'identifier assez simplement le formulaire correspondant car il correspond dans l'ordre (séparé par des tirets) au : + + * type d'objet concerné (par exemple : « Mobilier »), + * éventuellement, le numéro d'ordre dans les formulaires successifs, + * nom du formulaire. +* **À qui s'applique ce formulaire**, cela peut être au choix : + + * à tous les utilisateurs, + * à certains utilisateurs en particulier, + * à certains types d'utilisateurs. + +Une fois ce paramétrage de base enregistré, la configuration précise du formulaire peut se faire : + +* **champs à exclure** : chaque champ de base présent dans le formulaire actuel peut être sélectionné dans la liste pour être écarté de la saisie. +* **champs JSON** : tous les champs JSON préalablement paramétrés concernant l'élément courant (mobilier, OA, ...) peuvent être sélectionnés. La dénomination permet éventuellement de surcharger le nom par défaut du champ JSON. L'ordre permet de placer le champ dans le formulaire. L'aide permet éventuellement d'ajouter un texte pour aider à la saisie. + +.. warning:: Sur les formulaires de création, il est impératif de ne pas exclure des champs obligatoires sans quoi la création devient impossible. + +.. note:: En tant qu'administrateur, en modifiant son profil depuis les pages d'administration (*Ishtar - Commun › Profils d'utilisateurs*) et en cochant « Afficher les numéros des champs », les numéros des champs actuels des formulaires s'affichent sur l'interface, cela permet ainsi de placer plus aisément les champs personnalisés. + + +Gestion des permissions +----------------------- + +Gestion des comptes +******************* + +Dans Ishtar, un compte doit être associé à une personne. Si la personne n'existe pas dans la base, il faut l'ajouter via l'interface principale d'Ishtar : *Annuaire › Personne › Ajout*. + +Ensuite on crée un compte associé à cette personne, toujours via l'interface d'Ishtar : *Administration › Compte › Ajout/modification*. Dans les différents panneaux, il est demandé : l'identifiant du compte, le courriel rattaché, le mot de passe puis le type de profil. + +Les types de profil définiront les types de permissions auxquelles aura accès l'utilisateur. Sur ces types de profil, des zones peuvent être définies afin de permettre des règles de rattachement spécifique (cf. :ref:`permissions dans Ishtar<permissions-ishtar>`). + +Cette interface de création de compte permet aussi de modifier le mot de passe de comptes existants. + +Permissions dans Ishtar +*********************** + +Les permissions dans Ishtar sont essentiellement gérées par « Type de profil ». Chaque compte a un ou plusieurs « types de profil » associés à son compte. Chaque type de profil donne accès à des actions et des accès sur des types d'objets. + +La création/configuration d'un type de profil se fait via : *Ishtar - Commun › Types de profil* : + +- **dénomination** : ce champ doit être explicite car il va être retrouvé au niveau de l'interface utilisateur. +- **identifiant textuel** : rempli selon les règles habituelles des identifiants textuels. +- **groupes** : listes des groupes auxquels le profil est rattaché. + +Chaque groupe correspond à un type de permission pour un élément précis de la base de données : + +- droit de lecture ; +- droit d'ajout ; +- droit de modification/suppression. + +Chacun de ces droit est décliné en deux modalités : + +- droits sur tous les éléments ; +- droit sur les éléments rattachés. + +Un élément est dit « rattaché » à une personne en fonction de règles précises spécifiées dans l':ref:`annexe 1 - règles de rattachement à un élément <annexe-1-rattachement>`. La notion de rattachement permet de spécifier finement les permissions pour des personnes qui sont directement associées à l'élément. Par exemple cela permet donner les droits de modification du mobilier d'une opération au responsable scientifique de cette opération. + +En pratique, globalement, les groupes de droits permettent d'accéder à certaines actions : + +- le droit de lecture permet une ouverture de la fiche correspondant à l'élément ; +- le droit d'ajout permet d'accéder aux actions d'ajout d'un nouvel élément ; +- le droit de modification/suppression permet d'accéder aux actions concernant la modification/suppression des éléments. + +Dans le détail, il y a certaines actions qui sont ouvertes en fonction d'appartenance à des groupes en particulier. Tout cela est détaillé dans l':ref:`annexe 2 - permissions nécessaires pour les actions <annexe-2-permission-action>`. + +.. note:: La page *Ishtar - Commun › Résumés des types de profil* permet d'accéder à un tableau qui reprend et rend explicites toutes les permissions associées aux types de profil. + +Permissions dans les pages d'administration +******************************************* + +Les permissions des pages d'administration sont gérées différemment. Elles utilisent le système de permission du framework Django, framework (cadre de développement logiciel) utilisé par Ishtar. +Une fois le compte créé, les droits se spécifient dans les pages d'administration : *Authentification et autorisation › Utilisateurs*. + +L'ouverture de l'accès aux pages d'administration se fait en cochant le « Statut équipe ». Si l'on souhaite n'ouvrir l'accès qu'à certaines pages spécifiques, on ajoute les « Permissions de l'utilisateur » correspondant aux tables que l'on souhaite ouvrir, si l'on souhaite ouvrir l'accès à toutes les tables, il suffit de cocher le « Statut super-utilisateur ». + + +Patrons de documents +-------------------- + +Principes de base +***************** + +Ishtar propose une génération automatisée de document. Depuis un patron au format LibreOffice (ODT), les données relatives à un élément (acte administratif, mobilier, ...) remplacent les variables du patron pour obtenir le document désiré. + +On créé le patron au format ODT avec un contenu adapté, puis depuis l'interface d'administration, sous l'entrée *Ishtar - Commun › Patrons de document › Document de référence*, on créé un patron de document avec ce fichier ODT associé au type d'élément pour lequel il est destiné. + +Le document peut alors être généré depuis n'importe quelle fiche de l'élément concerné (en haut à droite sous « Documents »). + +Un premier patron +***************** + +Pour créer un patron, la première étape est de récupérer toutes les variables disponibles pour l'élément à partir duquel on veut générer un document. Il existe pour cela un `document de référence`_ que l'on peut attacher à l'élément pour lequel on souhaite éditer un nouveau document. + +.. _document de référence: https://gitlab.com/iggdrasil/ishtar/raw/master/archaeological_operations/tests/document_reference.odt + +.. note:: En cas d'indisponibilité du lien pour ce document, ce document est très simple et peut être recréé facilement, il suffit d'insérer : ``{{VALUES}}`` dans un document ODT vide et de sauvegarder le document. + +Depuis *Ishtar - Commun › Patrons de document › Document de référence*, on ajoute un nouveau patron de document : « Document de référence » auquel on associe le document de référence téléchargé et le type d'élément pour lequel on souhaite créer un patron de document. + +Ensuite, il faut récupérer un document de référence généré depuis la fiche d'un élément contenant tous les champs que l'on souhaite exploiter. + +On ouvre ce document sous LibreOffice. Le document produit contient une liste de clé avec la valeur associée concernant l'élément que l'on a choisi. + +Les différentes clés vont permettre de constituer un patron répondant à ce qui est attendu. Pour cela reprendre un exemple du document que l'on souhaite générer (toujours au format ODT) et remplacer chaque occurence d'une valeur par la clé entourée de deux acccolades, exemple : :: + + Je, sousigné, {{nom_de_ma_clef_1}}, vous accorde un prêt de {{nom_ma_clef_2}}. + +Une fois quelques substitutions faites, on peut l'enregistrer et créer le patron dans l'interface d'administration Ishtar. Ce premier patron est alors disponible depuis la fiche des éléments. + +Notions avancées +**************** + +Conditions +++++++++++ + +Des structures conditionnelles peuvent être mise en place. Cela permet notamment de tester si une valeur a été renseignée et de permettre de contextualiser l'affichage en fonction de cela. Exemple : :: + + Ce traitement sous + {% if responsable %}la responsabilité de {{responsable}} + {% else %}une responsabilité à définir + {% endif %} se tiendra... + +Les structures conditionnelles se structurent autour des mots clés ``if``, ``else`` et ``endif``. On utilise ``{%`` et ``%}`` autour de ces mots clés. La section ``else`` est facultative. + +Attributs ++++++++++ + +Les valeurs utilisées dans les patrons peuvent avoir des attributs correspondant aux noms des colonnes des tables d'éléments utilisés en base de données. Ces attributs sont accédés avec la notation ``.`` . Par exemple, si l'élément a un attribut ``nom``, on accède à la valeur de cet élément avec ``{{element.nom}}``. + + +Parcours de liste ++++++++++++++++++ + +Certaines clés peuvent parfois renvoyer à des listes d'éléments, chacun ayant des attributs. On peut alors parcourir cette liste d'élément de cette manière : :: + + {% for element in liste_elements %} + {{element.nom}} - {{element.prenom}} + {% endfor %} + +Cela se structure autour des mots clés ``for``, ``in`` et ``endfor``. Au lieu de doubles accolades, ``{%`` et ``%}`` encadrent ces mots clés. + +.. + Images + ++++++ + + Il est possible d'utiliser des images dans les patrons. Pour cela il faut placer une image dans le document du patron et modifier son attribut nom sous LibreOffice (clic droit sur l'image, « Propriétés... » et l'onglet « Options ») par une chaîne sous la forme ``{{ mon_image|image }}``. ``mon_image`` correspond au champ image + + -.. _configuration-instance-ishtar: -Configuration de l'instance Ishtar ----------------------------------- -WIP +.. + TODO: Profil d'instance Ishtar diff --git a/docs/fr/source/interface-utilisateur.rst b/docs/fr/source/interface-utilisateur.rst index ce8b5b82f..a7ab19a8c 100644 --- a/docs/fr/source/interface-utilisateur.rst +++ b/docs/fr/source/interface-utilisateur.rst @@ -9,6 +9,9 @@ Interface utilisateur :Copyright: CC-BY 3.0 +---------------------------- + + Interface générale ================== @@ -55,7 +58,7 @@ La zone centrale est totalement contextuelle. Néanmoins si certaines pages d'ac Zone d'alerte et de sélection épinglée -------------------------------------- -Cette zone reprend les éventuelles alertes (cf. :ref:`Page de recherche > Marques-pages et alertes <bookmarks>`), mise en place par l'utilisateur ainsi que les éléments actuellement épinglés (cf. :ref:`Utilisation avancée > Éléments épinglés <pinned>`). +Cette zone reprend les éventuelles alertes (cf. :ref:`Page de recherche > Marques-pages et alertes <bookmarks>`), mise en place par l'utilisateur ainsi que (si l'affichage de ceux-ci est activé) les éléments actuellement épinglés (cf. :ref:`Utilisation avancée > Éléments épinglés <pinned>`). .. _page-de-recherche: @@ -73,6 +76,7 @@ La barre de recherche est composée d'une zone de saisie et d'une série d'icôn - icône « loupe » : lancer la recherche, - icône « engrenage » : accéder à la recherche par facette, - icône « croix » : vider la zone de recherche, +- icône « épingle » : épingler la recherche actuelle pour qu'elle devienne la recherche par défaut pour cette session, - icône « étoile » : enregistrer une alerte, un marque-page, - icône « marque-page » : accéder aux marques-pages (les supprimer). @@ -179,7 +183,7 @@ Ensuite sur la droite, différentes actions sont disponibles. Ces actions dépen - une icône « épingle » : elle permet d'épingler l'élément de la fiche (cf. :ref:`épinglage <pinned>`). - une icône « crayon » : si l'on dispose des droits adéquats, elle permet d'éditer cette fiche. On accède au premier volet des pages d'assistants dédié à l'édition de ce type d'élément. - des icônes « + » : ces icônes permettent d'associer facilement un type particulier d'élément à l'élément de la fiche courante. Par exemple « + doc./image » permet d'associer un document/une image à l'élément de la fiche. -- les icônes « ODT », « PDF » : ces icônes permettent un export ODT ou PDF de la fiche actuelle. +- un menu « exporter » : les éléments de ce menu permettent un export dans différement format de la fiche actuelle. Contenu de la fiche +++++++++++++++++++ @@ -259,8 +263,9 @@ L'épinglage d'élément est un outil de travail permettant de travailler dans u **Exemple** : je souhaite travailler sur le mobilier d'une opération précise. En épinglant cette opération, par défaut, toutes les recherches de mobilier se feront sur cette opération. L'épinglage est disponible directement dans la barre d'outil des fiches. -L'épinglage est aussi disponible dans le menu de gestion des sélections épinglées (à droite de la zone 4 sur l'image de l'interface générale). -Un élément créé ou modifié est automatiquement épinglé. +L'épinglage est aussi disponible au niveau de la barre de recherche (cette recherche épinglée ne concerne que le tableau d'éléments en cours sans gestion hiérarchique). +Si celui-ci est activé dans son profil, l'épinglage est aussi disponible dans le menu de gestion des sélections épinglées (à droite de la zone 4 sur l'image de l'interface générale). +Si on a activé cette option dans son profil, un élément créé ou modifié est automatiquement épinglé. Une gestion hiérarchique des épingles est faites : le fait d'épingler un élément épingle automatiquement ses parents directs. @@ -269,7 +274,7 @@ Une gestion hiérarchique des épingles est faites : le fait d'épingler un élà Menu de gestion des sélections épinglées ++++++++++++++++++++++++++++++++++++++++ -Ce menu propose de sélectionner les éléments que l'on souhaite épingler. Différentes versions de ce menu sont disponible : +Ce menu n'est visible que s'il est activé dans son profil. Il propose de sélectionner les éléments que l'on souhaite épingler. Différentes versions de ce menu sont disponible : - « simple » : des menus déroulants permettent d'épingler les éléments qui sont directement rattachés à notre compte utilisateur (en particulier les éléments que l'on a créé) ; - « avancé - mes éléments » : on épingle ici seulement les éléments rattachés à notre compte utilisateur mais avec des champs fonctionnant en autocompletion ; diff --git a/docs/fr/source/media-src/interface-generale.xcf b/docs/fr/source/media-src/interface-generale.xcf Binary files differindex bb585bd09..f3158a233 100644 --- a/docs/fr/source/media-src/interface-generale.xcf +++ b/docs/fr/source/media-src/interface-generale.xcf diff --git a/docs/fr/source/principes.rst b/docs/fr/source/principes.rst index 5cfd6de3f..32313f990 100644 --- a/docs/fr/source/principes.rst +++ b/docs/fr/source/principes.rst @@ -107,20 +107,20 @@ Opération archéologique L'opération archéologique est le cÅ“ur du modèle de données d'Ishtar. Au sein d'Ishtar, l'opération archéologique est définie comme une action (ou un projet d'action) permettant d'acquérir des données archéologiques, sous la responsabilité d'une personne (exemples : découverte fortuite, diagnostic, fouille programmée, prospection, etc.) et dans un lieu si possible défini. +Si l'opération est au centre du modèle de données d'Ishtar plutôt que le site ou l'entité archéologique, c'est parce que ce dernier est une interprétation (comme toute interprétation, sujette à évolution dans le temps) des données, alors que l'opération est l'information qui permet au mieux de regrouper un corpus documentaire cohérent mettant en lien des documents (plans, rapports, photos, etc.) et du mobilier. + Il est possible de créer des liens entre des opérations, soit en les associant à un même dossier source (avec le module « administratif », ex. : un permis de construire qui est associé à un diagnostic et une fouille préventive), soit en définissant une relation entre des opérations globales (ex. : PCR, suivi d'autoroutes, etc.) et d'autres plus ponctuelles (phases, tranches, secteurs, etc.). Le regroupement d'opérations est également pratique en contexte de fouilles programmées, où il peut être utile d'avoir des inventaires pour chaque opération par année, mais également une vision globale de la succession des fouilles (opération globale). En contexte de grande opération préventive, ce système peut servir à individualiser des secteurs de fouilles disposant de modes d’enregistrements spécifiques. L'utilisateur a toute latitude pour organiser les opérations entres elles selon ses besoins, du moment que ces éléments clefs représentent bien des lots documentaires et mobilier a priori cohérents. Site/entité archéologique ------------------------- -L'opération archéologique a été préférée au site ou l'entité archéologique comme centre des données dans Ishtar parce que les sites/entités sont une interprétation (comme toute interprétation, sujette à évolution dans le temps) des données, alors que l'opération est l'information qui permet au mieux de regrouper un corpus documentaire cohérent mettant en lien des documents (plans, rapports, photos, etc.) et du mobilier. - -Malgré cela, Ishtar gère pleinement les sites (ou entité - notion paramétrable en administration) archéologiques et la migration depuis une base orientée site est tout à fait envisageable. +Malgré le choix de l'opération comme rôle central de son modèle de données, Ishtar gère pleinement les sites (ou entité - notion paramétrable en administration) archéologiques et la migration depuis une base orientée site est tout à fait envisageable. Parcelle -------- -Les parcelles sont gérées précisément au sein d'Ishtar en étant directement rattachées aux UE. Cela permet de faciliter la gestion des questions légales concernant le mobilier (réalisation du « partage » ou responsabilité en cas de restauration). Si la parcelle de l'UE n'est pas connue ou si elle n'est pas sujette a contrainte légale il est possible d'associer une parcelle virtuelle ou de ne pas renseigner ce champ. +Les parcelles sont gérées précisément au sein d'Ishtar en étant directement rattachées aux UE. Cela permet de faciliter la gestion des questions légales concernant le mobilier (réalisation du « partage » ou responsabilité en cas de restauration). Si la parcelle de l'UE n'est pas connue ou si elle n'est pas sujette a contrainte légale, il est possible d'associer une parcelle virtuelle ou de ne pas renseigner ce champ. Unité d'enregistrement ---------------------- diff --git a/drassm_app b/drassm_app -Subproject afd2824264664d7bfecaa3702f495b0fe176fa4 +Subproject db4ff79c01fb71527bac6c00fd1d6831bb90d27 diff --git a/fixtures/initial_data-auth-fr.json b/fixtures/initial_data-auth-fr.json index feecf1e8a..64fbd8051 100644 --- a/fixtures/initial_data-auth-fr.json +++ b/fixtures/initial_data-auth-fr.json @@ -3852,39 +3852,6 @@ { "model": "auth.permission", "fields": { - "name": "Can add Treatment file", - "content_type": [ - "archaeological_finds", - "treatmentfile" - ], - "codename": "add_treatmentfile" - } -}, -{ - "model": "auth.permission", - "fields": { - "name": "Can change Treatment file", - "content_type": [ - "archaeological_finds", - "treatmentfile" - ], - "codename": "change_treatmentfile" - } -}, -{ - "model": "auth.permission", - "fields": { - "name": "Can delete Treatment file", - "content_type": [ - "archaeological_finds", - "treatmentfile" - ], - "codename": "delete_treatmentfile" - } -}, -{ - "model": "auth.permission", - "fields": { "name": "Can add Warehouse division", "content_type": [ "archaeological_warehouse", @@ -4121,7 +4088,7 @@ "archaeological_finds", "treatmentfile" ], - "codename": "view_filetreatment" + "codename": "view_treatmentfile" } }, { @@ -4132,7 +4099,7 @@ "archaeological_finds", "treatmentfile" ], - "codename": "view_own_filetreatment" + "codename": "view_own_treatmentfile" } }, { @@ -4143,7 +4110,7 @@ "archaeological_finds", "treatmentfile" ], - "codename": "add_own_filetreatment" + "codename": "add_own_treatmentfile" } }, { @@ -4154,7 +4121,7 @@ "archaeological_finds", "treatmentfile" ], - "codename": "change_own_filetreatment" + "codename": "change_own_treatmentfile" } }, { @@ -4165,7 +4132,7 @@ "archaeological_finds", "treatmentfile" ], - "codename": "delete_own_filetreatment" + "codename": "delete_own_treatmentfile" } }, { @@ -4308,7 +4275,7 @@ "archaeological_finds", "treatmentfile" ], - "codename": "add_filetreatment" + "codename": "add_treatmentfile" } }, { @@ -4319,7 +4286,7 @@ "archaeological_finds", "treatmentfile" ], - "codename": "change_filetreatment" + "codename": "change_treatmentfile" } }, { @@ -4330,7 +4297,7 @@ "archaeological_finds", "treatmentfile" ], - "codename": "delete_filetreatment" + "codename": "delete_treatmentfile" } }, { @@ -5935,7 +5902,7 @@ "name": "Demandes de traitement : ajout", "permissions": [ [ - "add_filetreatment", + "add_treatmentfile", "archaeological_finds", "treatmentfile" ] @@ -5948,12 +5915,12 @@ "name": "Demandes de traitement : modification/suppression", "permissions": [ [ - "change_filetreatment", + "change_treatmentfile", "archaeological_finds", "treatmentfile" ], [ - "delete_filetreatment", + "delete_treatmentfile", "archaeological_finds", "treatmentfile" ] @@ -5966,7 +5933,7 @@ "name": "Demandes de traitement : lecture", "permissions": [ [ - "view_filetreatment", + "view_treatmentfile", "archaeological_finds", "treatmentfile" ] @@ -5979,7 +5946,7 @@ "name": "Demandes de traitement rattach\u00e9es : ajout", "permissions": [ [ - "add_own_filetreatment", + "add_own_treatmentfile", "archaeological_finds", "treatmentfile" ] @@ -5992,7 +5959,7 @@ "name": "Demandes de traitement rattach\u00e9es : lecture", "permissions": [ [ - "view_own_filetreatment", + "view_own_treatmentfile", "archaeological_finds", "treatmentfile" ] @@ -6005,12 +5972,12 @@ "name": "Demandes de traitement rattach\u00e9es : modification/suppression", "permissions": [ [ - "change_own_filetreatment", + "change_own_treatmentfile", "archaeological_finds", "treatmentfile" ], [ - "delete_own_filetreatment", + "delete_own_treatmentfile", "archaeological_finds", "treatmentfile" ] diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py index 20c65971e..91e9fb3e9 100644 --- a/ishtar_common/forms.py +++ b/ishtar_common/forms.py @@ -341,6 +341,37 @@ class CustomForm(BSForm): return sorted(customs, key=lambda x: x[1]) +class PkWizardSearch(object): + current_model = None + pk_key = None + + @classmethod + def get_formated_datas(cls, cleaned_datas): + if not cls.current_model or not cls.pk_key: + return [] + items = [] + for data in cleaned_datas: + if not data or cls.pk_key not in data or not data[cls.pk_key]: + continue + pks = data[cls.pk_key] + for pk in unicode(pks).split(u','): + if not pk: + continue + try: + items.append( + unicode(cls.current_model.objects.get(pk=int(pk))) + ) + except (cls.current_model.DoesNotExist, ValueError): + continue + return [ + (u"", + mark_safe( + u"<ul class='compact'><li>" + u"</li><li>".join(items) + + u"</li></ul>" + )) + ] + + class CustomFormSearch(forms.Form): need_user_for_initialization = True @@ -405,6 +436,22 @@ class FormSet(CustomForm, BaseFormSet): form.fields[DELETION_FIELD_NAME].label = '' form.fields[DELETION_FIELD_NAME].widget = self.delete_widget() + def _should_delete_form(self, form): + """ + Returns whether or not the form was marked for deletion. + If no data, set deletion to True + """ + if form.cleaned_data.get(DELETION_FIELD_NAME, False): + return True + if not form.cleaned_data or not [ + __ for __ in form.cleaned_data + if __ != DELETION_FIELD_NAME and + form.cleaned_data[__] is not None and + form.cleaned_data[__] != '']: + form.cleaned_data[DELETION_FIELD_NAME] = True + return True + return False + class FormSetWithDeleteSwitches(FormSet): delete_widget = widgets.DeleteSwitchWidget @@ -714,16 +761,19 @@ class QAForm(CustomForm, ManageOldType): elif hasattr(self.fields[k], "choices"): values = [] for v in kwargs['data'].getlist(k): - values.append( - dict(self.fields[k].choices)[int(v)]) + dct_choices = dict(self.fields[k].choices) + if v in dct_choices: + values.append(unicode(dct_choices[v])) + elif int(v) in dct_choices: + values.append(unicode(dct_choices[int(v)])) self.fields[k].rendered_value = mark_safe( u" ; ".join(values)) if k not in self.REPLACE_FIELDS: self.fields[k].label = unicode(self.fields[k].label) + \ - unicode(u" - append to existing") + unicode(_(u" - append to existing")) else: self.fields[k].label = unicode(self.fields[k].label) + \ - unicode(u" - replace") + unicode(_(u" - replace")) def _set_value(self, item, base_key): value = self.cleaned_data[base_key] diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py index 4cc0ca024..e5246d9bb 100644 --- a/ishtar_common/forms_common.py +++ b/ishtar_common/forms_common.py @@ -1176,7 +1176,7 @@ 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 have to attached at least " + raise forms.ValidationError(_(u"A document has to be attached at least " u"to one item")) def save(self, commit=True): diff --git a/ishtar_common/locale/django.pot b/ishtar_common/locale/django.pot index 638f29f22..371b21909 100644 --- a/ishtar_common/locale/django.pot +++ b/ishtar_common/locale/django.pot @@ -34,12 +34,12 @@ msgstr "" msgid "Export selected as CSV file" msgstr "" -#: admin.py:207 models.py:1686 templates/navbar.html:31 +#: admin.py:207 models.py:1703 templates/navbar.html:31 msgid "Profile" msgstr "" #: admin.py:208 forms_common.py:782 forms_common.py:801 forms_common.py:802 -#: models.py:3039 +#: models.py:3063 msgid "Profiles" msgstr "" @@ -61,7 +61,7 @@ msgstr "" msgid "These parents are missing: {}" msgstr "" -#: admin.py:386 admin.py:405 models.py:883 models.py:4141 +#: admin.py:386 admin.py:405 models.py:905 models.py:4214 msgid "Parent" msgstr "" @@ -69,11 +69,11 @@ msgstr "" msgid "Center" msgstr "" -#: admin.py:395 models.py:4003 +#: admin.py:395 models.py:4076 msgid "Limit" msgstr "" -#: admin.py:398 models.py:4013 +#: admin.py:398 models.py:4086 msgid "Town children" msgstr "" @@ -121,16 +121,16 @@ msgstr "" msgid "Hide selected" msgstr "" -#: admin.py:931 models.py:2080 +#: admin.py:931 models.py:2098 msgid "Form" msgstr "" -#: admin.py:933 models.py:2105 models_imports.py:127 +#: admin.py:933 models.py:2123 models_imports.py:127 #: templates/ishtar/dashboards/dashboard_main.html:39 msgid "Users" msgstr "" -#: admin.py:953 models.py:2180 +#: admin.py:953 models.py:2202 msgid "Field" msgstr "" @@ -224,7 +224,7 @@ msgstr "" msgid "Too many cols (%(user_col)d) when maximum is %(ref_col)d" msgstr "" -#: data_importer.py:730 views.py:1177 +#: data_importer.py:730 views.py:1200 msgid "No data provided" msgstr "" @@ -253,7 +253,7 @@ msgid "" "source file." msgstr "" -#: data_importer.py:1236 views.py:1255 views.py:1265 +#: data_importer.py:1236 views.py:1278 views.py:1288 msgid "Not imported" msgstr "" @@ -318,7 +318,7 @@ msgstr "" msgid "Enter a valid name consisting of letters, spaces and hyphens." msgstr "" -#: forms.py:96 forms_common.py:808 views.py:1968 +#: forms.py:96 forms_common.py:808 views.py:2017 msgid "Confirm" msgstr "" @@ -326,36 +326,44 @@ msgstr "" msgid "Are you sure you want to delete?" msgstr "" -#: forms.py:379 +#: forms.py:410 msgid "There are identical items." msgstr "" -#: forms.py:535 +#: forms.py:566 msgid "Last modified by" msgstr "" -#: forms.py:541 +#: forms.py:572 msgid "Modified since" msgstr "" -#: forms.py:565 forms.py:566 +#: forms.py:596 forms.py:597 msgid "Closing date" msgstr "" -#: forms.py:578 forms_common.py:1272 +#: forms.py:609 forms_common.py:1272 msgid "You should select an item." msgstr "" -#: forms.py:579 +#: forms.py:610 msgid "Add a new item" msgstr "" -#: forms.py:769 models.py:2434 +#: forms.py:757 +msgid " - append to existing" +msgstr "" + +#: forms.py:760 +msgid " - replace" +msgstr "" + +#: forms.py:803 models.py:2457 msgid "Template" msgstr "" #: forms_common.py:54 forms_common.py:72 forms_common.py:317 -#: forms_common.py:556 models.py:2568 models.py:4020 +#: forms_common.py:556 models.py:2591 models.py:4093 #: templates/blocks/JQueryAdvancedTown.html:19 msgid "Town" msgstr "" @@ -370,8 +378,8 @@ msgid "" "french town Saint-Denis in the Seine-Saint-Denis department.</p>" msgstr "" -#: forms_common.py:81 forms_common.py:1293 ishtar_menu.py:48 models.py:2952 -#: models.py:3204 models.py:3332 models.py:3495 +#: forms_common.py:81 forms_common.py:1293 ishtar_menu.py:48 models.py:2976 +#: models.py:3228 models.py:3357 models.py:3561 #: templates/ishtar/sheet_person.html:4 msgid "Person" msgstr "" @@ -423,17 +431,17 @@ msgid "all users" msgstr "" #: forms_common.py:305 forms_common.py:475 forms_common.py:609 -#: ishtar_menu.py:76 models.py:2773 models.py:2890 models.py:3292 +#: ishtar_menu.py:76 models.py:2796 models.py:2914 models.py:3317 #: templates/ishtar/sheet_organization.html:4 msgid "Organization" msgstr "" #: forms_common.py:308 forms_common.py:351 forms_common.py:470 #: forms_common.py:526 forms_common.py:604 forms_common.py:790 -#: forms_common.py:823 models.py:1056 models.py:1080 models.py:1879 -#: models.py:2079 models.py:2430 models.py:2765 models.py:2936 models.py:3192 -#: models.py:3999 models.py:4262 models_imports.py:98 models_imports.py:123 -#: models_imports.py:445 models_imports.py:537 models_imports.py:827 +#: forms_common.py:823 models.py:1078 models.py:1102 models.py:1897 +#: models.py:2097 models.py:2453 models.py:2788 models.py:2960 models.py:3216 +#: models.py:4072 models.py:4337 models_imports.py:98 models_imports.py:123 +#: models_imports.py:445 models_imports.py:537 models_imports.py:828 #: templates/ishtar/import_step_by_step.html:102 #: templates/ishtar/import_step_by_step.html:270 #: templates/ishtar/import_table.html:27 @@ -441,40 +449,40 @@ msgstr "" msgid "Name" msgstr "" -#: forms_common.py:309 models.py:2721 models_imports.py:630 +#: forms_common.py:309 models.py:2744 models_imports.py:630 #: models_imports.py:631 msgid "Organization type" msgstr "" -#: forms_common.py:311 forms_common.py:550 models.py:2563 +#: forms_common.py:311 forms_common.py:550 models.py:2586 #: templates/ishtar/blocks/sheet_address_section.html:4 msgid "Address" msgstr "" -#: forms_common.py:313 forms_common.py:553 models.py:2564 +#: forms_common.py:313 forms_common.py:553 models.py:2587 msgid "Address complement" msgstr "" -#: forms_common.py:315 forms_common.py:554 models.py:2566 +#: forms_common.py:315 forms_common.py:554 models.py:2589 msgid "Postal code" msgstr "" -#: forms_common.py:318 forms_common.py:557 models.py:2569 +#: forms_common.py:318 forms_common.py:557 models.py:2592 msgid "Country" msgstr "" #: forms_common.py:320 forms_common.py:472 forms_common.py:530 -#: forms_common.py:606 forms_common.py:731 models.py:2596 +#: forms_common.py:606 forms_common.py:731 models.py:2619 msgid "Email" msgstr "" -#: forms_common.py:321 forms_common.py:533 models.py:2581 +#: forms_common.py:321 forms_common.py:533 models.py:2604 #: templates/ishtar/sheet_person.html:27 #: templates/ishtar/wizard/wizard_person.html:33 msgid "Phone" msgstr "" -#: forms_common.py:322 forms_common.py:542 models.py:2593 +#: forms_common.py:322 forms_common.py:542 models.py:2616 #: templates/ishtar/sheet_person.html:45 #: templates/ishtar/wizard/wizard_person.html:54 msgid "Mobile phone" @@ -486,8 +494,8 @@ msgid "Full text search" msgstr "" #: forms_common.py:352 forms_common.py:473 forms_common.py:607 -#: forms_common.py:788 models.py:1089 models.py:2767 models.py:3738 -#: models_imports.py:680 templates/ishtar/blocks/window_image_detail.html:24 +#: forms_common.py:788 models.py:1111 models.py:2790 models.py:3804 +#: models_imports.py:681 templates/ishtar/blocks/window_image_detail.html:24 #: templates/ishtar/blocks/window_tables/documents.html:8 #: templates/ishtar/import_table.html:28 #: templates/ishtar/sheet_organization.html:25 @@ -510,7 +518,7 @@ msgstr "" msgid "Organization to merge" msgstr "" -#: forms_common.py:471 forms_common.py:524 forms_common.py:605 models.py:2934 +#: forms_common.py:471 forms_common.py:524 forms_common.py:605 models.py:2958 #: templates/ishtar/sheet_organization.html:24 msgid "Surname" msgstr "" @@ -527,25 +535,25 @@ msgstr "" msgid "Identity" msgstr "" -#: forms_common.py:521 forms_common.py:1095 forms_common.py:1217 models.py:2928 -#: models.py:2930 models.py:3729 models_imports.py:632 +#: forms_common.py:521 forms_common.py:1095 forms_common.py:1217 models.py:2952 +#: models.py:2954 models.py:3795 models_imports.py:633 #: templates/ishtar/blocks/window_tables/documents.html:7 msgid "Title" msgstr "" -#: forms_common.py:522 models.py:2932 +#: forms_common.py:522 models.py:2956 msgid "Salutation" msgstr "" -#: forms_common.py:528 models.py:2938 +#: forms_common.py:528 models.py:2962 msgid "Raw name" msgstr "" -#: forms_common.py:531 models.py:2582 +#: forms_common.py:531 models.py:2605 msgid "Phone description" msgstr "" -#: forms_common.py:534 models.py:2584 models.py:2586 +#: forms_common.py:534 models.py:2607 models.py:2609 msgid "Phone description 2" msgstr "" @@ -553,11 +561,11 @@ msgstr "" msgid "Phone 2" msgstr "" -#: forms_common.py:538 models.py:2590 +#: forms_common.py:538 models.py:2613 msgid "Phone description 3" msgstr "" -#: forms_common.py:540 models.py:2588 +#: forms_common.py:540 models.py:2611 msgid "Phone 3" msgstr "" @@ -565,23 +573,23 @@ msgstr "" msgid "Current organization" msgstr "" -#: forms_common.py:559 models.py:2571 +#: forms_common.py:559 models.py:2594 msgid "Other address: address" msgstr "" -#: forms_common.py:562 models.py:2574 +#: forms_common.py:562 models.py:2597 msgid "Other address: address complement" msgstr "" -#: forms_common.py:564 models.py:2575 +#: forms_common.py:564 models.py:2598 msgid "Other address: postal code" msgstr "" -#: forms_common.py:566 models.py:2577 +#: forms_common.py:566 models.py:2600 msgid "Other address: town" msgstr "" -#: forms_common.py:568 models.py:2579 +#: forms_common.py:568 models.py:2602 msgid "Other address: country" msgstr "" @@ -589,7 +597,7 @@ msgstr "" msgid "Already has an account" msgstr "" -#: forms_common.py:603 models.py:3293 +#: forms_common.py:603 models.py:3318 msgid "Username" msgstr "" @@ -597,7 +605,8 @@ msgstr "" msgid "Account search" msgstr "" -#: forms_common.py:669 forms_common.py:709 forms_common.py:713 models.py:2829 +#: forms_common.py:669 forms_common.py:709 forms_common.py:713 models.py:2853 +#: models_imports.py:632 msgid "Person type" msgstr "" @@ -605,7 +614,7 @@ msgstr "" msgid "Account" msgstr "" -#: forms_common.py:734 wizards.py:1639 +#: forms_common.py:734 wizards.py:1651 msgid "New password" msgstr "" @@ -625,7 +634,7 @@ msgstr "" msgid "This username already exists." msgstr "" -#: forms_common.py:789 models.py:3195 models.py:4148 +#: forms_common.py:789 models.py:3219 models.py:4221 msgid "Areas" msgstr "" @@ -633,11 +642,11 @@ msgstr "" msgid "Send the new password by email?" msgstr "" -#: forms_common.py:821 models.py:3197 views.py:968 +#: forms_common.py:821 models.py:3221 views.py:991 msgid "Current profile" msgstr "" -#: forms_common.py:824 models.py:3175 models.py:3194 +#: forms_common.py:824 models.py:3199 models.py:3218 msgid "Profile type" msgstr "" @@ -665,8 +674,8 @@ msgstr "" msgid " (duplicate)" msgstr "" -#: forms_common.py:932 forms_common.py:946 forms_common.py:947 models.py:4021 -#: models.py:4136 +#: forms_common.py:932 forms_common.py:946 forms_common.py:947 models.py:4094 +#: models.py:4209 msgid "Towns" msgstr "" @@ -693,19 +702,19 @@ msgstr "" msgid "Document - General" msgstr "" -#: forms_common.py:1098 forms_common.py:1218 models.py:3543 -#: models_imports.py:633 +#: forms_common.py:1098 forms_common.py:1218 models.py:3609 +#: models_imports.py:634 msgid "Source type" msgstr "" #: forms_common.py:1101 forms_common.py:1152 forms_common.py:1333 -#: forms_common.py:1334 models.py:3504 models.py:3612 models.py:3748 +#: forms_common.py:1334 models.py:3570 models.py:3678 models.py:3814 #: templates/ishtar/blocks/window_image_detail.html:9 #: templates/ishtar/blocks/window_tables/documents.html:9 msgid "Authors" msgstr "" -#: forms_common.py:1105 models.py:3754 +#: forms_common.py:1105 models.py:3820 msgid "Numerical ressource (web address)" msgstr "" @@ -718,7 +727,7 @@ msgctxt "Not directory" msgid "File" msgstr "" -#: forms_common.py:1113 forms_common.py:1219 models.py:4138 +#: forms_common.py:1113 forms_common.py:1219 models.py:4211 msgid "Reference" msgstr "" @@ -726,38 +735,38 @@ msgstr "" msgid "Internal reference" msgstr "" -#: forms_common.py:1118 models.py:3756 +#: forms_common.py:1118 models.py:3822 #: templates/ishtar/blocks/window_image_detail.html:150 msgid "Receipt date" msgstr "" -#: forms_common.py:1120 models.py:3758 models_imports.py:859 +#: forms_common.py:1120 models.py:3824 models_imports.py:860 #: templates/ishtar/blocks/window_image_detail.html:54 msgid "Creation date" msgstr "" -#: forms_common.py:1123 models.py:3761 +#: forms_common.py:1123 models.py:3827 #: templates/ishtar/blocks/window_image_detail.html:160 msgid "Receipt date in documentation" msgstr "" -#: forms_common.py:1125 forms_common.py:1222 models.py:473 models.py:2942 -#: models.py:3421 models.py:3764 models_imports.py:483 +#: forms_common.py:1125 forms_common.py:1222 models.py:496 models.py:2966 +#: models.py:3446 models.py:3830 models_imports.py:483 #: templates/ishtar/blocks/window_image_detail.html:170 msgid "Comment" msgstr "" -#: forms_common.py:1127 forms_common.py:1221 models.py:1884 models.py:3763 +#: forms_common.py:1127 forms_common.py:1221 models.py:1902 models.py:3829 #: models_imports.py:125 models_imports.py:372 models_imports.py:446 msgid "Description" msgstr "" -#: forms_common.py:1130 models.py:3765 +#: forms_common.py:1130 models.py:3831 #: templates/ishtar/blocks/window_image_detail.html:182 msgid "Additional information" msgstr "" -#: forms_common.py:1132 forms_common.py:1225 models.py:3767 +#: forms_common.py:1132 forms_common.py:1225 models.py:3833 #: templates/ishtar/blocks/window_image_detail.html:108 msgid "Has a duplicate" msgstr "" @@ -788,11 +797,11 @@ msgid "You should at least fill one of this field: title, url, image or file." msgstr "" #: forms_common.py:1179 -msgid "A document have to attached at least to one item" +msgid "A document has to be attached at least to one item" msgstr "" #: forms_common.py:1214 forms_common.py:1286 forms_common.py:1321 -#: models.py:3503 templates/ishtar/wizard/wizard_person_deletion.html:139 +#: models.py:3569 templates/ishtar/wizard/wizard_person_deletion.html:139 msgid "Author" msgstr "" @@ -820,7 +829,7 @@ msgstr "" msgid "Would you like to delete this documentation?" msgstr "" -#: forms_common.py:1294 models.py:3468 models.py:3497 models_imports.py:634 +#: forms_common.py:1294 models.py:3534 models.py:3563 models_imports.py:635 msgid "Author type" msgstr "" @@ -832,11 +841,11 @@ msgstr "" msgid "There are identical authors." msgstr "" -#: forms_common.py:1339 models.py:1683 +#: forms_common.py:1339 models.py:1700 msgid "Query" msgstr "" -#: forms_common.py:1344 models.py:1687 +#: forms_common.py:1344 models.py:1704 msgid "Is an alert" msgstr "" @@ -876,7 +885,7 @@ msgstr "" msgid "Deletion" msgstr "" -#: ishtar_menu.py:40 models.py:2209 views.py:992 +#: ishtar_menu.py:40 models.py:2231 views.py:1015 msgid "Global variables" msgstr "" @@ -896,7 +905,7 @@ msgid "Creation" msgstr "" #: ishtar_menu.py:59 ishtar_menu.py:89 ishtar_menu.py:139 -#: templates/ishtar/forms/qa_base.html:29 +#: templates/ishtar/forms/qa_base.html:28 #: templates/ishtar/forms/qa_form.html:16 msgid "Modification" msgstr "" @@ -909,19 +918,19 @@ msgstr "" msgid "Manual merge" msgstr "" -#: ishtar_menu.py:110 models_imports.py:882 +#: ishtar_menu.py:110 models_imports.py:883 msgid "Imports" msgstr "" -#: ishtar_menu.py:113 views.py:1000 +#: ishtar_menu.py:113 views.py:1023 msgid "New import" msgstr "" -#: ishtar_menu.py:117 views.py:1019 +#: ishtar_menu.py:117 views.py:1042 msgid "Current imports" msgstr "" -#: ishtar_menu.py:121 views.py:1468 +#: ishtar_menu.py:121 views.py:1491 msgid "Old imports" msgstr "" @@ -933,35 +942,35 @@ msgstr "" msgid "Not a valid item." msgstr "" -#: models.py:211 +#: models.py:212 msgid "A selected item is not a valid item." msgstr "" -#: models.py:222 +#: models.py:224 msgid "This item already exists." msgstr "" -#: models.py:465 models.py:1682 models.py:2191 models.py:2528 models.py:2544 -#: models.py:3420 models_imports.py:368 +#: models.py:488 models.py:1699 models.py:2213 models.py:2551 models.py:2567 +#: models.py:3445 models_imports.py:368 msgid "Label" msgstr "" -#: models.py:467 +#: models.py:490 msgid "Textual ID" msgstr "" -#: models.py:470 +#: models.py:493 msgid "" "The slug is the standardized version of the name. It contains only lowercase " "letters, numbers and hyphens. Each slug must be unique." msgstr "" -#: models.py:474 models.py:2081 models.py:2437 models.py:3425 +#: models.py:497 models.py:2099 models.py:2460 models.py:3450 #: models_imports.py:139 models_imports.py:542 msgid "Available" msgstr "" -#: models.py:898 models.py:1083 models_imports.py:563 +#: models.py:920 models.py:1105 models_imports.py:563 #: templates/ishtar/formset_import_match.html:21 #: templates/ishtar/import_step_by_step.html:171 #: templates/ishtar/import_step_by_step.html:199 @@ -970,56 +979,56 @@ msgstr "" msgid "Key" msgstr "" -#: models.py:904 +#: models.py:926 msgid "Specific key to an import" msgstr "" -#: models.py:1043 +#: models.py:1065 msgid "Generated relation image (SVG)" msgstr "" -#: models.py:1057 models.py:1091 models.py:1604 models.py:2193 models.py:3465 -#: models.py:4165 models.py:4247 +#: models.py:1079 models.py:1113 models.py:1621 models.py:2215 models.py:3531 +#: models.py:4238 models.py:4320 msgid "Order" msgstr "" -#: models.py:1060 +#: models.py:1082 msgid "Json data - Menu" msgstr "" -#: models.py:1061 +#: models.py:1083 msgid "Json data - Menus" msgstr "" -#: models.py:1069 +#: models.py:1091 msgid "Text" msgstr "" -#: models.py:1070 +#: models.py:1092 msgid "Long text" msgstr "" -#: models.py:1071 models_imports.py:676 +#: models.py:1093 models_imports.py:677 msgid "Integer" msgstr "" -#: models.py:1072 +#: models.py:1094 msgid "Boolean" msgstr "" -#: models.py:1073 models_imports.py:677 +#: models.py:1095 models_imports.py:678 msgid "Float" msgstr "" -#: models.py:1074 models_imports.py:679 +#: models.py:1096 models_imports.py:680 msgid "Date" msgstr "" -#: models.py:1075 +#: models.py:1097 msgid "Choices" msgstr "" -#: models.py:1084 +#: models.py:1106 msgid "" "Value of the key in the JSON schema. For hierarchical key use \"__\" to " "explain it. For instance for the key 'my_subkey' with data such as " @@ -1027,417 +1036,417 @@ msgid "" "my_key__my_subkey." msgstr "" -#: models.py:1088 +#: models.py:1110 msgid "Display" msgstr "" -#: models.py:1092 +#: models.py:1114 msgid "Use in search indexes" msgstr "" -#: models.py:1099 +#: models.py:1121 msgid "Json data - Field" msgstr "" -#: models.py:1100 +#: models.py:1122 msgid "Json data - Fields" msgstr "" -#: models.py:1111 +#: models.py:1133 msgid "Content types of the field and of the menu do not match" msgstr "" -#: models.py:1171 +#: models.py:1193 msgid "Search vector" msgstr "" -#: models.py:1172 +#: models.py:1194 msgid "Auto filled at save" msgstr "" -#: models.py:1392 +#: models.py:1409 msgid "Add document/image" msgstr "" -#: models.py:1394 +#: models.py:1411 msgid "doc./image" msgstr "" -#: models.py:1413 +#: models.py:1430 msgid "Last editor" msgstr "" -#: models.py:1416 +#: models.py:1433 msgid "Creator" msgstr "" -#: models.py:1597 +#: models.py:1614 msgid "Above" msgstr "" -#: models.py:1598 +#: models.py:1615 msgid "Bellow" msgstr "" -#: models.py:1599 +#: models.py:1616 msgid "Equal" msgstr "" -#: models.py:1605 +#: models.py:1622 msgid "Symmetrical" msgstr "" -#: models.py:1606 +#: models.py:1623 msgid "Tiny label" msgstr "" -#: models.py:1609 +#: models.py:1626 msgid "Inverse relation" msgstr "" -#: models.py:1612 +#: models.py:1629 msgid "Logical relation" msgstr "" -#: models.py:1622 +#: models.py:1639 msgid "Cannot have symmetrical and an inverse_relation" msgstr "" -#: models.py:1685 +#: models.py:1702 msgid "Content type" msgstr "" -#: models.py:1690 +#: models.py:1707 msgid "Search query" msgstr "" -#: models.py:1691 +#: models.py:1708 msgid "Search queries" msgstr "" -#: models.py:1855 +#: models.py:1873 msgid "Euro" msgstr "" -#: models.py:1856 +#: models.py:1874 msgid "US dollar" msgstr "" -#: models.py:1857 views.py:742 views.py:803 +#: models.py:1875 views.py:765 views.py:826 msgid "Operations" msgstr "" -#: models.py:1858 views.py:744 views.py:807 +#: models.py:1876 views.py:767 views.py:830 msgid "Context records" msgstr "" -#: models.py:1859 +#: models.py:1877 msgid "Site" msgstr "" -#: models.py:1859 +#: models.py:1877 msgid "Archaeological entity" msgstr "" -#: models.py:1863 +#: models.py:1881 msgid "Site search" msgstr "" -#: models.py:1864 +#: models.py:1882 msgid "New site" msgstr "" -#: models.py:1865 +#: models.py:1883 msgid "Site modification" msgstr "" -#: models.py:1866 +#: models.py:1884 msgid "Site deletion" msgstr "" -#: models.py:1869 +#: models.py:1887 msgid "Archaeological entity search" msgstr "" -#: models.py:1870 +#: models.py:1888 msgid "New archaeological entity" msgstr "" -#: models.py:1871 +#: models.py:1889 msgid "Archaeological entity modification" msgstr "" -#: models.py:1872 +#: models.py:1890 msgid "Archaeological entity deletion" msgstr "" -#: models.py:1880 models.py:2431 models_imports.py:124 +#: models.py:1898 models.py:2454 models_imports.py:124 msgid "Slug" msgstr "" -#: models.py:1881 +#: models.py:1899 msgid "Current active" msgstr "" -#: models.py:1883 +#: models.py:1901 msgid "Activate experimental feature" msgstr "" -#: models.py:1886 +#: models.py:1904 msgid "Alternate configuration" msgstr "" -#: models.py:1888 +#: models.py:1906 msgid "Choose an alternate configuration for label, index management" msgstr "" -#: models.py:1892 +#: models.py:1910 msgid "Files module" msgstr "" -#: models.py:1894 +#: models.py:1912 msgid "Archaeological site module" msgstr "" -#: models.py:1896 +#: models.py:1914 msgid "Archaeological site type" msgstr "" -#: models.py:1900 +#: models.py:1918 msgid "Context records module" msgstr "" -#: models.py:1902 +#: models.py:1920 msgid "Finds module" msgstr "" -#: models.py:1903 +#: models.py:1921 msgid "Need context records module" msgstr "" -#: models.py:1905 +#: models.py:1923 msgid "Find index is based on" msgstr "" -#: models.py:1907 +#: models.py:1925 msgid "" "To prevent irrelevant indexes, change this parameter only if there is no " "find in the database" msgstr "" -#: models.py:1910 +#: models.py:1928 msgid "Warehouses module" msgstr "" -#: models.py:1911 +#: models.py:1929 msgid "Need finds module" msgstr "" -#: models.py:1912 +#: models.py:1930 msgid "Preservation module" msgstr "" -#: models.py:1914 +#: models.py:1932 msgid "Mapping module" msgstr "" -#: models.py:1915 +#: models.py:1933 msgid "Underwater module" msgstr "" -#: models.py:1917 +#: models.py:1935 msgid "Parcel are mandatory for context records" msgstr "" -#: models.py:1919 +#: models.py:1937 msgid "Home page" msgstr "" -#: models.py:1920 +#: models.py:1938 #, python-brace-format msgid "" "Homepage of Ishtar - if not defined a default homepage will appear. Use the " "markdown syntax. {random_image} can be used to display a random image." msgstr "" -#: models.py:1924 +#: models.py:1942 msgid "Main operation code prefix" msgstr "" -#: models.py:1928 +#: models.py:1946 msgid "Default operation code prefix" msgstr "" -#: models.py:1932 +#: models.py:1950 msgid "Operation region code" msgstr "" -#: models.py:1936 +#: models.py:1954 msgid "File external id" msgstr "" -#: models.py:1938 +#: models.py:1956 msgid "" "Formula to manage file external ID. Change this with care. With incorrect " "formula, the application might be unusable and import of external data can " "be destructive." msgstr "" -#: models.py:1943 +#: models.py:1961 msgid "Parcel external id" msgstr "" -#: models.py:1946 +#: models.py:1964 msgid "" "Formula to manage parcel external ID. Change this with care. With incorrect " "formula, the application might be unusable and import of external data can " "be destructive." msgstr "" -#: models.py:1951 +#: models.py:1969 msgid "Context record external id" msgstr "" -#: models.py:1953 +#: models.py:1971 msgid "" "Formula to manage context record external ID. Change this with care. With " "incorrect formula, the application might be unusable and import of external " "data can be destructive." msgstr "" -#: models.py:1958 +#: models.py:1976 msgid "Base find external id" msgstr "" -#: models.py:1960 +#: models.py:1978 msgid "" "Formula to manage base find external ID. Change this with care. With " "incorrect formula, the application might be unusable and import of external " "data can be destructive." msgstr "" -#: models.py:1965 +#: models.py:1983 msgid "Find external id" msgstr "" -#: models.py:1967 +#: models.py:1985 msgid "" "Formula to manage find external ID. Change this with care. With incorrect " "formula, the application might be unusable and import of external data can " "be destructive." msgstr "" -#: models.py:1972 +#: models.py:1990 msgid "Container external id" msgstr "" -#: models.py:1974 +#: models.py:1992 msgid "" "Formula to manage container external ID. Change this with care. With " "incorrect formula, the application might be unusable and import of external " "data can be destructive." msgstr "" -#: models.py:1979 +#: models.py:1997 msgid "Warehouse external id" msgstr "" -#: models.py:1981 +#: models.py:1999 msgid "" "Formula to manage warehouse external ID. Change this with care. With " "incorrect formula, the application might be unusable and import of external " "data can be destructive." msgstr "" -#: models.py:1986 +#: models.py:2004 msgid "Raw name for person" msgstr "" -#: models.py:1988 +#: models.py:2006 msgid "" "Formula to manage person raw_name. Change this with care. With incorrect " "formula, the application might be unusable and import of external data can " "be destructive." msgstr "" -#: models.py:1992 +#: models.py:2010 msgid "Use auto index for finds" msgstr "" -#: models.py:1994 +#: models.py:2012 msgid "Currency" msgstr "" -#: models.py:1998 +#: models.py:2016 msgid "Ishtar site profile" msgstr "" -#: models.py:1999 +#: models.py:2017 msgid "Ishtar site profiles" msgstr "" -#: models.py:2083 +#: models.py:2101 msgid "Enable this form" msgstr "" -#: models.py:2084 +#: models.py:2102 msgid "" "Disable with caution: disabling a form with mandatory fields may lead to " "database errors." msgstr "" -#: models.py:2087 +#: models.py:2105 msgid "Apply to all" msgstr "" -#: models.py:2088 +#: models.py:2106 msgid "" "Apply this form to all users. If set to True, selecting user and user type " "is useless." msgstr "" -#: models.py:2094 +#: models.py:2112 msgid "Custom form" msgstr "" -#: models.py:2095 +#: models.py:2113 msgid "Custom forms" msgstr "" -#: models.py:2111 +#: models.py:2129 msgid "User types" msgstr "" -#: models.py:2183 +#: models.py:2205 msgid "Excluded field" msgstr "" -#: models.py:2184 +#: models.py:2206 msgid "Excluded fields" msgstr "" -#: models.py:2194 templates/blocks/form_flex_snippet.html:18 +#: models.py:2216 templates/blocks/form_flex_snippet.html:18 #: templates/blocks/table_form_snippet.html:9 msgid "Help" msgstr "" -#: models.py:2197 +#: models.py:2219 msgid "Custom form - Json data field" msgstr "" -#: models.py:2198 +#: models.py:2220 msgid "Custom form - Json data fields" msgstr "" -#: models.py:2202 +#: models.py:2224 msgid "Variable name" msgstr "" -#: models.py:2203 +#: models.py:2225 msgid "Description of the variable" msgstr "" -#: models.py:2205 models_imports.py:564 +#: models.py:2227 models_imports.py:564 #: templates/ishtar/formset_import_match.html:22 #: templates/ishtar/import_step_by_step.html:172 #: templates/ishtar/import_step_by_step.html:200 @@ -1445,559 +1454,563 @@ msgstr "" msgid "Value" msgstr "" -#: models.py:2208 +#: models.py:2230 msgid "Global variable" msgstr "" -#: models.py:2335 models.py:2365 +#: models.py:2358 models.py:2388 msgid "Total" msgstr "" -#: models.py:2342 models.py:2529 models.py:2545 +#: models.py:2365 models.py:2552 models.py:2568 #: templates/ishtar/dashboards/dashboard_main_detail.html:211 #: templates/ishtar/dashboards/dashboard_main_detail_users.html:5 #: templates/ishtar/sheet_person.html:30 msgid "Number" msgstr "" -#: models.py:2429 +#: models.py:2452 msgid "Administrative Act" msgstr "" -#: models.py:2436 +#: models.py:2459 msgid "Associated object" msgstr "" -#: models.py:2441 +#: models.py:2464 msgid "Document template" msgstr "" -#: models.py:2442 +#: models.py:2465 msgid "Document templates" msgstr "" -#: models.py:2533 models.py:2546 models.py:4285 models_imports.py:853 +#: models.py:2556 models.py:2569 models.py:4360 models_imports.py:854 msgid "State" msgstr "" -#: models.py:2551 models.py:4007 templates/blocks/JQueryAdvancedTown.html:12 +#: models.py:2574 models.py:4080 templates/blocks/JQueryAdvancedTown.html:12 msgid "Department" msgstr "" -#: models.py:2552 +#: models.py:2575 msgid "Departments" msgstr "" -#: models.py:2592 +#: models.py:2615 msgid "Raw phone" msgstr "" -#: models.py:2598 +#: models.py:2621 msgid "Alternative address is prefered" msgstr "" -#: models.py:2637 +#: models.py:2660 msgid "Tel: " msgstr "" -#: models.py:2641 +#: models.py:2664 msgid "Mobile: " msgstr "" -#: models.py:2645 +#: models.py:2668 msgid "Email: " msgstr "" -#: models.py:2650 +#: models.py:2673 msgid "Merge key" msgstr "" -#: models.py:2722 +#: models.py:2745 msgid "Organization types" msgstr "" -#: models.py:2749 models.py:2896 models.py:3303 +#: models.py:2772 models.py:2920 models.py:3328 msgctxt "key for text search" msgid "name" msgstr "" -#: models.py:2753 models.py:2908 models.py:3315 models.py:3639 +#: models.py:2776 models.py:2932 models.py:3340 models.py:3705 msgctxt "key for text search" msgid "type" msgstr "" -#: models.py:2768 models.py:2947 models.py:3498 models.py:4015 +#: models.py:2791 models.py:2971 models.py:3564 models.py:4088 msgid "Cached name" msgstr "" -#: models.py:2774 +#: models.py:2797 msgid "Organizations" msgstr "" -#: models.py:2804 +#: models.py:2828 msgid "unknown organization" msgstr "" -#: models.py:2830 +#: models.py:2854 msgid "Person types" msgstr "" -#: models.py:2843 models_imports.py:670 +#: models.py:2867 models_imports.py:671 msgid "Title type" msgstr "" -#: models.py:2844 +#: models.py:2868 msgid "Title types" msgstr "" -#: models.py:2868 +#: models.py:2892 msgid "Mr" msgstr "" -#: models.py:2869 +#: models.py:2893 msgid "Miss" msgstr "" -#: models.py:2870 +#: models.py:2894 msgid "Mr and Mrs" msgstr "" -#: models.py:2871 +#: models.py:2895 msgid "Mrs" msgstr "" -#: models.py:2872 +#: models.py:2896 msgid "Doctor" msgstr "" -#: models.py:2900 models.py:3307 +#: models.py:2924 models.py:3332 msgctxt "key for text search" msgid "surname" msgstr "" -#: models.py:2904 models.py:3311 +#: models.py:2928 models.py:3336 msgctxt "key for text search" msgid "email" msgstr "" -#: models.py:2912 models.py:3319 +#: models.py:2936 models.py:3344 msgctxt "key for text search" msgid "organization" msgstr "" -#: models.py:2916 +#: models.py:2940 msgctxt "key for text search" msgid "has-account" msgstr "" -#: models.py:2940 +#: models.py:2964 msgid "Contact type" msgstr "" -#: models.py:2943 models.py:3033 +#: models.py:2967 models.py:3057 msgid "Types" msgstr "" -#: models.py:2946 +#: models.py:2970 msgid "Is attached to" msgstr "" -#: models.py:2953 +#: models.py:2977 msgid "Persons" msgstr "" -#: models.py:3171 +#: models.py:3195 msgid "Groups" msgstr "" -#: models.py:3176 +#: models.py:3200 msgid "Profile types" msgstr "" -#: models.py:3187 +#: models.py:3211 msgid "Profile type summary" msgstr "" -#: models.py:3188 +#: models.py:3212 msgid "Profile types summary" msgstr "" -#: models.py:3199 +#: models.py:3223 msgid "Show field number" msgstr "" -#: models.py:3200 +#: models.py:3224 msgid "Automatically pin" msgstr "" -#: models.py:3201 +#: models.py:3225 msgid "Display pin menu" msgstr "" -#: models.py:3207 +#: models.py:3231 msgid "User profile" msgstr "" -#: models.py:3208 +#: models.py:3232 msgid "User profiles" msgstr "" -#: models.py:3243 +#: models.py:3267 models.py:3522 msgid " - duplicate" msgstr "" -#: models.py:3299 +#: models.py:3324 msgctxt "key for text search" msgid "username" msgstr "" -#: models.py:3335 +#: models.py:3360 msgid "Advanced shortcut menu" msgstr "" -#: models.py:3338 +#: models.py:3363 msgid "Ishtar user" msgstr "" -#: models.py:3339 +#: models.py:3364 msgid "Ishtar users" msgstr "" -#: models.py:3424 +#: models.py:3449 msgid "Owner" msgstr "" -#: models.py:3427 -msgid "Shared with" +#: models.py:3452 +msgid "Shared (read) with" +msgstr "" + +#: models.py:3456 +msgid "Shared (read/edit) with" msgstr "" -#: models.py:3469 +#: models.py:3535 msgid "Author types" msgstr "" -#: models.py:3544 +#: models.py:3610 msgid "Source types" msgstr "" -#: models.py:3554 models_imports.py:669 +#: models.py:3620 models_imports.py:670 msgid "Support type" msgstr "" -#: models.py:3555 +#: models.py:3621 msgid "Support types" msgstr "" -#: models.py:3564 +#: models.py:3630 msgid "Format type" msgstr "" -#: models.py:3565 +#: models.py:3631 msgid "Format types" msgstr "" -#: models.py:3574 +#: models.py:3640 msgid "URL" msgstr "" -#: models.py:3577 +#: models.py:3643 msgid "License type" msgstr "" -#: models.py:3578 +#: models.py:3644 msgid "License types" msgstr "" -#: models.py:3631 +#: models.py:3697 msgctxt "key for text search" msgid "author" msgstr "" -#: models.py:3635 +#: models.py:3701 msgctxt "key for text search" msgid "title" msgstr "" -#: models.py:3643 +#: models.py:3709 msgctxt "key for text search" msgid "reference" msgstr "" -#: models.py:3647 +#: models.py:3713 msgctxt "key for text search" msgid "internal-reference" msgstr "" -#: models.py:3651 +#: models.py:3717 msgctxt "key for text search" msgid "description" msgstr "" -#: models.py:3655 +#: models.py:3721 msgctxt "key for text search" msgid "comment" msgstr "" -#: models.py:3659 +#: models.py:3725 msgctxt "key for text search" msgid "additional-information" msgstr "" -#: models.py:3663 +#: models.py:3729 msgctxt "key for text search" msgid "has-duplicate" msgstr "" -#: models.py:3667 models.py:3714 +#: models.py:3733 models.py:3780 msgctxt "key for text search" msgid "operation" msgstr "" -#: models.py:3671 models.py:3717 +#: models.py:3737 models.py:3783 msgctxt "key for text search" msgid "context-record" msgstr "" -#: models.py:3675 models.py:3719 +#: models.py:3741 models.py:3785 msgctxt "key for text search" msgid "find" msgstr "" -#: models.py:3679 models.py:3718 +#: models.py:3745 models.py:3784 msgctxt "key for text search" msgid "file" msgstr "" -#: models.py:3683 models.py:3720 +#: models.py:3749 models.py:3786 msgctxt "key for text search" msgid "site" msgstr "" -#: models.py:3687 models.py:3721 +#: models.py:3753 models.py:3787 msgctxt "key for text search" msgid "warehouse" msgstr "" -#: models.py:3723 +#: models.py:3789 msgctxt "key for text search" msgid "treatment" msgstr "" -#: models.py:3726 +#: models.py:3792 msgctxt "key for text search" msgid "treatment-file" msgstr "" -#: models.py:3732 +#: models.py:3798 msgid "Index" msgstr "" -#: models.py:3734 +#: models.py:3800 msgid "External ID" msgstr "" -#: models.py:3735 templates/ishtar/blocks/window_image_detail.html:34 +#: models.py:3801 templates/ishtar/blocks/window_image_detail.html:34 msgid "Ref." msgstr "" -#: models.py:3736 templates/ishtar/blocks/window_image_detail.html:44 +#: models.py:3802 templates/ishtar/blocks/window_image_detail.html:44 msgid "Internal ref." msgstr "" -#: models.py:3740 +#: models.py:3806 msgid "License" msgstr "" -#: models.py:3742 templates/ishtar/blocks/window_image_detail.html:78 +#: models.py:3808 templates/ishtar/blocks/window_image_detail.html:78 msgid "Support" msgstr "" -#: models.py:3744 models_imports.py:635 +#: models.py:3810 models_imports.py:636 #: templates/ishtar/blocks/window_image_detail.html:88 msgid "Format" msgstr "" -#: models.py:3746 templates/ishtar/blocks/window_image_detail.html:98 +#: models.py:3812 templates/ishtar/blocks/window_image_detail.html:98 msgid "Scale" msgstr "" -#: models.py:3750 +#: models.py:3816 msgid "Authors (raw)" msgstr "" -#: models.py:3762 templates/ishtar/blocks/window_image_detail.html:118 +#: models.py:3828 templates/ishtar/blocks/window_image_detail.html:118 msgid "Number of items" msgstr "" -#: models.py:3769 +#: models.py:3835 msgid "Symbolic links" msgstr "" -#: models.py:3772 +#: models.py:3838 msgid "Related" msgstr "" -#: models.py:3773 +#: models.py:3839 msgid "Cached value - do not edit" msgstr "" -#: models.py:3776 templates/ishtar/sheet_document.html:4 +#: models.py:3842 templates/ishtar/sheet_document.html:4 msgid "Document" msgstr "" -#: models.py:3777 templates/ishtar/sheet_person.html:113 +#: models.py:3843 templates/ishtar/sheet_person.html:113 msgid "Documents" msgstr "" -#: models.py:3781 +#: models.py:3847 msgid "Can view all Documents" msgstr "" -#: models.py:3783 +#: models.py:3849 msgid "Can view own Document" msgstr "" -#: models.py:3785 +#: models.py:3851 msgid "Can add own Document" msgstr "" -#: models.py:3787 +#: models.py:3853 msgid "Can change own Document" msgstr "" -#: models.py:3789 +#: models.py:3855 msgid "Can delete own Document" msgstr "" -#: models.py:4000 +#: models.py:4073 msgid "Surface (m2)" msgstr "" -#: models.py:4001 +#: models.py:4074 msgid "Localisation" msgstr "" -#: models.py:4009 +#: models.py:4082 msgid "Year of creation" msgstr "" -#: models.py:4010 +#: models.py:4083 msgid "Filling this field is relevant to distinguish old towns from new towns." msgstr "" -#: models.py:4142 +#: models.py:4215 msgid "Only four level of parent are managed." msgstr "" -#: models.py:4147 +#: models.py:4220 msgid "Area" msgstr "" -#: models.py:4166 +#: models.py:4239 msgid "Is preventive" msgstr "" -#: models.py:4167 +#: models.py:4240 msgid "Is judiciary" msgstr "" -#: models.py:4170 models_imports.py:636 +#: models.py:4243 models_imports.py:637 msgid "Operation type" msgstr "" -#: models.py:4171 +#: models.py:4244 msgid "Operation types" msgstr "" -#: models.py:4210 +#: models.py:4283 msgid "Judiciary" msgstr "" -#: models.py:4212 +#: models.py:4285 msgid "Preventive" msgstr "" -#: models.py:4214 +#: models.py:4287 msgid "Research" msgstr "" -#: models.py:4249 +#: models.py:4322 msgid "Authority name" msgstr "" -#: models.py:4250 +#: models.py:4323 msgid "Authority SRID" msgstr "" -#: models.py:4253 models_imports.py:668 +#: models.py:4326 models_imports.py:669 msgid "Spatial reference system" msgstr "" -#: models.py:4254 +#: models.py:4327 msgid "Spatial reference systems" msgstr "" -#: models.py:4261 +#: models.py:4336 msgid "Filename" msgstr "" -#: models.py:4266 +#: models.py:4341 msgid "Administration script" msgstr "" -#: models.py:4267 +#: models.py:4342 msgid "Administration scripts" msgstr "" -#: models.py:4274 +#: models.py:4349 msgid "Scheduled" msgstr "" -#: models.py:4275 +#: models.py:4350 msgid "In progress" msgstr "" -#: models.py:4276 models_imports.py:792 +#: models.py:4351 models_imports.py:793 msgid "Finished with errors" msgstr "" -#: models.py:4277 models_imports.py:793 +#: models.py:4352 models_imports.py:794 msgid "Finished" msgstr "" -#: models.py:4290 +#: models.py:4365 msgid "Result" msgstr "" -#: models.py:4293 +#: models.py:4368 msgid "Administration task" msgstr "" -#: models.py:4294 +#: models.py:4369 msgid "Administration tasks" msgstr "" -#: models.py:4298 +#: models.py:4373 msgid "Unknown" msgstr "" -#: models.py:4313 +#: models.py:4388 msgid "" "ISHTAR_SCRIPT_DIR is not set in your local_settings. Contact your " "administrator." msgstr "" -#: models.py:4322 +#: models.py:4397 msgid "" "Your ISHTAR_SCRIPT_DIR is containing dots \"..\". As it can refer to " "relative paths, it can be a security issue and this is not allowed. Only put " "a full path." msgstr "" -#: models.py:4333 +#: models.py:4408 msgid "Your ISHTAR_SCRIPT_DIR: \"{}\" is not a valid directory." msgstr "" -#: models.py:4349 +#: models.py:4424 msgid "" "Script \"{}\" is not available in your script directory. Check your " "configuration." @@ -2028,7 +2041,7 @@ msgid "Leave blank for no restrictions" msgstr "" #: models_imports.py:136 -msgid "Is template" +msgid "Can be exported" msgstr "" #: models_imports.py:137 @@ -2136,11 +2149,11 @@ msgstr "" msgid "Importer - Targets" msgstr "" -#: models_imports.py:525 views_item.py:847 +#: models_imports.py:525 views_item.py:346 views_item.py:950 msgid "True" msgstr "" -#: models_imports.py:526 views_item.py:849 +#: models_imports.py:526 views_item.py:952 msgid "False" msgstr "" @@ -2172,327 +2185,327 @@ msgstr "" msgid "Importer - Targets keys" msgstr "" -#: models_imports.py:637 +#: models_imports.py:638 msgid "Period" msgstr "" -#: models_imports.py:638 +#: models_imports.py:639 msgid "Report state" msgstr "" -#: models_imports.py:639 +#: models_imports.py:640 msgid "Remain type" msgstr "" -#: models_imports.py:640 +#: models_imports.py:641 msgid "Unit" msgstr "" -#: models_imports.py:642 +#: models_imports.py:643 msgid "Activity type" msgstr "" -#: models_imports.py:644 +#: models_imports.py:645 msgid "Documentation type" msgstr "" -#: models_imports.py:645 +#: models_imports.py:646 msgid "Material" msgstr "" -#: models_imports.py:647 +#: models_imports.py:648 msgid "Conservatory state" msgstr "" -#: models_imports.py:648 +#: models_imports.py:649 msgid "Container type" msgstr "" -#: models_imports.py:650 +#: models_imports.py:651 msgid "Warehouse division" msgstr "" -#: models_imports.py:651 +#: models_imports.py:652 msgid "Warehouse type" msgstr "" -#: models_imports.py:652 +#: models_imports.py:653 msgid "Treatment type" msgstr "" -#: models_imports.py:654 +#: models_imports.py:655 msgid "Treatment emergency type" msgstr "" -#: models_imports.py:655 +#: models_imports.py:656 msgid "Object type" msgstr "" -#: models_imports.py:656 +#: models_imports.py:657 msgid "Integrity type" msgstr "" -#: models_imports.py:658 +#: models_imports.py:659 msgid "Remarkability type" msgstr "" -#: models_imports.py:659 +#: models_imports.py:660 msgid "Alteration type" msgstr "" -#: models_imports.py:661 +#: models_imports.py:662 msgid "Alteration cause type" msgstr "" -#: models_imports.py:662 +#: models_imports.py:663 msgid "Batch type" msgstr "" -#: models_imports.py:663 +#: models_imports.py:664 msgid "Checked type" msgstr "" -#: models_imports.py:665 +#: models_imports.py:666 msgid "Identification type" msgstr "" -#: models_imports.py:667 +#: models_imports.py:668 msgid "Context record relation type" msgstr "" -#: models_imports.py:678 +#: models_imports.py:679 msgid "String" msgstr "" -#: models_imports.py:681 +#: models_imports.py:682 #: templates/ishtar/dashboards/dashboard_main_detail.html:196 msgid "Year" msgstr "" -#: models_imports.py:682 +#: models_imports.py:683 msgid "INSEE code" msgstr "" -#: models_imports.py:683 +#: models_imports.py:684 msgid "String to boolean" msgstr "" -#: models_imports.py:684 +#: models_imports.py:685 msgctxt "filesystem" msgid "File" msgstr "" -#: models_imports.py:685 +#: models_imports.py:686 msgid "Unknow type" msgstr "" -#: models_imports.py:702 +#: models_imports.py:703 msgid "4 digit year. e.g.: \"2015\"" msgstr "" -#: models_imports.py:703 +#: models_imports.py:704 msgid "4 digit year/month/day. e.g.: \"2015/02/04\"" msgstr "" -#: models_imports.py:704 +#: models_imports.py:705 msgid "Day/month/4 digit year. e.g.: \"04/02/2015\"" msgstr "" -#: models_imports.py:720 +#: models_imports.py:721 msgid "Options" msgstr "" -#: models_imports.py:722 +#: models_imports.py:723 msgid "Split character(s)" msgstr "" -#: models_imports.py:727 +#: models_imports.py:728 msgid "Importer - Formater type" msgstr "" -#: models_imports.py:728 +#: models_imports.py:729 msgid "Importer - Formater types" msgstr "" -#: models_imports.py:784 +#: models_imports.py:785 #: templates/ishtar/dashboards/dashboard_main_detail.html:132 msgid "Created" msgstr "" -#: models_imports.py:785 +#: models_imports.py:786 msgid "Analyse in progress" msgstr "" -#: models_imports.py:786 +#: models_imports.py:787 msgid "Analysed" msgstr "" -#: models_imports.py:787 +#: models_imports.py:788 msgid "Check modified in queue" msgstr "" -#: models_imports.py:788 +#: models_imports.py:789 msgid "Import in queue" msgstr "" -#: models_imports.py:789 +#: models_imports.py:790 msgid "Check modified in progress" msgstr "" -#: models_imports.py:790 +#: models_imports.py:791 msgid "Import in progress" msgstr "" -#: models_imports.py:791 +#: models_imports.py:792 msgid "Partially imported" msgstr "" -#: models_imports.py:794 +#: models_imports.py:795 msgid "Archived" msgstr "" -#: models_imports.py:830 +#: models_imports.py:831 msgid "Imported file" msgstr "" -#: models_imports.py:832 +#: models_imports.py:833 msgid "Associated images (zip file)" msgstr "" -#: models_imports.py:836 +#: models_imports.py:837 msgid "If a group is selected, target key saved in this group will be used." msgstr "" -#: models_imports.py:839 +#: models_imports.py:840 msgid "Encoding" msgstr "" -#: models_imports.py:842 +#: models_imports.py:843 msgid "Skip lines" msgstr "" -#: models_imports.py:843 +#: models_imports.py:844 msgid "Number of header lines in your file (can be 0)." msgstr "" -#: models_imports.py:844 +#: models_imports.py:845 msgid "Error file" msgstr "" -#: models_imports.py:847 +#: models_imports.py:848 msgid "Result file" msgstr "" -#: models_imports.py:850 +#: models_imports.py:851 msgid "Match file" msgstr "" -#: models_imports.py:856 +#: models_imports.py:857 msgid "Conservative import" msgstr "" -#: models_imports.py:857 +#: models_imports.py:858 msgid "If set to true, do not overload existing values." msgstr "" -#: models_imports.py:860 +#: models_imports.py:861 msgid "End date" msgstr "" -#: models_imports.py:863 +#: models_imports.py:864 msgid "Remaining seconds" msgstr "" -#: models_imports.py:865 +#: models_imports.py:866 msgid "Current line" msgstr "" -#: models_imports.py:867 +#: models_imports.py:868 msgid "Number of line" msgstr "" -#: models_imports.py:870 +#: models_imports.py:871 msgid "Imported line numbers" msgstr "" -#: models_imports.py:873 +#: models_imports.py:874 msgid "Changed have been checked" msgstr "" -#: models_imports.py:876 +#: models_imports.py:877 msgid "Changed line numbers" msgstr "" -#: models_imports.py:881 +#: models_imports.py:882 msgid "Import" msgstr "" -#: models_imports.py:970 +#: models_imports.py:971 msgid "Analyse" msgstr "" -#: models_imports.py:972 models_imports.py:981 +#: models_imports.py:973 models_imports.py:982 msgid "Re-analyse" msgstr "" -#: models_imports.py:973 +#: models_imports.py:974 msgid "Launch import" msgstr "" -#: models_imports.py:976 +#: models_imports.py:977 msgid "Step by step import" msgstr "" -#: models_imports.py:977 models_imports.py:986 +#: models_imports.py:978 models_imports.py:987 msgid "Re-check for changes" msgstr "" -#: models_imports.py:979 models_imports.py:988 +#: models_imports.py:980 models_imports.py:989 msgid "Check for changes" msgstr "" -#: models_imports.py:982 +#: models_imports.py:983 msgid "Re-import" msgstr "" -#: models_imports.py:985 +#: models_imports.py:986 msgid "Step by step re-import" msgstr "" -#: models_imports.py:989 +#: models_imports.py:990 msgid "Archive" msgstr "" -#: models_imports.py:991 +#: models_imports.py:992 msgid "Unarchive" msgstr "" -#: models_imports.py:992 templates/ishtar/form_delete.html:11 views.py:1847 -#: widgets.py:371 widgets.py:403 +#: models_imports.py:993 templates/ishtar/form_delete.html:11 views.py:1896 +#: widgets.py:379 widgets.py:411 msgid "Delete" msgstr "" -#: models_imports.py:1042 +#: models_imports.py:1043 msgid "Error in the CSV file." msgstr "" -#: models_imports.py:1070 +#: models_imports.py:1071 msgid "Modification check {} added to the queue" msgstr "" -#: models_imports.py:1140 +#: models_imports.py:1141 msgid "Import {} added to the queue" msgstr "" -#: models_imports.py:1158 +#: models_imports.py:1159 msgid "Error on imported file: {}" msgstr "" -#: models_imports.py:1193 +#: models_imports.py:1194 msgid "Import {} finished with errors" msgstr "" -#: models_imports.py:1202 +#: models_imports.py:1203 msgid "Import {} finished with no errors" msgstr "" @@ -2544,12 +2557,12 @@ msgid "View on site" msgstr "" #: templates/admin/change_form.html:24 templates/admin/change_form.html:27 -#: views.py:1231 views.py:1236 +#: views.py:1254 views.py:1259 msgid "Previous" msgstr "" #: templates/admin/change_form.html:32 templates/admin/change_form.html:35 -#: views.py:1239 views.py:1242 +#: views.py:1262 views.py:1265 msgid "Next" msgstr "" @@ -2583,49 +2596,53 @@ msgid " items added." msgstr "" #: templates/base.html:47 -msgid "yes" +msgid "Select only one item." msgstr "" #: templates/base.html:48 -msgid "no" +msgid "yes" msgstr "" #: templates/base.html:49 -msgid "Autorefresh start. The form is disabled." +msgid "no" msgstr "" #: templates/base.html:50 +msgid "Autorefresh start. The form is disabled." +msgstr "" + +#: templates/base.html:51 msgid "Autorefresh end. The form is re-enabled." msgstr "" -#: templates/base.html:81 +#: templates/base.html:82 msgid "Current items" msgstr "" -#: templates/base.html:83 templates/ishtar/forms/qa_base.html:34 +#: templates/base.html:84 templates/ishtar/forms/qa_base.html:33 #: templates/ishtar/forms/qa_form.html:21 templates/ishtar/manage_basket.html:4 #: templates/welcome.html:11 templates/welcome.html:12 -#: templates/welcome.html:13 templates/welcome.html:14 wizards.py:423 +#: templates/welcome.html:13 templates/welcome.html:14 wizards.py:435 msgid ":" msgstr "" -#: templates/base.html:96 +#: templates/base.html:97 msgid "Sheets" msgstr "" -#: templates/base.html:146 +#: templates/base.html:158 msgid "Processing..." msgstr "" -#: templates/base.html:148 +#: templates/base.html:160 msgid "This can be long." msgstr "" -#: templates/base.html:150 +#: templates/base.html:162 msgid "Time to take a coffee?" msgstr "" -#: templates/base.html:152 +#: templates/base.html:164 msgid "Time to take another coffee?" msgstr "" @@ -2635,7 +2652,8 @@ msgid "Expand table" msgstr "" #: templates/blocks/DataTables.html:53 templates/blocks/JQueryJqGrid.html:26 -#: templates/ishtar/blocks/window_nav.html:59 +#: templates/ishtar/blocks/window_nav.html:62 +#: templates/ishtar/blocks/window_nav.html:68 #: templates/ishtar/blocks/window_tables/dynamic_documents.html:45 msgid "Export" msgstr "" @@ -2806,8 +2824,8 @@ msgstr "" #: templates/ishtar/blocks/modify_toolbar.html:1 #: templates/ishtar/blocks/window_image.html:11 -#: templates/ishtar/blocks/window_nav.html:47 -#: templates/ishtar/forms/qa_base.html:57 +#: templates/ishtar/blocks/window_nav.html:49 +#: templates/ishtar/forms/qa_base.html:56 #: templates/ishtar/organization_form.html:37 #: templates/ishtar/organization_person_form.html:32 #: templates/ishtar/person_form.html:43 @@ -2832,13 +2850,17 @@ msgstr "" msgid "Data" msgstr "" +#: templates/ishtar/blocks/sheet_json.html:9 +msgid "No data" +msgstr "" + #: templates/ishtar/blocks/window_image_detail.html:64 msgid "Licenses" msgstr "" #: templates/ishtar/blocks/window_image_detail.html:111 #: templates/ishtar/import_delete.html:20 templatetags/window_field.py:17 -#: views_item.py:486 wizards.py:393 +#: views_item.py:548 wizards.py:405 msgid "Yes" msgstr "" @@ -2851,6 +2873,11 @@ msgstr "" msgid "Web" msgstr "" +#: templates/ishtar/blocks/window_image_detail.html:193 +#: templates/ishtar/blocks/window_tables/documents.html:10 +msgid "Related to" +msgstr "" + #: templates/ishtar/blocks/window_nav.html:17 msgid "" "Are you sure to restore to this version? All changes made since this version " @@ -2870,26 +2897,22 @@ msgstr "" msgid "Item pined in your shortcut menu." msgstr "" -#: templates/ishtar/blocks/window_nav.html:43 +#: templates/ishtar/blocks/window_nav.html:45 msgid "Actions" msgstr "" -#: templates/ishtar/blocks/window_nav.html:61 +#: templates/ishtar/blocks/window_nav.html:73 msgid "Export as OpenOffice.org file" msgstr "" -#: templates/ishtar/blocks/window_nav.html:64 +#: templates/ishtar/blocks/window_nav.html:77 msgid "Export as PDF file" msgstr "" -#: templates/ishtar/blocks/window_nav.html:72 +#: templates/ishtar/blocks/window_nav.html:92 msgid "Relation between items are not historized." msgstr "" -#: templates/ishtar/blocks/window_tables/documents.html:10 -msgid "Related to" -msgstr "" - #: templates/ishtar/blocks/window_tables/documents.html:11 #: templates/ishtar/blocks/window_tables/documents.html:19 msgid "Link" @@ -2976,12 +2999,12 @@ msgstr "" msgid "User type" msgstr "" -#: templates/ishtar/form.html:20 templates/ishtar/forms/document.html:24 +#: templates/ishtar/form.html:23 templates/ishtar/forms/document.html:24 #: templates/ishtar/wizard/default_wizard.html:43 msgid "Search and select an item in the table" msgstr "" -#: templates/ishtar/form.html:26 templates/ishtar/forms/document.html:30 +#: templates/ishtar/form.html:29 templates/ishtar/forms/document.html:30 #: templates/ishtar/forms/search_query.html:77 templates/ishtar/formset.html:8 #: templates/ishtar/formset_import_match.html:51 #: templates/ishtar/import_list.html:30 templates/ishtar/merge.html:30 @@ -2994,12 +3017,12 @@ msgstr "" msgid "Are you sure you want to delete: " msgstr "" -#: templates/ishtar/forms/qa_base.html:25 +#: templates/ishtar/forms/qa_base.html:24 #: templates/ishtar/forms/qa_form.html:12 msgid "Modified items" msgstr "" -#: templates/ishtar/forms/qa_base.html:62 +#: templates/ishtar/forms/qa_base.html:61 #: templates/ishtar/import_step_by_step.html:126 #: templates/ishtar/import_step_by_step.html:305 #: templates/ishtar/organization_form.html:40 @@ -3081,7 +3104,7 @@ msgstr "" msgid "Go" msgstr "" -#: templates/ishtar/import_step_by_step.html:63 views.py:1081 +#: templates/ishtar/import_step_by_step.html:63 views.py:1104 msgid "Import step by step" msgstr "" @@ -3342,12 +3365,12 @@ msgstr "" msgid "Responsible for planning service of archaeological files" msgstr "" -#: templates/ishtar/wizard/confirm_wizard.html:12 +#: templates/ishtar/wizard/confirm_wizard.html:14 #: templates/ishtar/wizard/wizard_done_summary.html:6 msgid "You have entered the following informations:" msgstr "" -#: templates/ishtar/wizard/confirm_wizard.html:50 +#: templates/ishtar/wizard/confirm_wizard.html:56 msgid "Would you like to save them?" msgstr "" @@ -3646,15 +3669,15 @@ msgstr "" msgid "Bookmarks" msgstr "" -#: templatetags/window_field.py:22 wizards.py:395 +#: templatetags/window_field.py:22 wizards.py:407 msgid "No" msgstr "" -#: templatetags/window_tables.py:88 widgets.py:1065 +#: templatetags/window_tables.py:88 widgets.py:1102 msgid "No results" msgstr "" -#: templatetags/window_tables.py:89 widgets.py:1066 +#: templatetags/window_tables.py:89 widgets.py:1103 msgid "Loading..." msgstr "" @@ -3662,15 +3685,15 @@ msgstr "" msgid "You don't have sufficient permissions to do this action." msgstr "" -#: utils.py:338 +#: utils.py:344 msgid " (...)" msgstr "" -#: utils.py:418 +#: utils.py:424 msgid "Information" msgstr "" -#: utils.py:419 +#: utils.py:425 msgid "Load another random image?" msgstr "" @@ -3734,116 +3757,125 @@ msgstr "" msgid "Treatment" msgstr "" -#: views.py:724 views_item.py:103 +#: views.py:747 views_item.py:117 msgid "Operation not permitted." msgstr "" -#: views.py:741 views.py:799 +#: views.py:764 views.py:822 msgid "Archaeological files" msgstr "" -#: views.py:746 views.py:810 +#: views.py:769 views.py:833 msgid "Finds" msgstr "" -#: views.py:748 views.py:815 +#: views.py:771 views.py:838 msgid "Treatment requests" msgstr "" -#: views.py:749 views.py:821 +#: views.py:772 views.py:844 msgid "Treatments" msgstr "" -#: views.py:1423 +#: views.py:1446 msgid "Col. " msgstr "" -#: views.py:1429 views.py:1441 +#: views.py:1452 views.py:1464 msgid "* empty *" msgstr "" -#: views.py:1482 +#: views.py:1505 msgid "Link unmatched items" msgstr "" -#: views.py:1503 +#: views.py:1526 msgid "Delete import" msgstr "" -#: views.py:1542 +#: views.py:1565 msgid "Merge persons" msgstr "" -#: views.py:1566 +#: views.py:1589 msgid "Select the main person" msgstr "" -#: views.py:1575 +#: views.py:1598 msgid "Merge organization" msgstr "" -#: views.py:1585 +#: views.py:1608 msgid "Select the main organization" msgstr "" -#: views.py:1625 views.py:1641 +#: views.py:1648 views.py:1664 msgid "Corporation manager" msgstr "" -#: views.py:1662 +#: views.py:1685 msgid "Document: search" msgstr "" -#: views.py:1677 +#: views.py:1700 msgid "Document creation" msgstr "" -#: views.py:1710 +#: views.py:1733 msgid "Document modification" msgstr "" -#: views.py:1740 +#: views.py:1763 msgid "Document deletion" msgstr "" -#: views.py:1823 +#: views.py:1872 msgid "Delete bookmark" msgstr "" -#: views.py:1846 +#: views.py:1895 msgid "Bookmark - Delete" msgstr "" -#: views_item.py:105 +#: views_item.py:119 #, python-format msgid "New %s" msgstr "" +#: views_item.py:570 +msgctxt "key for text search" +msgid "today" +msgstr "" + #: widgets.py:174 msgid "The character \" is not accepted." msgstr "" -#: widgets.py:517 +#: widgets.py:555 msgid "{} is not a valid key for {}" msgstr "" -#: widgets.py:618 widgets.py:752 widgets.py:867 +#: widgets.py:656 widgets.py:790 widgets.py:905 msgid "Search..." msgstr "" -#: widgets.py:687 +#: widgets.py:725 msgid "Previous value:" msgstr "" -#: widgets.py:1067 +#: widgets.py:1104 msgid "Remove" msgstr "" -#: wizards.py:431 +#: wizards.py:171 +msgid "Permission error: you cannot do this action." +msgstr "" + +#: wizards.py:443 msgid "Deleted" msgstr "" -#: wizards.py:1757 +#: wizards.py:1769 #, python-format msgid "[%(app_name)s] Account creation/modification" msgstr "" diff --git a/ishtar_common/management/commands/ishtar_import.py b/ishtar_common/management/commands/ishtar_import.py index aba1e45d5..3b04528f0 100644 --- a/ishtar_common/management/commands/ishtar_import.py +++ b/ishtar_common/management/commands/ishtar_import.py @@ -3,22 +3,41 @@ from django.core.management.base import BaseCommand, CommandError -from ishtar_common import models +from ishtar_common import models, models_imports class Command(BaseCommand): help = "./manage.py ishtar_import <command> <import_id>\n\n"\ "Launch the importation a configured import.\n"\ - "<command> must be: \"analyse\", \"import\" or \"archive\"." + "<command> must be: \"list\", \"analyse\", \"import\" or " \ + "\"archive\"." + + def add_arguments(self, parser): + parser.add_argument('command', choices=["list", "analyse", "import", + "archive"]) + parser.add_argument('import_id', nargs='?', default=None) def handle(self, *args, **options): - if not args or len(args) < 2: - raise CommandError("<command> and <import_id> are mandatory") - command = args[0] - if args[0] not in ["analyse", "import", "archive"]: - raise CommandError( - "<command> must be: \"analyse\", \"import\" or \"archive\"." - ) + command = options['command'] + import_id = options['import_id'] + if command != "list" and not import_id: + raise CommandError("With {} <import_id> is mandatory".format( + command)) + if command == 'list': + state = dict(models_imports.IMPORT_STATE) + self.stdout.write("*" * 80 + "\n") + self.stdout.write( + "| pk | type | state " + "| name\n") + self.stdout.write("*" * 80 + "\n") + for imp in models.Import.objects.exclude(state="AC").all(): + self.stdout.write(u"|{: ^6}| {: ^32} | {: ^12} | {}\n".format( + imp.pk, unicode(imp.importer_type)[:32], + state[imp.state][:12], + imp.name[:128])) + self.stdout.write("*" * 80 + "\n") + self.stdout.flush() + return try: imp = models.Import.objects.get(pk=args[1]) except (ValueError, models.Import.DoesNotExist): diff --git a/ishtar_common/management/commands/reassociate_similar_images.py b/ishtar_common/management/commands/reassociate_similar_images.py index f6d432327..a0483ed3a 100644 --- a/ishtar_common/management/commands/reassociate_similar_images.py +++ b/ishtar_common/management/commands/reassociate_similar_images.py @@ -169,7 +169,7 @@ class Command(BaseCommand): for m2m in m2ms: for m2 in getattr(item, m2m).all(): - if m2 not in getattr(ref_item, m2m): + if m2 not in getattr(ref_item, m2m).all(): getattr(ref_item, m2m).add(m2) for rel_attr in Document.RELATED_MODELS: diff --git a/ishtar_common/management/commands/regenerate_search_vector_cached_label.py b/ishtar_common/management/commands/regenerate_search_vector_cached_label.py index 59e37d75b..404811acf 100644 --- a/ishtar_common/management/commands/regenerate_search_vector_cached_label.py +++ b/ishtar_common/management/commands/regenerate_search_vector_cached_label.py @@ -24,16 +24,32 @@ from django.core.management.base import BaseCommand from django.apps import apps +APPS = ['ishtar_common', 'archaeological_operations', + 'archaeological_context_records', 'archaeological_finds', + 'archaeological_warehouse'] + + class Command(BaseCommand): args = '' help = 'Regenerate cached labels and search vectors' + def add_arguments(self, parser): + parser.add_argument('app_name', nargs='?', default=None, + choices=APPS) + parser.add_argument('model_name', nargs='?', default=None) + def handle(self, *args, **options): - for app in ['ishtar_common', 'archaeological_operations', - 'archaeological_context_records', - 'archaeological_finds', 'archaeological_warehouse']: + limit = options['app_name'] + model_name = options['model_name'] + if model_name: + model_name = model_name.lower() + for app in APPS: + if limit and app != limit: + continue print(u"* app: {}".format(app)) for model in apps.get_app_config(app).get_models(): + if model_name and model.__name__.lower() != model_name: + continue if model.__name__.startswith('Historical'): continue if not bool( diff --git a/ishtar_common/migrations/0076_migrate_treatmentfile_permissions.py b/ishtar_common/migrations/0076_migrate_treatmentfile_permissions.py new file mode 100644 index 000000000..4edef4a44 --- /dev/null +++ b/ishtar_common/migrations/0076_migrate_treatmentfile_permissions.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-11-22 22:17 +from __future__ import unicode_literals + +from django.db import migrations + + +def migrate_perm(apps, schema_editor): + Permission = apps.get_model('auth', 'Permission') + Group = apps.get_model('auth', 'Group') + for perm in Permission.objects.filter( + codename__icontains='filetreatment').exclude( + codename__icontains='source').all(): + new_codename = perm.codename.replace('filetreatment', 'treatmentfile') + q = Permission.objects.filter( + codename=new_codename).exclude(pk=perm.pk) + if q.count(): + for gp in Group.objects.filter(permissions=q.all()[0]): + gp.permissions.add(perm) + q.all()[0].delete() + perm.codename = new_codename + perm.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('ishtar_common', '0075_auto_20181108_1908'), + ] + + operations = [ + migrations.RunPython(migrate_perm) + ] diff --git a/ishtar_common/migrations/0077_auto_20181129_1755.py b/ishtar_common/migrations/0077_auto_20181129_1755.py new file mode 100644 index 000000000..bd9003946 --- /dev/null +++ b/ishtar_common/migrations/0077_auto_20181129_1755.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-11-29 17:55 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ishtar_common', '0076_migrate_treatmentfile_permissions'), + ] + + operations = [ + migrations.AlterField( + model_name='importertype', + name='is_template', + field=models.BooleanField(default=False, verbose_name='Can be exported'), + ), + ] diff --git a/ishtar_common/migrations/0078_auto_20181203_1442.py b/ishtar_common/migrations/0078_auto_20181203_1442.py new file mode 100644 index 000000000..282356a55 --- /dev/null +++ b/ishtar_common/migrations/0078_auto_20181203_1442.py @@ -0,0 +1,1832 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-12-03 14:42 +from __future__ import unicode_literals + +from django.conf import settings +import django.contrib.gis.db.models.fields +import django.contrib.postgres.search +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import re + + +class Migration(migrations.Migration): + + dependencies = [ + ('ishtar_common', '0077_auto_20181129_1755'), + ] + + operations = [ + migrations.AlterModelOptions( + name='administrationscript', + options={'ordering': ['name'], 'verbose_name': "Script d'administration", 'verbose_name_plural': "Scripts d'administration"}, + ), + migrations.AlterModelOptions( + name='administrationtask', + options={'ordering': ['script'], 'verbose_name': "T\xe2che d'administration", 'verbose_name_plural': "T\xe2ches d'administration"}, + ), + migrations.AlterModelOptions( + name='area', + options={'ordering': ('label',), 'verbose_name': 'Zone', 'verbose_name_plural': 'Zones'}, + ), + migrations.AlterModelOptions( + name='author', + options={'ordering': ('author_type__order', 'person__name'), 'permissions': (('view_author', 'Can view all Authors'), ('view_own_author', 'Can view own Author'), ('add_own_author', 'Can add own Author'), ('change_own_author', 'Can change own Author'), ('delete_own_author', 'Can delete own Author')), 'verbose_name': 'Auteur', 'verbose_name_plural': 'Auteurs'}, + ), + migrations.AlterModelOptions( + name='authortype', + options={'ordering': ['order', 'label'], 'verbose_name': "Type d'auteur", 'verbose_name_plural': "Types d'auteur"}, + ), + migrations.AlterModelOptions( + name='customform', + options={'ordering': ['name', 'form'], 'verbose_name': 'Formulaire personnalis\xe9', 'verbose_name_plural': 'Formulaires personnalis\xe9s'}, + ), + migrations.AlterModelOptions( + name='customformjsonfield', + options={'verbose_name': 'Formulaire personnalis\xe9 - Champ de donn\xe9e Json', 'verbose_name_plural': 'Formulaire personnalis\xe9 - Champs de donn\xe9e Json'}, + ), + migrations.AlterModelOptions( + name='department', + options={'ordering': ['number'], 'verbose_name': 'D\xe9partement', 'verbose_name_plural': 'D\xe9partements'}, + ), + migrations.AlterModelOptions( + name='documenttemplate', + options={'ordering': ['associated_object_name', 'name'], 'verbose_name': 'Patron de document', 'verbose_name_plural': 'Patrons de document'}, + ), + migrations.AlterModelOptions( + name='excludedfield', + options={'verbose_name': 'Champ exclus', 'verbose_name_plural': 'Champs exclus'}, + ), + migrations.AlterModelOptions( + name='format', + options={'ordering': ['label'], 'verbose_name': 'Type de format', 'verbose_name_plural': 'Types de format'}, + ), + migrations.AlterModelOptions( + name='formatertype', + options={'ordering': ('formater_type', 'options'), 'verbose_name': 'Importeur - Type de mise en forme', 'verbose_name_plural': 'Importeur - Types de mise en forme'}, + ), + migrations.AlterModelOptions( + name='globalvar', + options={'ordering': ['slug'], 'verbose_name': 'Variable globale', 'verbose_name_plural': 'Variables globales'}, + ), + migrations.AlterModelOptions( + name='historicalorganization', + options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical Organisation'}, + ), + migrations.AlterModelOptions( + name='historicalperson', + options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical Personne'}, + ), + migrations.AlterModelOptions( + name='importercolumn', + options={'ordering': ('importer_type', 'col_number'), 'verbose_name': 'Importeur - Colonne', 'verbose_name_plural': 'Importeur - Colonnes'}, + ), + migrations.AlterModelOptions( + name='importerdefault', + options={'verbose_name': 'Importeur - Par d\xe9faut', 'verbose_name_plural': 'Importeur - Par d\xe9faut'}, + ), + migrations.AlterModelOptions( + name='importerdefaultvalues', + options={'verbose_name': 'Importeur - Valeur par d\xe9faut', 'verbose_name_plural': 'Importeur - Valeurs par d\xe9faut'}, + ), + migrations.AlterModelOptions( + name='importerduplicatefield', + options={'ordering': ('column', 'field_name'), 'verbose_name': 'Importeur - Champ dupliqu\xe9', 'verbose_name_plural': 'Importeur - Champs dupliqu\xe9s'}, + ), + migrations.AlterModelOptions( + name='importermodel', + options={'ordering': ('name',), 'verbose_name': 'Importeur - Mod\xe8le', 'verbose_name_plural': 'Importeur - Mod\xe8les'}, + ), + migrations.AlterModelOptions( + name='importertype', + options={'ordering': ('name',), 'verbose_name': 'Importeur - Type', 'verbose_name_plural': 'Importeur - Types'}, + ), + migrations.AlterModelOptions( + name='importtarget', + options={'verbose_name': 'Importeur - Cible', 'verbose_name_plural': 'Importeur - Cibles'}, + ), + migrations.AlterModelOptions( + name='ishtarsiteprofile', + options={'ordering': ['label'], 'verbose_name': "Profil d'instance Ishtar", 'verbose_name_plural': "Profils d'instance Ishtar"}, + ), + migrations.AlterModelOptions( + name='ishtaruser', + options={'verbose_name': "Utilisateur d'Ishtar", 'verbose_name_plural': "Utilisateurs d'Ishtar"}, + ), + migrations.AlterModelOptions( + name='jsondatafield', + options={'ordering': ['order', 'name'], 'verbose_name': 'Donn\xe9e JSON - Champ', 'verbose_name_plural': 'Donn\xe9e JSON - Champs'}, + ), + migrations.AlterModelOptions( + name='jsondatasection', + options={'ordering': ['order', 'name'], 'verbose_name': 'Donn\xe9es JSON - Menu', 'verbose_name_plural': 'Donn\xe9es JSON - Menus'}, + ), + migrations.AlterModelOptions( + name='licensetype', + options={'ordering': ('label',), 'verbose_name': 'Type de licence', 'verbose_name_plural': 'Types de licence'}, + ), + migrations.AlterModelOptions( + name='operationtype', + options={'ordering': ['judiciary', '-preventive', 'order', 'label'], 'verbose_name': "Type d'op\xe9ration", 'verbose_name_plural': "Types d'op\xe9ration"}, + ), + migrations.AlterModelOptions( + name='organization', + options={'permissions': (('view_organization', 'Can view all Organizations'), ('view_own_organization', 'Can view own Organization'), ('add_own_organization', 'Can add own Organization'), ('change_own_organization', 'Can change own Organization'), ('delete_own_organization', 'Can delete own Organization')), 'verbose_name': 'Organisation', 'verbose_name_plural': 'Organisations'}, + ), + migrations.AlterModelOptions( + name='organizationtype', + options={'ordering': ('label',), 'verbose_name': "Type d'organisation", 'verbose_name_plural': "Types d'organisation"}, + ), + migrations.AlterModelOptions( + name='person', + options={'permissions': (('view_person', 'Can view all Persons'), ('view_own_person', 'Can view own Person'), ('add_own_person', 'Can add own Person'), ('change_own_person', 'Can change own Person'), ('delete_own_person', 'Can delete own Person')), 'verbose_name': 'Personne', 'verbose_name_plural': 'Personnes'}, + ), + migrations.AlterModelOptions( + name='persontype', + options={'ordering': ('label',), 'verbose_name': 'Type de personne', 'verbose_name_plural': 'Types de personne'}, + ), + migrations.AlterModelOptions( + name='profiletype', + options={'ordering': ('label',), 'verbose_name': 'Type de profil', 'verbose_name_plural': 'Types de profil'}, + ), + migrations.AlterModelOptions( + name='regexp', + options={'verbose_name': 'Importeur - Expression r\xe9guli\xe8re', 'verbose_name_plural': 'Importeur - Expressions r\xe9guli\xe8res'}, + ), + migrations.AlterModelOptions( + name='searchquery', + options={'ordering': ['label'], 'verbose_name': 'Requ\xeate de recherche', 'verbose_name_plural': 'Requ\xeates de recherche'}, + ), + migrations.AlterModelOptions( + name='sourcetype', + options={'ordering': ['label'], 'verbose_name': 'Type de document', 'verbose_name_plural': 'Types de document'}, + ), + migrations.AlterModelOptions( + name='spatialreferencesystem', + options={'ordering': ('label',), 'verbose_name': 'Syst\xe8me de r\xe9f\xe9rence spatiale', 'verbose_name_plural': 'Syst\xe8mes de r\xe9f\xe9rence spatiale'}, + ), + migrations.AlterModelOptions( + name='state', + options={'ordering': ['number'], 'verbose_name': '\xc9tat'}, + ), + migrations.AlterModelOptions( + name='supporttype', + options={'verbose_name': 'Type de support', 'verbose_name_plural': 'Types de support'}, + ), + migrations.AlterModelOptions( + name='targetkey', + options={'ordering': ('target', 'key'), 'verbose_name': 'Importeur - Cl\xe9 de rapprochement', 'verbose_name_plural': 'Importeur - Cl\xe9s de rapprochement'}, + ), + migrations.AlterModelOptions( + name='targetkeygroup', + options={'verbose_name': 'Importeur - Groupe de cl\xe9 de rapprochement', 'verbose_name_plural': 'Importeur - Groupes de cl\xe9 de rapprochement'}, + ), + migrations.AlterModelOptions( + name='titletype', + options={'ordering': ('label',), 'verbose_name': 'Type de titre', 'verbose_name_plural': 'Types de titre'}, + ), + migrations.AlterModelOptions( + name='town', + options={'ordering': ['numero_insee'], 'verbose_name': 'Commune', 'verbose_name_plural': 'Communes'}, + ), + migrations.AlterModelOptions( + name='userprofile', + options={'verbose_name': "Profil d'utilisateur", 'verbose_name_plural': "Profils d'utilisateurs"}, + ), + migrations.AlterField( + model_name='administrationscript', + name='name', + field=models.TextField(blank=True, null=True, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='administrationscript', + name='path', + field=models.CharField(max_length=30, verbose_name='Nom de fichier'), + ), + migrations.AlterField( + model_name='administrationtask', + name='result', + field=models.TextField(blank=True, null=True, verbose_name='R\xe9sultat'), + ), + migrations.AlterField( + model_name='administrationtask', + name='state', + field=models.CharField(choices=[(b'S', 'Planifi\xe9'), (b'P', 'En cours'), (b'FE', 'Termin\xe9 avec des erreurs'), (b'F', 'Termin\xe9')], default=b'S', max_length=2, verbose_name='\xc9tat'), + ), + migrations.AlterField( + model_name='area', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='area', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='area', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='area', + name='parent', + field=models.ForeignKey(blank=True, help_text='Seulement quatre niveaux de parents sont g\xe9r\xe9s.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='children', to='ishtar_common.Area', verbose_name='Parent'), + ), + migrations.AlterField( + model_name='area', + name='reference', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='R\xe9f\xe9rence'), + ), + migrations.AlterField( + model_name='area', + name='towns', + field=models.ManyToManyField(blank=True, related_name='areas', to='ishtar_common.Town', verbose_name='Communes'), + ), + migrations.AlterField( + model_name='area', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='author', + name='author_type', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ishtar_common.AuthorType', verbose_name="Type d'auteur"), + ), + migrations.AlterField( + model_name='author', + name='cached_label', + field=models.TextField(blank=True, db_index=True, null=True, verbose_name='Nom en cache'), + ), + migrations.AlterField( + model_name='author', + name='person', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='author', to='ishtar_common.Person', verbose_name='Personne'), + ), + migrations.AlterField( + model_name='author', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='authortype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='authortype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='authortype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='authortype', + name='order', + field=models.IntegerField(default=1, verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='authortype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='customform', + name='apply_to_all', + field=models.BooleanField(default=False, help_text="Activer ce formulaire pour tous les utilisateurs. Si mis \xe0 Vrai, s\xe9lectionner des utilisateurs ou des types d'utilisateurs est inutile.", verbose_name="S'applique \xe0 tous"), + ), + migrations.AlterField( + model_name='customform', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='customform', + name='enabled', + field=models.BooleanField(default=True, help_text='D\xe9sactiver avec pr\xe9caution : d\xe9sactiver un formulaire avec des champs obligatoires peut entra\xeener des erreurs dans la base de donn\xe9es.', verbose_name='Activer ce formulaire'), + ), + migrations.AlterField( + model_name='customform', + name='form', + field=models.CharField(max_length=250, verbose_name='Formulaire'), + ), + migrations.AlterField( + model_name='customform', + name='name', + field=models.CharField(max_length=250, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='customformjsonfield', + name='help_text', + field=models.TextField(blank=True, null=True, verbose_name='Aide'), + ), + migrations.AlterField( + model_name='customformjsonfield', + name='label', + field=models.CharField(blank=True, default=b'', max_length=200, verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='customformjsonfield', + name='order', + field=models.IntegerField(default=1, verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='department', + name='label', + field=models.CharField(max_length=30, verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='department', + name='number', + field=models.CharField(max_length=3, unique=True, verbose_name='Nombre'), + ), + migrations.AlterField( + model_name='department', + name='state', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='ishtar_common.State', verbose_name='\xc9tat'), + ), + migrations.AlterField( + model_name='document', + name='additional_information', + field=models.TextField(blank=True, null=True, verbose_name='Information suppl\xe9mentaire'), + ), + migrations.AlterField( + model_name='document', + name='associated_links', + field=models.TextField(blank=True, null=True, verbose_name='Liens symboliques'), + ), + migrations.AlterField( + model_name='document', + name='associated_url', + field=models.URLField(blank=True, max_length=1000, null=True, verbose_name='Ressource num\xe9rique (adresse web)'), + ), + migrations.AlterField( + model_name='document', + name='authors', + field=models.ManyToManyField(related_name='documents', to='ishtar_common.Author', verbose_name='Auteurs'), + ), + migrations.AlterField( + model_name='document', + name='authors_raw', + field=models.CharField(blank=True, max_length=250, null=True, verbose_name='Auteurs (brut)'), + ), + migrations.AlterField( + model_name='document', + name='cache_related_label', + field=models.TextField(blank=True, db_index=True, help_text='Valeur en cache - ne pas \xe9diter', null=True, verbose_name='Li\xe9'), + ), + migrations.AlterField( + model_name='document', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='document', + name='creation_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de cr\xe9ation'), + ), + migrations.AlterField( + model_name='document', + name='duplicate', + field=models.NullBooleanField(verbose_name='Existe en doublon'), + ), + migrations.AlterField( + model_name='document', + name='external_id', + field=models.TextField(blank=True, null=True, verbose_name='Identifiant'), + ), + migrations.AlterField( + model_name='document', + name='internal_reference', + field=models.TextField(blank=True, null=True, verbose_name='R\xe9f. interne'), + ), + migrations.AlterField( + model_name='document', + name='item_number', + field=models.IntegerField(default=1, verbose_name="Nombre d'\xe9l\xe9ments"), + ), + migrations.AlterField( + model_name='document', + name='licenses', + field=models.ManyToManyField(blank=True, to='ishtar_common.LicenseType', verbose_name='Licence'), + ), + migrations.AlterField( + model_name='document', + name='receipt_date', + field=models.DateField(blank=True, null=True, verbose_name='Date de r\xe9ception'), + ), + migrations.AlterField( + model_name='document', + name='receipt_date_in_documentation', + field=models.DateField(blank=True, null=True, verbose_name='Date de r\xe9ception en documentation'), + ), + migrations.AlterField( + model_name='document', + name='reference', + field=models.TextField(blank=True, null=True, verbose_name='R\xe9f.'), + ), + migrations.AlterField( + model_name='document', + name='scale', + field=models.CharField(blank=True, max_length=30, null=True, verbose_name='\xc9chelle'), + ), + migrations.AlterField( + model_name='document', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='document', + name='title', + field=models.TextField(blank=True, default=b'', verbose_name='Titre'), + ), + migrations.AlterField( + model_name='documenttemplate', + name='associated_object_name', + field=models.CharField(choices=[(b'archaeological_operations.models.AdministrativeAct', 'Acte administratif')], max_length=100, verbose_name='Objet associ\xe9'), + ), + migrations.AlterField( + model_name='documenttemplate', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='documenttemplate', + name='name', + field=models.CharField(max_length=100, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='documenttemplate', + name='slug', + field=models.SlugField(blank=True, max_length=100, null=True, unique=True, verbose_name='Identifiant texte'), + ), + migrations.AlterField( + model_name='documenttemplate', + name='template', + field=models.FileField(upload_to=b'templates/%Y/', verbose_name='Patron'), + ), + migrations.AlterField( + model_name='excludedfield', + name='field', + field=models.CharField(max_length=250, verbose_name='Champ'), + ), + migrations.AlterField( + model_name='format', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='format', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='format', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='format', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='formatertype', + name='formater_type', + field=models.CharField(choices=[(b'IntegerFormater', 'Entier'), (b'FloatFormater', 'Nombre \xe0 virgule'), (b'UnicodeFormater', 'Cha\xeene de caract\xe8res'), (b'DateFormater', 'Date'), (b'TypeFormater', 'Type'), (b'YearFormater', 'Ann\xe9e'), (b'InseeFormater', 'Code INSEE'), (b'StrToBoolean', 'Cha\xeene de caract\xe8res vers bool\xe9en'), (b'FileFormater', 'Fichier'), (b'UnknowType', 'Type inconnu')], max_length=20, verbose_name='Formater type'), + ), + migrations.AlterField( + model_name='formatertype', + name='many_split', + field=models.CharField(blank=True, max_length=10, null=True, verbose_name='Caract\xe8re(s) de s\xe9paration'), + ), + migrations.AlterField( + model_name='globalvar', + name='description', + field=models.TextField(blank=True, null=True, verbose_name='Description de la variable'), + ), + migrations.AlterField( + model_name='globalvar', + name='slug', + field=models.SlugField(unique=True, verbose_name='Nom de la variable'), + ), + migrations.AlterField( + model_name='globalvar', + name='value', + field=models.TextField(blank=True, null=True, verbose_name='Valeur'), + ), + migrations.AlterField( + model_name='historicalorganization', + name='address', + field=models.TextField(blank=True, null=True, verbose_name='Adresse'), + ), + migrations.AlterField( + model_name='historicalorganization', + name='address_complement', + field=models.TextField(blank=True, null=True, verbose_name="Compl\xe9ment d'adresse"), + ), + migrations.AlterField( + model_name='historicalorganization', + name='alt_address', + field=models.TextField(blank=True, null=True, verbose_name='Autre adresse : adresse'), + ), + migrations.AlterField( + model_name='historicalorganization', + name='alt_address_complement', + field=models.TextField(blank=True, null=True, verbose_name="Autre adresse : compl\xe9ment d'adresse"), + ), + migrations.AlterField( + model_name='historicalorganization', + name='alt_address_is_prefered', + field=models.BooleanField(default=False, verbose_name="L'adresse alternative est pr\xe9f\xe9r\xe9e"), + ), + migrations.AlterField( + model_name='historicalorganization', + name='alt_country', + field=models.CharField(blank=True, max_length=30, null=True, verbose_name='Autre adresse : pays'), + ), + migrations.AlterField( + model_name='historicalorganization', + name='alt_postal_code', + field=models.CharField(blank=True, max_length=10, null=True, verbose_name='Autre adresse : code postal'), + ), + migrations.AlterField( + model_name='historicalorganization', + name='alt_town', + field=models.CharField(blank=True, max_length=70, null=True, verbose_name='Autre adresse : ville'), + ), + migrations.AlterField( + model_name='historicalorganization', + name='cached_label', + field=models.TextField(blank=True, db_index=True, null=True, verbose_name='Nom en cache'), + ), + migrations.AlterField( + model_name='historicalorganization', + name='country', + field=models.CharField(blank=True, max_length=30, null=True, verbose_name='Pays'), + ), + migrations.AlterField( + model_name='historicalorganization', + name='email', + field=models.EmailField(blank=True, max_length=300, null=True, verbose_name='Courriel'), + ), + migrations.AlterField( + model_name='historicalorganization', + name='merge_key', + field=models.TextField(blank=True, null=True, verbose_name='Cl\xe9 de fusion'), + ), + migrations.AlterField( + model_name='historicalorganization', + name='mobile_phone', + field=models.CharField(blank=True, max_length=18, null=True, verbose_name='T\xe9l\xe9phone portable'), + ), + migrations.AlterField( + model_name='historicalorganization', + name='name', + field=models.CharField(max_length=500, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='historicalorganization', + name='phone', + field=models.CharField(blank=True, max_length=18, null=True, verbose_name='T\xe9l\xe9phone'), + ), + migrations.AlterField( + model_name='historicalorganization', + name='phone2', + field=models.CharField(blank=True, max_length=18, null=True, verbose_name='Type de t\xe9l\xe9phone 2'), + ), + migrations.AlterField( + model_name='historicalorganization', + name='phone3', + field=models.CharField(blank=True, max_length=18, null=True, verbose_name='T\xe9l\xe9phone 3'), + ), + migrations.AlterField( + model_name='historicalorganization', + name='phone_desc', + field=models.CharField(blank=True, max_length=300, null=True, verbose_name='Type de t\xe9l\xe9phone'), + ), + migrations.AlterField( + model_name='historicalorganization', + name='phone_desc2', + field=models.CharField(blank=True, max_length=300, null=True, verbose_name='Type de t\xe9l\xe9phone 2'), + ), + migrations.AlterField( + model_name='historicalorganization', + name='phone_desc3', + field=models.CharField(blank=True, max_length=300, null=True, verbose_name='Type de t\xe9l\xe9phone 3'), + ), + migrations.AlterField( + model_name='historicalorganization', + name='postal_code', + field=models.CharField(blank=True, max_length=10, null=True, verbose_name='Code postal'), + ), + migrations.AlterField( + model_name='historicalorganization', + name='raw_phone', + field=models.TextField(blank=True, null=True, verbose_name='T\xe9l\xe9phone brut'), + ), + migrations.AlterField( + model_name='historicalorganization', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='historicalorganization', + name='town', + field=models.CharField(blank=True, max_length=70, null=True, verbose_name='Commune'), + ), + migrations.AlterField( + model_name='historicalperson', + name='address', + field=models.TextField(blank=True, null=True, verbose_name='Adresse'), + ), + migrations.AlterField( + model_name='historicalperson', + name='address_complement', + field=models.TextField(blank=True, null=True, verbose_name="Compl\xe9ment d'adresse"), + ), + migrations.AlterField( + model_name='historicalperson', + name='alt_address', + field=models.TextField(blank=True, null=True, verbose_name='Autre adresse : adresse'), + ), + migrations.AlterField( + model_name='historicalperson', + name='alt_address_complement', + field=models.TextField(blank=True, null=True, verbose_name="Autre adresse : compl\xe9ment d'adresse"), + ), + migrations.AlterField( + model_name='historicalperson', + name='alt_address_is_prefered', + field=models.BooleanField(default=False, verbose_name="L'adresse alternative est pr\xe9f\xe9r\xe9e"), + ), + migrations.AlterField( + model_name='historicalperson', + name='alt_country', + field=models.CharField(blank=True, max_length=30, null=True, verbose_name='Autre adresse : pays'), + ), + migrations.AlterField( + model_name='historicalperson', + name='alt_postal_code', + field=models.CharField(blank=True, max_length=10, null=True, verbose_name='Autre adresse : code postal'), + ), + migrations.AlterField( + model_name='historicalperson', + name='alt_town', + field=models.CharField(blank=True, max_length=70, null=True, verbose_name='Autre adresse : ville'), + ), + migrations.AlterField( + model_name='historicalperson', + name='cached_label', + field=models.TextField(blank=True, db_index=True, null=True, verbose_name='Nom en cache'), + ), + migrations.AlterField( + model_name='historicalperson', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='historicalperson', + name='contact_type', + field=models.CharField(blank=True, max_length=300, null=True, verbose_name='Type de contact'), + ), + migrations.AlterField( + model_name='historicalperson', + name='country', + field=models.CharField(blank=True, max_length=30, null=True, verbose_name='Pays'), + ), + migrations.AlterField( + model_name='historicalperson', + name='email', + field=models.EmailField(blank=True, max_length=300, null=True, verbose_name='Courriel'), + ), + migrations.AlterField( + model_name='historicalperson', + name='merge_key', + field=models.TextField(blank=True, null=True, verbose_name='Cl\xe9 de fusion'), + ), + migrations.AlterField( + model_name='historicalperson', + name='mobile_phone', + field=models.CharField(blank=True, max_length=18, null=True, verbose_name='T\xe9l\xe9phone portable'), + ), + migrations.AlterField( + model_name='historicalperson', + name='name', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='historicalperson', + name='old_title', + field=models.CharField(blank=True, choices=[(b'Mr', 'M.'), (b'Ms', 'Mlle'), (b'Mr and Miss', 'M. et Mme'), (b'Md', 'Mme'), (b'Dr', 'Dr.')], max_length=100, null=True, verbose_name='Titre'), + ), + migrations.AlterField( + model_name='historicalperson', + name='phone', + field=models.CharField(blank=True, max_length=18, null=True, verbose_name='T\xe9l\xe9phone'), + ), + migrations.AlterField( + model_name='historicalperson', + name='phone2', + field=models.CharField(blank=True, max_length=18, null=True, verbose_name='Type de t\xe9l\xe9phone 2'), + ), + migrations.AlterField( + model_name='historicalperson', + name='phone3', + field=models.CharField(blank=True, max_length=18, null=True, verbose_name='T\xe9l\xe9phone 3'), + ), + migrations.AlterField( + model_name='historicalperson', + name='phone_desc', + field=models.CharField(blank=True, max_length=300, null=True, verbose_name='Type de t\xe9l\xe9phone'), + ), + migrations.AlterField( + model_name='historicalperson', + name='phone_desc2', + field=models.CharField(blank=True, max_length=300, null=True, verbose_name='Type de t\xe9l\xe9phone 2'), + ), + migrations.AlterField( + model_name='historicalperson', + name='phone_desc3', + field=models.CharField(blank=True, max_length=300, null=True, verbose_name='Type de t\xe9l\xe9phone 3'), + ), + migrations.AlterField( + model_name='historicalperson', + name='postal_code', + field=models.CharField(blank=True, max_length=10, null=True, verbose_name='Code postal'), + ), + migrations.AlterField( + model_name='historicalperson', + name='raw_name', + field=models.CharField(blank=True, max_length=300, null=True, verbose_name='Nom brut'), + ), + migrations.AlterField( + model_name='historicalperson', + name='raw_phone', + field=models.TextField(blank=True, null=True, verbose_name='T\xe9l\xe9phone brut'), + ), + migrations.AlterField( + model_name='historicalperson', + name='salutation', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name="Formule d'appel"), + ), + migrations.AlterField( + model_name='historicalperson', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='historicalperson', + name='surname', + field=models.CharField(blank=True, max_length=50, null=True, verbose_name='Pr\xe9nom'), + ), + migrations.AlterField( + model_name='historicalperson', + name='town', + field=models.CharField(blank=True, max_length=70, null=True, verbose_name='Commune'), + ), + migrations.AlterField( + model_name='import', + name='associated_group', + field=models.ForeignKey(blank=True, help_text='Si un groupe est s\xe9lectionn\xe9, les cl\xe9s de rapprochement enregistr\xe9es dans ce groupe sont utilis\xe9es.', null=True, on_delete=django.db.models.deletion.CASCADE, to='ishtar_common.TargetKeyGroup'), + ), + migrations.AlterField( + model_name='import', + name='changed_checked', + field=models.BooleanField(default=False, verbose_name='Les changements ont \xe9t\xe9 v\xe9rifi\xe9s'), + ), + migrations.AlterField( + model_name='import', + name='changed_line_numbers', + field=models.TextField(blank=True, null=True, validators=[django.core.validators.RegexValidator(re.compile('^\\d+(?:\\,\\d+)*\\Z'), code='invalid', message='Saisissez uniquement des chiffres s\xe9par\xe9s par des virgules.')], verbose_name='Num\xe9ro des lignes modifi\xe9es'), + ), + migrations.AlterField( + model_name='import', + name='conservative_import', + field=models.BooleanField(default=False, help_text='Si coch\xe9, ne surchargera pas les valeurs existantes.', verbose_name='Import conservateur'), + ), + migrations.AlterField( + model_name='import', + name='creation_date', + field=models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date de cr\xe9ation'), + ), + migrations.AlterField( + model_name='import', + name='current_line', + field=models.IntegerField(blank=True, null=True, verbose_name='Ligne actuelle'), + ), + migrations.AlterField( + model_name='import', + name='encoding', + field=models.CharField(choices=[(b'windows-1252', b'windows-1252'), (b'ISO-8859-15', b'ISO-8859-15'), (b'utf-8', b'utf-8')], default='utf-8', max_length=15, verbose_name='Codage'), + ), + migrations.AlterField( + model_name='import', + name='end_date', + field=models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date de fin'), + ), + migrations.AlterField( + model_name='import', + name='error_file', + field=models.FileField(blank=True, max_length=255, null=True, upload_to=b'upload/imports/%Y/%m/', verbose_name='Fichier erreur'), + ), + migrations.AlterField( + model_name='import', + name='imported_file', + field=models.FileField(max_length=220, upload_to=b'upload/imports/%Y/%m/', verbose_name='Fichier import\xe9'), + ), + migrations.AlterField( + model_name='import', + name='imported_images', + field=models.FileField(blank=True, max_length=220, null=True, upload_to=b'upload/imports/%Y/%m/', verbose_name='Images associ\xe9es (fichier zip)'), + ), + migrations.AlterField( + model_name='import', + name='imported_line_numbers', + field=models.TextField(blank=True, null=True, validators=[django.core.validators.RegexValidator(re.compile('^\\d+(?:\\,\\d+)*\\Z'), code='invalid', message='Saisissez uniquement des chiffres s\xe9par\xe9s par des virgules.')], verbose_name='Num\xe9ros des lignes import\xe9es'), + ), + migrations.AlterField( + model_name='import', + name='match_file', + field=models.FileField(blank=True, max_length=255, null=True, upload_to=b'upload/imports/%Y/%m/', verbose_name='Fichier de correspondance'), + ), + migrations.AlterField( + model_name='import', + name='name', + field=models.CharField(max_length=500, null=True, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='import', + name='number_of_line', + field=models.IntegerField(blank=True, null=True, verbose_name='Nombre de lignes'), + ), + migrations.AlterField( + model_name='import', + name='result_file', + field=models.FileField(blank=True, max_length=255, null=True, upload_to=b'upload/imports/%Y/%m/', verbose_name='Fichier r\xe9sultant'), + ), + migrations.AlterField( + model_name='import', + name='seconds_remaining', + field=models.IntegerField(blank=True, editable=False, null=True, verbose_name='Secondes restantes'), + ), + migrations.AlterField( + model_name='import', + name='skip_lines', + field=models.IntegerField(default=1, help_text="Nombre de ligne d'ent\xeate dans votre fichier (peut \xeatre \xe9gal \xe0 z\xe9ro)", verbose_name="Nombre de lignes d'ent\xeate"), + ), + migrations.AlterField( + model_name='import', + name='state', + field=models.CharField(choices=[(b'C', 'Cr\xe9\xe9'), (b'AP', 'Analyse en cours'), (b'A', 'Analys\xe9'), (b'HQ', 'V\xe9rification des modifications dans la file'), (b'IQ', "Import en file d'attente"), (b'HP', 'V\xe9rification des modifications en cours'), (b'IP', 'Import en cours'), (b'PI', 'Import\xe9 partiellement'), (b'FE', 'Termin\xe9 avec des erreurs'), (b'F', 'Termin\xe9'), (b'AC', 'Archiv\xe9')], default='C', max_length=2, verbose_name='\xc9tat'), + ), + migrations.AlterField( + model_name='importercolumn', + name='col_number', + field=models.IntegerField(default=1, verbose_name='Num\xe9ro de colonne'), + ), + migrations.AlterField( + model_name='importercolumn', + name='export_field_name', + field=models.CharField(blank=True, help_text="Remplir ce champ si le nom du champ est ambigu pour l'export, par exemple dans le cas de champs concat\xe9n\xe9s.", max_length=200, null=True, verbose_name='Nom du champ \xe0 exporter'), + ), + migrations.AlterField( + model_name='importercolumn', + name='label', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='importercolumn', + name='required', + field=models.BooleanField(default=False, verbose_name='Requis'), + ), + migrations.AlterField( + model_name='importerduplicatefield', + name='concat', + field=models.BooleanField(default=False, verbose_name="Concat\xe9ner avec l'existant"), + ), + migrations.AlterField( + model_name='importerduplicatefield', + name='concat_str', + field=models.CharField(blank=True, max_length=5, null=True, verbose_name='Caract\xe8re de concat\xe9nation'), + ), + migrations.AlterField( + model_name='importerduplicatefield', + name='field_name', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Nom du champ'), + ), + migrations.AlterField( + model_name='importerduplicatefield', + name='force_new', + field=models.BooleanField(default=False, verbose_name='Forcer la cr\xe9ation de nouveaux \xe9l\xe9ments'), + ), + migrations.AlterField( + model_name='importermodel', + name='klass', + field=models.CharField(max_length=200, unique=True, verbose_name='Nom de la classe'), + ), + migrations.AlterField( + model_name='importermodel', + name='name', + field=models.CharField(max_length=200, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='importertype', + name='associated_models', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='ishtar_common.ImporterModel', verbose_name='Mod\xe8le associ\xe9'), + ), + migrations.AlterField( + model_name='importertype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='importertype', + name='created_models', + field=models.ManyToManyField(blank=True, help_text='Laissez vide pour aucune restriction', related_name='_importertype_created_models_+', to='ishtar_common.ImporterModel', verbose_name='Mod\xe8les qui peuvent accepter de nouveaux \xe9l\xe9ments'), + ), + migrations.AlterField( + model_name='importertype', + name='name', + field=models.CharField(max_length=200, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='importertype', + name='slug', + field=models.SlugField(max_length=100, unique=True, verbose_name='Identifiant texte'), + ), + migrations.AlterField( + model_name='importertype', + name='unicity_keys', + field=models.CharField(blank=True, max_length=500, null=True, verbose_name="Cl\xe9s d'unicit\xe9 (s\xe9parateur \xab ; \xbb)"), + ), + migrations.AlterField( + model_name='importertype', + name='users', + field=models.ManyToManyField(blank=True, to='ishtar_common.IshtarUser', verbose_name='Utilisateurs'), + ), + migrations.AlterField( + model_name='importtarget', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='importtarget', + name='concat', + field=models.BooleanField(default=False, verbose_name="Concat\xe9ner avec l'existant"), + ), + migrations.AlterField( + model_name='importtarget', + name='concat_str', + field=models.CharField(blank=True, max_length=5, null=True, verbose_name='Caract\xe8re de concat\xe9nation'), + ), + migrations.AlterField( + model_name='importtarget', + name='force_new', + field=models.BooleanField(default=False, verbose_name='Forcer la cr\xe9ation de nouveaux \xe9l\xe9ments'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='active', + field=models.BooleanField(default=False, verbose_name='Actuellement utilis\xe9'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='archaeological_site', + field=models.BooleanField(default=False, verbose_name='Module Site arch\xe9ologique'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='archaeological_site_label', + field=models.CharField(choices=[(b'site', 'Site'), (b'entity', 'Entit\xe9 (EA)')], default=b'site', max_length=200, verbose_name='Type de site arch\xe9ologique'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='base_find_external_id', + field=models.TextField(default='{context_record__external_id}-{label}', help_text="Formule pour g\xe9rer les identifiants de mobilier d'origine. \xc0 manipuler avec pr\xe9caution. Une formule incorrecte peut rendre l'application inutilisable et l'import de donn\xe9es externes peut alors \xeatre destructif.", verbose_name="Identifiant de mobilier d'origine"), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='container_external_id', + field=models.TextField(default='{responsible__external_id}-{index}', help_text="Formule pour g\xe9rer les identifiants de contenant. \xc0 manipuler avec pr\xe9caution. Une formule incorrecte peut rendre l'application inutilisable et l'import de donn\xe9es externes peut alors \xeatre destructif.", verbose_name='ID du contenant'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='context_record', + field=models.BooleanField(default=False, verbose_name="Module Unit\xe9s d'Enregistrement"), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='context_record_external_id', + field=models.TextField(default='{parcel__external_id}-{label}', help_text="Formule pour g\xe9rer les identifiants d'unit\xe9s d'enregistrement. \xc0 manipuler avec pr\xe9caution. Une formule incorrecte peut rendre l'application inutilisable et l'import de donn\xe9es externes peut alors \xeatre destructif.", verbose_name="Identifiant d'unit\xe9 d'enregistrement"), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='currency', + field=models.CharField(choices=[('\u20ac', 'Euro'), ('$', 'Dollar US')], default='\u20ac', max_length=5, verbose_name='Devise'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='experimental_feature', + field=models.BooleanField(default=False, verbose_name='Activer les fonctionnalit\xe9s exp\xe9rimentales'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='file_external_id', + field=models.TextField(default='{year}-{numeric_reference}', help_text="Formule pour g\xe9rer les identifiants de dossiers. \xc0 manipuler avec pr\xe9caution. Une formule incorrecte peut rendre l'application inutilisable et l'import de donn\xe9es externes peut alors \xeatre destructif.", verbose_name='Identifiant de fichier'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='files', + field=models.BooleanField(default=False, verbose_name='Module Dossiers'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='find', + field=models.BooleanField(default=False, help_text="N\xe9cessite le module Unit\xe9s d'Enregistrement", verbose_name='Module Mobilier'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='find_external_id', + field=models.TextField(default='{get_first_base_find__context_record__external_id}-{label}', help_text="Formule pour g\xe9rer les identifiants de mobilier. \xc0 manipuler avec pr\xe9caution. Une formule incorrecte peut rendre l'application inutilisable et l'import de donn\xe9es externes peut alors \xeatre destructif.", verbose_name='Identifiant de mobilier'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='find_index', + field=models.CharField(choices=[('O', 'Op\xe9rations'), ('CR', "Unit\xe9s d'Enregistrement")], default=b'O', help_text="Pour \xe9viter des index non pertinents, ne changer ce param\xe8tre que s'il n'y a pas encore de mobilier dans cette base de donn\xe9es", max_length=2, verbose_name='Index mobilier bas\xe9 sur'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='homepage', + field=models.TextField(blank=True, help_text="Page d'accueil d'Ishtar. Si elle n'est pas d\xe9finie, une page d'accueil par d\xe9faut appara\xeet. Utiliser la syntaxe Markdown. {random_image} peut \xeatre utilis\xe9 pour afficher une image au hasard.", null=True, verbose_name="Page d'accueil"), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='label', + field=models.TextField(verbose_name='Nom'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='mapping', + field=models.BooleanField(default=False, verbose_name='Module cartographique'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='parcel_external_id', + field=models.TextField(default='{associated_file__external_id}{operation__code_patriarche}-{town__numero_insee}-{section}{parcel_number}', help_text="Formule pour g\xe9rer les identifiants de parcelles. \xc0 manipuler avec pr\xe9caution. Une formule incorrecte peut rendre l'application inutilisable et l'import de donn\xe9es externes peut alors \xeatre destructif.", verbose_name='Identifiant de parcelle'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='parcel_mandatory', + field=models.BooleanField(default=True, verbose_name="Parcelles cadastrales obligatoires pour les Unit\xe9s d'Enregistrement"), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='person_raw_name', + field=models.TextField(default='{name|upper} {surname}', help_text="Formule pour g\xe9rer le nom brut des personnes. \xc0 manipuler avec pr\xe9caution. Une formule incorrecte peut rendre l'application inutilisable et l'import de donn\xe9es externes peut alors \xeatre destructif.", verbose_name='Nom brut pour une personne'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='preservation', + field=models.BooleanField(default=False, verbose_name='Module de conservation'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='slug', + field=models.SlugField(unique=True, verbose_name='Identifiant texte'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='underwater', + field=models.BooleanField(default=False, verbose_name='Module sous-marin / subaquatique'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='warehouse', + field=models.BooleanField(default=False, help_text='N\xe9cessite le module mobilier', verbose_name='Module Lieu de conservation'), + ), + migrations.AlterField( + model_name='ishtarsiteprofile', + name='warehouse_external_id', + field=models.TextField(default='{name|slug}', help_text="Formule pour g\xe9rer les identifiants de lieu de conservation. \xc0 manipuler avec pr\xe9caution. Une formule incorrecte peut rendre l'application inutilisable et l'import de donn\xe9es externes peut alors \xeatre destructif.", verbose_name='Identifiant du lieu de conservation'), + ), + migrations.AlterField( + model_name='ishtaruser', + name='advanced_shortcut_menu', + field=models.BooleanField(default=False, verbose_name='Menu de raccourci (avanc\xe9)'), + ), + migrations.AlterField( + model_name='ishtaruser', + name='person', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='ishtaruser', to='ishtar_common.Person', verbose_name='Personne'), + ), + migrations.AlterField( + model_name='ishtaruser', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='itemkey', + name='importer', + field=models.ForeignKey(blank=True, help_text='Cl\xe9 sp\xe9cifique \xe0 un import', null=True, on_delete=django.db.models.deletion.CASCADE, to='ishtar_common.Import'), + ), + migrations.AlterField( + model_name='itemkey', + name='key', + field=models.TextField(verbose_name='Cl\xe9'), + ), + migrations.AlterField( + model_name='jsondatafield', + name='display', + field=models.BooleanField(default=True, verbose_name='Afficher'), + ), + migrations.AlterField( + model_name='jsondatafield', + name='key', + field=models.CharField(help_text="Valeur de la cl\xe9 dans le format JSON. Pour les cl\xe9s hi\xe9rarchiques utiliser \xab __ \xbb. Par exemple pour la cl\xe9 'ma_sousclef' avec des donn\xe9es telles que {'ma_clef': {'ma_sousclef': 'valeur'}}, sa valeur sera atteinte avec : ma_clef__ma_sousclef.", max_length=200, verbose_name='Cl\xe9'), + ), + migrations.AlterField( + model_name='jsondatafield', + name='name', + field=models.CharField(max_length=200, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='jsondatafield', + name='order', + field=models.IntegerField(default=10, verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='jsondatafield', + name='search_index', + field=models.BooleanField(default=False, verbose_name='Utiliser dans les index de recherche'), + ), + migrations.AlterField( + model_name='jsondatafield', + name='value_type', + field=models.CharField(choices=[(b'T', 'Texte'), (b'LT', 'Texte long'), (b'I', 'Entier'), (b'B', 'Boolean'), (b'F', 'Nombre \xe0 virgule'), (b'D', 'Date'), (b'C', 'Choix')], default=b'T', max_length=10, verbose_name='Type'), + ), + migrations.AlterField( + model_name='jsondatasection', + name='name', + field=models.CharField(max_length=200, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='jsondatasection', + name='order', + field=models.IntegerField(default=10, verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='licensetype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='licensetype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='licensetype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='licensetype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='operationtype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='operationtype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='operationtype', + name='judiciary', + field=models.BooleanField(default=False, verbose_name='Est judiciaire'), + ), + migrations.AlterField( + model_name='operationtype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='operationtype', + name='order', + field=models.IntegerField(default=1, verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='operationtype', + name='preventive', + field=models.BooleanField(default=True, verbose_name='Est du pr\xe9ventif'), + ), + migrations.AlterField( + model_name='operationtype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='organization', + name='address', + field=models.TextField(blank=True, null=True, verbose_name='Adresse'), + ), + migrations.AlterField( + model_name='organization', + name='address_complement', + field=models.TextField(blank=True, null=True, verbose_name="Compl\xe9ment d'adresse"), + ), + migrations.AlterField( + model_name='organization', + name='alt_address', + field=models.TextField(blank=True, null=True, verbose_name='Autre adresse : adresse'), + ), + migrations.AlterField( + model_name='organization', + name='alt_address_complement', + field=models.TextField(blank=True, null=True, verbose_name="Autre adresse : compl\xe9ment d'adresse"), + ), + migrations.AlterField( + model_name='organization', + name='alt_address_is_prefered', + field=models.BooleanField(default=False, verbose_name="L'adresse alternative est pr\xe9f\xe9r\xe9e"), + ), + migrations.AlterField( + model_name='organization', + name='alt_country', + field=models.CharField(blank=True, max_length=30, null=True, verbose_name='Autre adresse : pays'), + ), + migrations.AlterField( + model_name='organization', + name='alt_postal_code', + field=models.CharField(blank=True, max_length=10, null=True, verbose_name='Autre adresse : code postal'), + ), + migrations.AlterField( + model_name='organization', + name='alt_town', + field=models.CharField(blank=True, max_length=70, null=True, verbose_name='Autre adresse : ville'), + ), + migrations.AlterField( + model_name='organization', + name='cached_label', + field=models.TextField(blank=True, db_index=True, null=True, verbose_name='Nom en cache'), + ), + migrations.AlterField( + model_name='organization', + name='country', + field=models.CharField(blank=True, max_length=30, null=True, verbose_name='Pays'), + ), + migrations.AlterField( + model_name='organization', + name='email', + field=models.EmailField(blank=True, max_length=300, null=True, verbose_name='Courriel'), + ), + migrations.AlterField( + model_name='organization', + name='history_creator', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Cr\xe9ateur'), + ), + migrations.AlterField( + model_name='organization', + name='history_modifier', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Dernier \xe9diteur'), + ), + migrations.AlterField( + model_name='organization', + name='merge_key', + field=models.TextField(blank=True, null=True, verbose_name='Cl\xe9 de fusion'), + ), + migrations.AlterField( + model_name='organization', + name='mobile_phone', + field=models.CharField(blank=True, max_length=18, null=True, verbose_name='T\xe9l\xe9phone portable'), + ), + migrations.AlterField( + model_name='organization', + name='name', + field=models.CharField(max_length=500, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='organization', + name='phone', + field=models.CharField(blank=True, max_length=18, null=True, verbose_name='T\xe9l\xe9phone'), + ), + migrations.AlterField( + model_name='organization', + name='phone2', + field=models.CharField(blank=True, max_length=18, null=True, verbose_name='Type de t\xe9l\xe9phone 2'), + ), + migrations.AlterField( + model_name='organization', + name='phone3', + field=models.CharField(blank=True, max_length=18, null=True, verbose_name='T\xe9l\xe9phone 3'), + ), + migrations.AlterField( + model_name='organization', + name='phone_desc', + field=models.CharField(blank=True, max_length=300, null=True, verbose_name='Type de t\xe9l\xe9phone'), + ), + migrations.AlterField( + model_name='organization', + name='phone_desc2', + field=models.CharField(blank=True, max_length=300, null=True, verbose_name='Type de t\xe9l\xe9phone 2'), + ), + migrations.AlterField( + model_name='organization', + name='phone_desc3', + field=models.CharField(blank=True, max_length=300, null=True, verbose_name='Type de t\xe9l\xe9phone 3'), + ), + migrations.AlterField( + model_name='organization', + name='postal_code', + field=models.CharField(blank=True, max_length=10, null=True, verbose_name='Code postal'), + ), + migrations.AlterField( + model_name='organization', + name='raw_phone', + field=models.TextField(blank=True, null=True, verbose_name='T\xe9l\xe9phone brut'), + ), + migrations.AlterField( + model_name='organization', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='organization', + name='town', + field=models.CharField(blank=True, max_length=70, null=True, verbose_name='Commune'), + ), + migrations.AlterField( + model_name='organizationtype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='organizationtype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='organizationtype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='organizationtype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='person', + name='address', + field=models.TextField(blank=True, null=True, verbose_name='Adresse'), + ), + migrations.AlterField( + model_name='person', + name='address_complement', + field=models.TextField(blank=True, null=True, verbose_name="Compl\xe9ment d'adresse"), + ), + migrations.AlterField( + model_name='person', + name='alt_address', + field=models.TextField(blank=True, null=True, verbose_name='Autre adresse : adresse'), + ), + migrations.AlterField( + model_name='person', + name='alt_address_complement', + field=models.TextField(blank=True, null=True, verbose_name="Autre adresse : compl\xe9ment d'adresse"), + ), + migrations.AlterField( + model_name='person', + name='alt_address_is_prefered', + field=models.BooleanField(default=False, verbose_name="L'adresse alternative est pr\xe9f\xe9r\xe9e"), + ), + migrations.AlterField( + model_name='person', + name='alt_country', + field=models.CharField(blank=True, max_length=30, null=True, verbose_name='Autre adresse : pays'), + ), + migrations.AlterField( + model_name='person', + name='alt_postal_code', + field=models.CharField(blank=True, max_length=10, null=True, verbose_name='Autre adresse : code postal'), + ), + migrations.AlterField( + model_name='person', + name='alt_town', + field=models.CharField(blank=True, max_length=70, null=True, verbose_name='Autre adresse : ville'), + ), + migrations.AlterField( + model_name='person', + name='attached_to', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='members', to='ishtar_common.Organization', verbose_name='Est rattach\xe9 \xe0'), + ), + migrations.AlterField( + model_name='person', + name='cached_label', + field=models.TextField(blank=True, db_index=True, null=True, verbose_name='Nom en cache'), + ), + migrations.AlterField( + model_name='person', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='person', + name='contact_type', + field=models.CharField(blank=True, max_length=300, null=True, verbose_name='Type de contact'), + ), + migrations.AlterField( + model_name='person', + name='country', + field=models.CharField(blank=True, max_length=30, null=True, verbose_name='Pays'), + ), + migrations.AlterField( + model_name='person', + name='email', + field=models.EmailField(blank=True, max_length=300, null=True, verbose_name='Courriel'), + ), + migrations.AlterField( + model_name='person', + name='history_creator', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Cr\xe9ateur'), + ), + migrations.AlterField( + model_name='person', + name='history_modifier', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Dernier \xe9diteur'), + ), + migrations.AlterField( + model_name='person', + name='merge_key', + field=models.TextField(blank=True, null=True, verbose_name='Cl\xe9 de fusion'), + ), + migrations.AlterField( + model_name='person', + name='mobile_phone', + field=models.CharField(blank=True, max_length=18, null=True, verbose_name='T\xe9l\xe9phone portable'), + ), + migrations.AlterField( + model_name='person', + name='name', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='person', + name='old_title', + field=models.CharField(blank=True, choices=[(b'Mr', 'M.'), (b'Ms', 'Mlle'), (b'Mr and Miss', 'M. et Mme'), (b'Md', 'Mme'), (b'Dr', 'Dr.')], max_length=100, null=True, verbose_name='Titre'), + ), + migrations.AlterField( + model_name='person', + name='phone', + field=models.CharField(blank=True, max_length=18, null=True, verbose_name='T\xe9l\xe9phone'), + ), + migrations.AlterField( + model_name='person', + name='phone2', + field=models.CharField(blank=True, max_length=18, null=True, verbose_name='Type de t\xe9l\xe9phone 2'), + ), + migrations.AlterField( + model_name='person', + name='phone3', + field=models.CharField(blank=True, max_length=18, null=True, verbose_name='T\xe9l\xe9phone 3'), + ), + migrations.AlterField( + model_name='person', + name='phone_desc', + field=models.CharField(blank=True, max_length=300, null=True, verbose_name='Type de t\xe9l\xe9phone'), + ), + migrations.AlterField( + model_name='person', + name='phone_desc2', + field=models.CharField(blank=True, max_length=300, null=True, verbose_name='Type de t\xe9l\xe9phone 2'), + ), + migrations.AlterField( + model_name='person', + name='phone_desc3', + field=models.CharField(blank=True, max_length=300, null=True, verbose_name='Type de t\xe9l\xe9phone 3'), + ), + migrations.AlterField( + model_name='person', + name='postal_code', + field=models.CharField(blank=True, max_length=10, null=True, verbose_name='Code postal'), + ), + migrations.AlterField( + model_name='person', + name='raw_name', + field=models.CharField(blank=True, max_length=300, null=True, verbose_name='Nom brut'), + ), + migrations.AlterField( + model_name='person', + name='raw_phone', + field=models.TextField(blank=True, null=True, verbose_name='T\xe9l\xe9phone brut'), + ), + migrations.AlterField( + model_name='person', + name='salutation', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name="Formule d'appel"), + ), + migrations.AlterField( + model_name='person', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto-rempli \xe0 la sauvegarde', null=True, verbose_name='Vecteur de recherche'), + ), + migrations.AlterField( + model_name='person', + name='surname', + field=models.CharField(blank=True, max_length=50, null=True, verbose_name='Pr\xe9nom'), + ), + migrations.AlterField( + model_name='person', + name='title', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='ishtar_common.TitleType', verbose_name='Titre'), + ), + migrations.AlterField( + model_name='person', + name='town', + field=models.CharField(blank=True, max_length=70, null=True, verbose_name='Commune'), + ), + migrations.AlterField( + model_name='persontype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='persontype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='persontype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='persontype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='profiletype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='profiletype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='profiletype', + name='groups', + field=models.ManyToManyField(blank=True, to='auth.Group', verbose_name='Groupes'), + ), + migrations.AlterField( + model_name='profiletype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='profiletype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='regexp', + name='name', + field=models.CharField(max_length=100, unique=True, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='regexp', + name='regexp', + field=models.CharField(max_length=500, verbose_name='Expression r\xe9guli\xe8re'), + ), + migrations.AlterField( + model_name='searchquery', + name='content_type', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType', verbose_name='Type de contenu'), + ), + migrations.AlterField( + model_name='searchquery', + name='is_alert', + field=models.BooleanField(default=False, verbose_name='Est une alerte'), + ), + migrations.AlterField( + model_name='searchquery', + name='label', + field=models.TextField(blank=True, verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='searchquery', + name='profile', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ishtar_common.UserProfile', verbose_name='Profil'), + ), + migrations.AlterField( + model_name='searchquery', + name='query', + field=models.TextField(blank=True, verbose_name='Requ\xeate'), + ), + migrations.AlterField( + model_name='sourcetype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='sourcetype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='sourcetype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='sourcetype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='spatialreferencesystem', + name='auth_name', + field=models.CharField(default='EPSG', max_length=256, verbose_name='Registre'), + ), + migrations.AlterField( + model_name='spatialreferencesystem', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='spatialreferencesystem', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='spatialreferencesystem', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='spatialreferencesystem', + name='order', + field=models.IntegerField(default=10, verbose_name='Ordre'), + ), + migrations.AlterField( + model_name='spatialreferencesystem', + name='srid', + field=models.IntegerField(verbose_name='SRID'), + ), + migrations.AlterField( + model_name='spatialreferencesystem', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='state', + name='label', + field=models.CharField(max_length=30, verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='state', + name='number', + field=models.CharField(max_length=3, unique=True, verbose_name='Nombre'), + ), + migrations.AlterField( + model_name='supporttype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='supporttype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='supporttype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='supporttype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='targetkey', + name='is_set', + field=models.BooleanField(default=False, verbose_name='Est d\xe9fini'), + ), + migrations.AlterField( + model_name='targetkey', + name='key', + field=models.TextField(verbose_name='Cl\xe9'), + ), + migrations.AlterField( + model_name='targetkey', + name='value', + field=models.TextField(blank=True, null=True, verbose_name='Valeur'), + ), + migrations.AlterField( + model_name='targetkeygroup', + name='all_user_can_modify', + field=models.BooleanField(default=False, verbose_name='Tous les utilisateurs peuvent le modifier'), + ), + migrations.AlterField( + model_name='targetkeygroup', + name='all_user_can_use', + field=models.BooleanField(default=False, verbose_name="Tous les utilisateurs peuvent l'utiliser"), + ), + migrations.AlterField( + model_name='targetkeygroup', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='targetkeygroup', + name='name', + field=models.TextField(unique=True, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='titletype', + name='available', + field=models.BooleanField(default=True, verbose_name='Disponible'), + ), + migrations.AlterField( + model_name='titletype', + name='comment', + field=models.TextField(blank=True, null=True, verbose_name='Commentaire'), + ), + migrations.AlterField( + model_name='titletype', + name='label', + field=models.TextField(verbose_name='D\xe9nomination'), + ), + migrations.AlterField( + model_name='titletype', + name='txt_idx', + field=models.TextField(help_text='Le "slug" est une version standardis\xe9e du nom. Il ne contient que des lettres en minuscule, des nombres et des tirets (-). Chaque "slug" doit \xeatre unique dans la typologie.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union.", 'invalid')], verbose_name='Identifiant textuel'), + ), + migrations.AlterField( + model_name='town', + name='cached_label', + field=models.CharField(blank=True, db_index=True, max_length=500, null=True, verbose_name='Nom en cache'), + ), + migrations.AlterField( + model_name='town', + name='children', + field=models.ManyToManyField(blank=True, related_name='parents', to='ishtar_common.Town', verbose_name='Communes enfants'), + ), + migrations.AlterField( + model_name='town', + name='departement', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='ishtar_common.Department', verbose_name='D\xe9partement'), + ), + migrations.AlterField( + model_name='town', + name='limit', + field=django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, null=True, srid=4326, verbose_name='Limite'), + ), + migrations.AlterField( + model_name='town', + name='name', + field=models.CharField(max_length=100, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='town', + name='year', + field=models.IntegerField(blank=True, help_text='Remplir ce champ est n\xe9cessaire pour distinguer les anciennes communes des nouvelles communes.', null=True, verbose_name='Ann\xe9e de cr\xe9ation'), + ), + migrations.AlterField( + model_name='userprofile', + name='areas', + field=models.ManyToManyField(blank=True, related_name='profiles', to='ishtar_common.Area', verbose_name='Zones'), + ), + migrations.AlterField( + model_name='userprofile', + name='current', + field=models.BooleanField(default=False, verbose_name='Profil actuel'), + ), + migrations.AlterField( + model_name='userprofile', + name='name', + field=models.CharField(blank=True, default='', max_length=100, verbose_name='Nom'), + ), + migrations.AlterField( + model_name='userprofile', + name='person', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='profiles', to='ishtar_common.Person', verbose_name='Personne'), + ), + migrations.AlterField( + model_name='userprofile', + name='profile_type', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ishtar_common.ProfileType', verbose_name='Type de profil'), + ), + ] diff --git a/ishtar_common/migrations/0079_migrate-importers.py b/ishtar_common/migrations/0079_migrate-importers.py new file mode 100644 index 000000000..3a66ffb30 --- /dev/null +++ b/ishtar_common/migrations/0079_migrate-importers.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-12-13 15:13 +from __future__ import unicode_literals + +from django.db import migrations + + +def migrate_importer(apps, schema): + ImporterDuplicateField = apps.get_model('ishtar_common', + 'ImporterDuplicateField') + ImportTarget = apps.get_model('ishtar_common', 'ImportTarget') + + idx = 0 + for k, model in (('field_name', ImporterDuplicateField), + ('target', ImportTarget),): + q = model.objects.filter( + **{k + "__icontains": 'container'} + ).exclude( + **{k + "__icontains": 'container_ref'} + ) + for item in q.all(): + value = getattr(item, k).replace( + 'container', 'container_ref').replace( + 'container_ref_type', 'container_type') + + dup_dct = {"column": item.column, + "field_name": value} + q2 = ImporterDuplicateField.objects.filter( + **dup_dct + ) + if q2.count(): + continue + idx += 1 + if item.concat_str: + dup_dct['concat_str'] = item.concat_str + if item.concat: + dup_dct['concat'] = item.concat + ImporterDuplicateField.objects.create(**dup_dct) + q = model.objects.filter( + **{k + "__icontains": 'set_localisation'} + ) + for item in q.all(): + value = getattr(item, k).replace( + 'set_localisation', 'set_reference_localisation') + dup_dct = {"column": item.column, + "field_name": value} + q2 = ImporterDuplicateField.objects.filter( + **dup_dct + ) + if q2.count(): + continue + idx += 1 + if item.concat_str: + dup_dct['concat_str'] = item.concat_str + if item.concat: + dup_dct['concat'] = item.concat + ImporterDuplicateField.objects.create(**dup_dct) + + print("{} dup field created".format(idx)) + + +class Migration(migrations.Migration): + + dependencies = [ + ('ishtar_common', '0078_auto_20181203_1442'), + ] + + operations = [ + migrations.RunPython(migrate_importer) + ] diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 1aa94836f..6eb36acdb 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -254,7 +254,7 @@ class OwnPerms(object): action_own_name, request.session) and self.is_own(request.user.ishtaruser)) - def is_own(self, user): + def is_own(self, user, alt_query_own=None): """ Check if the current object is owned by the user """ @@ -264,7 +264,10 @@ class OwnPerms(object): ishtaruser = user.ishtaruser else: return False - query = self.get_query_owns(ishtaruser) + if not alt_query_own: + query = self.get_query_owns(ishtaruser) + else: + query = getattr(self, alt_query_own)(ishtaruser) if not query: return False query &= Q(pk=self.pk) @@ -2181,7 +2184,11 @@ class CustomForm(models.Model): return [] res = [] for model_name in register_fields[app_name]: - ct = ContentType.objects.get(app_label=app_name, model=model_name) + q = ContentType.objects.filter(app_label=app_name, + model=model_name) + if not q.count(): + continue + ct = q.all()[0] for json_field in JsonDataField.objects.filter( content_type=ct).all(): res.append((json_field.pk, u"{} ({})".format( @@ -3293,6 +3300,7 @@ post_save.connect(post_save_userprofile, sender=UserProfile) class IshtarUser(FullSearch): + SLUG = "ishtaruser" TABLE_COLS = ('username', 'person__name', 'person__surname', 'person__email', 'person__person_types_list', 'person__attached_to__name') @@ -3428,7 +3436,7 @@ class IshtarUser(FullSearch): return self.person.full_label() -class Basket(FullSearch): +class Basket(FullSearch, OwnPerms): """ Abstract class for a basket Subclass must be defined with an "items" ManyToManyField @@ -3441,9 +3449,13 @@ class Basket(FullSearch): verbose_name=_(u"Owner")) available = models.BooleanField(_(u"Available"), default=True) shared_with = models.ManyToManyField( - IshtarUser, verbose_name=_(u"Shared with"), blank=True, + IshtarUser, verbose_name=_(u"Shared (read) with"), blank=True, related_name='shared_%(class)ss' ) + shared_write_with = models.ManyToManyField( + IshtarUser, verbose_name=_(u"Shared (read/edit) with"), blank=True, + related_name='shared_write_%(class)ss' + ) TABLE_COLS = ['label', 'user'] @@ -3462,12 +3474,17 @@ class Basket(FullSearch): if not request.user or not getattr(request.user, 'ishtaruser', None): return Q(pk=None) ishtaruser = request.user.ishtaruser - return Q(user=ishtaruser) | Q(shared_with=ishtaruser) + return Q(user=ishtaruser) | Q(shared_with=ishtaruser) | Q( + shared_write_with=ishtaruser) @property def cached_label(self): return unicode(self) + @property + def full_label(self): + return u"{} - {}".format(self.label, self.user) + @classmethod def get_short_menu_class(cls, pk): return 'basket' @@ -3477,6 +3494,38 @@ class Basket(FullSearch): return "{}-{}".format(datetime.date.today().strftime( "%Y-%m-%d"), slugify(self.label)) + @classmethod + def get_query_owns(cls, ishtaruser): + return Q(user=ishtaruser) | Q(shared_with=ishtaruser) | Q( + shared_write_with=ishtaruser) + + @classmethod + def get_write_query_owns(cls, ishtaruser): + return Q(user=ishtaruser) + + def duplicate(self, label=None, ishtaruser=None): + """ + Duplicate the basket. Items in basket are copied but not shared users + :param label: if provided use the name + :param ishtaruser: if provided an alternate user is used + :return: the new basket + """ + items = list(self.items.all()) + new_item = self + new_item.pk = None + if ishtaruser: + new_item.user = ishtaruser + if not label: + label = new_item.label + while self.__class__.objects.filter( + label=label, user=new_item.user).count(): + label += unicode(_(u" - duplicate")) + new_item.label = label + new_item.save() + for item in items: + new_item.items.add(item) + return new_item + class AuthorType(GeneralType): order = models.IntegerField(_(u"Order"), default=1) @@ -3844,11 +3893,18 @@ class Document(OwnPerms, ImageModel, FullSearch, Imported): def get_query_owns(cls, ishtaruser): Operation = cls.operations.rel.related_model ArchaeologicalSite = cls.sites.rel.related_model - q = cls._construct_query_own( - 'operations__', Operation._get_query_owns_dicts(ishtaruser) - ) | cls._construct_query_own( - 'sites__', ArchaeologicalSite._get_query_owns_dicts(ishtaruser) + query_own_list = ( + ('operations__', Operation._get_query_owns_dicts(ishtaruser)), + ('sites__', ArchaeologicalSite._get_query_owns_dicts(ishtaruser)), ) + q = None + for prefix, owns in query_own_list: + subq = cls._construct_query_own(prefix, owns) + if subq: + if not q: + q = subq + else: + q |= subq return q def get_associated_operation(self): diff --git a/ishtar_common/models_imports.py b/ishtar_common/models_imports.py index 9aae1d52d..b5ce3323d 100644 --- a/ishtar_common/models_imports.py +++ b/ishtar_common/models_imports.py @@ -133,7 +133,7 @@ class ImporterType(models.Model): ImporterModel, verbose_name=_(u"Models that can accept new items"), blank=True, help_text=_(u"Leave blank for no restrictions"), related_name='+') - is_template = models.BooleanField(_(u"Is template"), default=False) + is_template = models.BooleanField(_(u"Can be exported"), default=False) unicity_keys = models.CharField(_(u"Unicity keys (separator \";\")"), blank=True, null=True, max_length=500) available = models.BooleanField(_(u"Available"), default=True) @@ -629,6 +629,7 @@ class TargetKey(models.Model): TARGET_MODELS = [ ('OrganizationType', _(u"Organization type")), ('ishtar_common.models.OrganizationType', _(u"Organization type")), + ('ishtar_common.models.PersonType', _(u"Person type")), ('TitleType', _(u"Title")), ('SourceType', _(u"Source type")), ('AuthorType', _(u"Author type")), diff --git a/ishtar_common/static/bootstrap/bootstrap.css b/ishtar_common/static/bootstrap/bootstrap.css index c6407564d..3026e8f4f 100644 --- a/ishtar_common/static/bootstrap/bootstrap.css +++ b/ishtar_common/static/bootstrap/bootstrap.css @@ -3,4 +3,4 @@ * Copyright 2011-2018 The Bootstrap Authors * Copyright 2011-2018 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */:root{--blue: #007bff;--indigo: #6610f2;--purple: #6f42c1;--pink: #e83e8c;--red: #dc3545;--orange: #fd7e14;--yellow: #ffc107;--green: #28a745;--teal: #20c997;--cyan: #17a2b8;--white: #fff;--gray: #6c757d;--gray-dark: #343a40;--primary: #007bff;--secondary: #6c757d;--success: #28a745;--info: #17a2b8;--warning: #ffc107;--danger: #dc3545;--light: #f8f9fa;--dark: #343a40;--breakpoint-xs: 0;--breakpoint-sm: 576px;--breakpoint-md: 768px;--breakpoint-lg: 992px;--breakpoint-xl: 1200px;--font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace}*,*::before,*::after{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:rgba(0,0,0,0)}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0 !important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[title],abbr[data-original-title]{text-decoration:underline;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul,dl{margin-top:0;margin-bottom:1rem}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#6f3b93;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#542c6f;text-decoration:none}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):hover,a:not([href]):not([tabindex]):focus{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}pre,code,kbd,samp{font-family:monospace, monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}input,button,select,optgroup,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}button,html [type="button"],[type="reset"],[type="submit"]{-webkit-appearance:button}button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner{padding:0;border-style:none}input[type="radio"],input[type="checkbox"]{box-sizing:border-box;padding:0}input[type="date"],input[type="time"],input[type="datetime-local"],input[type="month"]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto}[type="search"]{outline-offset:-2px;-webkit-appearance:none}[type="search"]::-webkit-search-cancel-button,[type="search"]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none !important}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.2;color:inherit}h1,.h1{font-size:2.5rem}h2,.h2{font-size:2rem}h3,.h3{font-size:1.75rem}h4,.h4{font-size:1.5rem}h5,.h5{font-size:1.25rem}h6,.h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,0.1)}small,.small{font-size:80%;font-weight:400}mark,.mark{padding:.2em;background-color:#fcf8e3}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#6c757d}.blockquote-footer::before{content:"\2014 \00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#6c757d}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}code{font-size:87.5%;color:#e83e8c;word-break:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width: 576px){.container{max-width:540px}}@media (min-width: 768px){.container{max-width:720px}}@media (min-width: 992px){.container{max-width:960px}}@media (min-width: 1200px){.container{max-width:1140px}}.container-fluid{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{display:flex;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*="col-"]{padding-right:0;padding-left:0}.col-1,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-10,.col-11,.col-12,.col,.col-auto,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm,.col-sm-auto,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-md,.col-md-auto,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg,.col-lg-auto,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl,.col-xl-auto{position:relative;width:100%;min-height:1px;padding-right:15px;padding-left:15px}.col{flex-basis:0;flex-grow:1;max-width:100%}.col-auto{flex:0 0 auto;width:auto;max-width:none}.col-1{flex:0 0 8.33333%;max-width:8.33333%}.col-2{flex:0 0 16.66667%;max-width:16.66667%}.col-3{flex:0 0 25%;max-width:25%}.col-4{flex:0 0 33.33333%;max-width:33.33333%}.col-5{flex:0 0 41.66667%;max-width:41.66667%}.col-6{flex:0 0 50%;max-width:50%}.col-7{flex:0 0 58.33333%;max-width:58.33333%}.col-8{flex:0 0 66.66667%;max-width:66.66667%}.col-9{flex:0 0 75%;max-width:75%}.col-10{flex:0 0 83.33333%;max-width:83.33333%}.col-11{flex:0 0 91.66667%;max-width:91.66667%}.col-12{flex:0 0 100%;max-width:100%}.order-first{order:-1}.order-last{order:13}.order-0{order:0}.order-1{order:1}.order-2{order:2}.order-3{order:3}.order-4{order:4}.order-5{order:5}.order-6{order:6}.order-7{order:7}.order-8{order:8}.order-9{order:9}.order-10{order:10}.order-11{order:11}.order-12{order:12}.offset-1{margin-left:8.33333%}.offset-2{margin-left:16.66667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333%}.offset-5{margin-left:41.66667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333%}.offset-8{margin-left:66.66667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333%}.offset-11{margin-left:91.66667%}@media (min-width: 576px){.col-sm{flex-basis:0;flex-grow:1;max-width:100%}.col-sm-auto{flex:0 0 auto;width:auto;max-width:none}.col-sm-1{flex:0 0 8.33333%;max-width:8.33333%}.col-sm-2{flex:0 0 16.66667%;max-width:16.66667%}.col-sm-3{flex:0 0 25%;max-width:25%}.col-sm-4{flex:0 0 33.33333%;max-width:33.33333%}.col-sm-5{flex:0 0 41.66667%;max-width:41.66667%}.col-sm-6{flex:0 0 50%;max-width:50%}.col-sm-7{flex:0 0 58.33333%;max-width:58.33333%}.col-sm-8{flex:0 0 66.66667%;max-width:66.66667%}.col-sm-9{flex:0 0 75%;max-width:75%}.col-sm-10{flex:0 0 83.33333%;max-width:83.33333%}.col-sm-11{flex:0 0 91.66667%;max-width:91.66667%}.col-sm-12{flex:0 0 100%;max-width:100%}.order-sm-first{order:-1}.order-sm-last{order:13}.order-sm-0{order:0}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333%}.offset-sm-2{margin-left:16.66667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333%}.offset-sm-5{margin-left:41.66667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333%}.offset-sm-8{margin-left:66.66667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333%}.offset-sm-11{margin-left:91.66667%}}@media (min-width: 768px){.col-md{flex-basis:0;flex-grow:1;max-width:100%}.col-md-auto{flex:0 0 auto;width:auto;max-width:none}.col-md-1{flex:0 0 8.33333%;max-width:8.33333%}.col-md-2{flex:0 0 16.66667%;max-width:16.66667%}.col-md-3{flex:0 0 25%;max-width:25%}.col-md-4{flex:0 0 33.33333%;max-width:33.33333%}.col-md-5{flex:0 0 41.66667%;max-width:41.66667%}.col-md-6{flex:0 0 50%;max-width:50%}.col-md-7{flex:0 0 58.33333%;max-width:58.33333%}.col-md-8{flex:0 0 66.66667%;max-width:66.66667%}.col-md-9{flex:0 0 75%;max-width:75%}.col-md-10{flex:0 0 83.33333%;max-width:83.33333%}.col-md-11{flex:0 0 91.66667%;max-width:91.66667%}.col-md-12{flex:0 0 100%;max-width:100%}.order-md-first{order:-1}.order-md-last{order:13}.order-md-0{order:0}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333%}.offset-md-2{margin-left:16.66667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333%}.offset-md-5{margin-left:41.66667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333%}.offset-md-8{margin-left:66.66667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333%}.offset-md-11{margin-left:91.66667%}}@media (min-width: 992px){.col-lg{flex-basis:0;flex-grow:1;max-width:100%}.col-lg-auto{flex:0 0 auto;width:auto;max-width:none}.col-lg-1{flex:0 0 8.33333%;max-width:8.33333%}.col-lg-2{flex:0 0 16.66667%;max-width:16.66667%}.col-lg-3{flex:0 0 25%;max-width:25%}.col-lg-4{flex:0 0 33.33333%;max-width:33.33333%}.col-lg-5{flex:0 0 41.66667%;max-width:41.66667%}.col-lg-6{flex:0 0 50%;max-width:50%}.col-lg-7{flex:0 0 58.33333%;max-width:58.33333%}.col-lg-8{flex:0 0 66.66667%;max-width:66.66667%}.col-lg-9{flex:0 0 75%;max-width:75%}.col-lg-10{flex:0 0 83.33333%;max-width:83.33333%}.col-lg-11{flex:0 0 91.66667%;max-width:91.66667%}.col-lg-12{flex:0 0 100%;max-width:100%}.order-lg-first{order:-1}.order-lg-last{order:13}.order-lg-0{order:0}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333%}.offset-lg-2{margin-left:16.66667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333%}.offset-lg-5{margin-left:41.66667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333%}.offset-lg-8{margin-left:66.66667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333%}.offset-lg-11{margin-left:91.66667%}}@media (min-width: 1200px){.col-xl{flex-basis:0;flex-grow:1;max-width:100%}.col-xl-auto{flex:0 0 auto;width:auto;max-width:none}.col-xl-1{flex:0 0 8.33333%;max-width:8.33333%}.col-xl-2{flex:0 0 16.66667%;max-width:16.66667%}.col-xl-3{flex:0 0 25%;max-width:25%}.col-xl-4{flex:0 0 33.33333%;max-width:33.33333%}.col-xl-5{flex:0 0 41.66667%;max-width:41.66667%}.col-xl-6{flex:0 0 50%;max-width:50%}.col-xl-7{flex:0 0 58.33333%;max-width:58.33333%}.col-xl-8{flex:0 0 66.66667%;max-width:66.66667%}.col-xl-9{flex:0 0 75%;max-width:75%}.col-xl-10{flex:0 0 83.33333%;max-width:83.33333%}.col-xl-11{flex:0 0 91.66667%;max-width:91.66667%}.col-xl-12{flex:0 0 100%;max-width:100%}.order-xl-first{order:-1}.order-xl-last{order:13}.order-xl-0{order:0}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333%}.offset-xl-2{margin-left:16.66667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333%}.offset-xl-5{margin-left:41.66667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333%}.offset-xl-8{margin-left:66.66667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333%}.offset-xl-11{margin-left:91.66667%}}.table{width:100%;max-width:100%;margin-bottom:1rem;background-color:rgba(0,0,0,0)}.table th,.table td{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table .table{background-color:#fff}.table-sm th,.table-sm td{padding:.3rem}.table-bordered{border:1px solid #dee2e6}.table-bordered th,.table-bordered td{border:1px solid #dee2e6}.table-bordered thead th,.table-bordered thead td{border-bottom-width:2px}.table-borderless th,.table-borderless td,.table-borderless thead th,.table-borderless tbody+tbody{border:0}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,0.05)}.table-hover tbody tr:hover{background-color:rgba(0,0,0,0.075)}.table-primary,.table-primary>th,.table-primary>td{background-color:#b8daff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>th,.table-secondary>td{background-color:#d6d8db}.table-hover .table-secondary:hover{background-color:#c8cbcf}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>th,.table-success>td{background-color:#c3e6cb}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>th,.table-info>td{background-color:#bee5eb}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>th,.table-warning>td{background-color:#ffeeba}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>th,.table-danger>td{background-color:#f5c6cb}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>th,.table-light>td{background-color:#fdfdfe}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>th,.table-dark>td{background-color:#c6c8ca}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>th,.table-active>td{background-color:rgba(0,0,0,0.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,0.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,0.075)}.table .thead-dark th{color:#fff;background-color:#212529;border-color:#32383e}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#dee2e6}.table-dark{color:#fff;background-color:#212529}.table-dark th,.table-dark td,.table-dark thead th{border-color:#32383e}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,0.05)}.table-dark.table-hover tbody tr:hover{background-color:rgba(255,255,255,0.075)}@media (max-width: 575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-sm>.table-bordered{border:0}}@media (max-width: 767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-md>.table-bordered{border:0}}@media (max-width: 991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-lg>.table-bordered{border:0}}@media (max-width: 1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color 0.15s ease-in-out,box-shadow 0.15s ease-in-out}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,0.25)}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}select.form-control:not([size]):not([multiple]){height:calc(2.25rem + 2px)}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding-top:.375rem;padding-bottom:.375rem;margin-bottom:0;line-height:1.5;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-sm,.input-group-sm>.form-control-plaintext.form-control,.input-group-sm>.input-group-prepend>.form-control-plaintext.input-group-text,.input-group-sm>.input-group-append>.form-control-plaintext.input-group-text,.input-group-sm>.input-group-prepend>.form-control-plaintext.btn,.input-group-sm>.input-group-append>.form-control-plaintext.btn,.form-control-plaintext.form-control-lg,.input-group-lg>.form-control-plaintext.form-control,.input-group-lg>.input-group-prepend>.form-control-plaintext.input-group-text,.input-group-lg>.input-group-append>.form-control-plaintext.input-group-text,.input-group-lg>.input-group-prepend>.form-control-plaintext.btn,.input-group-lg>.input-group-append>.form-control-plaintext.btn{padding-right:0;padding-left:0}.form-control-sm,.input-group-sm>.form-control,.input-group-sm>.input-group-prepend>.input-group-text,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-append>.btn{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}select.form-control-sm:not([size]):not([multiple]),.input-group-sm>select.form-control:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-sm>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-sm>.input-group-append>select.btn:not([size]):not([multiple]){height:calc(1.8125rem + 2px)}.form-control-lg,.input-group-lg>.form-control,.input-group-lg>.input-group-prepend>.input-group-text,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-append>.btn{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}select.form-control-lg:not([size]):not([multiple]),.input-group-lg>select.form-control:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-lg>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-lg>.input-group-append>select.btn:not([size]):not([multiple]){height:calc(2.875rem + 2px)}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:flex;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*="col-"]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled ~ .form-check-label{color:#6c757d}.form-check-label{margin-bottom:0}.form-check-inline{display:inline-flex;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#28a745}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(40,167,69,0.8);border-radius:.2rem}.was-validated .form-control:valid,.form-control.is-valid,.was-validated .custom-select:valid,.custom-select.is-valid{border-color:#28a745}.was-validated .form-control:valid:focus,.form-control.is-valid:focus,.was-validated .custom-select:valid:focus,.custom-select.is-valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,0.25)}.was-validated .form-control:valid ~ .valid-feedback,.was-validated .form-control:valid ~ .valid-tooltip,.form-control.is-valid ~ .valid-feedback,.form-control.is-valid ~ .valid-tooltip,.was-validated .custom-select:valid ~ .valid-feedback,.was-validated .custom-select:valid ~ .valid-tooltip,.custom-select.is-valid ~ .valid-feedback,.custom-select.is-valid ~ .valid-tooltip{display:block}.was-validated .form-check-input:valid ~ .form-check-label,.form-check-input.is-valid ~ .form-check-label{color:#28a745}.was-validated .form-check-input:valid ~ .valid-feedback,.was-validated .form-check-input:valid ~ .valid-tooltip,.form-check-input.is-valid ~ .valid-feedback,.form-check-input.is-valid ~ .valid-tooltip{display:block}.was-validated .custom-control-input:valid ~ .custom-control-label,.custom-control-input.is-valid ~ .custom-control-label{color:#28a745}.was-validated .custom-control-input:valid ~ .custom-control-label::before,.custom-control-input.is-valid ~ .custom-control-label::before{background-color:#71dd8a}.was-validated .custom-control-input:valid ~ .valid-feedback,.was-validated .custom-control-input:valid ~ .valid-tooltip,.custom-control-input.is-valid ~ .valid-feedback,.custom-control-input.is-valid ~ .valid-tooltip{display:block}.was-validated .custom-control-input:valid:checked ~ .custom-control-label::before,.custom-control-input.is-valid:checked ~ .custom-control-label::before{background-color:#34ce57}.was-validated .custom-control-input:valid:focus ~ .custom-control-label::before,.custom-control-input.is-valid:focus ~ .custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(40,167,69,0.25)}.was-validated .custom-file-input:valid ~ .custom-file-label,.custom-file-input.is-valid ~ .custom-file-label{border-color:#28a745}.was-validated .custom-file-input:valid ~ .custom-file-label::before,.custom-file-input.is-valid ~ .custom-file-label::before{border-color:inherit}.was-validated .custom-file-input:valid ~ .valid-feedback,.was-validated .custom-file-input:valid ~ .valid-tooltip,.custom-file-input.is-valid ~ .valid-feedback,.custom-file-input.is-valid ~ .valid-tooltip{display:block}.was-validated .custom-file-input:valid:focus ~ .custom-file-label,.custom-file-input.is-valid:focus ~ .custom-file-label{box-shadow:0 0 0 .2rem rgba(40,167,69,0.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(220,53,69,0.8);border-radius:.2rem}.was-validated .form-control:invalid,.form-control.is-invalid,.was-validated .custom-select:invalid,.custom-select.is-invalid{border-color:#dc3545}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus,.was-validated .custom-select:invalid:focus,.custom-select.is-invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,0.25)}.was-validated .form-control:invalid ~ .invalid-feedback,.was-validated .form-control:invalid ~ .invalid-tooltip,.form-control.is-invalid ~ .invalid-feedback,.form-control.is-invalid ~ .invalid-tooltip,.was-validated .custom-select:invalid ~ .invalid-feedback,.was-validated .custom-select:invalid ~ .invalid-tooltip,.custom-select.is-invalid ~ .invalid-feedback,.custom-select.is-invalid ~ .invalid-tooltip{display:block}.was-validated .form-check-input:invalid ~ .form-check-label,.form-check-input.is-invalid ~ .form-check-label{color:#dc3545}.was-validated .form-check-input:invalid ~ .invalid-feedback,.was-validated .form-check-input:invalid ~ .invalid-tooltip,.form-check-input.is-invalid ~ .invalid-feedback,.form-check-input.is-invalid ~ .invalid-tooltip{display:block}.was-validated .custom-control-input:invalid ~ .custom-control-label,.custom-control-input.is-invalid ~ .custom-control-label{color:#dc3545}.was-validated .custom-control-input:invalid ~ .custom-control-label::before,.custom-control-input.is-invalid ~ .custom-control-label::before{background-color:#efa2a9}.was-validated .custom-control-input:invalid ~ .invalid-feedback,.was-validated .custom-control-input:invalid ~ .invalid-tooltip,.custom-control-input.is-invalid ~ .invalid-feedback,.custom-control-input.is-invalid ~ .invalid-tooltip{display:block}.was-validated .custom-control-input:invalid:checked ~ .custom-control-label::before,.custom-control-input.is-invalid:checked ~ .custom-control-label::before{background-color:#e4606d}.was-validated .custom-control-input:invalid:focus ~ .custom-control-label::before,.custom-control-input.is-invalid:focus ~ .custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(220,53,69,0.25)}.was-validated .custom-file-input:invalid ~ .custom-file-label,.custom-file-input.is-invalid ~ .custom-file-label{border-color:#dc3545}.was-validated .custom-file-input:invalid ~ .custom-file-label::before,.custom-file-input.is-invalid ~ .custom-file-label::before{border-color:inherit}.was-validated .custom-file-input:invalid ~ .invalid-feedback,.was-validated .custom-file-input:invalid ~ .invalid-tooltip,.custom-file-input.is-invalid ~ .invalid-feedback,.custom-file-input.is-invalid ~ .invalid-tooltip{display:block}.was-validated .custom-file-input:invalid:focus ~ .custom-file-label,.custom-file-input.is-invalid:focus ~ .custom-file-label{box-shadow:0 0 0 .2rem rgba(220,53,69,0.25)}.form-inline{display:flex;flex-flow:row wrap;align-items:center}.form-inline .form-check{width:100%}@media (min-width: 576px){.form-inline label{display:flex;align-items:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:flex;flex:0 0 auto;flex-flow:row wrap;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .input-group,.form-inline .custom-select{width:auto}.form-inline .form-check{display:flex;align-items:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{align-items:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;user-select:none;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color 0.15s ease-in-out,background-color 0.15s ease-in-out,border-color 0.15s ease-in-out,box-shadow 0.15s ease-in-out}.btn:hover,.btn:focus{text-decoration:none}.btn:focus,.btn.focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,0.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}.btn:not(:disabled):not(.disabled):active,.btn:not(:disabled):not(.disabled).active{background-image:none}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary:focus,.btn-primary.focus{box-shadow:0 0 0 .2rem rgba(0,123,255,0.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:not(:disabled):not(.disabled):active,.btn-primary:not(:disabled):not(.disabled).active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0062cc;border-color:#005cbf}.btn-primary:not(:disabled):not(.disabled):active:focus,.btn-primary:not(:disabled):not(.disabled).active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,0.5)}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5a6268;border-color:#545b62}.btn-secondary:focus,.btn-secondary.focus{box-shadow:0 0 0 .2rem rgba(108,117,125,0.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:not(:disabled):not(.disabled):active,.btn-secondary:not(:disabled):not(.disabled).active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#545b62;border-color:#4e555b}.btn-secondary:not(:disabled):not(.disabled):active:focus,.btn-secondary:not(:disabled):not(.disabled).active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,0.5)}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success:focus,.btn-success.focus{box-shadow:0 0 0 .2rem rgba(40,167,69,0.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:not(:disabled):not(.disabled):active,.btn-success:not(:disabled):not(.disabled).active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.btn-success:not(:disabled):not(.disabled):active:focus,.btn-success:not(:disabled):not(.disabled).active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,0.5)}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info:focus,.btn-info.focus{box-shadow:0 0 0 .2rem rgba(23,162,184,0.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:not(:disabled):not(.disabled):active,.btn-info:not(:disabled):not(.disabled).active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#117a8b;border-color:#10707f}.btn-info:not(:disabled):not(.disabled):active:focus,.btn-info:not(:disabled):not(.disabled).active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,0.5)}.btn-warning{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#212529;background-color:#e0a800;border-color:#d39e00}.btn-warning:focus,.btn-warning.focus{box-shadow:0 0 0 .2rem rgba(255,193,7,0.5)}.btn-warning.disabled,.btn-warning:disabled{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:not(:disabled):not(.disabled):active,.btn-warning:not(:disabled):not(.disabled).active,.show>.btn-warning.dropdown-toggle{color:#212529;background-color:#d39e00;border-color:#c69500}.btn-warning:not(:disabled):not(.disabled):active:focus,.btn-warning:not(:disabled):not(.disabled).active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,0.5)}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger:focus,.btn-danger.focus{box-shadow:0 0 0 .2rem rgba(220,53,69,0.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:not(:disabled):not(.disabled):active,.btn-danger:not(:disabled):not(.disabled).active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#bd2130;border-color:#b21f2d}.btn-danger:not(:disabled):not(.disabled):active:focus,.btn-danger:not(:disabled):not(.disabled).active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,0.5)}.btn-light{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#212529;background-color:#e2e6ea;border-color:#dae0e5}.btn-light:focus,.btn-light.focus{box-shadow:0 0 0 .2rem rgba(248,249,250,0.5)}.btn-light.disabled,.btn-light:disabled{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:not(:disabled):not(.disabled):active,.btn-light:not(:disabled):not(.disabled).active,.show>.btn-light.dropdown-toggle{color:#212529;background-color:#dae0e5;border-color:#d3d9df}.btn-light:not(:disabled):not(.disabled):active:focus,.btn-light:not(:disabled):not(.disabled).active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,0.5)}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark:focus,.btn-dark.focus{box-shadow:0 0 0 .2rem rgba(52,58,64,0.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:not(:disabled):not(.disabled):active,.btn-dark:not(:disabled):not(.disabled).active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1d2124;border-color:#171a1d}.btn-dark:not(:disabled):not(.disabled):active:focus,.btn-dark:not(:disabled):not(.disabled).active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,0.5)}.btn-outline-primary{color:#007bff;background-color:transparent;background-image:none;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:focus,.btn-outline-primary.focus{box-shadow:0 0 0 .2rem rgba(0,123,255,0.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled):active,.btn-outline-primary:not(:disabled):not(.disabled).active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,0.5)}.btn-outline-secondary{color:#6c757d;background-color:transparent;background-image:none;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:focus,.btn-outline-secondary.focus{box-shadow:0 0 0 .2rem rgba(108,117,125,0.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled):active,.btn-outline-secondary:not(:disabled):not(.disabled).active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,0.5)}.btn-outline-success{color:#28a745;background-color:transparent;background-image:none;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:focus,.btn-outline-success.focus{box-shadow:0 0 0 .2rem rgba(40,167,69,0.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled):active,.btn-outline-success:not(:disabled):not(.disabled).active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:not(:disabled):not(.disabled):active:focus,.btn-outline-success:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,0.5)}.btn-outline-info{color:#17a2b8;background-color:transparent;background-image:none;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:focus,.btn-outline-info.focus{box-shadow:0 0 0 .2rem rgba(23,162,184,0.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled):active,.btn-outline-info:not(:disabled):not(.disabled).active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:not(:disabled):not(.disabled):active:focus,.btn-outline-info:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,0.5)}.btn-outline-warning{color:#ffc107;background-color:transparent;background-image:none;border-color:#ffc107}.btn-outline-warning:hover{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:focus,.btn-outline-warning.focus{box-shadow:0 0 0 .2rem rgba(255,193,7,0.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled):active,.btn-outline-warning:not(:disabled):not(.disabled).active,.show>.btn-outline-warning.dropdown-toggle{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,0.5)}.btn-outline-danger{color:#dc3545;background-color:transparent;background-image:none;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:focus,.btn-outline-danger.focus{box-shadow:0 0 0 .2rem rgba(220,53,69,0.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled):active,.btn-outline-danger:not(:disabled):not(.disabled).active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,0.5)}.btn-outline-light{color:#f8f9fa;background-color:transparent;background-image:none;border-color:#f8f9fa}.btn-outline-light:hover{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:focus,.btn-outline-light.focus{box-shadow:0 0 0 .2rem rgba(248,249,250,0.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled):active,.btn-outline-light:not(:disabled):not(.disabled).active,.show>.btn-outline-light.dropdown-toggle{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:not(:disabled):not(.disabled):active:focus,.btn-outline-light:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,0.5)}.btn-outline-dark{color:#343a40;background-color:transparent;background-image:none;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:focus,.btn-outline-dark.focus{box-shadow:0 0 0 .2rem rgba(52,58,64,0.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled):active,.btn-outline-dark:not(:disabled):not(.disabled).active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,0.5)}.btn-link{font-weight:400;color:#6f3b93;background-color:transparent}.btn-link:hover{color:#542c6f;text-decoration:none;background-color:transparent;border-color:transparent}.btn-link:focus,.btn-link.focus{text-decoration:none;border-color:transparent;box-shadow:none}.btn-link:disabled,.btn-link.disabled{color:#6c757d}.btn-lg,.btn-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-sm,.btn-group-sm>.btn{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;transition:opacity 0.15s linear}.fade.show{opacity:1}.collapse{display:none}.collapse.show{display:block}tr.collapse.show{display:table-row}tbody.collapse.show{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;transition:height 0.35s ease}.dropup,.dropdown{position:relative}.dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,0.15);border-radius:.25rem}.dropup .dropdown-menu{margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;width:0;height:0;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:hover,.dropdown-item:focus{color:#16181b;text-decoration:none;background-color:#f8f9fa}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#6c757d;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1.5rem;color:#212529}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:0 1 auto}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover{z-index:1}.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group,.btn-group-vertical .btn+.btn,.btn-group-vertical .btn+.btn-group,.btn-group-vertical .btn-group+.btn,.btn-group-vertical .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:not(:last-child):not(.dropdown-toggle),.btn-group>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:not(:first-child),.btn-group>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after{margin-left:0}.btn-sm+.dropdown-toggle-split,.btn-group-sm>.btn+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical .btn,.btn-group-vertical .btn-group{width:100%}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle),.btn-group-vertical>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type="radio"],.btn-group-toggle>.btn input[type="checkbox"],.btn-group-toggle>.btn-group>.btn input[type="radio"],.btn-group-toggle>.btn-group>.btn input[type="checkbox"]{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.custom-select,.input-group>.custom-file{position:relative;flex:1 1 auto;width:1%;margin-bottom:0}.input-group>.form-control:focus,.input-group>.custom-select:focus,.input-group>.custom-file:focus{z-index:3}.input-group>.form-control+.form-control,.input-group>.form-control+.custom-select,.input-group>.form-control+.custom-file,.input-group>.custom-select+.form-control,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.custom-file,.input-group>.custom-file+.form-control,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.custom-file{margin-left:-1px}.input-group>.form-control:not(:last-child),.input-group>.custom-select:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.form-control:not(:first-child),.input-group>.custom-select:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:flex;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::before{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label,.input-group>.custom-file:not(:first-child) .custom-file-label::before{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-prepend,.input-group-append{display:flex}.input-group-prepend .btn,.input-group-append .btn{position:relative;z-index:2}.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.input-group-text,.input-group-append .input-group-text+.btn{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-text input[type="radio"],.input-group-text input[type="checkbox"]{margin-top:0}.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text,.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;display:block;min-height:1.5rem;padding-left:1.5rem}.custom-control-inline{display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked ~ .custom-control-label::before{color:#fff;background-color:#007bff}.custom-control-input:focus ~ .custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,0.25)}.custom-control-input:active ~ .custom-control-label::before{color:#fff;background-color:#b3d7ff}.custom-control-input:disabled ~ .custom-control-label{color:#6c757d}.custom-control-input:disabled ~ .custom-control-label::before{background-color:#e9ecef}.custom-control-label{margin-bottom:0}.custom-control-label::before{position:absolute;top:.25rem;left:0;display:block;width:1rem;height:1rem;pointer-events:none;content:"";user-select:none;background-color:#dee2e6}.custom-control-label::after{position:absolute;top:.25rem;left:0;display:block;width:1rem;height:1rem;content:"";background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked ~ .custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:checked ~ .custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:disabled:checked ~ .custom-control-label::before{background-color:rgba(0,123,255,0.5)}.custom-checkbox .custom-control-input:disabled:indeterminate ~ .custom-control-label::before{background-color:rgba(0,123,255,0.5)}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked ~ .custom-control-label::before{background-color:#007bff}.custom-radio .custom-control-input:checked ~ .custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E")}.custom-radio .custom-control-input:disabled:checked ~ .custom-control-label::before{background-color:rgba(0,123,255,0.5)}.custom-select{display:inline-block;width:100%;height:calc(2.25rem + 2px);padding:.375rem 1.75rem .375rem .75rem;line-height:1.5;color:#495057;vertical-align:middle;background:#fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;background-size:8px 10px;border:1px solid #ced4da;border-radius:.25rem;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0;box-shadow:inset 0 1px 2px rgba(0,0,0,0.075),0 0 5px rgba(128,189,255,0.5)}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#6c757d;background-color:#e9ecef}.custom-select::-ms-expand{opacity:0}.custom-select-sm{height:calc(1.8125rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:75%}.custom-select-lg{height:calc(2.875rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:125%}.custom-file{position:relative;display:inline-block;width:100%;height:calc(2.25rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(2.25rem + 2px);margin:0;opacity:0}.custom-file-input:focus ~ .custom-file-control{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,0.25)}.custom-file-input:focus ~ .custom-file-control::before{border-color:#80bdff}.custom-file-input:lang(en) ~ .custom-file-label::after{content:"Browse"}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(2.25rem + 2px);padding:.375rem .75rem;line-height:1.5;color:#495057;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:calc(calc(2.25rem + 2px) - 1px * 2);padding:.375rem .75rem;line-height:1.5;color:#495057;content:"Browse";background-color:#e9ecef;border-left:1px solid #ced4da;border-radius:0 .25rem .25rem 0}.nav{display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:hover,.nav-link:focus{text-decoration:none}.nav-link.disabled{color:#6c757d}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item{flex:1 1 auto;text-align:center}.nav-justified .nav-item{flex-basis:0;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:.5rem 1rem}.navbar>.container,.navbar>.container-fluid{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}.navbar-nav{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:hover,.navbar-toggler:focus{text-decoration:none}.navbar-toggler:not(:disabled):not(.disabled){cursor:pointer}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width: 575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{padding-right:0;padding-left:0}}@media (min-width: 576px){.navbar-expand-sm{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .dropup .dropdown-menu{top:auto;bottom:100%}}@media (max-width: 767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{padding-right:0;padding-left:0}}@media (min-width: 768px){.navbar-expand-md{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .dropup .dropdown-menu{top:auto;bottom:100%}}@media (max-width: 991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{padding-right:0;padding-left:0}}@media (min-width: 992px){.navbar-expand-lg{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .dropup .dropdown-menu{top:auto;bottom:100%}}@media (max-width: 1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{padding-right:0;padding-left:0}}@media (min-width: 1200px){.navbar-expand-xl{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .dropup .dropdown-menu{top:auto;bottom:100%}}.navbar-expand{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid{flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .dropup .dropdown-menu{top:auto;bottom:100%}.navbar-light .navbar-brand{color:rgba(0,0,0,0.9)}.navbar-light .navbar-brand:hover,.navbar-light .navbar-brand:focus{color:rgba(0,0,0,0.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,0.5)}.navbar-light .navbar-nav .nav-link:hover,.navbar-light .navbar-nav .nav-link:focus{color:rgba(0,0,0,0.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,0.3)}.navbar-light .navbar-nav .show>.nav-link,.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .nav-link.active{color:rgba(0,0,0,0.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,0.5);border-color:rgba(0,0,0,0.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0,0,0,0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-light .navbar-text{color:rgba(0,0,0,0.5)}.navbar-light .navbar-text a{color:rgba(0,0,0,0.9)}.navbar-light .navbar-text a:hover,.navbar-light .navbar-text a:focus{color:rgba(0,0,0,0.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:hover,.navbar-dark .navbar-brand:focus{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,0.5)}.navbar-dark .navbar-nav .nav-link:hover,.navbar-dark .navbar-nav .nav-link:focus{color:rgba(255,255,255,0.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,0.25)}.navbar-dark .navbar-nav .show>.nav-link,.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .nav-link.active{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,0.5);border-color:rgba(255,255,255,0.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255,255,255,0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-dark .navbar-text{color:rgba(255,255,255,0.5)}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:hover,.navbar-dark .navbar-text a:focus{color:#fff}.card{position:relative;display:flex;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,0.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-body{flex:1 1 auto;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,0.03);border-bottom:1px solid rgba(0,0,0,0.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,0.03);border-top:1px solid rgba(0,0,0,0.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img{width:100%;border-radius:calc(.25rem - 1px)}.card-img-top{width:100%;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img-bottom{width:100%;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck{display:flex;flex-direction:column}.card-deck .card{margin-bottom:15px}@media (min-width: 576px){.card-deck{flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{display:flex;flex:1 0 0%;flex-direction:column;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group{display:flex;flex-direction:column}.card-group>.card{margin-bottom:15px}@media (min-width: 576px){.card-group{flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:first-child .card-img-top,.card-group>.card:first-child .card-header{border-top-right-radius:0}.card-group>.card:first-child .card-img-bottom,.card-group>.card:first-child .card-footer{border-bottom-right-radius:0}.card-group>.card:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:last-child .card-img-top,.card-group>.card:last-child .card-header{border-top-left-radius:0}.card-group>.card:last-child .card-img-bottom,.card-group>.card:last-child .card-footer{border-bottom-left-radius:0}.card-group>.card:only-child{border-radius:.25rem}.card-group>.card:only-child .card-img-top,.card-group>.card:only-child .card-header{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-group>.card:only-child .card-img-bottom,.card-group>.card:only-child .card-footer{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-group>.card:not(:first-child):not(:last-child):not(:only-child){border-radius:0}.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-top,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-bottom,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-header,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-footer{border-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width: 576px){.card-columns{column-count:3;column-gap:1.25rem}.card-columns .card{display:inline-block;width:100%}}.breadcrumb{display:flex;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;padding-left:.5rem;color:#6c757d;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#6c757d}.pagination{display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#6f3b93;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{z-index:2;color:#542c6f;text-decoration:none;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:2;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,0.25)}.page-link:not(:disabled):not(.disabled){cursor:pointer}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:1;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;cursor:auto;background-color:#fff;border-color:#dee2e6}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}.badge-primary[href]:hover,.badge-primary[href]:focus{color:#fff;text-decoration:none;background-color:#0062cc}.badge-secondary{color:#fff;background-color:#6c757d}.badge-secondary[href]:hover,.badge-secondary[href]:focus{color:#fff;text-decoration:none;background-color:#545b62}.badge-success{color:#fff;background-color:#28a745}.badge-success[href]:hover,.badge-success[href]:focus{color:#fff;text-decoration:none;background-color:#1e7e34}.badge-info{color:#fff;background-color:#17a2b8}.badge-info[href]:hover,.badge-info[href]:focus{color:#fff;text-decoration:none;background-color:#117a8b}.badge-warning{color:#212529;background-color:#ffc107}.badge-warning[href]:hover,.badge-warning[href]:focus{color:#212529;text-decoration:none;background-color:#d39e00}.badge-danger{color:#fff;background-color:#dc3545}.badge-danger[href]:hover,.badge-danger[href]:focus{color:#fff;text-decoration:none;background-color:#bd2130}.badge-light{color:#212529;background-color:#f8f9fa}.badge-light[href]:hover,.badge-light[href]:focus{color:#212529;text-decoration:none;background-color:#dae0e5}.badge-dark{color:#fff;background-color:#343a40}.badge-dark[href]:hover,.badge-dark[href]:focus{color:#fff;text-decoration:none;background-color:#1d2124}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width: 576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#383d41;background-color:#e2e3e5;border-color:#d6d8db}.alert-secondary hr{border-top-color:#c8cbcf}.alert-secondary .alert-link{color:#202326}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:flex;flex-direction:column;justify-content:center;color:#fff;text-align:center;background-color:#007bff;transition:width 0.6s ease}.progress-bar-striped{background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-size:1rem 1rem}.progress-bar-animated{animation:progress-bar-stripes 1s linear infinite}.media{display:flex;align-items:flex-start}.media-body{flex:1}.list-group{display:flex;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,0.125)}.list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-item:hover,.list-group-item:focus{z-index:1;text-decoration:none}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-flush .list-group-item{border-right:0;border-left:0;border-radius:0}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{border-bottom:0}.list-group-item-primary{color:#004085;background-color:#b8daff}.list-group-item-primary.list-group-item-action:hover,.list-group-item-primary.list-group-item-action:focus{color:#004085;background-color:#9fcdff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#383d41;background-color:#d6d8db}.list-group-item-secondary.list-group-item-action:hover,.list-group-item-secondary.list-group-item-action:focus{color:#383d41;background-color:#c8cbcf}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#383d41;border-color:#383d41}.list-group-item-success{color:#155724;background-color:#c3e6cb}.list-group-item-success.list-group-item-action:hover,.list-group-item-success.list-group-item-action:focus{color:#155724;background-color:#b1dfbb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}.list-group-item-info.list-group-item-action:hover,.list-group-item-info.list-group-item-action:focus{color:#0c5460;background-color:#abdde5}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}.list-group-item-warning.list-group-item-action:hover,.list-group-item-warning.list-group-item-action:focus{color:#856404;background-color:#ffe8a1}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:hover,.list-group-item-danger.list-group-item-action:focus{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:hover,.list-group-item-light.list-group-item-action:focus{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:hover,.list-group-item-dark.list-group-item-action:focus{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:hover,.close:focus{color:#000;text-decoration:none;opacity:.75}.close:not(:disabled):not(.disabled){cursor:pointer}button.close{padding:0;background-color:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;outline:0}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform 0.3s ease-out;transform:translate(0, -25%)}.modal.show .modal-dialog{transform:translate(0, 0)}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - (.5rem * 2))}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,0.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;align-items:flex-start;justify-content:space-between;padding:1rem;border-bottom:1px solid #e9ecef;border-top-left-radius:.3rem;border-top-right-radius:.3rem}.modal-header .close{padding:1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;padding:1rem}.modal-footer{display:flex;align-items:center;justify-content:flex-end;padding:1rem;border-top:1px solid #e9ecef}.modal-footer>:not(:first-child){margin-left:.25rem}.modal-footer>:not(:last-child){margin-right:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width: 576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-centered{min-height:calc(100% - (1.75rem * 2))}.modal-sm{max-width:300px}}@media (min-width: 992px){.modal-lg{max-width:800px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-top,.bs-tooltip-auto[x-placement^="top"]{padding:.4rem 0}.bs-tooltip-top .arrow,.bs-tooltip-auto[x-placement^="top"] .arrow{bottom:0}.bs-tooltip-top .arrow::before,.bs-tooltip-auto[x-placement^="top"] .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-right,.bs-tooltip-auto[x-placement^="right"]{padding:0 .4rem}.bs-tooltip-right .arrow,.bs-tooltip-auto[x-placement^="right"] .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-right .arrow::before,.bs-tooltip-auto[x-placement^="right"] .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-bottom,.bs-tooltip-auto[x-placement^="bottom"]{padding:.4rem 0}.bs-tooltip-bottom .arrow,.bs-tooltip-auto[x-placement^="bottom"] .arrow{top:0}.bs-tooltip-bottom .arrow::before,.bs-tooltip-auto[x-placement^="bottom"] .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-left,.bs-tooltip-auto[x-placement^="left"]{padding:0 .4rem}.bs-tooltip-left .arrow,.bs-tooltip-auto[x-placement^="left"] .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-left .arrow::before,.bs-tooltip-auto[x-placement^="left"] .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,0.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::before,.popover .arrow::after{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-top,.bs-popover-auto[x-placement^="top"]{margin-bottom:.5rem}.bs-popover-top .arrow,.bs-popover-auto[x-placement^="top"] .arrow{bottom:calc((.5rem + 1px) * -1)}.bs-popover-top .arrow::before,.bs-popover-auto[x-placement^="top"] .arrow::before,.bs-popover-top .arrow::after,.bs-popover-auto[x-placement^="top"] .arrow::after{border-width:.5rem .5rem 0}.bs-popover-top .arrow::before,.bs-popover-auto[x-placement^="top"] .arrow::before{bottom:0;border-top-color:rgba(0,0,0,0.25)}.bs-popover-top .arrow::after,.bs-popover-auto[x-placement^="top"] .arrow::after{bottom:1px;border-top-color:#fff}.bs-popover-right,.bs-popover-auto[x-placement^="right"]{margin-left:.5rem}.bs-popover-right .arrow,.bs-popover-auto[x-placement^="right"] .arrow{left:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-right .arrow::before,.bs-popover-auto[x-placement^="right"] .arrow::before,.bs-popover-right .arrow::after,.bs-popover-auto[x-placement^="right"] .arrow::after{border-width:.5rem .5rem .5rem 0}.bs-popover-right .arrow::before,.bs-popover-auto[x-placement^="right"] .arrow::before{left:0;border-right-color:rgba(0,0,0,0.25)}.bs-popover-right .arrow::after,.bs-popover-auto[x-placement^="right"] .arrow::after{left:1px;border-right-color:#fff}.bs-popover-bottom,.bs-popover-auto[x-placement^="bottom"]{margin-top:.5rem}.bs-popover-bottom .arrow,.bs-popover-auto[x-placement^="bottom"] .arrow{top:calc((.5rem + 1px) * -1)}.bs-popover-bottom .arrow::before,.bs-popover-auto[x-placement^="bottom"] .arrow::before,.bs-popover-bottom .arrow::after,.bs-popover-auto[x-placement^="bottom"] .arrow::after{border-width:0 .5rem .5rem .5rem}.bs-popover-bottom .arrow::before,.bs-popover-auto[x-placement^="bottom"] .arrow::before{top:0;border-bottom-color:rgba(0,0,0,0.25)}.bs-popover-bottom .arrow::after,.bs-popover-auto[x-placement^="bottom"] .arrow::after{top:1px;border-bottom-color:#fff}.bs-popover-bottom .popover-header::before,.bs-popover-auto[x-placement^="bottom"] .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.bs-popover-left,.bs-popover-auto[x-placement^="left"]{margin-right:.5rem}.bs-popover-left .arrow,.bs-popover-auto[x-placement^="left"] .arrow{right:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-left .arrow::before,.bs-popover-auto[x-placement^="left"] .arrow::before,.bs-popover-left .arrow::after,.bs-popover-auto[x-placement^="left"] .arrow::after{border-width:.5rem 0 .5rem .5rem}.bs-popover-left .arrow::before,.bs-popover-auto[x-placement^="left"] .arrow::before{right:0;border-left-color:rgba(0,0,0,0.25)}.bs-popover-left .arrow::after,.bs-popover-auto[x-placement^="left"] .arrow::after{right:1px;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;color:inherit;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#212529}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-item{position:relative;display:none;align-items:center;width:100%;transition:transform 0.6s ease;backface-visibility:hidden;perspective:1000px}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next,.carousel-item-prev{position:absolute;top:0}.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{transform:translateX(0)}@supports (transform-style: preserve-3d){.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{transform:translate3d(0, 0, 0)}}.carousel-item-next,.active.carousel-item-right{transform:translateX(100%)}@supports (transform-style: preserve-3d){.carousel-item-next,.active.carousel-item-right{transform:translate3d(100%, 0, 0)}}.carousel-item-prev,.active.carousel-item-left{transform:translateX(-100%)}@supports (transform-style: preserve-3d){.carousel-item-prev,.active.carousel-item-left{transform:translate3d(-100%, 0, 0)}}.carousel-fade .carousel-item{opacity:0;transition-duration:.6s;transition-property:opacity}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-left,.carousel-fade .carousel-item-prev.carousel-item-right{opacity:1}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{opacity:0}.carousel-fade .carousel-item-next,.carousel-fade .carousel-item-prev,.carousel-fade .carousel-item.active,.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-prev{transform:translateX(0)}@supports (transform-style: preserve-3d){.carousel-fade .carousel-item-next,.carousel-fade .carousel-item-prev,.carousel-fade .carousel-item.active,.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-prev{transform:translate3d(0, 0, 0)}}.carousel-control-prev,.carousel-control-next{position:absolute;top:0;bottom:0;display:flex;align-items:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5}.carousel-control-prev:hover,.carousel-control-prev:focus,.carousel-control-next:hover,.carousel-control-next:focus{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-prev-icon,.carousel-control-next-icon{display:inline-block;width:20px;height:20px;background:transparent no-repeat center center;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E")}.carousel-control-next-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E")}.carousel-indicators{position:absolute;right:0;bottom:10px;left:0;z-index:15;display:flex;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{position:relative;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;background-color:rgba(255,255,255,0.5)}.carousel-indicators li::before{position:absolute;top:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators li::after{position:absolute;bottom:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}.align-baseline{vertical-align:baseline !important}.align-top{vertical-align:top !important}.align-middle{vertical-align:middle !important}.align-bottom{vertical-align:bottom !important}.align-text-bottom{vertical-align:text-bottom !important}.align-text-top{vertical-align:text-top !important}.bg-primary{background-color:#007bff !important}a.bg-primary:hover,a.bg-primary:focus,button.bg-primary:hover,button.bg-primary:focus{background-color:#0062cc !important}.bg-secondary{background-color:#6c757d !important}a.bg-secondary:hover,a.bg-secondary:focus,button.bg-secondary:hover,button.bg-secondary:focus{background-color:#545b62 !important}.bg-success{background-color:#28a745 !important}a.bg-success:hover,a.bg-success:focus,button.bg-success:hover,button.bg-success:focus{background-color:#1e7e34 !important}.bg-info{background-color:#17a2b8 !important}a.bg-info:hover,a.bg-info:focus,button.bg-info:hover,button.bg-info:focus{background-color:#117a8b !important}.bg-warning{background-color:#ffc107 !important}a.bg-warning:hover,a.bg-warning:focus,button.bg-warning:hover,button.bg-warning:focus{background-color:#d39e00 !important}.bg-danger{background-color:#dc3545 !important}a.bg-danger:hover,a.bg-danger:focus,button.bg-danger:hover,button.bg-danger:focus{background-color:#bd2130 !important}.bg-light{background-color:#f8f9fa !important}a.bg-light:hover,a.bg-light:focus,button.bg-light:hover,button.bg-light:focus{background-color:#dae0e5 !important}.bg-dark{background-color:#343a40 !important}a.bg-dark:hover,a.bg-dark:focus,button.bg-dark:hover,button.bg-dark:focus{background-color:#1d2124 !important}.bg-white{background-color:#fff !important}.bg-transparent{background-color:transparent !important}.border{border:1px solid #dee2e6 !important}.border-top{border-top:1px solid #dee2e6 !important}.border-right{border-right:1px solid #dee2e6 !important}.border-bottom{border-bottom:1px solid #dee2e6 !important}.border-left{border-left:1px solid #dee2e6 !important}.border-0{border:0 !important}.border-top-0{border-top:0 !important}.border-right-0{border-right:0 !important}.border-bottom-0{border-bottom:0 !important}.border-left-0{border-left:0 !important}.border-primary{border-color:#007bff !important}.border-secondary{border-color:#6c757d !important}.border-success{border-color:#28a745 !important}.border-info{border-color:#17a2b8 !important}.border-warning{border-color:#ffc107 !important}.border-danger{border-color:#dc3545 !important}.border-light{border-color:#f8f9fa !important}.border-dark{border-color:#343a40 !important}.border-white{border-color:#fff !important}.rounded{border-radius:.25rem !important}.rounded-top{border-top-left-radius:.25rem !important;border-top-right-radius:.25rem !important}.rounded-right{border-top-right-radius:.25rem !important;border-bottom-right-radius:.25rem !important}.rounded-bottom{border-bottom-right-radius:.25rem !important;border-bottom-left-radius:.25rem !important}.rounded-left{border-top-left-radius:.25rem !important;border-bottom-left-radius:.25rem !important}.rounded-circle{border-radius:50% !important}.rounded-0{border-radius:0 !important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none !important}.d-inline{display:inline !important}.d-inline-block{display:inline-block !important}.d-block{display:block !important}.d-table{display:table !important}.d-table-row{display:table-row !important}.d-table-cell{display:table-cell !important}.d-flex{display:flex !important}.d-inline-flex{display:inline-flex !important}@media (min-width: 576px){.d-sm-none{display:none !important}.d-sm-inline{display:inline !important}.d-sm-inline-block{display:inline-block !important}.d-sm-block{display:block !important}.d-sm-table{display:table !important}.d-sm-table-row{display:table-row !important}.d-sm-table-cell{display:table-cell !important}.d-sm-flex{display:flex !important}.d-sm-inline-flex{display:inline-flex !important}}@media (min-width: 768px){.d-md-none{display:none !important}.d-md-inline{display:inline !important}.d-md-inline-block{display:inline-block !important}.d-md-block{display:block !important}.d-md-table{display:table !important}.d-md-table-row{display:table-row !important}.d-md-table-cell{display:table-cell !important}.d-md-flex{display:flex !important}.d-md-inline-flex{display:inline-flex !important}}@media (min-width: 992px){.d-lg-none{display:none !important}.d-lg-inline{display:inline !important}.d-lg-inline-block{display:inline-block !important}.d-lg-block{display:block !important}.d-lg-table{display:table !important}.d-lg-table-row{display:table-row !important}.d-lg-table-cell{display:table-cell !important}.d-lg-flex{display:flex !important}.d-lg-inline-flex{display:inline-flex !important}}@media (min-width: 1200px){.d-xl-none{display:none !important}.d-xl-inline{display:inline !important}.d-xl-inline-block{display:inline-block !important}.d-xl-block{display:block !important}.d-xl-table{display:table !important}.d-xl-table-row{display:table-row !important}.d-xl-table-cell{display:table-cell !important}.d-xl-flex{display:flex !important}.d-xl-inline-flex{display:inline-flex !important}}@media print{.d-print-none{display:none !important}.d-print-inline{display:inline !important}.d-print-inline-block{display:inline-block !important}.d-print-block{display:block !important}.d-print-table{display:table !important}.d-print-table-row{display:table-row !important}.d-print-table-cell{display:table-cell !important}.d-print-flex{display:flex !important}.d-print-inline-flex{display:inline-flex !important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.85714%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{flex-direction:row !important}.flex-column{flex-direction:column !important}.flex-row-reverse{flex-direction:row-reverse !important}.flex-column-reverse{flex-direction:column-reverse !important}.flex-wrap{flex-wrap:wrap !important}.flex-nowrap{flex-wrap:nowrap !important}.flex-wrap-reverse{flex-wrap:wrap-reverse !important}.flex-fill{flex:1 1 auto !important}.justify-content-start{justify-content:flex-start !important}.justify-content-end{justify-content:flex-end !important}.justify-content-center{justify-content:center !important}.justify-content-between{justify-content:space-between !important}.justify-content-around{justify-content:space-around !important}.align-items-start{align-items:flex-start !important}.align-items-end{align-items:flex-end !important}.align-items-center{align-items:center !important}.align-items-baseline{align-items:baseline !important}.align-items-stretch{align-items:stretch !important}.align-content-start{align-content:flex-start !important}.align-content-end{align-content:flex-end !important}.align-content-center{align-content:center !important}.align-content-between{align-content:space-between !important}.align-content-around{align-content:space-around !important}.align-content-stretch{align-content:stretch !important}.align-self-auto{align-self:auto !important}.align-self-start{align-self:flex-start !important}.align-self-end{align-self:flex-end !important}.align-self-center{align-self:center !important}.align-self-baseline{align-self:baseline !important}.align-self-stretch{align-self:stretch !important}@media (min-width: 576px){.flex-sm-row{flex-direction:row !important}.flex-sm-column{flex-direction:column !important}.flex-sm-row-reverse{flex-direction:row-reverse !important}.flex-sm-column-reverse{flex-direction:column-reverse !important}.flex-sm-wrap{flex-wrap:wrap !important}.flex-sm-nowrap{flex-wrap:nowrap !important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse !important}.flex-sm-fill{flex:1 1 auto !important}.justify-content-sm-start{justify-content:flex-start !important}.justify-content-sm-end{justify-content:flex-end !important}.justify-content-sm-center{justify-content:center !important}.justify-content-sm-between{justify-content:space-between !important}.justify-content-sm-around{justify-content:space-around !important}.align-items-sm-start{align-items:flex-start !important}.align-items-sm-end{align-items:flex-end !important}.align-items-sm-center{align-items:center !important}.align-items-sm-baseline{align-items:baseline !important}.align-items-sm-stretch{align-items:stretch !important}.align-content-sm-start{align-content:flex-start !important}.align-content-sm-end{align-content:flex-end !important}.align-content-sm-center{align-content:center !important}.align-content-sm-between{align-content:space-between !important}.align-content-sm-around{align-content:space-around !important}.align-content-sm-stretch{align-content:stretch !important}.align-self-sm-auto{align-self:auto !important}.align-self-sm-start{align-self:flex-start !important}.align-self-sm-end{align-self:flex-end !important}.align-self-sm-center{align-self:center !important}.align-self-sm-baseline{align-self:baseline !important}.align-self-sm-stretch{align-self:stretch !important}}@media (min-width: 768px){.flex-md-row{flex-direction:row !important}.flex-md-column{flex-direction:column !important}.flex-md-row-reverse{flex-direction:row-reverse !important}.flex-md-column-reverse{flex-direction:column-reverse !important}.flex-md-wrap{flex-wrap:wrap !important}.flex-md-nowrap{flex-wrap:nowrap !important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse !important}.flex-md-fill{flex:1 1 auto !important}.justify-content-md-start{justify-content:flex-start !important}.justify-content-md-end{justify-content:flex-end !important}.justify-content-md-center{justify-content:center !important}.justify-content-md-between{justify-content:space-between !important}.justify-content-md-around{justify-content:space-around !important}.align-items-md-start{align-items:flex-start !important}.align-items-md-end{align-items:flex-end !important}.align-items-md-center{align-items:center !important}.align-items-md-baseline{align-items:baseline !important}.align-items-md-stretch{align-items:stretch !important}.align-content-md-start{align-content:flex-start !important}.align-content-md-end{align-content:flex-end !important}.align-content-md-center{align-content:center !important}.align-content-md-between{align-content:space-between !important}.align-content-md-around{align-content:space-around !important}.align-content-md-stretch{align-content:stretch !important}.align-self-md-auto{align-self:auto !important}.align-self-md-start{align-self:flex-start !important}.align-self-md-end{align-self:flex-end !important}.align-self-md-center{align-self:center !important}.align-self-md-baseline{align-self:baseline !important}.align-self-md-stretch{align-self:stretch !important}}@media (min-width: 992px){.flex-lg-row{flex-direction:row !important}.flex-lg-column{flex-direction:column !important}.flex-lg-row-reverse{flex-direction:row-reverse !important}.flex-lg-column-reverse{flex-direction:column-reverse !important}.flex-lg-wrap{flex-wrap:wrap !important}.flex-lg-nowrap{flex-wrap:nowrap !important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse !important}.flex-lg-fill{flex:1 1 auto !important}.justify-content-lg-start{justify-content:flex-start !important}.justify-content-lg-end{justify-content:flex-end !important}.justify-content-lg-center{justify-content:center !important}.justify-content-lg-between{justify-content:space-between !important}.justify-content-lg-around{justify-content:space-around !important}.align-items-lg-start{align-items:flex-start !important}.align-items-lg-end{align-items:flex-end !important}.align-items-lg-center{align-items:center !important}.align-items-lg-baseline{align-items:baseline !important}.align-items-lg-stretch{align-items:stretch !important}.align-content-lg-start{align-content:flex-start !important}.align-content-lg-end{align-content:flex-end !important}.align-content-lg-center{align-content:center !important}.align-content-lg-between{align-content:space-between !important}.align-content-lg-around{align-content:space-around !important}.align-content-lg-stretch{align-content:stretch !important}.align-self-lg-auto{align-self:auto !important}.align-self-lg-start{align-self:flex-start !important}.align-self-lg-end{align-self:flex-end !important}.align-self-lg-center{align-self:center !important}.align-self-lg-baseline{align-self:baseline !important}.align-self-lg-stretch{align-self:stretch !important}}@media (min-width: 1200px){.flex-xl-row{flex-direction:row !important}.flex-xl-column{flex-direction:column !important}.flex-xl-row-reverse{flex-direction:row-reverse !important}.flex-xl-column-reverse{flex-direction:column-reverse !important}.flex-xl-wrap{flex-wrap:wrap !important}.flex-xl-nowrap{flex-wrap:nowrap !important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse !important}.flex-xl-fill{flex:1 1 auto !important}.justify-content-xl-start{justify-content:flex-start !important}.justify-content-xl-end{justify-content:flex-end !important}.justify-content-xl-center{justify-content:center !important}.justify-content-xl-between{justify-content:space-between !important}.justify-content-xl-around{justify-content:space-around !important}.align-items-xl-start{align-items:flex-start !important}.align-items-xl-end{align-items:flex-end !important}.align-items-xl-center{align-items:center !important}.align-items-xl-baseline{align-items:baseline !important}.align-items-xl-stretch{align-items:stretch !important}.align-content-xl-start{align-content:flex-start !important}.align-content-xl-end{align-content:flex-end !important}.align-content-xl-center{align-content:center !important}.align-content-xl-between{align-content:space-between !important}.align-content-xl-around{align-content:space-around !important}.align-content-xl-stretch{align-content:stretch !important}.align-self-xl-auto{align-self:auto !important}.align-self-xl-start{align-self:flex-start !important}.align-self-xl-end{align-self:flex-end !important}.align-self-xl-center{align-self:center !important}.align-self-xl-baseline{align-self:baseline !important}.align-self-xl-stretch{align-self:stretch !important}}.float-left{float:left !important}.float-right{float:right !important}.float-none{float:none !important}@media (min-width: 576px){.float-sm-left{float:left !important}.float-sm-right{float:right !important}.float-sm-none{float:none !important}}@media (min-width: 768px){.float-md-left{float:left !important}.float-md-right{float:right !important}.float-md-none{float:none !important}}@media (min-width: 992px){.float-lg-left{float:left !important}.float-lg-right{float:right !important}.float-lg-none{float:none !important}}@media (min-width: 1200px){.float-xl-left{float:left !important}.float-xl-right{float:right !important}.float-xl-none{float:none !important}}.position-static{position:static !important}.position-relative{position:relative !important}.position-absolute{position:absolute !important}.position-fixed{position:fixed !important}.position-sticky{position:sticky !important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports (position: sticky){.sticky-top{position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;clip-path:inset(50%);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal;clip-path:none}.w-25{width:25% !important}.w-50{width:50% !important}.w-75{width:75% !important}.w-100{width:100% !important}.w-auto{width:auto !important}.h-25{height:25% !important}.h-50{height:50% !important}.h-75{height:75% !important}.h-100{height:100% !important}.h-auto{height:auto !important}.mw-100{max-width:100% !important}.mh-100{max-height:100% !important}.m-0{margin:0 !important}.mt-0,.my-0{margin-top:0 !important}.mr-0,.mx-0{margin-right:0 !important}.mb-0,.my-0{margin-bottom:0 !important}.ml-0,.mx-0{margin-left:0 !important}.m-1{margin:.25rem !important}.mt-1,.my-1{margin-top:.25rem !important}.mr-1,.mx-1{margin-right:.25rem !important}.mb-1,.my-1{margin-bottom:.25rem !important}.ml-1,.mx-1{margin-left:.25rem !important}.m-2{margin:.5rem !important}.mt-2,.my-2{margin-top:.5rem !important}.mr-2,.mx-2{margin-right:.5rem !important}.mb-2,.my-2{margin-bottom:.5rem !important}.ml-2,.mx-2{margin-left:.5rem !important}.m-3{margin:1rem !important}.mt-3,.my-3{margin-top:1rem !important}.mr-3,.mx-3{margin-right:1rem !important}.mb-3,.my-3{margin-bottom:1rem !important}.ml-3,.mx-3{margin-left:1rem !important}.m-4{margin:1.5rem !important}.mt-4,.my-4{margin-top:1.5rem !important}.mr-4,.mx-4{margin-right:1.5rem !important}.mb-4,.my-4{margin-bottom:1.5rem !important}.ml-4,.mx-4{margin-left:1.5rem !important}.m-5{margin:3rem !important}.mt-5,.my-5{margin-top:3rem !important}.mr-5,.mx-5{margin-right:3rem !important}.mb-5,.my-5{margin-bottom:3rem !important}.ml-5,.mx-5{margin-left:3rem !important}.p-0{padding:0 !important}.pt-0,.py-0{padding-top:0 !important}.pr-0,.px-0{padding-right:0 !important}.pb-0,.py-0{padding-bottom:0 !important}.pl-0,.px-0{padding-left:0 !important}.p-1{padding:.25rem !important}.pt-1,.py-1{padding-top:.25rem !important}.pr-1,.px-1{padding-right:.25rem !important}.pb-1,.py-1{padding-bottom:.25rem !important}.pl-1,.px-1{padding-left:.25rem !important}.p-2{padding:.5rem !important}.pt-2,.py-2{padding-top:.5rem !important}.pr-2,.px-2{padding-right:.5rem !important}.pb-2,.py-2{padding-bottom:.5rem !important}.pl-2,.px-2{padding-left:.5rem !important}.p-3{padding:1rem !important}.pt-3,.py-3{padding-top:1rem !important}.pr-3,.px-3{padding-right:1rem !important}.pb-3,.py-3{padding-bottom:1rem !important}.pl-3,.px-3{padding-left:1rem !important}.p-4{padding:1.5rem !important}.pt-4,.py-4{padding-top:1.5rem !important}.pr-4,.px-4{padding-right:1.5rem !important}.pb-4,.py-4{padding-bottom:1.5rem !important}.pl-4,.px-4{padding-left:1.5rem !important}.p-5{padding:3rem !important}.pt-5,.py-5{padding-top:3rem !important}.pr-5,.px-5{padding-right:3rem !important}.pb-5,.py-5{padding-bottom:3rem !important}.pl-5,.px-5{padding-left:3rem !important}.m-auto{margin:auto !important}.mt-auto,.my-auto{margin-top:auto !important}.mr-auto,.mx-auto{margin-right:auto !important}.mb-auto,.my-auto{margin-bottom:auto !important}.ml-auto,.mx-auto{margin-left:auto !important}@media (min-width: 576px){.m-sm-0{margin:0 !important}.mt-sm-0,.my-sm-0{margin-top:0 !important}.mr-sm-0,.mx-sm-0{margin-right:0 !important}.mb-sm-0,.my-sm-0{margin-bottom:0 !important}.ml-sm-0,.mx-sm-0{margin-left:0 !important}.m-sm-1{margin:.25rem !important}.mt-sm-1,.my-sm-1{margin-top:.25rem !important}.mr-sm-1,.mx-sm-1{margin-right:.25rem !important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem !important}.ml-sm-1,.mx-sm-1{margin-left:.25rem !important}.m-sm-2{margin:.5rem !important}.mt-sm-2,.my-sm-2{margin-top:.5rem !important}.mr-sm-2,.mx-sm-2{margin-right:.5rem !important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem !important}.ml-sm-2,.mx-sm-2{margin-left:.5rem !important}.m-sm-3{margin:1rem !important}.mt-sm-3,.my-sm-3{margin-top:1rem !important}.mr-sm-3,.mx-sm-3{margin-right:1rem !important}.mb-sm-3,.my-sm-3{margin-bottom:1rem !important}.ml-sm-3,.mx-sm-3{margin-left:1rem !important}.m-sm-4{margin:1.5rem !important}.mt-sm-4,.my-sm-4{margin-top:1.5rem !important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem !important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem !important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem !important}.m-sm-5{margin:3rem !important}.mt-sm-5,.my-sm-5{margin-top:3rem !important}.mr-sm-5,.mx-sm-5{margin-right:3rem !important}.mb-sm-5,.my-sm-5{margin-bottom:3rem !important}.ml-sm-5,.mx-sm-5{margin-left:3rem !important}.p-sm-0{padding:0 !important}.pt-sm-0,.py-sm-0{padding-top:0 !important}.pr-sm-0,.px-sm-0{padding-right:0 !important}.pb-sm-0,.py-sm-0{padding-bottom:0 !important}.pl-sm-0,.px-sm-0{padding-left:0 !important}.p-sm-1{padding:.25rem !important}.pt-sm-1,.py-sm-1{padding-top:.25rem !important}.pr-sm-1,.px-sm-1{padding-right:.25rem !important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem !important}.pl-sm-1,.px-sm-1{padding-left:.25rem !important}.p-sm-2{padding:.5rem !important}.pt-sm-2,.py-sm-2{padding-top:.5rem !important}.pr-sm-2,.px-sm-2{padding-right:.5rem !important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem !important}.pl-sm-2,.px-sm-2{padding-left:.5rem !important}.p-sm-3{padding:1rem !important}.pt-sm-3,.py-sm-3{padding-top:1rem !important}.pr-sm-3,.px-sm-3{padding-right:1rem !important}.pb-sm-3,.py-sm-3{padding-bottom:1rem !important}.pl-sm-3,.px-sm-3{padding-left:1rem !important}.p-sm-4{padding:1.5rem !important}.pt-sm-4,.py-sm-4{padding-top:1.5rem !important}.pr-sm-4,.px-sm-4{padding-right:1.5rem !important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem !important}.pl-sm-4,.px-sm-4{padding-left:1.5rem !important}.p-sm-5{padding:3rem !important}.pt-sm-5,.py-sm-5{padding-top:3rem !important}.pr-sm-5,.px-sm-5{padding-right:3rem !important}.pb-sm-5,.py-sm-5{padding-bottom:3rem !important}.pl-sm-5,.px-sm-5{padding-left:3rem !important}.m-sm-auto{margin:auto !important}.mt-sm-auto,.my-sm-auto{margin-top:auto !important}.mr-sm-auto,.mx-sm-auto{margin-right:auto !important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto !important}.ml-sm-auto,.mx-sm-auto{margin-left:auto !important}}@media (min-width: 768px){.m-md-0{margin:0 !important}.mt-md-0,.my-md-0{margin-top:0 !important}.mr-md-0,.mx-md-0{margin-right:0 !important}.mb-md-0,.my-md-0{margin-bottom:0 !important}.ml-md-0,.mx-md-0{margin-left:0 !important}.m-md-1{margin:.25rem !important}.mt-md-1,.my-md-1{margin-top:.25rem !important}.mr-md-1,.mx-md-1{margin-right:.25rem !important}.mb-md-1,.my-md-1{margin-bottom:.25rem !important}.ml-md-1,.mx-md-1{margin-left:.25rem !important}.m-md-2{margin:.5rem !important}.mt-md-2,.my-md-2{margin-top:.5rem !important}.mr-md-2,.mx-md-2{margin-right:.5rem !important}.mb-md-2,.my-md-2{margin-bottom:.5rem !important}.ml-md-2,.mx-md-2{margin-left:.5rem !important}.m-md-3{margin:1rem !important}.mt-md-3,.my-md-3{margin-top:1rem !important}.mr-md-3,.mx-md-3{margin-right:1rem !important}.mb-md-3,.my-md-3{margin-bottom:1rem !important}.ml-md-3,.mx-md-3{margin-left:1rem !important}.m-md-4{margin:1.5rem !important}.mt-md-4,.my-md-4{margin-top:1.5rem !important}.mr-md-4,.mx-md-4{margin-right:1.5rem !important}.mb-md-4,.my-md-4{margin-bottom:1.5rem !important}.ml-md-4,.mx-md-4{margin-left:1.5rem !important}.m-md-5{margin:3rem !important}.mt-md-5,.my-md-5{margin-top:3rem !important}.mr-md-5,.mx-md-5{margin-right:3rem !important}.mb-md-5,.my-md-5{margin-bottom:3rem !important}.ml-md-5,.mx-md-5{margin-left:3rem !important}.p-md-0{padding:0 !important}.pt-md-0,.py-md-0{padding-top:0 !important}.pr-md-0,.px-md-0{padding-right:0 !important}.pb-md-0,.py-md-0{padding-bottom:0 !important}.pl-md-0,.px-md-0{padding-left:0 !important}.p-md-1{padding:.25rem !important}.pt-md-1,.py-md-1{padding-top:.25rem !important}.pr-md-1,.px-md-1{padding-right:.25rem !important}.pb-md-1,.py-md-1{padding-bottom:.25rem !important}.pl-md-1,.px-md-1{padding-left:.25rem !important}.p-md-2{padding:.5rem !important}.pt-md-2,.py-md-2{padding-top:.5rem !important}.pr-md-2,.px-md-2{padding-right:.5rem !important}.pb-md-2,.py-md-2{padding-bottom:.5rem !important}.pl-md-2,.px-md-2{padding-left:.5rem !important}.p-md-3{padding:1rem !important}.pt-md-3,.py-md-3{padding-top:1rem !important}.pr-md-3,.px-md-3{padding-right:1rem !important}.pb-md-3,.py-md-3{padding-bottom:1rem !important}.pl-md-3,.px-md-3{padding-left:1rem !important}.p-md-4{padding:1.5rem !important}.pt-md-4,.py-md-4{padding-top:1.5rem !important}.pr-md-4,.px-md-4{padding-right:1.5rem !important}.pb-md-4,.py-md-4{padding-bottom:1.5rem !important}.pl-md-4,.px-md-4{padding-left:1.5rem !important}.p-md-5{padding:3rem !important}.pt-md-5,.py-md-5{padding-top:3rem !important}.pr-md-5,.px-md-5{padding-right:3rem !important}.pb-md-5,.py-md-5{padding-bottom:3rem !important}.pl-md-5,.px-md-5{padding-left:3rem !important}.m-md-auto{margin:auto !important}.mt-md-auto,.my-md-auto{margin-top:auto !important}.mr-md-auto,.mx-md-auto{margin-right:auto !important}.mb-md-auto,.my-md-auto{margin-bottom:auto !important}.ml-md-auto,.mx-md-auto{margin-left:auto !important}}@media (min-width: 992px){.m-lg-0{margin:0 !important}.mt-lg-0,.my-lg-0{margin-top:0 !important}.mr-lg-0,.mx-lg-0{margin-right:0 !important}.mb-lg-0,.my-lg-0{margin-bottom:0 !important}.ml-lg-0,.mx-lg-0{margin-left:0 !important}.m-lg-1{margin:.25rem !important}.mt-lg-1,.my-lg-1{margin-top:.25rem !important}.mr-lg-1,.mx-lg-1{margin-right:.25rem !important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem !important}.ml-lg-1,.mx-lg-1{margin-left:.25rem !important}.m-lg-2{margin:.5rem !important}.mt-lg-2,.my-lg-2{margin-top:.5rem !important}.mr-lg-2,.mx-lg-2{margin-right:.5rem !important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem !important}.ml-lg-2,.mx-lg-2{margin-left:.5rem !important}.m-lg-3{margin:1rem !important}.mt-lg-3,.my-lg-3{margin-top:1rem !important}.mr-lg-3,.mx-lg-3{margin-right:1rem !important}.mb-lg-3,.my-lg-3{margin-bottom:1rem !important}.ml-lg-3,.mx-lg-3{margin-left:1rem !important}.m-lg-4{margin:1.5rem !important}.mt-lg-4,.my-lg-4{margin-top:1.5rem !important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem !important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem !important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem !important}.m-lg-5{margin:3rem !important}.mt-lg-5,.my-lg-5{margin-top:3rem !important}.mr-lg-5,.mx-lg-5{margin-right:3rem !important}.mb-lg-5,.my-lg-5{margin-bottom:3rem !important}.ml-lg-5,.mx-lg-5{margin-left:3rem !important}.p-lg-0{padding:0 !important}.pt-lg-0,.py-lg-0{padding-top:0 !important}.pr-lg-0,.px-lg-0{padding-right:0 !important}.pb-lg-0,.py-lg-0{padding-bottom:0 !important}.pl-lg-0,.px-lg-0{padding-left:0 !important}.p-lg-1{padding:.25rem !important}.pt-lg-1,.py-lg-1{padding-top:.25rem !important}.pr-lg-1,.px-lg-1{padding-right:.25rem !important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem !important}.pl-lg-1,.px-lg-1{padding-left:.25rem !important}.p-lg-2{padding:.5rem !important}.pt-lg-2,.py-lg-2{padding-top:.5rem !important}.pr-lg-2,.px-lg-2{padding-right:.5rem !important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem !important}.pl-lg-2,.px-lg-2{padding-left:.5rem !important}.p-lg-3{padding:1rem !important}.pt-lg-3,.py-lg-3{padding-top:1rem !important}.pr-lg-3,.px-lg-3{padding-right:1rem !important}.pb-lg-3,.py-lg-3{padding-bottom:1rem !important}.pl-lg-3,.px-lg-3{padding-left:1rem !important}.p-lg-4{padding:1.5rem !important}.pt-lg-4,.py-lg-4{padding-top:1.5rem !important}.pr-lg-4,.px-lg-4{padding-right:1.5rem !important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem !important}.pl-lg-4,.px-lg-4{padding-left:1.5rem !important}.p-lg-5{padding:3rem !important}.pt-lg-5,.py-lg-5{padding-top:3rem !important}.pr-lg-5,.px-lg-5{padding-right:3rem !important}.pb-lg-5,.py-lg-5{padding-bottom:3rem !important}.pl-lg-5,.px-lg-5{padding-left:3rem !important}.m-lg-auto{margin:auto !important}.mt-lg-auto,.my-lg-auto{margin-top:auto !important}.mr-lg-auto,.mx-lg-auto{margin-right:auto !important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto !important}.ml-lg-auto,.mx-lg-auto{margin-left:auto !important}}@media (min-width: 1200px){.m-xl-0{margin:0 !important}.mt-xl-0,.my-xl-0{margin-top:0 !important}.mr-xl-0,.mx-xl-0{margin-right:0 !important}.mb-xl-0,.my-xl-0{margin-bottom:0 !important}.ml-xl-0,.mx-xl-0{margin-left:0 !important}.m-xl-1{margin:.25rem !important}.mt-xl-1,.my-xl-1{margin-top:.25rem !important}.mr-xl-1,.mx-xl-1{margin-right:.25rem !important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem !important}.ml-xl-1,.mx-xl-1{margin-left:.25rem !important}.m-xl-2{margin:.5rem !important}.mt-xl-2,.my-xl-2{margin-top:.5rem !important}.mr-xl-2,.mx-xl-2{margin-right:.5rem !important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem !important}.ml-xl-2,.mx-xl-2{margin-left:.5rem !important}.m-xl-3{margin:1rem !important}.mt-xl-3,.my-xl-3{margin-top:1rem !important}.mr-xl-3,.mx-xl-3{margin-right:1rem !important}.mb-xl-3,.my-xl-3{margin-bottom:1rem !important}.ml-xl-3,.mx-xl-3{margin-left:1rem !important}.m-xl-4{margin:1.5rem !important}.mt-xl-4,.my-xl-4{margin-top:1.5rem !important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem !important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem !important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem !important}.m-xl-5{margin:3rem !important}.mt-xl-5,.my-xl-5{margin-top:3rem !important}.mr-xl-5,.mx-xl-5{margin-right:3rem !important}.mb-xl-5,.my-xl-5{margin-bottom:3rem !important}.ml-xl-5,.mx-xl-5{margin-left:3rem !important}.p-xl-0{padding:0 !important}.pt-xl-0,.py-xl-0{padding-top:0 !important}.pr-xl-0,.px-xl-0{padding-right:0 !important}.pb-xl-0,.py-xl-0{padding-bottom:0 !important}.pl-xl-0,.px-xl-0{padding-left:0 !important}.p-xl-1{padding:.25rem !important}.pt-xl-1,.py-xl-1{padding-top:.25rem !important}.pr-xl-1,.px-xl-1{padding-right:.25rem !important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem !important}.pl-xl-1,.px-xl-1{padding-left:.25rem !important}.p-xl-2{padding:.5rem !important}.pt-xl-2,.py-xl-2{padding-top:.5rem !important}.pr-xl-2,.px-xl-2{padding-right:.5rem !important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem !important}.pl-xl-2,.px-xl-2{padding-left:.5rem !important}.p-xl-3{padding:1rem !important}.pt-xl-3,.py-xl-3{padding-top:1rem !important}.pr-xl-3,.px-xl-3{padding-right:1rem !important}.pb-xl-3,.py-xl-3{padding-bottom:1rem !important}.pl-xl-3,.px-xl-3{padding-left:1rem !important}.p-xl-4{padding:1.5rem !important}.pt-xl-4,.py-xl-4{padding-top:1.5rem !important}.pr-xl-4,.px-xl-4{padding-right:1.5rem !important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem !important}.pl-xl-4,.px-xl-4{padding-left:1.5rem !important}.p-xl-5{padding:3rem !important}.pt-xl-5,.py-xl-5{padding-top:3rem !important}.pr-xl-5,.px-xl-5{padding-right:3rem !important}.pb-xl-5,.py-xl-5{padding-bottom:3rem !important}.pl-xl-5,.px-xl-5{padding-left:3rem !important}.m-xl-auto{margin:auto !important}.mt-xl-auto,.my-xl-auto{margin-top:auto !important}.mr-xl-auto,.mx-xl-auto{margin-right:auto !important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto !important}.ml-xl-auto,.mx-xl-auto{margin-left:auto !important}}.text-justify{text-align:justify !important}.text-nowrap{white-space:nowrap !important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left !important}.text-right{text-align:right !important}.text-center{text-align:center !important}@media (min-width: 576px){.text-sm-left{text-align:left !important}.text-sm-right{text-align:right !important}.text-sm-center{text-align:center !important}}@media (min-width: 768px){.text-md-left{text-align:left !important}.text-md-right{text-align:right !important}.text-md-center{text-align:center !important}}@media (min-width: 992px){.text-lg-left{text-align:left !important}.text-lg-right{text-align:right !important}.text-lg-center{text-align:center !important}}@media (min-width: 1200px){.text-xl-left{text-align:left !important}.text-xl-right{text-align:right !important}.text-xl-center{text-align:center !important}}.text-lowercase{text-transform:lowercase !important}.text-uppercase{text-transform:uppercase !important}.text-capitalize{text-transform:capitalize !important}.font-weight-light{font-weight:300 !important}.font-weight-normal{font-weight:400 !important}.font-weight-bold{font-weight:700 !important}.font-italic{font-style:italic !important}.text-white{color:#fff !important}.text-primary{color:#007bff !important}a.text-primary:hover,a.text-primary:focus{color:#0062cc !important}.text-secondary{color:#6c757d !important}a.text-secondary:hover,a.text-secondary:focus{color:#545b62 !important}.text-success{color:#28a745 !important}a.text-success:hover,a.text-success:focus{color:#1e7e34 !important}.text-info{color:#17a2b8 !important}a.text-info:hover,a.text-info:focus{color:#117a8b !important}.text-warning{color:#ffc107 !important}a.text-warning:hover,a.text-warning:focus{color:#d39e00 !important}.text-danger{color:#dc3545 !important}a.text-danger:hover,a.text-danger:focus{color:#bd2130 !important}.text-light{color:#f8f9fa !important}a.text-light:hover,a.text-light:focus{color:#dae0e5 !important}.text-dark{color:#343a40 !important}a.text-dark:hover,a.text-dark:focus{color:#1d2124 !important}.text-muted{color:#6c757d !important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.visible{visibility:visible !important}.invisible{visibility:hidden !important}@media print{*,*::before,*::after{text-shadow:none !important;box-shadow:none !important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap !important}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px !important}.container{min-width:992px !important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse !important}.table td,.table th{background-color:#fff !important}.table-bordered th,.table-bordered td{border:1px solid #ddd !important}}.switch{font-size:1rem;position:relative}.switch input{position:absolute;height:1px;width:1px;background:none;border:0;clip:rect(0 0 0 0);clip-path:inset(50%);overflow:hidden;padding:0}.switch input+label{position:relative;min-width:calc(calc(2.375rem * .8) * 2);border-radius:calc(2.375rem * .8);height:calc(2.375rem * .8);line-height:calc(2.375rem * .8);display:inline-block;cursor:pointer;outline:none;user-select:none;vertical-align:middle;text-indent:calc(calc(calc(2.375rem * .8) * 2) + .5rem)}.switch input+label::before,.switch input+label::after{content:'';position:absolute;top:0;left:0;width:calc(calc(2.375rem * .8) * 2);bottom:0;display:block}.switch input+label::before{right:0;background-color:#dee2e6;border-radius:calc(2.375rem * .8);transition:0.2s all}.switch input+label::after{top:2px;left:2px;width:calc(calc(2.375rem * .8) - calc(2px * 2));height:calc(calc(2.375rem * .8) - calc(2px * 2));border-radius:50%;background-color:#fff;transition:0.2s all}.switch input:checked+label::before{background-color:#08d}.switch input:checked+label::after{margin-left:calc(2.375rem * .8)}.switch input:focus+label::before{outline:none;box-shadow:0 0 0 .2rem rgba(0,136,221,0.25)}.switch input:disabled+label{color:#868e96;cursor:not-allowed}.switch input:disabled+label::before{background-color:#e9ecef}.switch.switch-sm{font-size:.875rem}.switch.switch-sm input+label{min-width:calc(calc(1.9375rem * .8) * 2);height:calc(1.9375rem * .8);line-height:calc(1.9375rem * .8);text-indent:calc(calc(calc(1.9375rem * .8) * 2) + .5rem)}.switch.switch-sm input+label::before{width:calc(calc(1.9375rem * .8) * 2)}.switch.switch-sm input+label::after{width:calc(calc(1.9375rem * .8) - calc(2px * 2));height:calc(calc(1.9375rem * .8) - calc(2px * 2))}.switch.switch-sm input:checked+label::after{margin-left:calc(1.9375rem * .8)}.switch.switch-lg{font-size:1.25rem}.switch.switch-lg input+label{min-width:calc(calc(3rem * .8) * 2);height:calc(3rem * .8);line-height:calc(3rem * .8);text-indent:calc(calc(calc(3rem * .8) * 2) + .5rem)}.switch.switch-lg input+label::before{width:calc(calc(3rem * .8) * 2)}.switch.switch-lg input+label::after{width:calc(calc(3rem * .8) - calc(2px * 2));height:calc(calc(3rem * .8) - calc(2px * 2))}.switch.switch-lg input:checked+label::after{margin-left:calc(3rem * .8)}.switch+.switch{margin-left:1rem}.switch.danger input:checked+label::before{background-color:#dc3545}.switch.danger input:focus+label::before{box-shadow:0 0 0 .2rem rgba(220,53,69,0.25)}html{font-size:0.8em;background-color:#f8f9fa}body{background-color:transparent;position:relative}label{margin-bottom:.2rem;min-height:1.5rem}.form-group span label{display:inline-block}.form-group label{display:block}.form-group li label{display:inline-block}.form-group li .form-control{width:auto}.form-group li input[type="radio"].form-control,.form-group li input[type="checkbox"].form-control{display:inline}pre{white-space:pre-wrap}.raw-description{white-space:pre-line}.form-control.small-input,.input-group>.form-control.small-input{width:110px;flex:none}.input-group>input[type=checkbox]{margin:0.5em 1em}.form-row.odd{background-color:#e9ecef}.form-row-modal{padding:0.5rem 2rem}.field-tip{position:absolute;right:10px;top:5px;opacity:0.7}.form-group .select2-container--default .select2-selection--multiple{border:1px solid #ced4da}.page-link.imported-page{color:#aa8fda}.page-link.imported-page.current-page,.page-link.current-page{color:black;font-weight:bold}#modal-advanced-search .modal-header{flex-wrap:wrap;padding-bottom:0}#modal-advanced-search .modal-header .alert-secondary{background-color:#fff}.modal-header,.modal-footer{background-color:#e9ecef}.modal-body.body-scroll{max-height:calc(100vh - 200px);overflow-y:auto}.modal-dialog.full{width:98%;height:98%;max-width:none;padding:1%}.modal-dialog.full .display.dataTable{width:100% !important}.modal-dialog.full .modal-content{height:auto;min-height:100%;border-radius:0}.table{background-color:white}.input-progress.form-control:focus,.input-progress{background-color:#dee2e6}.card-header,.input-progress,.table-striped tbody tr:nth-of-type(2n+1),.dt-bootstrap4 table.dataTable.stripe tbody tr.odd,.dt-bootstrap4 table.dataTable.display tbody tr.odd{background-color:#e9ecef}.dropdown-item:hover,.dropdown-item:focus,.dt-bootstrap4 table.dataTable.hover tbody tr:hover,.dt-bootstrap4 table.dataTable.display tbody tr:hover{background-color:#f6f6f6;background-color:#dee2e6}table.dataTable{font-size:0.8em}.table-modal-lg table.dataTable{font-size:1em}div.dt-buttons{float:right}.dt-button{color:#fff;background-color:#007bff;border-color:#007bff;display:inline-block;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;border:1px solid transparent;color:#fff;background-color:#6c757d;border-color:#6c757d;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color 0.15s ease-in-out,background-color 0.15s ease-in-out,border-color 0.15s ease-in-out,box-shadow 0.15s ease-in-out}.dt-button:hover{color:#fff;background-color:#5a6268;border-color:#545b62}.dt-button:focus,.dt-button.focus{box-shadow:0 0 0 .2rem rgba(108,117,125,0.5)}.dt-button.disabled,.dt-button:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.dt-button:not(:disabled):not(.disabled):active,.dt-button:not(:disabled):not(.disabled).active,.show>.dt-button.dropdown-toggle{color:#fff;background-color:#545b62;border-color:#4e555b}.dt-button:not(:disabled):not(.disabled):active:focus,.dt-button:not(:disabled):not(.disabled).active:focus,.show>.dt-button.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,0.5)}.dt-button.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.dt-button.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.dt-button.btn-success:focus,.dt-button.btn-success.focus{box-shadow:0 0 0 .2rem rgba(40,167,69,0.5)}.dt-button.btn-success.disabled,.dt-button.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.dt-button.btn-success:not(:disabled):not(.disabled):active,.dt-button.btn-success:not(:disabled):not(.disabled).active,.show>.dt-button.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.dt-button.btn-success:not(:disabled):not(.disabled):active:focus,.dt-button.btn-success:not(:disabled):not(.disabled).active:focus,.show>.dt-button.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,0.5)}.dt-button.disabled{background-color:#f8f9fa;border-color:#f8f9fa;color:#adb5bd;cursor:not-allowed}.small-button{padding:0.1em 0.2em}.previous-value{margin:0.4em 0;display:block}h3,.h3{font-size:1.5rem}h4,.h4{font-size:1.1rem}textarea{height:90px}.sheet h4{color:#6c757d}#bookmark-list .input-link{width:100%;padding-right:5px}#window-fixed-menu{background-color:#e9ecef;position:fixed;right:0;margin-top:100px;z-index:50;width:200px}#window-fixed-menu-list li{padding-bottom:0.5em}#window-fixed-menu-list li a.nav-link{background-color:white}#window-fixed-menu-list li a.nav-link.active{background-color:#007bff}#window-menu-title{font-size:1.3em}#window-menu-control{font-size:0.6em;padding-top:0.2em}#window-fixed-menu.hidden{transform:rotate(270deg);transform-origin:right bottom 0}#window-fixed-menu.hidden i.fa-times{transform:rotate(45deg);transform-origin:10px 10px 0;padding-left:0.1em}.form h4,.form h3,.collapse-form .card-header,#window h3{background-color:#ced4da}.collapse-form .card,.collapse-form .card-header{border-radius:0;border:0 solid}.collapse-form .card-header{padding:0;text-align:center}.collapse-form .card-header h4{margin-bottom:0}.collapse-form .card-header .btn.btn-link{color:#212529;width:100%}.collapse-form .card-body{border:1px solid #ced4da}.collapse-form .fa-expand,.collapse-form .collapsed .fa-compress{display:none}.collapse-form .collapsed .fa-expand,.collapse-form .fa-compress{display:inline-block}.clean-table h4,.form h4,.form h3,.collapse-form .card-header h4 .btn,.sheet h4,.sheet h3,.sheet h2{text-align:center;text-shadow:2px 2px 2px rgba(150,150,150,0.7)}.sheet .subsection{background-color:#e9ecef}.sheet .row.toolbar{padding:0.5em 0.75em}.sheet .row{padding:0 0.75em;margin:0}.clean-table h4{margin-top:1em}.container{margin-top:1em;margin-bottom:8em}.bg-dark{background-color:#432776 !important}.navbar{padding:0 0.5rem}.navbar-dark .navbar-nav.action-menu .nav-link{color:#ffe484;border:1px solid #ffe484;border-radius:4px;margin:0.2em;padding:0.3em 0.6em}.navbar-dark .navbar-nav.action-menu .d-none .nav-link{border:0px solid transparent}.navbar-dark .navbar-nav.action-menu .d-none .nav-link:hover{background-color:transparent;color:#ffe484}.navbar-dark .navbar-nav.action-menu .nav-link:hover{background-color:#ffe484;color:#343a40}.navbar-dark .navbar-nav.action-menu .nav-link.dropdown-toggle::after{color:#ffe484}.navbar-dark .navbar-nav.action-menu .nav-link.dropdown-toggle:hover::after{color:#343a40}#context-menu,#reminder,.confirm-message,div#validation-bar{background-color:#6f42c1;color:rgba(255,255,255,0.8)}#reminder{padding:0.6em 1em 0.1em 1em}#alert-list{padding:0.6em 0}#alert-list a{font-size:1.1rem}.confirm-message{text-align:center;margin:0;padding:0.5rem;font-weight:bold}.is-invalid input{border-color:#f99}.errorlist{color:#900}#shortcut-menu{width:700px;padding:1em}#context-menu a.nav-link{color:rgba(255,255,255,0.8);padding:0.8rem 0.5rem 0.7rem 0.5rem}#context-menu .breadcrumb{margin-bottom:0;background-color:transparent}#current_items{width:100%}div#foot{background-color:#432776;color:rgba(255,255,255,0.5)}div#foot a{color:#ddd}div#foot a:hover{color:#fff}.breadcrumb button{border:0 transparent;background-color:transparent}.breadcrumb a:hover{text-decoration:none}.breadcrumb button:hover{cursor:pointer;color:#0062cc}.input-group.date input{border:1px solid #dee2e6;border-radius:.25rem;padding:.375rem .75rem;font-size:1rem;line-height:1.5}.input-group.date .input-group-text:hover{cursor:pointer}.input-group>ul{padding:0.5em;border:1px solid #dee2e6;border-radius:.25rem;margin:0;list-style:none}.help-text{max-height:250px;overflow:auto}.input-link{color:#6c757d}.input-link.disabled{color:#adb5bd}.input-link:hover{color:#343a40;cursor:pointer}.input-link.disabled:hover{color:#adb5bd;cursor:not-allowed}.input-sep{background-color:#fff;padding:0.3rem}.search_button{display:none}.lightgallery-captions{display:none}.lightgallery-subimage{display:inline-block;width:80px;padding:0.2em}.lightgallery-subimage img{width:100%}.lg .lg-sub-html{text-align:left}.lg .lg-sub-html .close{color:#fff}.lg .lg-sub-html .close:hover{opacity:0.9}#basket-manage #foot_pk{display:none}#basket-manage #grid_pk_meta_wrapper{width:50%;float:left;padding-bottom:80px}#basket-add-button{width:8%;float:left;margin:20vh 1% 0 1%}#basket-content-wrapper{width:40%;float:left}#basket-content{text-align:left;overflow:auto;max-height:60vh}.ui-widget-content{border:1px solid #dee2e6;background-color:#fff}.ui-menu-item{padding:0.2em 0.4em;border:1px solid #fff}.ui-menu-item:hover{color:#6f3b93;border:1px solid #6f3b93;cursor:pointer}.ui-autocomplete{font-size:0.7em;z-index:10000 !important;width:350px;border:5px solid #dee2e6;outline:none}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:none}.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px} + */:root{--blue: #007bff;--indigo: #6610f2;--purple: #6f42c1;--pink: #e83e8c;--red: #dc3545;--orange: #fd7e14;--yellow: #ffc107;--green: #28a745;--teal: #20c997;--cyan: #17a2b8;--white: #fff;--gray: #6c757d;--gray-dark: #343a40;--primary: #007bff;--secondary: #6c757d;--success: #28a745;--info: #17a2b8;--warning: #ffc107;--danger: #dc3545;--light: #f8f9fa;--dark: #343a40;--breakpoint-xs: 0;--breakpoint-sm: 576px;--breakpoint-md: 768px;--breakpoint-lg: 992px;--breakpoint-xl: 1200px;--font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace}*,*::before,*::after{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:rgba(0,0,0,0)}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0 !important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[title],abbr[data-original-title]{text-decoration:underline;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul,dl{margin-top:0;margin-bottom:1rem}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#6f3b93;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#542c6f;text-decoration:none}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):hover,a:not([href]):not([tabindex]):focus{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}pre,code,kbd,samp{font-family:monospace, monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}input,button,select,optgroup,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}button,html [type="button"],[type="reset"],[type="submit"]{-webkit-appearance:button}button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner{padding:0;border-style:none}input[type="radio"],input[type="checkbox"]{box-sizing:border-box;padding:0}input[type="date"],input[type="time"],input[type="datetime-local"],input[type="month"]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto}[type="search"]{outline-offset:-2px;-webkit-appearance:none}[type="search"]::-webkit-search-cancel-button,[type="search"]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none !important}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.2;color:inherit}h1,.h1{font-size:2.5rem}h2,.h2{font-size:2rem}h3,.h3{font-size:1.75rem}h4,.h4{font-size:1.5rem}h5,.h5{font-size:1.25rem}h6,.h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,0.1)}small,.small{font-size:80%;font-weight:400}mark,.mark{padding:.2em;background-color:#fcf8e3}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#6c757d}.blockquote-footer::before{content:"\2014 \00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#6c757d}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}code{font-size:87.5%;color:#e83e8c;word-break:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width: 576px){.container{max-width:540px}}@media (min-width: 768px){.container{max-width:720px}}@media (min-width: 992px){.container{max-width:960px}}@media (min-width: 1200px){.container{max-width:1140px}}.container-fluid{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{display:flex;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*="col-"]{padding-right:0;padding-left:0}.col-1,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-10,.col-11,.col-12,.col,.col-auto,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm,.col-sm-auto,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-md,.col-md-auto,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg,.col-lg-auto,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl,.col-xl-auto{position:relative;width:100%;min-height:1px;padding-right:15px;padding-left:15px}.col{flex-basis:0;flex-grow:1;max-width:100%}.col-auto{flex:0 0 auto;width:auto;max-width:none}.col-1{flex:0 0 8.33333%;max-width:8.33333%}.col-2{flex:0 0 16.66667%;max-width:16.66667%}.col-3{flex:0 0 25%;max-width:25%}.col-4{flex:0 0 33.33333%;max-width:33.33333%}.col-5{flex:0 0 41.66667%;max-width:41.66667%}.col-6{flex:0 0 50%;max-width:50%}.col-7{flex:0 0 58.33333%;max-width:58.33333%}.col-8{flex:0 0 66.66667%;max-width:66.66667%}.col-9{flex:0 0 75%;max-width:75%}.col-10{flex:0 0 83.33333%;max-width:83.33333%}.col-11{flex:0 0 91.66667%;max-width:91.66667%}.col-12{flex:0 0 100%;max-width:100%}.order-first{order:-1}.order-last{order:13}.order-0{order:0}.order-1{order:1}.order-2{order:2}.order-3{order:3}.order-4{order:4}.order-5{order:5}.order-6{order:6}.order-7{order:7}.order-8{order:8}.order-9{order:9}.order-10{order:10}.order-11{order:11}.order-12{order:12}.offset-1{margin-left:8.33333%}.offset-2{margin-left:16.66667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333%}.offset-5{margin-left:41.66667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333%}.offset-8{margin-left:66.66667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333%}.offset-11{margin-left:91.66667%}@media (min-width: 576px){.col-sm{flex-basis:0;flex-grow:1;max-width:100%}.col-sm-auto{flex:0 0 auto;width:auto;max-width:none}.col-sm-1{flex:0 0 8.33333%;max-width:8.33333%}.col-sm-2{flex:0 0 16.66667%;max-width:16.66667%}.col-sm-3{flex:0 0 25%;max-width:25%}.col-sm-4{flex:0 0 33.33333%;max-width:33.33333%}.col-sm-5{flex:0 0 41.66667%;max-width:41.66667%}.col-sm-6{flex:0 0 50%;max-width:50%}.col-sm-7{flex:0 0 58.33333%;max-width:58.33333%}.col-sm-8{flex:0 0 66.66667%;max-width:66.66667%}.col-sm-9{flex:0 0 75%;max-width:75%}.col-sm-10{flex:0 0 83.33333%;max-width:83.33333%}.col-sm-11{flex:0 0 91.66667%;max-width:91.66667%}.col-sm-12{flex:0 0 100%;max-width:100%}.order-sm-first{order:-1}.order-sm-last{order:13}.order-sm-0{order:0}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333%}.offset-sm-2{margin-left:16.66667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333%}.offset-sm-5{margin-left:41.66667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333%}.offset-sm-8{margin-left:66.66667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333%}.offset-sm-11{margin-left:91.66667%}}@media (min-width: 768px){.col-md{flex-basis:0;flex-grow:1;max-width:100%}.col-md-auto{flex:0 0 auto;width:auto;max-width:none}.col-md-1{flex:0 0 8.33333%;max-width:8.33333%}.col-md-2{flex:0 0 16.66667%;max-width:16.66667%}.col-md-3{flex:0 0 25%;max-width:25%}.col-md-4{flex:0 0 33.33333%;max-width:33.33333%}.col-md-5{flex:0 0 41.66667%;max-width:41.66667%}.col-md-6{flex:0 0 50%;max-width:50%}.col-md-7{flex:0 0 58.33333%;max-width:58.33333%}.col-md-8{flex:0 0 66.66667%;max-width:66.66667%}.col-md-9{flex:0 0 75%;max-width:75%}.col-md-10{flex:0 0 83.33333%;max-width:83.33333%}.col-md-11{flex:0 0 91.66667%;max-width:91.66667%}.col-md-12{flex:0 0 100%;max-width:100%}.order-md-first{order:-1}.order-md-last{order:13}.order-md-0{order:0}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333%}.offset-md-2{margin-left:16.66667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333%}.offset-md-5{margin-left:41.66667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333%}.offset-md-8{margin-left:66.66667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333%}.offset-md-11{margin-left:91.66667%}}@media (min-width: 992px){.col-lg{flex-basis:0;flex-grow:1;max-width:100%}.col-lg-auto{flex:0 0 auto;width:auto;max-width:none}.col-lg-1{flex:0 0 8.33333%;max-width:8.33333%}.col-lg-2{flex:0 0 16.66667%;max-width:16.66667%}.col-lg-3{flex:0 0 25%;max-width:25%}.col-lg-4{flex:0 0 33.33333%;max-width:33.33333%}.col-lg-5{flex:0 0 41.66667%;max-width:41.66667%}.col-lg-6{flex:0 0 50%;max-width:50%}.col-lg-7{flex:0 0 58.33333%;max-width:58.33333%}.col-lg-8{flex:0 0 66.66667%;max-width:66.66667%}.col-lg-9{flex:0 0 75%;max-width:75%}.col-lg-10{flex:0 0 83.33333%;max-width:83.33333%}.col-lg-11{flex:0 0 91.66667%;max-width:91.66667%}.col-lg-12{flex:0 0 100%;max-width:100%}.order-lg-first{order:-1}.order-lg-last{order:13}.order-lg-0{order:0}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333%}.offset-lg-2{margin-left:16.66667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333%}.offset-lg-5{margin-left:41.66667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333%}.offset-lg-8{margin-left:66.66667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333%}.offset-lg-11{margin-left:91.66667%}}@media (min-width: 1200px){.col-xl{flex-basis:0;flex-grow:1;max-width:100%}.col-xl-auto{flex:0 0 auto;width:auto;max-width:none}.col-xl-1{flex:0 0 8.33333%;max-width:8.33333%}.col-xl-2{flex:0 0 16.66667%;max-width:16.66667%}.col-xl-3{flex:0 0 25%;max-width:25%}.col-xl-4{flex:0 0 33.33333%;max-width:33.33333%}.col-xl-5{flex:0 0 41.66667%;max-width:41.66667%}.col-xl-6{flex:0 0 50%;max-width:50%}.col-xl-7{flex:0 0 58.33333%;max-width:58.33333%}.col-xl-8{flex:0 0 66.66667%;max-width:66.66667%}.col-xl-9{flex:0 0 75%;max-width:75%}.col-xl-10{flex:0 0 83.33333%;max-width:83.33333%}.col-xl-11{flex:0 0 91.66667%;max-width:91.66667%}.col-xl-12{flex:0 0 100%;max-width:100%}.order-xl-first{order:-1}.order-xl-last{order:13}.order-xl-0{order:0}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333%}.offset-xl-2{margin-left:16.66667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333%}.offset-xl-5{margin-left:41.66667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333%}.offset-xl-8{margin-left:66.66667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333%}.offset-xl-11{margin-left:91.66667%}}.table{width:100%;max-width:100%;margin-bottom:1rem;background-color:rgba(0,0,0,0)}.table th,.table td{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table .table{background-color:#fff}.table-sm th,.table-sm td{padding:.3rem}.table-bordered{border:1px solid #dee2e6}.table-bordered th,.table-bordered td{border:1px solid #dee2e6}.table-bordered thead th,.table-bordered thead td{border-bottom-width:2px}.table-borderless th,.table-borderless td,.table-borderless thead th,.table-borderless tbody+tbody{border:0}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,0.05)}.table-hover tbody tr:hover{background-color:rgba(0,0,0,0.075)}.table-primary,.table-primary>th,.table-primary>td{background-color:#b8daff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>th,.table-secondary>td{background-color:#d6d8db}.table-hover .table-secondary:hover{background-color:#c8cbcf}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>th,.table-success>td{background-color:#c3e6cb}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>th,.table-info>td{background-color:#bee5eb}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>th,.table-warning>td{background-color:#ffeeba}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>th,.table-danger>td{background-color:#f5c6cb}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>th,.table-light>td{background-color:#fdfdfe}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>th,.table-dark>td{background-color:#c6c8ca}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>th,.table-active>td{background-color:rgba(0,0,0,0.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,0.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,0.075)}.table .thead-dark th{color:#fff;background-color:#212529;border-color:#32383e}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#dee2e6}.table-dark{color:#fff;background-color:#212529}.table-dark th,.table-dark td,.table-dark thead th{border-color:#32383e}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,0.05)}.table-dark.table-hover tbody tr:hover{background-color:rgba(255,255,255,0.075)}@media (max-width: 575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-sm>.table-bordered{border:0}}@media (max-width: 767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-md>.table-bordered{border:0}}@media (max-width: 991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-lg>.table-bordered{border:0}}@media (max-width: 1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color 0.15s ease-in-out,box-shadow 0.15s ease-in-out}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,0.25)}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}select.form-control:not([size]):not([multiple]){height:calc(2.25rem + 2px)}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding-top:.375rem;padding-bottom:.375rem;margin-bottom:0;line-height:1.5;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-sm,.input-group-sm>.form-control-plaintext.form-control,.input-group-sm>.input-group-prepend>.form-control-plaintext.input-group-text,.input-group-sm>.input-group-append>.form-control-plaintext.input-group-text,.input-group-sm>.input-group-prepend>.form-control-plaintext.btn,.input-group-sm>.input-group-append>.form-control-plaintext.btn,.form-control-plaintext.form-control-lg,.input-group-lg>.form-control-plaintext.form-control,.input-group-lg>.input-group-prepend>.form-control-plaintext.input-group-text,.input-group-lg>.input-group-append>.form-control-plaintext.input-group-text,.input-group-lg>.input-group-prepend>.form-control-plaintext.btn,.input-group-lg>.input-group-append>.form-control-plaintext.btn{padding-right:0;padding-left:0}.form-control-sm,.input-group-sm>.form-control,.input-group-sm>.input-group-prepend>.input-group-text,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-append>.btn{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}select.form-control-sm:not([size]):not([multiple]),.input-group-sm>select.form-control:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-sm>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-sm>.input-group-append>select.btn:not([size]):not([multiple]){height:calc(1.8125rem + 2px)}.form-control-lg,.input-group-lg>.form-control,.input-group-lg>.input-group-prepend>.input-group-text,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-append>.btn{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}select.form-control-lg:not([size]):not([multiple]),.input-group-lg>select.form-control:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-lg>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-lg>.input-group-append>select.btn:not([size]):not([multiple]){height:calc(2.875rem + 2px)}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:flex;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*="col-"]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled ~ .form-check-label{color:#6c757d}.form-check-label{margin-bottom:0}.form-check-inline{display:inline-flex;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#28a745}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(40,167,69,0.8);border-radius:.2rem}.was-validated .form-control:valid,.form-control.is-valid,.was-validated .custom-select:valid,.custom-select.is-valid{border-color:#28a745}.was-validated .form-control:valid:focus,.form-control.is-valid:focus,.was-validated .custom-select:valid:focus,.custom-select.is-valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,0.25)}.was-validated .form-control:valid ~ .valid-feedback,.was-validated .form-control:valid ~ .valid-tooltip,.form-control.is-valid ~ .valid-feedback,.form-control.is-valid ~ .valid-tooltip,.was-validated .custom-select:valid ~ .valid-feedback,.was-validated .custom-select:valid ~ .valid-tooltip,.custom-select.is-valid ~ .valid-feedback,.custom-select.is-valid ~ .valid-tooltip{display:block}.was-validated .form-check-input:valid ~ .form-check-label,.form-check-input.is-valid ~ .form-check-label{color:#28a745}.was-validated .form-check-input:valid ~ .valid-feedback,.was-validated .form-check-input:valid ~ .valid-tooltip,.form-check-input.is-valid ~ .valid-feedback,.form-check-input.is-valid ~ .valid-tooltip{display:block}.was-validated .custom-control-input:valid ~ .custom-control-label,.custom-control-input.is-valid ~ .custom-control-label{color:#28a745}.was-validated .custom-control-input:valid ~ .custom-control-label::before,.custom-control-input.is-valid ~ .custom-control-label::before{background-color:#71dd8a}.was-validated .custom-control-input:valid ~ .valid-feedback,.was-validated .custom-control-input:valid ~ .valid-tooltip,.custom-control-input.is-valid ~ .valid-feedback,.custom-control-input.is-valid ~ .valid-tooltip{display:block}.was-validated .custom-control-input:valid:checked ~ .custom-control-label::before,.custom-control-input.is-valid:checked ~ .custom-control-label::before{background-color:#34ce57}.was-validated .custom-control-input:valid:focus ~ .custom-control-label::before,.custom-control-input.is-valid:focus ~ .custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(40,167,69,0.25)}.was-validated .custom-file-input:valid ~ .custom-file-label,.custom-file-input.is-valid ~ .custom-file-label{border-color:#28a745}.was-validated .custom-file-input:valid ~ .custom-file-label::before,.custom-file-input.is-valid ~ .custom-file-label::before{border-color:inherit}.was-validated .custom-file-input:valid ~ .valid-feedback,.was-validated .custom-file-input:valid ~ .valid-tooltip,.custom-file-input.is-valid ~ .valid-feedback,.custom-file-input.is-valid ~ .valid-tooltip{display:block}.was-validated .custom-file-input:valid:focus ~ .custom-file-label,.custom-file-input.is-valid:focus ~ .custom-file-label{box-shadow:0 0 0 .2rem rgba(40,167,69,0.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(220,53,69,0.8);border-radius:.2rem}.was-validated .form-control:invalid,.form-control.is-invalid,.was-validated .custom-select:invalid,.custom-select.is-invalid{border-color:#dc3545}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus,.was-validated .custom-select:invalid:focus,.custom-select.is-invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,0.25)}.was-validated .form-control:invalid ~ .invalid-feedback,.was-validated .form-control:invalid ~ .invalid-tooltip,.form-control.is-invalid ~ .invalid-feedback,.form-control.is-invalid ~ .invalid-tooltip,.was-validated .custom-select:invalid ~ .invalid-feedback,.was-validated .custom-select:invalid ~ .invalid-tooltip,.custom-select.is-invalid ~ .invalid-feedback,.custom-select.is-invalid ~ .invalid-tooltip{display:block}.was-validated .form-check-input:invalid ~ .form-check-label,.form-check-input.is-invalid ~ .form-check-label{color:#dc3545}.was-validated .form-check-input:invalid ~ .invalid-feedback,.was-validated .form-check-input:invalid ~ .invalid-tooltip,.form-check-input.is-invalid ~ .invalid-feedback,.form-check-input.is-invalid ~ .invalid-tooltip{display:block}.was-validated .custom-control-input:invalid ~ .custom-control-label,.custom-control-input.is-invalid ~ .custom-control-label{color:#dc3545}.was-validated .custom-control-input:invalid ~ .custom-control-label::before,.custom-control-input.is-invalid ~ .custom-control-label::before{background-color:#efa2a9}.was-validated .custom-control-input:invalid ~ .invalid-feedback,.was-validated .custom-control-input:invalid ~ .invalid-tooltip,.custom-control-input.is-invalid ~ .invalid-feedback,.custom-control-input.is-invalid ~ .invalid-tooltip{display:block}.was-validated .custom-control-input:invalid:checked ~ .custom-control-label::before,.custom-control-input.is-invalid:checked ~ .custom-control-label::before{background-color:#e4606d}.was-validated .custom-control-input:invalid:focus ~ .custom-control-label::before,.custom-control-input.is-invalid:focus ~ .custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(220,53,69,0.25)}.was-validated .custom-file-input:invalid ~ .custom-file-label,.custom-file-input.is-invalid ~ .custom-file-label{border-color:#dc3545}.was-validated .custom-file-input:invalid ~ .custom-file-label::before,.custom-file-input.is-invalid ~ .custom-file-label::before{border-color:inherit}.was-validated .custom-file-input:invalid ~ .invalid-feedback,.was-validated .custom-file-input:invalid ~ .invalid-tooltip,.custom-file-input.is-invalid ~ .invalid-feedback,.custom-file-input.is-invalid ~ .invalid-tooltip{display:block}.was-validated .custom-file-input:invalid:focus ~ .custom-file-label,.custom-file-input.is-invalid:focus ~ .custom-file-label{box-shadow:0 0 0 .2rem rgba(220,53,69,0.25)}.form-inline{display:flex;flex-flow:row wrap;align-items:center}.form-inline .form-check{width:100%}@media (min-width: 576px){.form-inline label{display:flex;align-items:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:flex;flex:0 0 auto;flex-flow:row wrap;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .input-group,.form-inline .custom-select{width:auto}.form-inline .form-check{display:flex;align-items:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{align-items:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;user-select:none;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color 0.15s ease-in-out,background-color 0.15s ease-in-out,border-color 0.15s ease-in-out,box-shadow 0.15s ease-in-out}.btn:hover,.btn:focus{text-decoration:none}.btn:focus,.btn.focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,0.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}.btn:not(:disabled):not(.disabled):active,.btn:not(:disabled):not(.disabled).active{background-image:none}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary:focus,.btn-primary.focus{box-shadow:0 0 0 .2rem rgba(0,123,255,0.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:not(:disabled):not(.disabled):active,.btn-primary:not(:disabled):not(.disabled).active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0062cc;border-color:#005cbf}.btn-primary:not(:disabled):not(.disabled):active:focus,.btn-primary:not(:disabled):not(.disabled).active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,0.5)}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5a6268;border-color:#545b62}.btn-secondary:focus,.btn-secondary.focus{box-shadow:0 0 0 .2rem rgba(108,117,125,0.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:not(:disabled):not(.disabled):active,.btn-secondary:not(:disabled):not(.disabled).active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#545b62;border-color:#4e555b}.btn-secondary:not(:disabled):not(.disabled):active:focus,.btn-secondary:not(:disabled):not(.disabled).active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,0.5)}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success:focus,.btn-success.focus{box-shadow:0 0 0 .2rem rgba(40,167,69,0.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:not(:disabled):not(.disabled):active,.btn-success:not(:disabled):not(.disabled).active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.btn-success:not(:disabled):not(.disabled):active:focus,.btn-success:not(:disabled):not(.disabled).active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,0.5)}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info:focus,.btn-info.focus{box-shadow:0 0 0 .2rem rgba(23,162,184,0.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:not(:disabled):not(.disabled):active,.btn-info:not(:disabled):not(.disabled).active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#117a8b;border-color:#10707f}.btn-info:not(:disabled):not(.disabled):active:focus,.btn-info:not(:disabled):not(.disabled).active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,0.5)}.btn-warning{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#212529;background-color:#e0a800;border-color:#d39e00}.btn-warning:focus,.btn-warning.focus{box-shadow:0 0 0 .2rem rgba(255,193,7,0.5)}.btn-warning.disabled,.btn-warning:disabled{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:not(:disabled):not(.disabled):active,.btn-warning:not(:disabled):not(.disabled).active,.show>.btn-warning.dropdown-toggle{color:#212529;background-color:#d39e00;border-color:#c69500}.btn-warning:not(:disabled):not(.disabled):active:focus,.btn-warning:not(:disabled):not(.disabled).active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,0.5)}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger:focus,.btn-danger.focus{box-shadow:0 0 0 .2rem rgba(220,53,69,0.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:not(:disabled):not(.disabled):active,.btn-danger:not(:disabled):not(.disabled).active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#bd2130;border-color:#b21f2d}.btn-danger:not(:disabled):not(.disabled):active:focus,.btn-danger:not(:disabled):not(.disabled).active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,0.5)}.btn-light{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#212529;background-color:#e2e6ea;border-color:#dae0e5}.btn-light:focus,.btn-light.focus{box-shadow:0 0 0 .2rem rgba(248,249,250,0.5)}.btn-light.disabled,.btn-light:disabled{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:not(:disabled):not(.disabled):active,.btn-light:not(:disabled):not(.disabled).active,.show>.btn-light.dropdown-toggle{color:#212529;background-color:#dae0e5;border-color:#d3d9df}.btn-light:not(:disabled):not(.disabled):active:focus,.btn-light:not(:disabled):not(.disabled).active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,0.5)}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark:focus,.btn-dark.focus{box-shadow:0 0 0 .2rem rgba(52,58,64,0.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:not(:disabled):not(.disabled):active,.btn-dark:not(:disabled):not(.disabled).active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1d2124;border-color:#171a1d}.btn-dark:not(:disabled):not(.disabled):active:focus,.btn-dark:not(:disabled):not(.disabled).active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,0.5)}.btn-outline-primary{color:#007bff;background-color:transparent;background-image:none;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:focus,.btn-outline-primary.focus{box-shadow:0 0 0 .2rem rgba(0,123,255,0.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled):active,.btn-outline-primary:not(:disabled):not(.disabled).active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,0.5)}.btn-outline-secondary{color:#6c757d;background-color:transparent;background-image:none;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:focus,.btn-outline-secondary.focus{box-shadow:0 0 0 .2rem rgba(108,117,125,0.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled):active,.btn-outline-secondary:not(:disabled):not(.disabled).active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,0.5)}.btn-outline-success{color:#28a745;background-color:transparent;background-image:none;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:focus,.btn-outline-success.focus{box-shadow:0 0 0 .2rem rgba(40,167,69,0.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled):active,.btn-outline-success:not(:disabled):not(.disabled).active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:not(:disabled):not(.disabled):active:focus,.btn-outline-success:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,0.5)}.btn-outline-info{color:#17a2b8;background-color:transparent;background-image:none;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:focus,.btn-outline-info.focus{box-shadow:0 0 0 .2rem rgba(23,162,184,0.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled):active,.btn-outline-info:not(:disabled):not(.disabled).active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:not(:disabled):not(.disabled):active:focus,.btn-outline-info:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,0.5)}.btn-outline-warning{color:#ffc107;background-color:transparent;background-image:none;border-color:#ffc107}.btn-outline-warning:hover{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:focus,.btn-outline-warning.focus{box-shadow:0 0 0 .2rem rgba(255,193,7,0.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled):active,.btn-outline-warning:not(:disabled):not(.disabled).active,.show>.btn-outline-warning.dropdown-toggle{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,0.5)}.btn-outline-danger{color:#dc3545;background-color:transparent;background-image:none;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:focus,.btn-outline-danger.focus{box-shadow:0 0 0 .2rem rgba(220,53,69,0.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled):active,.btn-outline-danger:not(:disabled):not(.disabled).active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,0.5)}.btn-outline-light{color:#f8f9fa;background-color:transparent;background-image:none;border-color:#f8f9fa}.btn-outline-light:hover{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:focus,.btn-outline-light.focus{box-shadow:0 0 0 .2rem rgba(248,249,250,0.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled):active,.btn-outline-light:not(:disabled):not(.disabled).active,.show>.btn-outline-light.dropdown-toggle{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:not(:disabled):not(.disabled):active:focus,.btn-outline-light:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,0.5)}.btn-outline-dark{color:#343a40;background-color:transparent;background-image:none;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:focus,.btn-outline-dark.focus{box-shadow:0 0 0 .2rem rgba(52,58,64,0.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled):active,.btn-outline-dark:not(:disabled):not(.disabled).active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,0.5)}.btn-link{font-weight:400;color:#6f3b93;background-color:transparent}.btn-link:hover{color:#542c6f;text-decoration:none;background-color:transparent;border-color:transparent}.btn-link:focus,.btn-link.focus{text-decoration:none;border-color:transparent;box-shadow:none}.btn-link:disabled,.btn-link.disabled{color:#6c757d}.btn-lg,.btn-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-sm,.btn-group-sm>.btn{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;transition:opacity 0.15s linear}.fade.show{opacity:1}.collapse{display:none}.collapse.show{display:block}tr.collapse.show{display:table-row}tbody.collapse.show{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;transition:height 0.35s ease}.dropup,.dropdown{position:relative}.dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,0.15);border-radius:.25rem}.dropup .dropdown-menu{margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;width:0;height:0;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:hover,.dropdown-item:focus{color:#16181b;text-decoration:none;background-color:#f8f9fa}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#6c757d;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1.5rem;color:#212529}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:0 1 auto}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover{z-index:1}.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group,.btn-group-vertical .btn+.btn,.btn-group-vertical .btn+.btn-group,.btn-group-vertical .btn-group+.btn,.btn-group-vertical .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:not(:last-child):not(.dropdown-toggle),.btn-group>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:not(:first-child),.btn-group>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after{margin-left:0}.btn-sm+.dropdown-toggle-split,.btn-group-sm>.btn+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical .btn,.btn-group-vertical .btn-group{width:100%}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle),.btn-group-vertical>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type="radio"],.btn-group-toggle>.btn input[type="checkbox"],.btn-group-toggle>.btn-group>.btn input[type="radio"],.btn-group-toggle>.btn-group>.btn input[type="checkbox"]{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.custom-select,.input-group>.custom-file{position:relative;flex:1 1 auto;width:1%;margin-bottom:0}.input-group>.form-control:focus,.input-group>.custom-select:focus,.input-group>.custom-file:focus{z-index:3}.input-group>.form-control+.form-control,.input-group>.form-control+.custom-select,.input-group>.form-control+.custom-file,.input-group>.custom-select+.form-control,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.custom-file,.input-group>.custom-file+.form-control,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.custom-file{margin-left:-1px}.input-group>.form-control:not(:last-child),.input-group>.custom-select:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.form-control:not(:first-child),.input-group>.custom-select:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:flex;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::before{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label,.input-group>.custom-file:not(:first-child) .custom-file-label::before{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-prepend,.input-group-append{display:flex}.input-group-prepend .btn,.input-group-append .btn{position:relative;z-index:2}.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.input-group-text,.input-group-append .input-group-text+.btn{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-text input[type="radio"],.input-group-text input[type="checkbox"]{margin-top:0}.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text,.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;display:block;min-height:1.5rem;padding-left:1.5rem}.custom-control-inline{display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked ~ .custom-control-label::before{color:#fff;background-color:#007bff}.custom-control-input:focus ~ .custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,0.25)}.custom-control-input:active ~ .custom-control-label::before{color:#fff;background-color:#b3d7ff}.custom-control-input:disabled ~ .custom-control-label{color:#6c757d}.custom-control-input:disabled ~ .custom-control-label::before{background-color:#e9ecef}.custom-control-label{margin-bottom:0}.custom-control-label::before{position:absolute;top:.25rem;left:0;display:block;width:1rem;height:1rem;pointer-events:none;content:"";user-select:none;background-color:#dee2e6}.custom-control-label::after{position:absolute;top:.25rem;left:0;display:block;width:1rem;height:1rem;content:"";background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked ~ .custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:checked ~ .custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:disabled:checked ~ .custom-control-label::before{background-color:rgba(0,123,255,0.5)}.custom-checkbox .custom-control-input:disabled:indeterminate ~ .custom-control-label::before{background-color:rgba(0,123,255,0.5)}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked ~ .custom-control-label::before{background-color:#007bff}.custom-radio .custom-control-input:checked ~ .custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E")}.custom-radio .custom-control-input:disabled:checked ~ .custom-control-label::before{background-color:rgba(0,123,255,0.5)}.custom-select{display:inline-block;width:100%;height:calc(2.25rem + 2px);padding:.375rem 1.75rem .375rem .75rem;line-height:1.5;color:#495057;vertical-align:middle;background:#fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;background-size:8px 10px;border:1px solid #ced4da;border-radius:.25rem;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0;box-shadow:inset 0 1px 2px rgba(0,0,0,0.075),0 0 5px rgba(128,189,255,0.5)}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#6c757d;background-color:#e9ecef}.custom-select::-ms-expand{opacity:0}.custom-select-sm{height:calc(1.8125rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:75%}.custom-select-lg{height:calc(2.875rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:125%}.custom-file{position:relative;display:inline-block;width:100%;height:calc(2.25rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(2.25rem + 2px);margin:0;opacity:0}.custom-file-input:focus ~ .custom-file-control{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,0.25)}.custom-file-input:focus ~ .custom-file-control::before{border-color:#80bdff}.custom-file-input:lang(en) ~ .custom-file-label::after{content:"Browse"}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(2.25rem + 2px);padding:.375rem .75rem;line-height:1.5;color:#495057;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:calc(calc(2.25rem + 2px) - 1px * 2);padding:.375rem .75rem;line-height:1.5;color:#495057;content:"Browse";background-color:#e9ecef;border-left:1px solid #ced4da;border-radius:0 .25rem .25rem 0}.nav{display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:hover,.nav-link:focus{text-decoration:none}.nav-link.disabled{color:#6c757d}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item{flex:1 1 auto;text-align:center}.nav-justified .nav-item{flex-basis:0;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:.5rem 1rem}.navbar>.container,.navbar>.container-fluid{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}.navbar-nav{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:hover,.navbar-toggler:focus{text-decoration:none}.navbar-toggler:not(:disabled):not(.disabled){cursor:pointer}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width: 575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{padding-right:0;padding-left:0}}@media (min-width: 576px){.navbar-expand-sm{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .dropup .dropdown-menu{top:auto;bottom:100%}}@media (max-width: 767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{padding-right:0;padding-left:0}}@media (min-width: 768px){.navbar-expand-md{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .dropup .dropdown-menu{top:auto;bottom:100%}}@media (max-width: 991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{padding-right:0;padding-left:0}}@media (min-width: 992px){.navbar-expand-lg{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .dropup .dropdown-menu{top:auto;bottom:100%}}@media (max-width: 1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{padding-right:0;padding-left:0}}@media (min-width: 1200px){.navbar-expand-xl{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .dropup .dropdown-menu{top:auto;bottom:100%}}.navbar-expand{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid{flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .dropup .dropdown-menu{top:auto;bottom:100%}.navbar-light .navbar-brand{color:rgba(0,0,0,0.9)}.navbar-light .navbar-brand:hover,.navbar-light .navbar-brand:focus{color:rgba(0,0,0,0.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,0.5)}.navbar-light .navbar-nav .nav-link:hover,.navbar-light .navbar-nav .nav-link:focus{color:rgba(0,0,0,0.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,0.3)}.navbar-light .navbar-nav .show>.nav-link,.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .nav-link.active{color:rgba(0,0,0,0.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,0.5);border-color:rgba(0,0,0,0.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0,0,0,0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-light .navbar-text{color:rgba(0,0,0,0.5)}.navbar-light .navbar-text a{color:rgba(0,0,0,0.9)}.navbar-light .navbar-text a:hover,.navbar-light .navbar-text a:focus{color:rgba(0,0,0,0.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:hover,.navbar-dark .navbar-brand:focus{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,0.5)}.navbar-dark .navbar-nav .nav-link:hover,.navbar-dark .navbar-nav .nav-link:focus{color:rgba(255,255,255,0.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,0.25)}.navbar-dark .navbar-nav .show>.nav-link,.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .nav-link.active{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,0.5);border-color:rgba(255,255,255,0.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255,255,255,0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-dark .navbar-text{color:rgba(255,255,255,0.5)}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:hover,.navbar-dark .navbar-text a:focus{color:#fff}.card{position:relative;display:flex;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,0.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-body{flex:1 1 auto;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,0.03);border-bottom:1px solid rgba(0,0,0,0.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,0.03);border-top:1px solid rgba(0,0,0,0.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img{width:100%;border-radius:calc(.25rem - 1px)}.card-img-top{width:100%;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img-bottom{width:100%;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck{display:flex;flex-direction:column}.card-deck .card{margin-bottom:15px}@media (min-width: 576px){.card-deck{flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{display:flex;flex:1 0 0%;flex-direction:column;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group{display:flex;flex-direction:column}.card-group>.card{margin-bottom:15px}@media (min-width: 576px){.card-group{flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:first-child .card-img-top,.card-group>.card:first-child .card-header{border-top-right-radius:0}.card-group>.card:first-child .card-img-bottom,.card-group>.card:first-child .card-footer{border-bottom-right-radius:0}.card-group>.card:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:last-child .card-img-top,.card-group>.card:last-child .card-header{border-top-left-radius:0}.card-group>.card:last-child .card-img-bottom,.card-group>.card:last-child .card-footer{border-bottom-left-radius:0}.card-group>.card:only-child{border-radius:.25rem}.card-group>.card:only-child .card-img-top,.card-group>.card:only-child .card-header{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-group>.card:only-child .card-img-bottom,.card-group>.card:only-child .card-footer{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-group>.card:not(:first-child):not(:last-child):not(:only-child){border-radius:0}.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-top,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-bottom,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-header,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-footer{border-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width: 576px){.card-columns{column-count:3;column-gap:1.25rem}.card-columns .card{display:inline-block;width:100%}}.breadcrumb{display:flex;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;padding-left:.5rem;color:#6c757d;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#6c757d}.pagination{display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#6f3b93;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{z-index:2;color:#542c6f;text-decoration:none;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:2;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,0.25)}.page-link:not(:disabled):not(.disabled){cursor:pointer}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:1;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;cursor:auto;background-color:#fff;border-color:#dee2e6}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}.badge-primary[href]:hover,.badge-primary[href]:focus{color:#fff;text-decoration:none;background-color:#0062cc}.badge-secondary{color:#fff;background-color:#6c757d}.badge-secondary[href]:hover,.badge-secondary[href]:focus{color:#fff;text-decoration:none;background-color:#545b62}.badge-success{color:#fff;background-color:#28a745}.badge-success[href]:hover,.badge-success[href]:focus{color:#fff;text-decoration:none;background-color:#1e7e34}.badge-info{color:#fff;background-color:#17a2b8}.badge-info[href]:hover,.badge-info[href]:focus{color:#fff;text-decoration:none;background-color:#117a8b}.badge-warning{color:#212529;background-color:#ffc107}.badge-warning[href]:hover,.badge-warning[href]:focus{color:#212529;text-decoration:none;background-color:#d39e00}.badge-danger{color:#fff;background-color:#dc3545}.badge-danger[href]:hover,.badge-danger[href]:focus{color:#fff;text-decoration:none;background-color:#bd2130}.badge-light{color:#212529;background-color:#f8f9fa}.badge-light[href]:hover,.badge-light[href]:focus{color:#212529;text-decoration:none;background-color:#dae0e5}.badge-dark{color:#fff;background-color:#343a40}.badge-dark[href]:hover,.badge-dark[href]:focus{color:#fff;text-decoration:none;background-color:#1d2124}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width: 576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#383d41;background-color:#e2e3e5;border-color:#d6d8db}.alert-secondary hr{border-top-color:#c8cbcf}.alert-secondary .alert-link{color:#202326}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:flex;flex-direction:column;justify-content:center;color:#fff;text-align:center;background-color:#007bff;transition:width 0.6s ease}.progress-bar-striped{background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-size:1rem 1rem}.progress-bar-animated{animation:progress-bar-stripes 1s linear infinite}.media{display:flex;align-items:flex-start}.media-body{flex:1}.list-group{display:flex;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,0.125)}.list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-item:hover,.list-group-item:focus{z-index:1;text-decoration:none}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-flush .list-group-item{border-right:0;border-left:0;border-radius:0}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{border-bottom:0}.list-group-item-primary{color:#004085;background-color:#b8daff}.list-group-item-primary.list-group-item-action:hover,.list-group-item-primary.list-group-item-action:focus{color:#004085;background-color:#9fcdff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#383d41;background-color:#d6d8db}.list-group-item-secondary.list-group-item-action:hover,.list-group-item-secondary.list-group-item-action:focus{color:#383d41;background-color:#c8cbcf}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#383d41;border-color:#383d41}.list-group-item-success{color:#155724;background-color:#c3e6cb}.list-group-item-success.list-group-item-action:hover,.list-group-item-success.list-group-item-action:focus{color:#155724;background-color:#b1dfbb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}.list-group-item-info.list-group-item-action:hover,.list-group-item-info.list-group-item-action:focus{color:#0c5460;background-color:#abdde5}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}.list-group-item-warning.list-group-item-action:hover,.list-group-item-warning.list-group-item-action:focus{color:#856404;background-color:#ffe8a1}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:hover,.list-group-item-danger.list-group-item-action:focus{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:hover,.list-group-item-light.list-group-item-action:focus{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:hover,.list-group-item-dark.list-group-item-action:focus{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:hover,.close:focus{color:#000;text-decoration:none;opacity:.75}.close:not(:disabled):not(.disabled){cursor:pointer}button.close{padding:0;background-color:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;outline:0}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform 0.3s ease-out;transform:translate(0, -25%)}.modal.show .modal-dialog{transform:translate(0, 0)}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - (.5rem * 2))}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,0.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;align-items:flex-start;justify-content:space-between;padding:1rem;border-bottom:1px solid #e9ecef;border-top-left-radius:.3rem;border-top-right-radius:.3rem}.modal-header .close{padding:1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;padding:1rem}.modal-footer{display:flex;align-items:center;justify-content:flex-end;padding:1rem;border-top:1px solid #e9ecef}.modal-footer>:not(:first-child){margin-left:.25rem}.modal-footer>:not(:last-child){margin-right:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width: 576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-centered{min-height:calc(100% - (1.75rem * 2))}.modal-sm{max-width:300px}}@media (min-width: 992px){.modal-lg{max-width:800px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-top,.bs-tooltip-auto[x-placement^="top"]{padding:.4rem 0}.bs-tooltip-top .arrow,.bs-tooltip-auto[x-placement^="top"] .arrow{bottom:0}.bs-tooltip-top .arrow::before,.bs-tooltip-auto[x-placement^="top"] .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-right,.bs-tooltip-auto[x-placement^="right"]{padding:0 .4rem}.bs-tooltip-right .arrow,.bs-tooltip-auto[x-placement^="right"] .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-right .arrow::before,.bs-tooltip-auto[x-placement^="right"] .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-bottom,.bs-tooltip-auto[x-placement^="bottom"]{padding:.4rem 0}.bs-tooltip-bottom .arrow,.bs-tooltip-auto[x-placement^="bottom"] .arrow{top:0}.bs-tooltip-bottom .arrow::before,.bs-tooltip-auto[x-placement^="bottom"] .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-left,.bs-tooltip-auto[x-placement^="left"]{padding:0 .4rem}.bs-tooltip-left .arrow,.bs-tooltip-auto[x-placement^="left"] .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-left .arrow::before,.bs-tooltip-auto[x-placement^="left"] .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,0.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::before,.popover .arrow::after{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-top,.bs-popover-auto[x-placement^="top"]{margin-bottom:.5rem}.bs-popover-top .arrow,.bs-popover-auto[x-placement^="top"] .arrow{bottom:calc((.5rem + 1px) * -1)}.bs-popover-top .arrow::before,.bs-popover-auto[x-placement^="top"] .arrow::before,.bs-popover-top .arrow::after,.bs-popover-auto[x-placement^="top"] .arrow::after{border-width:.5rem .5rem 0}.bs-popover-top .arrow::before,.bs-popover-auto[x-placement^="top"] .arrow::before{bottom:0;border-top-color:rgba(0,0,0,0.25)}.bs-popover-top .arrow::after,.bs-popover-auto[x-placement^="top"] .arrow::after{bottom:1px;border-top-color:#fff}.bs-popover-right,.bs-popover-auto[x-placement^="right"]{margin-left:.5rem}.bs-popover-right .arrow,.bs-popover-auto[x-placement^="right"] .arrow{left:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-right .arrow::before,.bs-popover-auto[x-placement^="right"] .arrow::before,.bs-popover-right .arrow::after,.bs-popover-auto[x-placement^="right"] .arrow::after{border-width:.5rem .5rem .5rem 0}.bs-popover-right .arrow::before,.bs-popover-auto[x-placement^="right"] .arrow::before{left:0;border-right-color:rgba(0,0,0,0.25)}.bs-popover-right .arrow::after,.bs-popover-auto[x-placement^="right"] .arrow::after{left:1px;border-right-color:#fff}.bs-popover-bottom,.bs-popover-auto[x-placement^="bottom"]{margin-top:.5rem}.bs-popover-bottom .arrow,.bs-popover-auto[x-placement^="bottom"] .arrow{top:calc((.5rem + 1px) * -1)}.bs-popover-bottom .arrow::before,.bs-popover-auto[x-placement^="bottom"] .arrow::before,.bs-popover-bottom .arrow::after,.bs-popover-auto[x-placement^="bottom"] .arrow::after{border-width:0 .5rem .5rem .5rem}.bs-popover-bottom .arrow::before,.bs-popover-auto[x-placement^="bottom"] .arrow::before{top:0;border-bottom-color:rgba(0,0,0,0.25)}.bs-popover-bottom .arrow::after,.bs-popover-auto[x-placement^="bottom"] .arrow::after{top:1px;border-bottom-color:#fff}.bs-popover-bottom .popover-header::before,.bs-popover-auto[x-placement^="bottom"] .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.bs-popover-left,.bs-popover-auto[x-placement^="left"]{margin-right:.5rem}.bs-popover-left .arrow,.bs-popover-auto[x-placement^="left"] .arrow{right:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-left .arrow::before,.bs-popover-auto[x-placement^="left"] .arrow::before,.bs-popover-left .arrow::after,.bs-popover-auto[x-placement^="left"] .arrow::after{border-width:.5rem 0 .5rem .5rem}.bs-popover-left .arrow::before,.bs-popover-auto[x-placement^="left"] .arrow::before{right:0;border-left-color:rgba(0,0,0,0.25)}.bs-popover-left .arrow::after,.bs-popover-auto[x-placement^="left"] .arrow::after{right:1px;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;color:inherit;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#212529}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-item{position:relative;display:none;align-items:center;width:100%;transition:transform 0.6s ease;backface-visibility:hidden;perspective:1000px}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next,.carousel-item-prev{position:absolute;top:0}.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{transform:translateX(0)}@supports (transform-style: preserve-3d){.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{transform:translate3d(0, 0, 0)}}.carousel-item-next,.active.carousel-item-right{transform:translateX(100%)}@supports (transform-style: preserve-3d){.carousel-item-next,.active.carousel-item-right{transform:translate3d(100%, 0, 0)}}.carousel-item-prev,.active.carousel-item-left{transform:translateX(-100%)}@supports (transform-style: preserve-3d){.carousel-item-prev,.active.carousel-item-left{transform:translate3d(-100%, 0, 0)}}.carousel-fade .carousel-item{opacity:0;transition-duration:.6s;transition-property:opacity}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-left,.carousel-fade .carousel-item-prev.carousel-item-right{opacity:1}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{opacity:0}.carousel-fade .carousel-item-next,.carousel-fade .carousel-item-prev,.carousel-fade .carousel-item.active,.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-prev{transform:translateX(0)}@supports (transform-style: preserve-3d){.carousel-fade .carousel-item-next,.carousel-fade .carousel-item-prev,.carousel-fade .carousel-item.active,.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-prev{transform:translate3d(0, 0, 0)}}.carousel-control-prev,.carousel-control-next{position:absolute;top:0;bottom:0;display:flex;align-items:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5}.carousel-control-prev:hover,.carousel-control-prev:focus,.carousel-control-next:hover,.carousel-control-next:focus{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-prev-icon,.carousel-control-next-icon{display:inline-block;width:20px;height:20px;background:transparent no-repeat center center;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E")}.carousel-control-next-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E")}.carousel-indicators{position:absolute;right:0;bottom:10px;left:0;z-index:15;display:flex;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{position:relative;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;background-color:rgba(255,255,255,0.5)}.carousel-indicators li::before{position:absolute;top:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators li::after{position:absolute;bottom:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}.align-baseline{vertical-align:baseline !important}.align-top{vertical-align:top !important}.align-middle{vertical-align:middle !important}.align-bottom{vertical-align:bottom !important}.align-text-bottom{vertical-align:text-bottom !important}.align-text-top{vertical-align:text-top !important}.bg-primary{background-color:#007bff !important}a.bg-primary:hover,a.bg-primary:focus,button.bg-primary:hover,button.bg-primary:focus{background-color:#0062cc !important}.bg-secondary{background-color:#6c757d !important}a.bg-secondary:hover,a.bg-secondary:focus,button.bg-secondary:hover,button.bg-secondary:focus{background-color:#545b62 !important}.bg-success{background-color:#28a745 !important}a.bg-success:hover,a.bg-success:focus,button.bg-success:hover,button.bg-success:focus{background-color:#1e7e34 !important}.bg-info{background-color:#17a2b8 !important}a.bg-info:hover,a.bg-info:focus,button.bg-info:hover,button.bg-info:focus{background-color:#117a8b !important}.bg-warning{background-color:#ffc107 !important}a.bg-warning:hover,a.bg-warning:focus,button.bg-warning:hover,button.bg-warning:focus{background-color:#d39e00 !important}.bg-danger{background-color:#dc3545 !important}a.bg-danger:hover,a.bg-danger:focus,button.bg-danger:hover,button.bg-danger:focus{background-color:#bd2130 !important}.bg-light{background-color:#f8f9fa !important}a.bg-light:hover,a.bg-light:focus,button.bg-light:hover,button.bg-light:focus{background-color:#dae0e5 !important}.bg-dark{background-color:#343a40 !important}a.bg-dark:hover,a.bg-dark:focus,button.bg-dark:hover,button.bg-dark:focus{background-color:#1d2124 !important}.bg-white{background-color:#fff !important}.bg-transparent{background-color:transparent !important}.border{border:1px solid #dee2e6 !important}.border-top{border-top:1px solid #dee2e6 !important}.border-right{border-right:1px solid #dee2e6 !important}.border-bottom{border-bottom:1px solid #dee2e6 !important}.border-left{border-left:1px solid #dee2e6 !important}.border-0{border:0 !important}.border-top-0{border-top:0 !important}.border-right-0{border-right:0 !important}.border-bottom-0{border-bottom:0 !important}.border-left-0{border-left:0 !important}.border-primary{border-color:#007bff !important}.border-secondary{border-color:#6c757d !important}.border-success{border-color:#28a745 !important}.border-info{border-color:#17a2b8 !important}.border-warning{border-color:#ffc107 !important}.border-danger{border-color:#dc3545 !important}.border-light{border-color:#f8f9fa !important}.border-dark{border-color:#343a40 !important}.border-white{border-color:#fff !important}.rounded{border-radius:.25rem !important}.rounded-top{border-top-left-radius:.25rem !important;border-top-right-radius:.25rem !important}.rounded-right{border-top-right-radius:.25rem !important;border-bottom-right-radius:.25rem !important}.rounded-bottom{border-bottom-right-radius:.25rem !important;border-bottom-left-radius:.25rem !important}.rounded-left{border-top-left-radius:.25rem !important;border-bottom-left-radius:.25rem !important}.rounded-circle{border-radius:50% !important}.rounded-0{border-radius:0 !important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none !important}.d-inline{display:inline !important}.d-inline-block{display:inline-block !important}.d-block{display:block !important}.d-table{display:table !important}.d-table-row{display:table-row !important}.d-table-cell{display:table-cell !important}.d-flex{display:flex !important}.d-inline-flex{display:inline-flex !important}@media (min-width: 576px){.d-sm-none{display:none !important}.d-sm-inline{display:inline !important}.d-sm-inline-block{display:inline-block !important}.d-sm-block{display:block !important}.d-sm-table{display:table !important}.d-sm-table-row{display:table-row !important}.d-sm-table-cell{display:table-cell !important}.d-sm-flex{display:flex !important}.d-sm-inline-flex{display:inline-flex !important}}@media (min-width: 768px){.d-md-none{display:none !important}.d-md-inline{display:inline !important}.d-md-inline-block{display:inline-block !important}.d-md-block{display:block !important}.d-md-table{display:table !important}.d-md-table-row{display:table-row !important}.d-md-table-cell{display:table-cell !important}.d-md-flex{display:flex !important}.d-md-inline-flex{display:inline-flex !important}}@media (min-width: 992px){.d-lg-none{display:none !important}.d-lg-inline{display:inline !important}.d-lg-inline-block{display:inline-block !important}.d-lg-block{display:block !important}.d-lg-table{display:table !important}.d-lg-table-row{display:table-row !important}.d-lg-table-cell{display:table-cell !important}.d-lg-flex{display:flex !important}.d-lg-inline-flex{display:inline-flex !important}}@media (min-width: 1200px){.d-xl-none{display:none !important}.d-xl-inline{display:inline !important}.d-xl-inline-block{display:inline-block !important}.d-xl-block{display:block !important}.d-xl-table{display:table !important}.d-xl-table-row{display:table-row !important}.d-xl-table-cell{display:table-cell !important}.d-xl-flex{display:flex !important}.d-xl-inline-flex{display:inline-flex !important}}@media print{.d-print-none{display:none !important}.d-print-inline{display:inline !important}.d-print-inline-block{display:inline-block !important}.d-print-block{display:block !important}.d-print-table{display:table !important}.d-print-table-row{display:table-row !important}.d-print-table-cell{display:table-cell !important}.d-print-flex{display:flex !important}.d-print-inline-flex{display:inline-flex !important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.85714%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{flex-direction:row !important}.flex-column{flex-direction:column !important}.flex-row-reverse{flex-direction:row-reverse !important}.flex-column-reverse{flex-direction:column-reverse !important}.flex-wrap{flex-wrap:wrap !important}.flex-nowrap{flex-wrap:nowrap !important}.flex-wrap-reverse{flex-wrap:wrap-reverse !important}.flex-fill{flex:1 1 auto !important}.justify-content-start{justify-content:flex-start !important}.justify-content-end{justify-content:flex-end !important}.justify-content-center{justify-content:center !important}.justify-content-between{justify-content:space-between !important}.justify-content-around{justify-content:space-around !important}.align-items-start{align-items:flex-start !important}.align-items-end{align-items:flex-end !important}.align-items-center{align-items:center !important}.align-items-baseline{align-items:baseline !important}.align-items-stretch{align-items:stretch !important}.align-content-start{align-content:flex-start !important}.align-content-end{align-content:flex-end !important}.align-content-center{align-content:center !important}.align-content-between{align-content:space-between !important}.align-content-around{align-content:space-around !important}.align-content-stretch{align-content:stretch !important}.align-self-auto{align-self:auto !important}.align-self-start{align-self:flex-start !important}.align-self-end{align-self:flex-end !important}.align-self-center{align-self:center !important}.align-self-baseline{align-self:baseline !important}.align-self-stretch{align-self:stretch !important}@media (min-width: 576px){.flex-sm-row{flex-direction:row !important}.flex-sm-column{flex-direction:column !important}.flex-sm-row-reverse{flex-direction:row-reverse !important}.flex-sm-column-reverse{flex-direction:column-reverse !important}.flex-sm-wrap{flex-wrap:wrap !important}.flex-sm-nowrap{flex-wrap:nowrap !important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse !important}.flex-sm-fill{flex:1 1 auto !important}.justify-content-sm-start{justify-content:flex-start !important}.justify-content-sm-end{justify-content:flex-end !important}.justify-content-sm-center{justify-content:center !important}.justify-content-sm-between{justify-content:space-between !important}.justify-content-sm-around{justify-content:space-around !important}.align-items-sm-start{align-items:flex-start !important}.align-items-sm-end{align-items:flex-end !important}.align-items-sm-center{align-items:center !important}.align-items-sm-baseline{align-items:baseline !important}.align-items-sm-stretch{align-items:stretch !important}.align-content-sm-start{align-content:flex-start !important}.align-content-sm-end{align-content:flex-end !important}.align-content-sm-center{align-content:center !important}.align-content-sm-between{align-content:space-between !important}.align-content-sm-around{align-content:space-around !important}.align-content-sm-stretch{align-content:stretch !important}.align-self-sm-auto{align-self:auto !important}.align-self-sm-start{align-self:flex-start !important}.align-self-sm-end{align-self:flex-end !important}.align-self-sm-center{align-self:center !important}.align-self-sm-baseline{align-self:baseline !important}.align-self-sm-stretch{align-self:stretch !important}}@media (min-width: 768px){.flex-md-row{flex-direction:row !important}.flex-md-column{flex-direction:column !important}.flex-md-row-reverse{flex-direction:row-reverse !important}.flex-md-column-reverse{flex-direction:column-reverse !important}.flex-md-wrap{flex-wrap:wrap !important}.flex-md-nowrap{flex-wrap:nowrap !important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse !important}.flex-md-fill{flex:1 1 auto !important}.justify-content-md-start{justify-content:flex-start !important}.justify-content-md-end{justify-content:flex-end !important}.justify-content-md-center{justify-content:center !important}.justify-content-md-between{justify-content:space-between !important}.justify-content-md-around{justify-content:space-around !important}.align-items-md-start{align-items:flex-start !important}.align-items-md-end{align-items:flex-end !important}.align-items-md-center{align-items:center !important}.align-items-md-baseline{align-items:baseline !important}.align-items-md-stretch{align-items:stretch !important}.align-content-md-start{align-content:flex-start !important}.align-content-md-end{align-content:flex-end !important}.align-content-md-center{align-content:center !important}.align-content-md-between{align-content:space-between !important}.align-content-md-around{align-content:space-around !important}.align-content-md-stretch{align-content:stretch !important}.align-self-md-auto{align-self:auto !important}.align-self-md-start{align-self:flex-start !important}.align-self-md-end{align-self:flex-end !important}.align-self-md-center{align-self:center !important}.align-self-md-baseline{align-self:baseline !important}.align-self-md-stretch{align-self:stretch !important}}@media (min-width: 992px){.flex-lg-row{flex-direction:row !important}.flex-lg-column{flex-direction:column !important}.flex-lg-row-reverse{flex-direction:row-reverse !important}.flex-lg-column-reverse{flex-direction:column-reverse !important}.flex-lg-wrap{flex-wrap:wrap !important}.flex-lg-nowrap{flex-wrap:nowrap !important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse !important}.flex-lg-fill{flex:1 1 auto !important}.justify-content-lg-start{justify-content:flex-start !important}.justify-content-lg-end{justify-content:flex-end !important}.justify-content-lg-center{justify-content:center !important}.justify-content-lg-between{justify-content:space-between !important}.justify-content-lg-around{justify-content:space-around !important}.align-items-lg-start{align-items:flex-start !important}.align-items-lg-end{align-items:flex-end !important}.align-items-lg-center{align-items:center !important}.align-items-lg-baseline{align-items:baseline !important}.align-items-lg-stretch{align-items:stretch !important}.align-content-lg-start{align-content:flex-start !important}.align-content-lg-end{align-content:flex-end !important}.align-content-lg-center{align-content:center !important}.align-content-lg-between{align-content:space-between !important}.align-content-lg-around{align-content:space-around !important}.align-content-lg-stretch{align-content:stretch !important}.align-self-lg-auto{align-self:auto !important}.align-self-lg-start{align-self:flex-start !important}.align-self-lg-end{align-self:flex-end !important}.align-self-lg-center{align-self:center !important}.align-self-lg-baseline{align-self:baseline !important}.align-self-lg-stretch{align-self:stretch !important}}@media (min-width: 1200px){.flex-xl-row{flex-direction:row !important}.flex-xl-column{flex-direction:column !important}.flex-xl-row-reverse{flex-direction:row-reverse !important}.flex-xl-column-reverse{flex-direction:column-reverse !important}.flex-xl-wrap{flex-wrap:wrap !important}.flex-xl-nowrap{flex-wrap:nowrap !important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse !important}.flex-xl-fill{flex:1 1 auto !important}.justify-content-xl-start{justify-content:flex-start !important}.justify-content-xl-end{justify-content:flex-end !important}.justify-content-xl-center{justify-content:center !important}.justify-content-xl-between{justify-content:space-between !important}.justify-content-xl-around{justify-content:space-around !important}.align-items-xl-start{align-items:flex-start !important}.align-items-xl-end{align-items:flex-end !important}.align-items-xl-center{align-items:center !important}.align-items-xl-baseline{align-items:baseline !important}.align-items-xl-stretch{align-items:stretch !important}.align-content-xl-start{align-content:flex-start !important}.align-content-xl-end{align-content:flex-end !important}.align-content-xl-center{align-content:center !important}.align-content-xl-between{align-content:space-between !important}.align-content-xl-around{align-content:space-around !important}.align-content-xl-stretch{align-content:stretch !important}.align-self-xl-auto{align-self:auto !important}.align-self-xl-start{align-self:flex-start !important}.align-self-xl-end{align-self:flex-end !important}.align-self-xl-center{align-self:center !important}.align-self-xl-baseline{align-self:baseline !important}.align-self-xl-stretch{align-self:stretch !important}}.float-left{float:left !important}.float-right{float:right !important}.float-none{float:none !important}@media (min-width: 576px){.float-sm-left{float:left !important}.float-sm-right{float:right !important}.float-sm-none{float:none !important}}@media (min-width: 768px){.float-md-left{float:left !important}.float-md-right{float:right !important}.float-md-none{float:none !important}}@media (min-width: 992px){.float-lg-left{float:left !important}.float-lg-right{float:right !important}.float-lg-none{float:none !important}}@media (min-width: 1200px){.float-xl-left{float:left !important}.float-xl-right{float:right !important}.float-xl-none{float:none !important}}.position-static{position:static !important}.position-relative{position:relative !important}.position-absolute{position:absolute !important}.position-fixed{position:fixed !important}.position-sticky{position:sticky !important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports (position: sticky){.sticky-top{position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;clip-path:inset(50%);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal;clip-path:none}.w-25{width:25% !important}.w-50{width:50% !important}.w-75{width:75% !important}.w-100{width:100% !important}.w-auto{width:auto !important}.h-25{height:25% !important}.h-50{height:50% !important}.h-75{height:75% !important}.h-100{height:100% !important}.h-auto{height:auto !important}.mw-100{max-width:100% !important}.mh-100{max-height:100% !important}.m-0{margin:0 !important}.mt-0,.my-0{margin-top:0 !important}.mr-0,.mx-0{margin-right:0 !important}.mb-0,.my-0{margin-bottom:0 !important}.ml-0,.mx-0{margin-left:0 !important}.m-1{margin:.25rem !important}.mt-1,.my-1{margin-top:.25rem !important}.mr-1,.mx-1{margin-right:.25rem !important}.mb-1,.my-1{margin-bottom:.25rem !important}.ml-1,.mx-1{margin-left:.25rem !important}.m-2{margin:.5rem !important}.mt-2,.my-2{margin-top:.5rem !important}.mr-2,.mx-2{margin-right:.5rem !important}.mb-2,.my-2{margin-bottom:.5rem !important}.ml-2,.mx-2{margin-left:.5rem !important}.m-3{margin:1rem !important}.mt-3,.my-3{margin-top:1rem !important}.mr-3,.mx-3{margin-right:1rem !important}.mb-3,.my-3{margin-bottom:1rem !important}.ml-3,.mx-3{margin-left:1rem !important}.m-4{margin:1.5rem !important}.mt-4,.my-4{margin-top:1.5rem !important}.mr-4,.mx-4{margin-right:1.5rem !important}.mb-4,.my-4{margin-bottom:1.5rem !important}.ml-4,.mx-4{margin-left:1.5rem !important}.m-5{margin:3rem !important}.mt-5,.my-5{margin-top:3rem !important}.mr-5,.mx-5{margin-right:3rem !important}.mb-5,.my-5{margin-bottom:3rem !important}.ml-5,.mx-5{margin-left:3rem !important}.p-0{padding:0 !important}.pt-0,.py-0{padding-top:0 !important}.pr-0,.px-0{padding-right:0 !important}.pb-0,.py-0{padding-bottom:0 !important}.pl-0,.px-0{padding-left:0 !important}.p-1{padding:.25rem !important}.pt-1,.py-1{padding-top:.25rem !important}.pr-1,.px-1{padding-right:.25rem !important}.pb-1,.py-1{padding-bottom:.25rem !important}.pl-1,.px-1{padding-left:.25rem !important}.p-2{padding:.5rem !important}.pt-2,.py-2{padding-top:.5rem !important}.pr-2,.px-2{padding-right:.5rem !important}.pb-2,.py-2{padding-bottom:.5rem !important}.pl-2,.px-2{padding-left:.5rem !important}.p-3{padding:1rem !important}.pt-3,.py-3{padding-top:1rem !important}.pr-3,.px-3{padding-right:1rem !important}.pb-3,.py-3{padding-bottom:1rem !important}.pl-3,.px-3{padding-left:1rem !important}.p-4{padding:1.5rem !important}.pt-4,.py-4{padding-top:1.5rem !important}.pr-4,.px-4{padding-right:1.5rem !important}.pb-4,.py-4{padding-bottom:1.5rem !important}.pl-4,.px-4{padding-left:1.5rem !important}.p-5{padding:3rem !important}.pt-5,.py-5{padding-top:3rem !important}.pr-5,.px-5{padding-right:3rem !important}.pb-5,.py-5{padding-bottom:3rem !important}.pl-5,.px-5{padding-left:3rem !important}.m-auto{margin:auto !important}.mt-auto,.my-auto{margin-top:auto !important}.mr-auto,.mx-auto{margin-right:auto !important}.mb-auto,.my-auto{margin-bottom:auto !important}.ml-auto,.mx-auto{margin-left:auto !important}@media (min-width: 576px){.m-sm-0{margin:0 !important}.mt-sm-0,.my-sm-0{margin-top:0 !important}.mr-sm-0,.mx-sm-0{margin-right:0 !important}.mb-sm-0,.my-sm-0{margin-bottom:0 !important}.ml-sm-0,.mx-sm-0{margin-left:0 !important}.m-sm-1{margin:.25rem !important}.mt-sm-1,.my-sm-1{margin-top:.25rem !important}.mr-sm-1,.mx-sm-1{margin-right:.25rem !important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem !important}.ml-sm-1,.mx-sm-1{margin-left:.25rem !important}.m-sm-2{margin:.5rem !important}.mt-sm-2,.my-sm-2{margin-top:.5rem !important}.mr-sm-2,.mx-sm-2{margin-right:.5rem !important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem !important}.ml-sm-2,.mx-sm-2{margin-left:.5rem !important}.m-sm-3{margin:1rem !important}.mt-sm-3,.my-sm-3{margin-top:1rem !important}.mr-sm-3,.mx-sm-3{margin-right:1rem !important}.mb-sm-3,.my-sm-3{margin-bottom:1rem !important}.ml-sm-3,.mx-sm-3{margin-left:1rem !important}.m-sm-4{margin:1.5rem !important}.mt-sm-4,.my-sm-4{margin-top:1.5rem !important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem !important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem !important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem !important}.m-sm-5{margin:3rem !important}.mt-sm-5,.my-sm-5{margin-top:3rem !important}.mr-sm-5,.mx-sm-5{margin-right:3rem !important}.mb-sm-5,.my-sm-5{margin-bottom:3rem !important}.ml-sm-5,.mx-sm-5{margin-left:3rem !important}.p-sm-0{padding:0 !important}.pt-sm-0,.py-sm-0{padding-top:0 !important}.pr-sm-0,.px-sm-0{padding-right:0 !important}.pb-sm-0,.py-sm-0{padding-bottom:0 !important}.pl-sm-0,.px-sm-0{padding-left:0 !important}.p-sm-1{padding:.25rem !important}.pt-sm-1,.py-sm-1{padding-top:.25rem !important}.pr-sm-1,.px-sm-1{padding-right:.25rem !important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem !important}.pl-sm-1,.px-sm-1{padding-left:.25rem !important}.p-sm-2{padding:.5rem !important}.pt-sm-2,.py-sm-2{padding-top:.5rem !important}.pr-sm-2,.px-sm-2{padding-right:.5rem !important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem !important}.pl-sm-2,.px-sm-2{padding-left:.5rem !important}.p-sm-3{padding:1rem !important}.pt-sm-3,.py-sm-3{padding-top:1rem !important}.pr-sm-3,.px-sm-3{padding-right:1rem !important}.pb-sm-3,.py-sm-3{padding-bottom:1rem !important}.pl-sm-3,.px-sm-3{padding-left:1rem !important}.p-sm-4{padding:1.5rem !important}.pt-sm-4,.py-sm-4{padding-top:1.5rem !important}.pr-sm-4,.px-sm-4{padding-right:1.5rem !important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem !important}.pl-sm-4,.px-sm-4{padding-left:1.5rem !important}.p-sm-5{padding:3rem !important}.pt-sm-5,.py-sm-5{padding-top:3rem !important}.pr-sm-5,.px-sm-5{padding-right:3rem !important}.pb-sm-5,.py-sm-5{padding-bottom:3rem !important}.pl-sm-5,.px-sm-5{padding-left:3rem !important}.m-sm-auto{margin:auto !important}.mt-sm-auto,.my-sm-auto{margin-top:auto !important}.mr-sm-auto,.mx-sm-auto{margin-right:auto !important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto !important}.ml-sm-auto,.mx-sm-auto{margin-left:auto !important}}@media (min-width: 768px){.m-md-0{margin:0 !important}.mt-md-0,.my-md-0{margin-top:0 !important}.mr-md-0,.mx-md-0{margin-right:0 !important}.mb-md-0,.my-md-0{margin-bottom:0 !important}.ml-md-0,.mx-md-0{margin-left:0 !important}.m-md-1{margin:.25rem !important}.mt-md-1,.my-md-1{margin-top:.25rem !important}.mr-md-1,.mx-md-1{margin-right:.25rem !important}.mb-md-1,.my-md-1{margin-bottom:.25rem !important}.ml-md-1,.mx-md-1{margin-left:.25rem !important}.m-md-2{margin:.5rem !important}.mt-md-2,.my-md-2{margin-top:.5rem !important}.mr-md-2,.mx-md-2{margin-right:.5rem !important}.mb-md-2,.my-md-2{margin-bottom:.5rem !important}.ml-md-2,.mx-md-2{margin-left:.5rem !important}.m-md-3{margin:1rem !important}.mt-md-3,.my-md-3{margin-top:1rem !important}.mr-md-3,.mx-md-3{margin-right:1rem !important}.mb-md-3,.my-md-3{margin-bottom:1rem !important}.ml-md-3,.mx-md-3{margin-left:1rem !important}.m-md-4{margin:1.5rem !important}.mt-md-4,.my-md-4{margin-top:1.5rem !important}.mr-md-4,.mx-md-4{margin-right:1.5rem !important}.mb-md-4,.my-md-4{margin-bottom:1.5rem !important}.ml-md-4,.mx-md-4{margin-left:1.5rem !important}.m-md-5{margin:3rem !important}.mt-md-5,.my-md-5{margin-top:3rem !important}.mr-md-5,.mx-md-5{margin-right:3rem !important}.mb-md-5,.my-md-5{margin-bottom:3rem !important}.ml-md-5,.mx-md-5{margin-left:3rem !important}.p-md-0{padding:0 !important}.pt-md-0,.py-md-0{padding-top:0 !important}.pr-md-0,.px-md-0{padding-right:0 !important}.pb-md-0,.py-md-0{padding-bottom:0 !important}.pl-md-0,.px-md-0{padding-left:0 !important}.p-md-1{padding:.25rem !important}.pt-md-1,.py-md-1{padding-top:.25rem !important}.pr-md-1,.px-md-1{padding-right:.25rem !important}.pb-md-1,.py-md-1{padding-bottom:.25rem !important}.pl-md-1,.px-md-1{padding-left:.25rem !important}.p-md-2{padding:.5rem !important}.pt-md-2,.py-md-2{padding-top:.5rem !important}.pr-md-2,.px-md-2{padding-right:.5rem !important}.pb-md-2,.py-md-2{padding-bottom:.5rem !important}.pl-md-2,.px-md-2{padding-left:.5rem !important}.p-md-3{padding:1rem !important}.pt-md-3,.py-md-3{padding-top:1rem !important}.pr-md-3,.px-md-3{padding-right:1rem !important}.pb-md-3,.py-md-3{padding-bottom:1rem !important}.pl-md-3,.px-md-3{padding-left:1rem !important}.p-md-4{padding:1.5rem !important}.pt-md-4,.py-md-4{padding-top:1.5rem !important}.pr-md-4,.px-md-4{padding-right:1.5rem !important}.pb-md-4,.py-md-4{padding-bottom:1.5rem !important}.pl-md-4,.px-md-4{padding-left:1.5rem !important}.p-md-5{padding:3rem !important}.pt-md-5,.py-md-5{padding-top:3rem !important}.pr-md-5,.px-md-5{padding-right:3rem !important}.pb-md-5,.py-md-5{padding-bottom:3rem !important}.pl-md-5,.px-md-5{padding-left:3rem !important}.m-md-auto{margin:auto !important}.mt-md-auto,.my-md-auto{margin-top:auto !important}.mr-md-auto,.mx-md-auto{margin-right:auto !important}.mb-md-auto,.my-md-auto{margin-bottom:auto !important}.ml-md-auto,.mx-md-auto{margin-left:auto !important}}@media (min-width: 992px){.m-lg-0{margin:0 !important}.mt-lg-0,.my-lg-0{margin-top:0 !important}.mr-lg-0,.mx-lg-0{margin-right:0 !important}.mb-lg-0,.my-lg-0{margin-bottom:0 !important}.ml-lg-0,.mx-lg-0{margin-left:0 !important}.m-lg-1{margin:.25rem !important}.mt-lg-1,.my-lg-1{margin-top:.25rem !important}.mr-lg-1,.mx-lg-1{margin-right:.25rem !important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem !important}.ml-lg-1,.mx-lg-1{margin-left:.25rem !important}.m-lg-2{margin:.5rem !important}.mt-lg-2,.my-lg-2{margin-top:.5rem !important}.mr-lg-2,.mx-lg-2{margin-right:.5rem !important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem !important}.ml-lg-2,.mx-lg-2{margin-left:.5rem !important}.m-lg-3{margin:1rem !important}.mt-lg-3,.my-lg-3{margin-top:1rem !important}.mr-lg-3,.mx-lg-3{margin-right:1rem !important}.mb-lg-3,.my-lg-3{margin-bottom:1rem !important}.ml-lg-3,.mx-lg-3{margin-left:1rem !important}.m-lg-4{margin:1.5rem !important}.mt-lg-4,.my-lg-4{margin-top:1.5rem !important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem !important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem !important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem !important}.m-lg-5{margin:3rem !important}.mt-lg-5,.my-lg-5{margin-top:3rem !important}.mr-lg-5,.mx-lg-5{margin-right:3rem !important}.mb-lg-5,.my-lg-5{margin-bottom:3rem !important}.ml-lg-5,.mx-lg-5{margin-left:3rem !important}.p-lg-0{padding:0 !important}.pt-lg-0,.py-lg-0{padding-top:0 !important}.pr-lg-0,.px-lg-0{padding-right:0 !important}.pb-lg-0,.py-lg-0{padding-bottom:0 !important}.pl-lg-0,.px-lg-0{padding-left:0 !important}.p-lg-1{padding:.25rem !important}.pt-lg-1,.py-lg-1{padding-top:.25rem !important}.pr-lg-1,.px-lg-1{padding-right:.25rem !important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem !important}.pl-lg-1,.px-lg-1{padding-left:.25rem !important}.p-lg-2{padding:.5rem !important}.pt-lg-2,.py-lg-2{padding-top:.5rem !important}.pr-lg-2,.px-lg-2{padding-right:.5rem !important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem !important}.pl-lg-2,.px-lg-2{padding-left:.5rem !important}.p-lg-3{padding:1rem !important}.pt-lg-3,.py-lg-3{padding-top:1rem !important}.pr-lg-3,.px-lg-3{padding-right:1rem !important}.pb-lg-3,.py-lg-3{padding-bottom:1rem !important}.pl-lg-3,.px-lg-3{padding-left:1rem !important}.p-lg-4{padding:1.5rem !important}.pt-lg-4,.py-lg-4{padding-top:1.5rem !important}.pr-lg-4,.px-lg-4{padding-right:1.5rem !important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem !important}.pl-lg-4,.px-lg-4{padding-left:1.5rem !important}.p-lg-5{padding:3rem !important}.pt-lg-5,.py-lg-5{padding-top:3rem !important}.pr-lg-5,.px-lg-5{padding-right:3rem !important}.pb-lg-5,.py-lg-5{padding-bottom:3rem !important}.pl-lg-5,.px-lg-5{padding-left:3rem !important}.m-lg-auto{margin:auto !important}.mt-lg-auto,.my-lg-auto{margin-top:auto !important}.mr-lg-auto,.mx-lg-auto{margin-right:auto !important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto !important}.ml-lg-auto,.mx-lg-auto{margin-left:auto !important}}@media (min-width: 1200px){.m-xl-0{margin:0 !important}.mt-xl-0,.my-xl-0{margin-top:0 !important}.mr-xl-0,.mx-xl-0{margin-right:0 !important}.mb-xl-0,.my-xl-0{margin-bottom:0 !important}.ml-xl-0,.mx-xl-0{margin-left:0 !important}.m-xl-1{margin:.25rem !important}.mt-xl-1,.my-xl-1{margin-top:.25rem !important}.mr-xl-1,.mx-xl-1{margin-right:.25rem !important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem !important}.ml-xl-1,.mx-xl-1{margin-left:.25rem !important}.m-xl-2{margin:.5rem !important}.mt-xl-2,.my-xl-2{margin-top:.5rem !important}.mr-xl-2,.mx-xl-2{margin-right:.5rem !important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem !important}.ml-xl-2,.mx-xl-2{margin-left:.5rem !important}.m-xl-3{margin:1rem !important}.mt-xl-3,.my-xl-3{margin-top:1rem !important}.mr-xl-3,.mx-xl-3{margin-right:1rem !important}.mb-xl-3,.my-xl-3{margin-bottom:1rem !important}.ml-xl-3,.mx-xl-3{margin-left:1rem !important}.m-xl-4{margin:1.5rem !important}.mt-xl-4,.my-xl-4{margin-top:1.5rem !important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem !important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem !important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem !important}.m-xl-5{margin:3rem !important}.mt-xl-5,.my-xl-5{margin-top:3rem !important}.mr-xl-5,.mx-xl-5{margin-right:3rem !important}.mb-xl-5,.my-xl-5{margin-bottom:3rem !important}.ml-xl-5,.mx-xl-5{margin-left:3rem !important}.p-xl-0{padding:0 !important}.pt-xl-0,.py-xl-0{padding-top:0 !important}.pr-xl-0,.px-xl-0{padding-right:0 !important}.pb-xl-0,.py-xl-0{padding-bottom:0 !important}.pl-xl-0,.px-xl-0{padding-left:0 !important}.p-xl-1{padding:.25rem !important}.pt-xl-1,.py-xl-1{padding-top:.25rem !important}.pr-xl-1,.px-xl-1{padding-right:.25rem !important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem !important}.pl-xl-1,.px-xl-1{padding-left:.25rem !important}.p-xl-2{padding:.5rem !important}.pt-xl-2,.py-xl-2{padding-top:.5rem !important}.pr-xl-2,.px-xl-2{padding-right:.5rem !important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem !important}.pl-xl-2,.px-xl-2{padding-left:.5rem !important}.p-xl-3{padding:1rem !important}.pt-xl-3,.py-xl-3{padding-top:1rem !important}.pr-xl-3,.px-xl-3{padding-right:1rem !important}.pb-xl-3,.py-xl-3{padding-bottom:1rem !important}.pl-xl-3,.px-xl-3{padding-left:1rem !important}.p-xl-4{padding:1.5rem !important}.pt-xl-4,.py-xl-4{padding-top:1.5rem !important}.pr-xl-4,.px-xl-4{padding-right:1.5rem !important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem !important}.pl-xl-4,.px-xl-4{padding-left:1.5rem !important}.p-xl-5{padding:3rem !important}.pt-xl-5,.py-xl-5{padding-top:3rem !important}.pr-xl-5,.px-xl-5{padding-right:3rem !important}.pb-xl-5,.py-xl-5{padding-bottom:3rem !important}.pl-xl-5,.px-xl-5{padding-left:3rem !important}.m-xl-auto{margin:auto !important}.mt-xl-auto,.my-xl-auto{margin-top:auto !important}.mr-xl-auto,.mx-xl-auto{margin-right:auto !important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto !important}.ml-xl-auto,.mx-xl-auto{margin-left:auto !important}}.text-justify{text-align:justify !important}.text-nowrap{white-space:nowrap !important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left !important}.text-right{text-align:right !important}.text-center{text-align:center !important}@media (min-width: 576px){.text-sm-left{text-align:left !important}.text-sm-right{text-align:right !important}.text-sm-center{text-align:center !important}}@media (min-width: 768px){.text-md-left{text-align:left !important}.text-md-right{text-align:right !important}.text-md-center{text-align:center !important}}@media (min-width: 992px){.text-lg-left{text-align:left !important}.text-lg-right{text-align:right !important}.text-lg-center{text-align:center !important}}@media (min-width: 1200px){.text-xl-left{text-align:left !important}.text-xl-right{text-align:right !important}.text-xl-center{text-align:center !important}}.text-lowercase{text-transform:lowercase !important}.text-uppercase{text-transform:uppercase !important}.text-capitalize{text-transform:capitalize !important}.font-weight-light{font-weight:300 !important}.font-weight-normal{font-weight:400 !important}.font-weight-bold{font-weight:700 !important}.font-italic{font-style:italic !important}.text-white{color:#fff !important}.text-primary{color:#007bff !important}a.text-primary:hover,a.text-primary:focus{color:#0062cc !important}.text-secondary{color:#6c757d !important}a.text-secondary:hover,a.text-secondary:focus{color:#545b62 !important}.text-success{color:#28a745 !important}a.text-success:hover,a.text-success:focus{color:#1e7e34 !important}.text-info{color:#17a2b8 !important}a.text-info:hover,a.text-info:focus{color:#117a8b !important}.text-warning{color:#ffc107 !important}a.text-warning:hover,a.text-warning:focus{color:#d39e00 !important}.text-danger{color:#dc3545 !important}a.text-danger:hover,a.text-danger:focus{color:#bd2130 !important}.text-light{color:#f8f9fa !important}a.text-light:hover,a.text-light:focus{color:#dae0e5 !important}.text-dark{color:#343a40 !important}a.text-dark:hover,a.text-dark:focus{color:#1d2124 !important}.text-muted{color:#6c757d !important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.visible{visibility:visible !important}.invisible{visibility:hidden !important}@media print{*,*::before,*::after{text-shadow:none !important;box-shadow:none !important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap !important}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px !important}.container{min-width:992px !important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse !important}.table td,.table th{background-color:#fff !important}.table-bordered th,.table-bordered td{border:1px solid #ddd !important}}.switch{font-size:1rem;position:relative}.switch input{position:absolute;height:1px;width:1px;background:none;border:0;clip:rect(0 0 0 0);clip-path:inset(50%);overflow:hidden;padding:0}.switch input+label{position:relative;min-width:calc(calc(2.375rem * .8) * 2);border-radius:calc(2.375rem * .8);height:calc(2.375rem * .8);line-height:calc(2.375rem * .8);display:inline-block;cursor:pointer;outline:none;user-select:none;vertical-align:middle;text-indent:calc(calc(calc(2.375rem * .8) * 2) + .5rem)}.switch input+label::before,.switch input+label::after{content:'';position:absolute;top:0;left:0;width:calc(calc(2.375rem * .8) * 2);bottom:0;display:block}.switch input+label::before{right:0;background-color:#dee2e6;border-radius:calc(2.375rem * .8);transition:0.2s all}.switch input+label::after{top:2px;left:2px;width:calc(calc(2.375rem * .8) - calc(2px * 2));height:calc(calc(2.375rem * .8) - calc(2px * 2));border-radius:50%;background-color:#fff;transition:0.2s all}.switch input:checked+label::before{background-color:#08d}.switch input:checked+label::after{margin-left:calc(2.375rem * .8)}.switch input:focus+label::before{outline:none;box-shadow:0 0 0 .2rem rgba(0,136,221,0.25)}.switch input:disabled+label{color:#868e96;cursor:not-allowed}.switch input:disabled+label::before{background-color:#e9ecef}.switch.switch-sm{font-size:.875rem}.switch.switch-sm input+label{min-width:calc(calc(1.9375rem * .8) * 2);height:calc(1.9375rem * .8);line-height:calc(1.9375rem * .8);text-indent:calc(calc(calc(1.9375rem * .8) * 2) + .5rem)}.switch.switch-sm input+label::before{width:calc(calc(1.9375rem * .8) * 2)}.switch.switch-sm input+label::after{width:calc(calc(1.9375rem * .8) - calc(2px * 2));height:calc(calc(1.9375rem * .8) - calc(2px * 2))}.switch.switch-sm input:checked+label::after{margin-left:calc(1.9375rem * .8)}.switch.switch-lg{font-size:1.25rem}.switch.switch-lg input+label{min-width:calc(calc(3rem * .8) * 2);height:calc(3rem * .8);line-height:calc(3rem * .8);text-indent:calc(calc(calc(3rem * .8) * 2) + .5rem)}.switch.switch-lg input+label::before{width:calc(calc(3rem * .8) * 2)}.switch.switch-lg input+label::after{width:calc(calc(3rem * .8) - calc(2px * 2));height:calc(calc(3rem * .8) - calc(2px * 2))}.switch.switch-lg input:checked+label::after{margin-left:calc(3rem * .8)}.switch+.switch{margin-left:1rem}.switch.danger input:checked+label::before{background-color:#dc3545}.switch.danger input:focus+label::before{box-shadow:0 0 0 .2rem rgba(220,53,69,0.25)}html{font-size:0.8em;background-color:#f8f9fa}body{background-color:transparent;position:relative}label{margin-bottom:.2rem;min-height:1.5rem}.form-group span label{display:inline-block}.form-group label{display:block}.form-group li label{display:inline-block}.form-group li .form-control{width:auto}.form-group li input[type="radio"].form-control,.form-group li input[type="checkbox"].form-control{display:inline}pre{white-space:pre-wrap}.raw-description{white-space:pre-line}.form-control.small-input,.input-group>.form-control.small-input{width:110px;flex:none}.input-group>input[type=checkbox]{margin:0.5em 1em}.form-row.odd{background-color:#e9ecef}.form-row-modal{padding:0.5rem 2rem}.field-tip{position:absolute;right:10px;top:5px;opacity:0.7}.form-group .select2-container--default .select2-selection--multiple{border:1px solid #ced4da}.page-link.imported-page{color:#aa8fda}.page-link.imported-page.current-page,.page-link.current-page{color:black;font-weight:bold}#modal-advanced-search .modal-header{flex-wrap:wrap;padding-bottom:0}#modal-advanced-search .modal-header .alert-secondary{background-color:#fff}.modal-header,.modal-footer{background-color:#e9ecef}.modal-body.body-scroll{max-height:calc(100vh - 200px);overflow-y:auto}.modal-dialog.full{width:98%;height:98%;max-width:none;padding:1%}.modal-dialog.full .display.dataTable{width:100% !important}.modal-dialog.full .modal-content{height:auto;min-height:100%;border-radius:0}.table{background-color:white}.tab-content{padding-top:1em}.input-progress.form-control:focus,.input-progress{background-color:#dee2e6}.card-header,.input-progress,.table-striped tbody tr:nth-of-type(2n+1),.dt-bootstrap4 table.dataTable.stripe tbody tr.odd,.dt-bootstrap4 table.dataTable.display tbody tr.odd{background-color:#e9ecef}.dropdown-item:hover,.dropdown-item:focus,.dt-bootstrap4 table.dataTable.hover tbody tr:hover,.dt-bootstrap4 table.dataTable.display tbody tr:hover{background-color:#f6f6f6;background-color:#dee2e6}table.dataTable{font-size:0.8em}.table-modal-lg table.dataTable{font-size:1em}div.dt-buttons{float:right}.dt-button{color:#fff;background-color:#007bff;border-color:#007bff;display:inline-block;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;border:1px solid transparent;color:#fff;background-color:#6c757d;border-color:#6c757d;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color 0.15s ease-in-out,background-color 0.15s ease-in-out,border-color 0.15s ease-in-out,box-shadow 0.15s ease-in-out}.dt-button:hover{color:#fff;background-color:#5a6268;border-color:#545b62}.dt-button:focus,.dt-button.focus{box-shadow:0 0 0 .2rem rgba(108,117,125,0.5)}.dt-button.disabled,.dt-button:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.dt-button:not(:disabled):not(.disabled):active,.dt-button:not(:disabled):not(.disabled).active,.show>.dt-button.dropdown-toggle{color:#fff;background-color:#545b62;border-color:#4e555b}.dt-button:not(:disabled):not(.disabled):active:focus,.dt-button:not(:disabled):not(.disabled).active:focus,.show>.dt-button.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,0.5)}.dt-button.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.dt-button.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.dt-button.btn-success:focus,.dt-button.btn-success.focus{box-shadow:0 0 0 .2rem rgba(40,167,69,0.5)}.dt-button.btn-success.disabled,.dt-button.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.dt-button.btn-success:not(:disabled):not(.disabled):active,.dt-button.btn-success:not(:disabled):not(.disabled).active,.show>.dt-button.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.dt-button.btn-success:not(:disabled):not(.disabled):active:focus,.dt-button.btn-success:not(:disabled):not(.disabled).active:focus,.show>.dt-button.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,0.5)}.dt-button.disabled{background-color:#f8f9fa;border-color:#f8f9fa;color:#adb5bd;cursor:not-allowed}.small-button{padding:0.1em 0.2em}.previous-value{margin:0.4em 0;display:block}h3,.h3{font-size:1.5rem}h4,.h4{font-size:1.1rem}textarea{height:90px}.sheet h4{color:#6c757d}#bookmark-list .input-link{width:100%;padding-right:5px}#window-fixed-menu{background-color:#e9ecef;position:fixed;right:0;margin-top:100px;z-index:50;width:200px}#window-fixed-menu-list li{padding-bottom:0.5em}#window-fixed-menu-list li a.nav-link{background-color:white}#window-fixed-menu-list li a.nav-link.active{background-color:#007bff}#window-menu-title{font-size:1.3em}#window-menu-control{font-size:0.6em;padding-top:0.2em}#window-fixed-menu.hidden{transform:rotate(270deg);transform-origin:right bottom 0}#window-fixed-menu.hidden i.fa-times{transform:rotate(45deg);transform-origin:10px 10px 0;padding-left:0.1em}.form h4,.form h3,.collapse-form .card-header,#window h3{background-color:#ced4da}.collapse-form .card,.collapse-form .card-header{border-radius:0;border:0 solid}.collapse-form .card-header{padding:0;text-align:center}.collapse-form .card-header h4{margin-bottom:0}.collapse-form .card-header .btn.btn-link{color:#212529;width:100%}.collapse-form .card-body{border:1px solid #ced4da}.collapse-form .fa-expand,.collapse-form .collapsed .fa-compress{display:none}.collapse-form .collapsed .fa-expand,.collapse-form .fa-compress{display:inline-block}.clean-table h4,.form h4,.form h3,.collapse-form .card-header h4 .btn,.sheet h4,.sheet h3,.sheet h2{text-align:center;text-shadow:2px 2px 2px rgba(150,150,150,0.7)}.sheet .subsection{background-color:#e9ecef}.sheet .row.toolbar{padding:0.5em 0.75em}.sheet .row{padding:0 0.75em;margin:0}.clean-table h4{margin-top:1em}.container{margin-top:1em;margin-bottom:8em}.bg-dark{background-color:#432776 !important}.navbar{padding:0 0.5rem}.navbar-dark .navbar-nav.action-menu .nav-link{color:#ffe484;border:1px solid #ffe484;border-radius:4px;margin:0.2em;padding:0.3em 0.6em}.navbar-dark .navbar-nav.action-menu .d-none .nav-link{border:0px solid transparent}.navbar-dark .navbar-nav.action-menu .d-none .nav-link:hover{background-color:transparent;color:#ffe484}.navbar-dark .navbar-nav.action-menu .nav-link:hover{background-color:#ffe484;color:#343a40}.navbar-dark .navbar-nav.action-menu .nav-link.dropdown-toggle::after{color:#ffe484}.navbar-dark .navbar-nav.action-menu .nav-link.dropdown-toggle:hover::after{color:#343a40}#context-menu,#reminder,.confirm-message,div#validation-bar{background-color:#6f42c1;color:rgba(255,255,255,0.8)}#reminder{padding:0.6em 1em 0.1em 1em}#alert-list{padding:0.6em 0}#alert-list a{font-size:1.1rem}.confirm-message{text-align:center;margin:0;padding:0.5rem;font-weight:bold}.is-invalid input{border-color:#f99}.errorlist{color:#900}#shortcut-menu{width:700px;padding:1em}#context-menu a.nav-link{color:rgba(255,255,255,0.8);padding:0.8rem 0.5rem 0.7rem 0.5rem}#context-menu .breadcrumb{margin-bottom:0;background-color:transparent}#current_items{width:100%}div#foot{background-color:#432776;color:rgba(255,255,255,0.5)}div#foot a{color:#ddd}div#foot a:hover{color:#fff}.breadcrumb button{border:0 transparent;background-color:transparent}.breadcrumb a:hover{text-decoration:none}.breadcrumb button:hover{cursor:pointer;color:#0062cc}.input-group.date input{border:1px solid #dee2e6;border-radius:.25rem;padding:.375rem .75rem;font-size:1rem;line-height:1.5}.input-group.date .input-group-text:hover{cursor:pointer}.input-group>ul{padding:0.5em;border:1px solid #dee2e6;border-radius:.25rem;margin:0;list-style:none}ul.compact{padding:0;margin:0}.help-text{max-height:250px;overflow:auto}.input-link{color:#6c757d}.input-link.disabled{color:#adb5bd}.input-link:hover{color:#343a40;cursor:pointer}.input-link.disabled:hover{color:#adb5bd;cursor:not-allowed}.input-sep{background-color:#fff;padding:0.3rem}.search_button{display:none}.lightgallery-captions{display:none}.lightgallery-subimage{display:inline-block;width:80px;padding:0.2em}.lightgallery-subimage img{width:100%}.lg .lg-sub-html{text-align:left}.lg .lg-sub-html .close{color:#fff}.lg .lg-sub-html .close:hover{opacity:0.9}#basket-manage #foot_pk{display:none}#basket-manage #grid_pk_meta_wrapper{width:50%;float:left;padding-bottom:80px}#basket-add-button{width:8%;float:left;margin:20vh 1% 0 1%}#basket-content-wrapper{width:40%;float:left}#basket-content{text-align:left;overflow:auto;max-height:60vh}.ui-widget-content{border:1px solid #dee2e6;background-color:#fff}.ui-menu-item{padding:0.2em 0.4em;border:1px solid #fff}.ui-menu-item:hover{color:#6f3b93;border:1px solid #6f3b93;cursor:pointer}.ui-autocomplete{font-size:0.7em;z-index:10000 !important;width:350px;border:5px solid #dee2e6;outline:none}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:none;font-size:1.1em}.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px} diff --git a/ishtar_common/static/js/ishtar.js b/ishtar_common/static/js/ishtar.js index ff8e43b54..ea0ccc516 100644 --- a/ishtar_common/static/js/ishtar.js +++ b/ishtar_common/static/js/ishtar.js @@ -70,6 +70,7 @@ var datatables_static_default = { var activate_all_search_msg = "Searches in the shortcut menu deals with all items."; var activate_own_search_msg = "Searches in the shortcut menu deals with only your items."; var added_message = " items added."; +var select_only_one_msg = "Select only one item."; var search_pinned_msg = ""; var advanced_menu = false; @@ -956,3 +957,25 @@ var qa_action_register = function(url) { ); }); }; + +var dt_single_enable_disable_submit_button = function(e, dt, type, indexes){ + var rows = dt.rows( { selected: true } ).count(); + if (rows == 1) { + $("#validation-bar #submit_form").prop('title', ""); + $("#validation-bar #submit_form").prop('disabled', false); + } else { + $("#validation-bar #submit_form").prop('title', select_only_one_msg); + $("#validation-bar #submit_form").prop('disabled', true); + } +}; + +var dt_multi_enable_disable_submit_button = function(e, dt, type, indexes){ + var rows = dt.rows( { selected: true } ).count(); + if (rows >= 1) { + $("#validation-bar #submit_form").prop('title', ""); + $("#validation-bar #submit_form").prop('disabled', false); + } else { + $("#validation-bar #submit_form").prop('title', select_only_one_msg); + $("#validation-bar #submit_form").prop('disabled', true); + } +}; diff --git a/ishtar_common/templates/actions.html b/ishtar_common/templates/actions.html index bd70ddf15..97d95c726 100644 --- a/ishtar_common/templates/actions.html +++ b/ishtar_common/templates/actions.html @@ -6,7 +6,7 @@ {% if MENU.current_subsections %} <li class="nav-item d-none d-lg-block"> - <span class="nav-link">></span> + <span class="nav-link">›</span> </li> {% with MENU.current_subsection as section_label %} {% with MENU.current_subsections as sections %} @@ -16,7 +16,7 @@ {% if MENU.current_subsubsections %} <li class="nav-item d-none d-lg-block"> - <span class="nav-link">></span> + <span class="nav-link">›</span> </li> {% with MENU.current_subsubsection as section_label %} {% with MENU.current_subsubsections as sections %} diff --git a/ishtar_common/templates/base.html b/ishtar_common/templates/base.html index 652df14b3..e5af101d5 100644 --- a/ishtar_common/templates/base.html +++ b/ishtar_common/templates/base.html @@ -44,6 +44,7 @@ var activate_own_search_msg = "{% trans 'Searches in the shortcut menu deal with only your items.' %}"; var search_pinned_msg = "{% trans 'Search pinned' %}"; var added_message = "{% trans " items added." %}"; + var select_only_one_msg = "{% trans "Select only one item." %}"; var YES = "{% trans 'yes' %}"; var NO = "{% trans 'no' %}"; var autorefresh_message_start = "{% trans 'Autorefresh start. The form is disabled.' %}"; @@ -107,20 +108,28 @@ <ul class="nav nav-pills flex-column" id="window-fixed-menu-list"> </ul> </nav> - <div id="window_wrapper"> - <div id="window" role="tablist"></div> - </div> <div id="message_list"> - {% if MESSAGES %}{% for message, message_type in MESSAGES %} - <div class="alert alert-{{message_type}} alert-dismissible fade show" - role="alert"> - {{message}} - <button type="button" class="close" data-dismiss="alert" - aria-label="Close"> - <span aria-hidden="true">×</span> - </button> - </div> - {% endfor %}{% endif %} + {% if messages %} + {% for message in messages %} + <div class="alert alert-{{ message.tags }} alert-dismissible fade show" + role="alert"> + {{message|safe}} + <button type="button" class="close" data-dismiss="alert" + aria-label="Close"> + <span aria-hidden="true">×</span> + </button> + </div>{% endfor %} + {% endif %} + {% if MESSAGES %}{% for message, message_type in MESSAGES %} + <div class="alert alert-{{message_type}} alert-dismissible fade show" + role="alert"> + {{message}} + <button type="button" class="close" data-dismiss="alert" + aria-label="Close"> + <span aria-hidden="true">×</span> + </button> + </div> + {% endfor %}{% endif %} </div> {% if warnings %}{% for warning in warnings %} <div class="alert alert-warning alert-dismissible fade show" role="alert"> @@ -129,6 +138,9 @@ </button> </div> {% endfor %}{% endif %} + <div id="window_wrapper"> + <div id="window" role="tablist"></div> + </div> {% block content %}{% endblock %} </div> diff --git a/ishtar_common/templates/blocks/CentimeterMeterWidget.html b/ishtar_common/templates/blocks/CentimeterMeterWidget.html new file mode 100644 index 000000000..00c1614b5 --- /dev/null +++ b/ishtar_common/templates/blocks/CentimeterMeterWidget.html @@ -0,0 +1,21 @@ +<div class="input-group"> + <input class="area_widget form-control" type="text"{{final_attrs|safe}}> + <div class="input-group-append"> + <div class="input-group-text"> + {{unit}} (<span id="meter_{{id}}">0</span> m) + </div> + </div> +</div> +<script type="text/javascript"><!--// + function evaluate_{{safe_id}}(){ + value = parseFloat($("#{{id}}").val()); + if(!isNaN(value)){ + value = value/100; + } else { + value = 0; + } + $("#meter_{{id}}").html(value); + } + $("#{{id}}").keyup(evaluate_{{safe_id}}); + $(document).ready(evaluate_{{safe_id}}()); +//--></script> diff --git a/ishtar_common/templates/blocks/DataTables.html b/ishtar_common/templates/blocks/DataTables.html index b5f669963..096650115 100644 --- a/ishtar_common/templates/blocks/DataTables.html +++ b/ishtar_common/templates/blocks/DataTables.html @@ -152,7 +152,7 @@ jQuery(document).ready(function(){ } }, "select": { - "style": {% if multiple_select %}'multi'{% else %}'single'{% endif %} + "style": {% if multiple_select or quick_actions %}'multi'{% else %}'single'{% endif %} }, {% if multiple_select or quick_actions %}"buttons": [ {% for url, title, icon, target in quick_actions %} @@ -170,7 +170,7 @@ jQuery(document).ready(function(){ } }, {% if not forloop.last %},{% endif %} - {% endfor %}{% if multiple_select %}{% if quick_actions%},{% endif %} + {% endfor %}{% if quick_actions%},{% endif %} { extend: 'selectAll', text: '<i class="fa fa-check-circle-o"></i>', @@ -181,7 +181,6 @@ jQuery(document).ready(function(){ text: '<i class="fa fa-times"></i>', titleAttr: "{% trans 'Deselect' %}" } - {% endif %} ], "dom": 'lBtip', {% else %} @@ -192,7 +191,12 @@ jQuery(document).ready(function(){ { "data": "link", "orderable": false },{% for col in extra_cols %} { "data": "{{col}}", "defaultContent": "-", "render": $.fn.dataTable.render.ellipsis( 70, true ) }{% if not forloop.last %},{% endif %}{% endfor %} - ] + ], + "initComplete": function(settings, json) { + var api = new $.fn.dataTable.Api(settings); + {% if not multiple_select %}dt_single_enable_disable_submit_button(null, api); + {% else %}dt_multi_enable_disable_submit_button(null, api);{% endif %} + } }; if (!debug) $.fn.dataTable.ext.errMode = 'none'; @@ -201,6 +205,14 @@ jQuery(document).ready(function(){ if (datatables_i18n) datatable_options['language'] = datatables_i18n; datatable_{{sname}} = jQuery("#grid_{{name}}").DataTable(datatable_options); + {% if not multiple_select %} + datatable_{{sname}}.on('select', dt_single_enable_disable_submit_button); + datatable_{{sname}}.on('deselect', dt_single_enable_disable_submit_button); + {% else %} + datatable_{{sname}}.on('select', dt_multi_enable_disable_submit_button); + datatable_{{sname}}.on('deselect', dt_multi_enable_disable_submit_button); + {% endif %} + {% if multiple %} jQuery("#add_button_{{name}}").click(function (){ var mygrid = jQuery("#grid_{{name}}"); diff --git a/ishtar_common/templates/blocks/GramKilogramWidget.html b/ishtar_common/templates/blocks/GramKilogramWidget.html new file mode 100644 index 000000000..27c066d13 --- /dev/null +++ b/ishtar_common/templates/blocks/GramKilogramWidget.html @@ -0,0 +1,21 @@ +<div class="input-group"> + <input class="area_widget form-control" type="text"{{final_attrs|safe}}> + <div class="input-group-append"> + <div class="input-group-text"> + {{unit}} (<span id="kg_{{id}}">0</span> kg) + </div> + </div> +</div> +<script type="text/javascript"><!--// + function evaluate_{{safe_id}}(){ + value = parseFloat($("#{{id}}").val()); + if(!isNaN(value)){ + value = value/1000; + } else { + value = 0; + } + $("#kg_{{id}}").html(value); + } + $("#{{id}}").keyup(evaluate_{{safe_id}}); + $(document).ready(evaluate_{{safe_id}}()); +//--></script> diff --git a/ishtar_common/templates/blocks/action_list.html b/ishtar_common/templates/blocks/action_list.html index 50a6554c4..384082ad4 100644 --- a/ishtar_common/templates/blocks/action_list.html +++ b/ishtar_common/templates/blocks/action_list.html @@ -1,12 +1,12 @@ <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" - aria-expanded="false">{{section_label}}</a> + aria-expanded="false">{{section_label|safe}}</a> <div class="dropdown-menu"> {% for label, url, has_children in sections %} <a class="dropdown-item{% if has_children%} font-weight-bold{%endif%}" href="{{url}}"> - {{ label }} + {{ label|safe }} </a>{% endfor %} </div> </li> diff --git a/ishtar_common/templates/blocks/bs_field_snippet.html b/ishtar_common/templates/blocks/bs_field_snippet.html index 830dd4cfa..f46b15209 100644 --- a/ishtar_common/templates/blocks/bs_field_snippet.html +++ b/ishtar_common/templates/blocks/bs_field_snippet.html @@ -1,5 +1,5 @@ {% load i18n %} - <div class="form-group {% if field.field.widget.attrs.cols %}col-lg-12{% else %}col-lg-6{% endif %}{% if field.errors %} is-invalid{% endif %}{% if field.field.required %} required{% endif %}" + <div class="form-group {% if field.field.widget.attrs.cols or force_large_col %}col-lg-12{% else %}col-lg-6{% endif %}{% if field.errors %} is-invalid{% endif %}{% if field.field.required %} required{% endif %}" data-alt-name="{{field.field.alt_name}}"> {% if field.label %}{{ field.label_tag }}{% endif %} {% if show_field_number and field.field.order_number %}<span class="badge badge-pill badge-success field-tip"> diff --git a/ishtar_common/templates/ishtar/blocks/sheet_json.html b/ishtar_common/templates/ishtar/blocks/sheet_json.html index 8927eb057..df9340c6f 100644 --- a/ishtar_common/templates/ishtar/blocks/sheet_json.html +++ b/ishtar_common/templates/ishtar/blocks/sheet_json.html @@ -5,5 +5,7 @@ {% if forloop.first %}<div class='row'>{% endif %} {% field_flex label value %} {% if forloop.last %}</div>{% endif %} +{% empty %} +{% trans "No data" %} {% endfor %} {% endfor %} diff --git a/ishtar_common/templates/ishtar/blocks/window_field_flex_multiple_full.html b/ishtar_common/templates/ishtar/blocks/window_field_flex_multiple_full.html new file mode 100644 index 000000000..b70c1d2fc --- /dev/null +++ b/ishtar_common/templates/ishtar/blocks/window_field_flex_multiple_full.html @@ -0,0 +1,8 @@ +{% load i18n %}{% if data.count %} + <dl class="col-12 row"> + <dt class="col-12">{% trans caption %}</dt> + <dd class="col-12">{% for d in data.distinct.all %} + {% if forloop.counter0 %} ; {% endif %}{{ d }} + {% endfor %}</dd> + </dl> +{% endif %} diff --git a/ishtar_common/templates/ishtar/blocks/window_nav.html b/ishtar_common/templates/ishtar/blocks/window_nav.html index 6cd4bff40..62caff142 100644 --- a/ishtar_common/templates/ishtar/blocks/window_nav.html +++ b/ishtar_common/templates/ishtar/blocks/window_nav.html @@ -27,9 +27,9 @@ {% endif %} </div> </div> - <div class='offset-md-6 col-md-4 text-right'> + <div class='offset-md-4 col-md-6 text-right'> {% else %} - <div class='offset-md-8 col-md-4 text-right'> + <div class='offset-md-6 col-md-6 text-right'> {% endif %} {% if pin_action and item.SLUG %} <div class="btn-group btn-group-sm" role="group" @@ -38,6 +38,8 @@ onclick='$.get("{% url "pin" item.SLUG item.pk %}", function(){load_shortcut_menu(); display_info("{% trans 'Item pined in your shortcut menu.' %}")});' title="{% trans 'Pin' %}"> <i class="fa fa-thumb-tack"></i> </a> + {% block post_pin %} + {% endblock %} </div> {% endif %} <div class="btn-group btn-group-sm" role="group" aria-label="{% trans 'Actions' %}"> @@ -55,15 +57,33 @@ </a> {% endfor %} </div> + <div class="btn-group btn-group-sm" role="group" aria-label="{% trans 'Export' %}"> - <a class="btn btn-secondary" href='{% url show_url item.pk "odt" %}' - title='{% trans "Export as OpenOffice.org file"%}'> - ODT <i class="fa fa-file-word-o" aria-hidden="true"></i> - <a class="btn btn-secondary" href='{% url show_url item.pk "pdf" %}' - title='{% trans "Export as PDF file"%}'> - PDF <i class="fa fa-file-pdf-o" aria-hidden="true"></i> - </a> + <div class="dropdown btn-secondary"> + <button class="btn btn-sm btn-secondary dropdown-toggle" type="button" + id="dropdown-sheet-export-{{window_id}}" + data-toggle="dropdown"aria-haspopup="true" + aria-expanded="false"> + <i class="fa fa-file-word-o"></i> {% trans "Export" %} + </button> + <div class="dropdown-menu" + aria-labelledby="dropdown-sheet-export-{{window_id}}"> + <a class="dropdown-item" href='{% url show_url item.pk "odt" %}' + title='{% trans "Export as OpenOffice.org file"%}'> + ODT <i class="fa fa-file-word-o" aria-hidden="true"></i> + </a> + <a class="dropdown-item" href='{% url show_url item.pk "pdf" %}' + title='{% trans "Export as PDF file"%}'> + PDF <i class="fa fa-file-pdf-o" aria-hidden="true"></i> + </a>{% for template_name, template_url in extra_templates %} + <a class="dropdown-item" href='{{template_url}}'> + {{template_name}} <i class="fa fa-file-word-o" aria-hidden="true"></i> + </a>{% endfor %} + </div> + </div> + + </div> </div> </div> diff --git a/ishtar_common/templates/ishtar/form.html b/ishtar_common/templates/ishtar/form.html index b99d504a0..bcd69959e 100644 --- a/ishtar_common/templates/ishtar/form.html +++ b/ishtar_common/templates/ishtar/form.html @@ -1,5 +1,8 @@ {% extends "base.html" %} {% load i18n inline_formset table_form %} +{% block extra_head %} +{{form.media}} +{% endblock %} {% block pre_container %} <form enctype="multipart/form-data" action="." method="post"{% if confirm %} onsubmit='return confirm("{{confirm}}");'{% endif %}>{% csrf_token %} diff --git a/ishtar_common/templates/ishtar/forms/qa_base.html b/ishtar_common/templates/ishtar/forms/qa_base.html index 70fe70e65..367acfcd8 100644 --- a/ishtar_common/templates/ishtar/forms/qa_base.html +++ b/ishtar_common/templates/ishtar/forms/qa_base.html @@ -1,7 +1,6 @@ {% load i18n inline_formset table_form %} -<div - class="modal-dialog {% if modal_size == 'large' %}modal-lg {% elif modal_size == 'small'%}modal-sm {% endif%}modal-dialog-centered"> +<div class="modal-dialog {% if modal_size == 'large' %}modal-lg {% elif modal_size == 'small'%}modal-sm {% endif%}modal-dialog-centered"> <div class="modal-content"> <div class="modal-header"> <h2>{{page_name|safe}}</h2> diff --git a/ishtar_common/templates/ishtar/wizard/confirm_wizard.html b/ishtar_common/templates/ishtar/wizard/confirm_wizard.html index 401fe570c..9829058a8 100644 --- a/ishtar_common/templates/ishtar/wizard/confirm_wizard.html +++ b/ishtar_common/templates/ishtar/wizard/confirm_wizard.html @@ -9,7 +9,12 @@ <form action="." method="post">{% csrf_token %} <div class='form'> {% block "warning_informations" %}{% endblock %} - <p>{% if confirm_msg %}{{confirm_msg|safe}}{%else%}{% trans "You have entered the following informations:" %}{%endif%}</p> + {% block "warning_message" %} + <div class="alert alert-info"> + {% if confirm_msg %}{{confirm_msg|safe}}{%else%}{% trans "You have entered the following informations:" %}{%endif%} + </div> + {% endblock %} + {% block "detailed_informations" %} {% for form_label, form_data in datas %} <div class="card"> @@ -42,6 +47,7 @@ {{ extra_form }} </table> {% endif %} + {% endblock %} {% block "extra_informations" %}{% endblock %} {% block "footer" %} diff --git a/ishtar_common/templatetags/ishtar_helpers.py b/ishtar_common/templatetags/ishtar_helpers.py new file mode 100644 index 000000000..88dd68b57 --- /dev/null +++ b/ishtar_common/templatetags/ishtar_helpers.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from datetime import datetime + +from django.template import Library +from django.utils.translation import ugettext as _ + +register = Library() + + +@register.filter +def or_(value1, value2): + return value1 or value2 + + +@register.filter +def and_(value1, value2): + return value1 and value2 diff --git a/ishtar_common/templatetags/window_field.py b/ishtar_common/templatetags/window_field.py index 46329a3fa..a5bae3b72 100644 --- a/ishtar_common/templatetags/window_field.py +++ b/ishtar_common/templatetags/window_field.py @@ -108,6 +108,14 @@ def field_flex_multiple(caption, data, small=False): return field_multiple(caption, data, size=size) +@register.inclusion_tag('ishtar/blocks/window_field_flex_multiple_full.html') +def field_flex_multiple_full(caption, data, small=False): + size = None + if small: + size = 2 + return field_multiple(caption, data, size=size) + + @register.inclusion_tag('ishtar/blocks/window_field_detail.html') def field_detail(caption, item, li=False, size=None): return {'caption': caption, 'item': item, 'link': link_to_window(item), diff --git a/ishtar_common/templatetags/window_header.py b/ishtar_common/templatetags/window_header.py index 18dc793bf..bbd923d41 100644 --- a/ishtar_common/templatetags/window_header.py +++ b/ishtar_common/templatetags/window_header.py @@ -10,8 +10,17 @@ def window_nav(context, item, window_id, show_url, modify_url='', histo_url='', extra_actions = [] if hasattr(item, 'get_extra_actions'): extra_actions = item.get_extra_actions(context['request']) - if modify_url and hasattr(item, 'can_do') and hasattr(item, 'SLUG') and \ - not item.can_do(context['request'], 'change_' + item.SLUG): + extra_templates = [] + if hasattr(item, 'get_extra_templates'): + extra_templates = item.get_extra_templates(context['request']) + + slug = None + if hasattr(item, "LONG_SLUG"): + slug = item.LONG_SLUG + elif hasattr(item, "SLUG"): + slug = item.SLUG + if modify_url and hasattr(item, 'can_do') and slug and \ + not item.can_do(context['request'], 'change_' + slug): modify_url = "" return { 'show_url': show_url, @@ -23,7 +32,21 @@ def window_nav(context, item, window_id, show_url, modify_url='', histo_url='', 'previous': previous, 'next': nxt, 'extra_actions': extra_actions, - 'pin_action': pin_action} + 'pin_action': pin_action, + 'extra_templates': extra_templates, + } + + +@register.inclusion_tag('ishtar/blocks/window_find_nav.html', + takes_context=True) +def window_find_nav(context, item, window_id, show_url, modify_url='', + histo_url='', revert_url='', previous=None, nxt=None, + pin_action=False, baskets=None): + dct = window_nav(context, item, window_id, show_url, modify_url=modify_url, + histo_url=histo_url, revert_url=revert_url, + previous=previous, nxt=nxt, pin_action=pin_action) + dct['baskets'] = baskets + return dct @register.inclusion_tag('ishtar/blocks/window_file_nav.html', diff --git a/ishtar_common/tests.py b/ishtar_common/tests.py index bd1833594..cf9f599c4 100644 --- a/ishtar_common/tests.py +++ b/ishtar_common/tests.py @@ -1235,10 +1235,14 @@ class ShortMenuTest(TestCase): self.assertFalse(str(tf.cached_label) in response.content) def _create_treatment(self): - from archaeological_finds.models import Treatment + from archaeological_finds.models import Treatment, TreatmentState + completed, created = TreatmentState.objects.get_or_create( + txt_idx='completed', defaults={"executed": True, "label": u"Done"} + ) return Treatment.objects.create( label="My treatment", - year=2052 + year=2052, + treatment_state=completed ) def test_treatment(self): diff --git a/ishtar_common/urls.py b/ishtar_common/urls.py index 8d06b6862..aea419d08 100644 --- a/ishtar_common/urls.py +++ b/ishtar_common/urls.py @@ -174,6 +174,8 @@ urlpatterns += [ views.new_person_noorga, name='new-person-noorga'), url(r'autocomplete-user/$', views.autocomplete_user, name='autocomplete-user'), + url(r'autocomplete-ishtaruser/$', + views.autocomplete_ishtaruser, name='autocomplete-ishtaruser'), url(r'autocomplete-person(?:/([0-9_]+))?(?:/([0-9_]*))?/(user)?$', views.autocomplete_person, name='autocomplete-person'), url(r'autocomplete-person-permissive(?:/([0-9_]+))?(?:/([0-9_]*))?' diff --git a/ishtar_common/utils.py b/ishtar_common/utils.py index 4f968af31..ff67fc470 100644 --- a/ishtar_common/utils.py +++ b/ishtar_common/utils.py @@ -145,18 +145,24 @@ def check_model_access_control(request, model, available_perms=None): return allowed, own -def update_data(data_1, data_2): +def update_data(data_1, data_2, merge=False): """ Update a data directory taking account of key detail """ res = {} if not isinstance(data_1, dict) or not isinstance(data_2, dict): + if data_2 and not data_1: + return data_2 + if not merge: + return data_1 + if data_2 and data_2 != data_1: + return data_1 + u" ; " + data_2 return data_1 for k in data_1: if k not in data_2: res[k] = data_1[k] else: - res[k] = update_data(data_1[k], data_2[k]) + res[k] = update_data(data_1[k], data_2[k], merge=merge) for k in data_2: if k not in data_1: res[k] = data_2[k] diff --git a/ishtar_common/views.py b/ishtar_common/views.py index 3d64535d4..72418e4fa 100644 --- a/ishtar_common/views.py +++ b/ishtar_common/views.py @@ -527,6 +527,29 @@ def autocomplete_user(request): return HttpResponse(data, content_type='text/plain') +def autocomplete_ishtaruser(request): + if not request.user.has_perm('ishtar_common.view_person', models.Person): + return HttpResponse('[]', content_type='text/plain') + q = request.GET.get('term', '') + limit = request.GET.get('limit', 20) + try: + limit = int(limit) + except ValueError: + return HttpResponseBadRequest() + query = Q() + for q in q.split(' '): + qu = (Q(person__name__icontains=q) | + Q(person__surname__icontains=q) | + Q(person__raw_name__icontains=q)) + query = query & qu + users = models.IshtarUser.objects.filter(query)[:limit] + data = json.dumps([ + {'id': user.pk, + 'value': unicode(user)} + for user in users]) + return HttpResponse(data, content_type='text/plain') + + def autocomplete_person(request, person_types=None, attached_to=None, is_ishtar_user=None, permissive=False): all_items = request.user.has_perm('ishtar_common.view_person', @@ -1754,6 +1777,32 @@ def get_bookmark(request, pk): ) +def gen_generate_doc(model): + + def func(request, pk, template_pk=None): + if not request.user.has_perm('view_' + model.SLUG, model): + return HttpResponse(content_type='text/plain') + try: + item = model.objects.get(pk=pk) + doc = item.publish(template_pk) + except model.DoesNotExist: + doc = None + if doc: + MIMES = {'odt': 'application/vnd.oasis.opendocument.text', + 'ods': 'application/vnd.oasis.opendocument.spreadsheet'} + ext = doc.split('.')[-1] + doc_name = item.get_filename() + "." + ext + mimetype = 'text/csv' + if ext in MIMES: + mimetype = MIMES[ext] + response = HttpResponse(open(doc), content_type=mimetype) + response['Content-Disposition'] = 'attachment; filename=%s' % \ + doc_name + return response + return HttpResponse(content_type='text/plain') + return func + + class SearchQueryMixin(object): """ Manage content type and profile init @@ -1978,3 +2027,5 @@ class QAItemEditForm(QAItemForm): def form_save(self, form): form.save(self.items, self.request.user) return HttpResponseRedirect(reverse("success")) + + diff --git a/ishtar_common/views_item.py b/ishtar_common/views_item.py index cde3f8d87..6f4abdee9 100644 --- a/ishtar_common/views_item.py +++ b/ishtar_common/views_item.py @@ -22,7 +22,8 @@ from django.db.models.fields import FieldDoesNotExist from django.http import HttpResponse from django.shortcuts import render from django.template import loader -from django.utils.translation import ugettext, ugettext_lazy as _ +from django.utils.translation import ugettext, ugettext_lazy as _, \ + activate, deactivate, pgettext_lazy from tidylib import tidy_document as tidy from unidecode import unidecode from weasyprint import HTML, CSS @@ -65,17 +66,29 @@ CURRENT_ITEM_KEYS = ( CURRENT_ITEM_KEYS_DICT = dict(CURRENT_ITEM_KEYS) +def get_autocomplete_query(request, label_attributes, extra=None): + q = request.GET.get('term') or "" + if not label_attributes: + return Q(pk__isnull=True) + query = Q() + if extra: + query = Q(**extra) + for q in q.split(' '): + if not q: + continue + sub_q = Q(**{label_attributes[0] + "__icontains": q}) + for other_label in label_attributes[1:]: + sub_q = sub_q | Q(**{other_label + "__icontains": q}) + query = query & sub_q + return query + + def get_autocomplete_item(model, extra=None): if not extra: extra = {} def func(request, current_right=None): - q = request.GET.get('term') or "" - query = Q(**extra) - for q in q.split(' '): - if not q: - continue - query = query & Q(cached_label__icontains=q) + query = get_autocomplete_query(request, ['cached_label'], extra=extra) limit = 20 objects = model.objects.filter(query)[:limit] data = json.dumps([{'id': obj.pk, 'value': obj.cached_label} @@ -133,22 +146,25 @@ def display_item(model, extra_dct=None, show_url=None): return func -def show_item(model, name, extra_dct=None): +def show_item(model, name, extra_dct=None, model_for_perms=None): def func(request, pk, **dct): - allowed, own = check_model_access_control(request, model) + check_model = model + if model_for_perms: + check_model = model_for_perms + allowed, own = check_model_access_control(request, check_model) if not allowed: return HttpResponse('', content_type="application/xhtml") q = model.objects if own: if not hasattr(request.user, 'ishtaruser'): - return HttpResponse('NOK') + return HttpResponse('') query_own = model.get_query_owns(request.user.ishtaruser) if query_own: q = q.filter(query_own).distinct() try: item = q.get(pk=pk) - except ObjectDoesNotExist: - return HttpResponse('NOK') + except (ObjectDoesNotExist, ValueError): + return HttpResponse('') doc_type = 'type' in dct and dct.pop('type') url_name = u"/".join(reverse('show-' + name, args=['0', ''] ).split('/')[:-2]) + u"/" @@ -325,6 +341,12 @@ def _push_to_list(obj, current_group, depth): current_group.append(obj) +def is_true_string(val): + val = unicode(val).lower().replace(u'"', u"") + if val in (u"1", u"true", unicode(_(u"True")).lower()): + return True + + def _parse_parentheses(s): """ Parse parentheses into list. @@ -368,14 +390,31 @@ def _parse_query_string(string, request_keys, current_dct, exc_dct): if excluded: term = term[1:] if term in request_keys: - term = request_keys[term] dct = current_dct - if excluded: - dct = exc_dct - if term in dct: - dct[term] += u";" + query + term = request_keys[term] + # callable request key for complex queries + if callable(term): + is_true = is_true_string(query) + if excluded: + is_true = not is_true + cfltr, cexclude, cextra = term(is_true=is_true) + if cfltr: + if 'and_reqs' not in dct: + dct['and_reqs'] = [] + dct['and_reqs'].append(cfltr) + if cexclude: + if 'exc_and_reqs' not in dct: + dct['exc_and_reqs'] = [] + dct['exc_and_reqs'].append(cexclude) + if cextra: + dct['extras'].append(cextra) else: - dct[term] = query + if excluded: + dct = exc_dct + if term in dct: + dct[term] += u";" + query + else: + dct[term] = query return u"" for reserved_char in FORBIDDEN_CHAR: string = string.replace(reserved_char, u"") @@ -487,6 +526,8 @@ def _search_manage_search_vector(model, dct, exc_dct, request_keys): search_query = \ search_query.replace(u'(', u'').replace(u')', u'').strip() if search_query: + if 'extras' not in dct: + dct['extras'] = [] dct['extras'].append( {'where': [model._meta.db_table + ".search_vector @@ (to_tsquery(%s, %s)) = true"], @@ -526,13 +567,47 @@ def _manage_bool_fields(model, bool_fields, reversed_bool_fields, dct, or_reqs): pass +today_lbl = pgettext_lazy("key for text search", u"today"), +TODAYS = ['today'] + +for language_code, language_lbl in settings.LANGUAGES: + activate(language_code) + TODAYS.append(unicode(today_lbl)) + deactivate() + + def _manage_dated_fields(dated_fields, dct): for k in dated_fields: if k in dct: if not dct[k]: dct.pop(k) + continue + value = dct[k].replace('"', '').strip() + has_today = False + for today in TODAYS: + if value.startswith(today): + base_date = datetime.date.today() + value = value[len(today):].replace(' ', '') + if value and value[0] in (u"-", u"+"): + sign = value[0] + try: + days = int(value[1:]) + except ValueError: + days = 0 + if days: + if sign == u"-": + base_date = base_date - datetime.timedelta( + days=days) + else: + base_date = base_date + datetime.timedelta( + days=days) + dct[k] = base_date.strftime('%Y-%m-%d') + has_today = True + break + if has_today: + continue try: - items = dct[k].replace('"', '').split('/') + items = value.split('/') assert len(items) == 3 dct[k] = virtualtime.datetime(*map(lambda x: int(x), reversed(items))) \ @@ -795,7 +870,12 @@ def _construct_query(relation_types, dct, or_reqs, and_reqs): query |= Q(**alt_dct) query = _manage_relation_types(relation_types, dct, query, or_reqs) + done = [] for and_req in and_reqs: + str_q = unicode(and_req) + if str_q in done: + continue + done.append(str_q) query = query & and_req return query @@ -880,11 +960,13 @@ DEFAULT_ROW_NUMBER = 10 EXCLUDED_FIELDS = ['length'] -def get_item(model, func_name, default_name, extra_request_keys=[], - base_request=None, bool_fields=[], reversed_bool_fields=[], - dated_fields=[], associated_models=[], relative_session_names=[], - specific_perms=[], own_table_cols=None, relation_types_prefix={}, - do_not_deduplicate=False): +def get_item(model, func_name, default_name, extra_request_keys=None, + base_request=None, bool_fields=None, reversed_bool_fields=None, + dated_fields=None, associated_models=None, + relative_session_names=None, specific_perms=None, + own_table_cols=None, relation_types_prefix=None, + do_not_deduplicate=False, model_for_perms=None, + alt_query_own=None): """ Generic treatment of tables @@ -904,6 +986,8 @@ def get_item(model, func_name, default_name, extra_request_keys=[], :param do_not_deduplicate: duplication of id can occurs on large queryset a mecanism of deduplication is used. But duplicate ids can be normal (for instance for record_relations view). + :param model_for_perms: use another model to check permission + :param alt_query_own: name of alternate method to get query_own :return: """ def func(request, data_type='json', full=False, force_own=False, @@ -915,10 +999,15 @@ def get_item(model, func_name, default_name, extra_request_keys=[], if 'type' in dct: data_type = dct.pop('type') if not data_type: - EMPTY = '[]' data_type = 'json' + if data_type == "json": + EMPTY = '[]' - allowed, own = check_model_access_control(request, model, + model_to_check = model + if model_for_perms: + model_to_check = model_for_perms + + allowed, own = check_model_access_control(request, model_to_check, available_perms) if not allowed: return HttpResponse(EMPTY, content_type='text/plain') @@ -934,13 +1023,16 @@ def get_item(model, func_name, default_name, extra_request_keys=[], q = models.IshtarUser.objects.filter(user_ptr=request.user) if not q.count(): return HttpResponse(EMPTY, content_type='text/plain') - query_own = model.get_query_owns(q.all()[0]) + if alt_query_own: + query_own = getattr(model, alt_query_own)(q.all()[0]) + else: + query_own = model.get_query_owns(q.all()[0]) # get defaults from model if not extra_request_keys and hasattr(model, 'EXTRA_REQUEST_KEYS'): my_extra_request_keys = copy(model.EXTRA_REQUEST_KEYS) else: - my_extra_request_keys = copy(extra_request_keys) + my_extra_request_keys = copy(extra_request_keys or []) if base_request is None and hasattr(model, 'BASE_REQUEST'): if callable(model.BASE_REQUEST): my_base_request = model.BASE_REQUEST(request) @@ -953,32 +1045,35 @@ def get_item(model, func_name, default_name, extra_request_keys=[], if not bool_fields and hasattr(model, 'BOOL_FIELDS'): my_bool_fields = model.BOOL_FIELDS[:] else: - my_bool_fields = bool_fields[:] + my_bool_fields = bool_fields[:] if bool_fields else [] if not reversed_bool_fields and hasattr(model, 'REVERSED_BOOL_FIELDS'): my_reversed_bool_fields = model.REVERSED_BOOL_FIELDS[:] else: - my_reversed_bool_fields = reversed_bool_fields[:] + my_reversed_bool_fields = reversed_bool_fields[:] \ + if reversed_bool_fields else [] if not dated_fields and hasattr(model, 'DATED_FIELDS'): my_dated_fields = model.DATED_FIELDS[:] else: - my_dated_fields = dated_fields[:] + my_dated_fields = dated_fields[:] if dated_fields else [] if not associated_models and hasattr(model, 'ASSOCIATED_MODELS'): my_associated_models = model.ASSOCIATED_MODELS[:] else: - my_associated_models = associated_models[:] + my_associated_models = associated_models[:] \ + if associated_models else [] if not relative_session_names and hasattr(model, 'RELATIVE_SESSION_NAMES'): my_relative_session_names = model.RELATIVE_SESSION_NAMES[:] else: - my_relative_session_names = relative_session_names[:] + my_relative_session_names = relative_session_names[:] \ + if relative_session_names else [] if not relation_types_prefix and hasattr(model, 'RELATION_TYPES_PREFIX'): my_relation_types_prefix = copy(model.RELATION_TYPES_PREFIX) else: - my_relation_types_prefix = copy(relation_types_prefix) + my_relation_types_prefix = copy(relation_types_prefix) \ + if relation_types_prefix else {} - fields = [model._meta.get_field(k) - for k in get_all_field_names(model)] + fields = [model._meta.get_field(k) for k in get_all_field_names(model)] request_keys = dict([ (field.name, @@ -1039,6 +1134,7 @@ def get_item(model, func_name, default_name, extra_request_keys=[], excluded_dct = {} and_reqs, or_reqs = [], [] exc_and_reqs, exc_or_reqs = [], [] + dct['extras'], dct['and_reqs'], dct['exc_and_reqs'] = [], [], [] if full == 'shortcut': if model.SLUG == "warehouse": @@ -1057,7 +1153,10 @@ def get_item(model, func_name, default_name, extra_request_keys=[], if not val: continue req_keys = request_keys[k] - if type(req_keys) not in (list, tuple): + if callable(req_keys): + # callable request key for complex queries not managed on GET + continue + elif type(req_keys) not in (list, tuple): dct[req_keys] = val continue # multiple choice target @@ -1080,7 +1179,6 @@ def get_item(model, func_name, default_name, extra_request_keys=[], else: request.session[func_name] = dct - dct['extras'] = [] dct, excluded_dct = _search_manage_search_vector( model, dct, excluded_dct, request_keys) search_vector = "" @@ -1116,7 +1214,13 @@ def get_item(model, func_name, default_name, extra_request_keys=[], _manage_facet_search(model, dct, and_reqs) _manage_facet_search(model, excluded_dct, exc_and_reqs) - extras = dct.pop('extras') + extras = [] + if 'extras' in dct: + extras = dct.pop('extras') + if 'and_reqs' in dct: + and_reqs += dct.pop('and_reqs') + if 'exc_and_reqs' in dct: + exc_and_reqs += dct.pop('exc_and_reqs') _manage_clean_search_field(dct) _manage_clean_search_field(excluded_dct) diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py index 7d9e06926..5853c9675 100644 --- a/ishtar_common/widgets.py +++ b/ishtar_common/widgets.py @@ -224,6 +224,10 @@ class Select2Base(Select2Media): else: attrs['style'] = "width: 370px" + if value: + if type(value) not in (list, tuple): + value = value.split(',') + options = "" if self.remote: options = """{ @@ -248,8 +252,6 @@ class Select2Base(Select2Media): }""" % self.remote if value: choices = [] - if type(value) not in (list, tuple): - value = value.split(',') for v in value: try: choices.append((v, self.model.objects.get(pk=v))) @@ -300,7 +302,7 @@ class CheckboxSelectMultiple(CheckboxSelectMultipleBase): def render(self, name, value, attrs=None, choices=()): if type(value) in (str, unicode): value = value.split(',') - if type(value) not in (list, tuple): + if not isinstance(value, (list, tuple)): value = [value] return super(CheckboxSelectMultiple, self).render(name, value, attrs) @@ -356,6 +358,14 @@ class Select2BaseField(object): class Select2MultipleField(Select2BaseField, forms.MultipleChoiceField): multiple = True + def to_python(self, value): + if not isinstance(value, (list, tuple)): + if value: + value = value.split(',') + else: + value = [] + return super(Select2MultipleField, self).to_python(value) + class Select2SimpleField(Select2BaseField, forms.ChoiceField): pass @@ -470,6 +480,36 @@ class SquareMeterWidget(forms.TextInput): return mark_safe(rendered) +class GramKilogramWidget(forms.TextInput): + def render(self, name, value, attrs=None, renderer=None): + if not value: + value = u"" + final_attrs = flatatt( + self.build_attrs(attrs, {"name": name, "value": value})) + dct = {'final_attrs': final_attrs, + 'unit': u"g", + 'id': attrs['id'], + "safe_id": attrs['id'].replace('-', '_')} + t = loader.get_template('blocks/GramKilogramWidget.html') + rendered = t.render(dct) + return mark_safe(rendered) + + +class CentimeterMeterWidget(forms.TextInput): + def render(self, name, value, attrs=None, renderer=None): + if not value: + value = u"" + final_attrs = flatatt( + self.build_attrs(attrs, {"name": name, "value": value})) + dct = {'final_attrs': final_attrs, + 'unit': u"cm", + 'id': attrs['id'], + "safe_id": attrs['id'].replace('-', '_')} + t = loader.get_template('blocks/CentimeterMeterWidget.html') + rendered = t.render(dct) + return mark_safe(rendered) + + AreaWidget = forms.TextInput if settings.SURFACE_UNIT == 'square-metre': @@ -927,7 +967,7 @@ class DataTable(Select2Media, forms.RadioSelect): :param new: :param new_message: :param source_full: url to get full listing - :param multiple_select: + :param multiple_select: select multiple is available :param sortname: column name (model attribute) to use to sort :param col_prefix: prefix to remove to col_names """ @@ -1055,7 +1095,6 @@ class DataTable(Select2Media, forms.RadioSelect): if hasattr(self.associated_model, "QUICK_ACTIONS"): dct['quick_actions'] = \ self.associated_model.get_quick_actions(user=self.user) - self.multiple_select = True source = unicode(self.source) dct.update({'name': name, 'col_names': col_names, diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py index a439cc014..47355dd06 100644 --- a/ishtar_common/wizards.py +++ b/ishtar_common/wizards.py @@ -23,6 +23,7 @@ import os # from functools import wraps from django.conf import settings +from django.contrib import messages from formtools.wizard.views import NamedUrlWizardView, normalize_name, \ get_storage, StepsHelper @@ -115,6 +116,7 @@ class Wizard(IshtarWizard): ) main_item_select_keys = ('selec-',) formset_pop_deleted = True + alt_is_own_method = None # alternate method name for "is_own" check saved_args = {} # argument to pass on object save @@ -145,29 +147,39 @@ class Wizard(IshtarWizard): form, other_check) return kwargs + def check_own_permissions(self, request, step=None, *args, **kwargs): + # reinit default dispatch of a wizard - not clean... + self.request = request + self.session = request.session + self.prefix = self.get_prefix(request, *args, **kwargs) + self.storage = get_storage( + self.storage_name, self.prefix, request, + getattr(self, 'file_storage', None)) + self.steps = StepsHelper(self) + + current_object = self.get_current_object() + ishtaruser = request.user.ishtaruser \ + if hasattr(request.user, 'ishtaruser') else None + + # not the first step and current object is not owned + if self.steps and self.steps.first != step and current_object: + is_own = current_object.is_own( + ishtaruser, alt_query_own=self.alt_is_own_method) + if not is_own: + messages.add_message( + request, messages.WARNING, + _(u"Permission error: you cannot do this action.") + ) + self.session_reset(request, self.url_name) + return + return True + def dispatch(self, request, *args, **kwargs): self.current_right = kwargs.get('current_right', None) step = kwargs.get('step', None) # check that the current object is really owned by the current user if step and self.current_right and '_own_' in self.current_right: - - # reinit default dispatch of a wizard - not clean... - self.request = request - self.session = request.session - self.prefix = self.get_prefix(request, *args, **kwargs) - self.storage = get_storage( - self.storage_name, self.prefix, request, - getattr(self, 'file_storage', None)) - self.steps = StepsHelper(self) - - current_object = self.get_current_object() - ishtaruser = request.user.ishtaruser \ - if hasattr(request.user, 'ishtaruser') else None - - # not the fisrt step and current object is not owned - if self.steps and self.steps.first != step and\ - current_object and not current_object.is_own(ishtaruser): - self.session_reset(request, self.url_name) + if not self.check_own_permissions(request, *args, **kwargs): return HttpResponseRedirect('/') # extra filter on forms self.filter_owns_items = True @@ -439,7 +451,7 @@ class Wizard(IshtarWizard): datas.append((form.form_label, form_datas)) return datas - def get_extra_model(self, dct, form_list): + def get_extra_model(self, dct, m2m, form_list): dct['history_modifier'] = self.request.user return dct @@ -552,7 +564,7 @@ class Wizard(IshtarWizard): def save_model(self, dct, m2m, whole_associated_models, form_list, return_object): - dct = self.get_extra_model(dct, form_list) + dct = self.get_extra_model(dct, m2m, form_list) obj = self.get_current_saved_object() data = {} if obj and hasattr(obj, 'data'): @@ -1181,7 +1193,7 @@ class Wizard(IshtarWizard): return vals def get_current_object(self): - """Get the current object for an instancied wizard""" + """Get the current object for an instanced wizard""" current_obj = None for key in self.main_item_select_keys: main_form_key = key + self.url_name @@ -1787,8 +1799,8 @@ class AccountWizard(Wizard): class SourceWizard(Wizard): model = None - def get_extra_model(self, dct, form_list): - dct = super(SourceWizard, self).get_extra_model(dct, form_list) + def get_extra_model(self, dct, m2m, form_list): + dct = super(SourceWizard, self).get_extra_model(dct, m2m, form_list) if 'history_modifier' in dct: dct.pop('history_modifier') return dct diff --git a/scss/custom.scss b/scss/custom.scss index 788220466..56dbffab6 100644 --- a/scss/custom.scss +++ b/scss/custom.scss @@ -136,6 +136,11 @@ pre { background-color: white; } + +.tab-content{ + padding-top: 1em; +} + .input-progress.form-control:focus, .input-progress{ background-color: $gray-300; @@ -477,6 +482,11 @@ div#foot a:hover { list-style: none; } +ul.compact{ + padding: 0; + margin: 0; +} + .help-text{ max-height: 250px; overflow: auto; @@ -600,6 +610,7 @@ div#foot a:hover { margin: 0; display: block; outline: none; + font-size: 1.1em; } .ui-helper-hidden { diff --git a/translations/de/ishtar_common.po b/translations/de/ishtar_common.po index 46a8e7b7f..bb535ee56 100644 --- a/translations/de/ishtar_common.po +++ b/translations/de/ishtar_common.po @@ -36,12 +36,12 @@ msgstr "" msgid "Export selected as CSV file" msgstr "" -#: admin.py:207 models.py:1686 templates/navbar.html:31 +#: admin.py:207 models.py:1703 templates/navbar.html:31 msgid "Profile" msgstr "" #: admin.py:208 forms_common.py:782 forms_common.py:801 forms_common.py:802 -#: models.py:3039 +#: models.py:3063 msgid "Profiles" msgstr "" @@ -63,7 +63,7 @@ msgstr "" msgid "These parents are missing: {}" msgstr "" -#: admin.py:386 admin.py:405 models.py:883 models.py:4141 +#: admin.py:386 admin.py:405 models.py:905 models.py:4214 msgid "Parent" msgstr "" @@ -71,11 +71,11 @@ msgstr "" msgid "Center" msgstr "" -#: admin.py:395 models.py:4003 +#: admin.py:395 models.py:4076 msgid "Limit" msgstr "" -#: admin.py:398 models.py:4013 +#: admin.py:398 models.py:4086 msgid "Town children" msgstr "" @@ -123,16 +123,16 @@ msgstr "" msgid "Hide selected" msgstr "" -#: admin.py:931 models.py:2080 +#: admin.py:931 models.py:2098 msgid "Form" msgstr "" -#: admin.py:933 models.py:2105 models_imports.py:127 +#: admin.py:933 models.py:2123 models_imports.py:127 #: templates/ishtar/dashboards/dashboard_main.html:39 msgid "Users" msgstr "" -#: admin.py:953 models.py:2180 +#: admin.py:953 models.py:2202 msgid "Field" msgstr "" @@ -226,7 +226,7 @@ msgstr "" msgid "Too many cols (%(user_col)d) when maximum is %(ref_col)d" msgstr "" -#: data_importer.py:730 views.py:1177 +#: data_importer.py:730 views.py:1200 msgid "No data provided" msgstr "" @@ -255,7 +255,7 @@ msgid "" "source file." msgstr "" -#: data_importer.py:1236 views.py:1255 views.py:1265 +#: data_importer.py:1236 views.py:1278 views.py:1288 msgid "Not imported" msgstr "" @@ -320,7 +320,7 @@ msgstr "" msgid "Enter a valid name consisting of letters, spaces and hyphens." msgstr "" -#: forms.py:96 forms_common.py:808 views.py:1968 +#: forms.py:96 forms_common.py:808 views.py:2017 msgid "Confirm" msgstr "" @@ -328,36 +328,44 @@ msgstr "" msgid "Are you sure you want to delete?" msgstr "" -#: forms.py:379 +#: forms.py:410 msgid "There are identical items." msgstr "" -#: forms.py:535 +#: forms.py:566 msgid "Last modified by" msgstr "" -#: forms.py:541 +#: forms.py:572 msgid "Modified since" msgstr "" -#: forms.py:565 forms.py:566 +#: forms.py:596 forms.py:597 msgid "Closing date" msgstr "" -#: forms.py:578 forms_common.py:1272 +#: forms.py:609 forms_common.py:1272 msgid "You should select an item." msgstr "" -#: forms.py:579 +#: forms.py:610 msgid "Add a new item" msgstr "" -#: forms.py:769 models.py:2434 +#: forms.py:757 +msgid " - append to existing" +msgstr "" + +#: forms.py:760 +msgid " - replace" +msgstr "" + +#: forms.py:803 models.py:2457 msgid "Template" msgstr "" #: forms_common.py:54 forms_common.py:72 forms_common.py:317 -#: forms_common.py:556 models.py:2568 models.py:4020 +#: forms_common.py:556 models.py:2591 models.py:4093 #: templates/blocks/JQueryAdvancedTown.html:19 msgid "Town" msgstr "" @@ -372,8 +380,8 @@ msgid "" "french town Saint-Denis in the Seine-Saint-Denis department.</p>" msgstr "" -#: forms_common.py:81 forms_common.py:1293 ishtar_menu.py:48 models.py:2952 -#: models.py:3204 models.py:3332 models.py:3495 +#: forms_common.py:81 forms_common.py:1293 ishtar_menu.py:48 models.py:2976 +#: models.py:3228 models.py:3357 models.py:3561 #: templates/ishtar/sheet_person.html:4 msgid "Person" msgstr "" @@ -425,17 +433,17 @@ msgid "all users" msgstr "" #: forms_common.py:305 forms_common.py:475 forms_common.py:609 -#: ishtar_menu.py:76 models.py:2773 models.py:2890 models.py:3292 +#: ishtar_menu.py:76 models.py:2796 models.py:2914 models.py:3317 #: templates/ishtar/sheet_organization.html:4 msgid "Organization" msgstr "" #: forms_common.py:308 forms_common.py:351 forms_common.py:470 #: forms_common.py:526 forms_common.py:604 forms_common.py:790 -#: forms_common.py:823 models.py:1056 models.py:1080 models.py:1879 -#: models.py:2079 models.py:2430 models.py:2765 models.py:2936 models.py:3192 -#: models.py:3999 models.py:4262 models_imports.py:98 models_imports.py:123 -#: models_imports.py:445 models_imports.py:537 models_imports.py:827 +#: forms_common.py:823 models.py:1078 models.py:1102 models.py:1897 +#: models.py:2097 models.py:2453 models.py:2788 models.py:2960 models.py:3216 +#: models.py:4072 models.py:4337 models_imports.py:98 models_imports.py:123 +#: models_imports.py:445 models_imports.py:537 models_imports.py:828 #: templates/ishtar/import_step_by_step.html:102 #: templates/ishtar/import_step_by_step.html:270 #: templates/ishtar/import_table.html:27 @@ -443,40 +451,40 @@ msgstr "" msgid "Name" msgstr "Name" -#: forms_common.py:309 models.py:2721 models_imports.py:630 +#: forms_common.py:309 models.py:2744 models_imports.py:630 #: models_imports.py:631 msgid "Organization type" msgstr "" -#: forms_common.py:311 forms_common.py:550 models.py:2563 +#: forms_common.py:311 forms_common.py:550 models.py:2586 #: templates/ishtar/blocks/sheet_address_section.html:4 msgid "Address" msgstr "" -#: forms_common.py:313 forms_common.py:553 models.py:2564 +#: forms_common.py:313 forms_common.py:553 models.py:2587 msgid "Address complement" msgstr "" -#: forms_common.py:315 forms_common.py:554 models.py:2566 +#: forms_common.py:315 forms_common.py:554 models.py:2589 msgid "Postal code" msgstr "Postleitzahl" -#: forms_common.py:318 forms_common.py:557 models.py:2569 +#: forms_common.py:318 forms_common.py:557 models.py:2592 msgid "Country" msgstr "" #: forms_common.py:320 forms_common.py:472 forms_common.py:530 -#: forms_common.py:606 forms_common.py:731 models.py:2596 +#: forms_common.py:606 forms_common.py:731 models.py:2619 msgid "Email" msgstr "E-Mail-Adresse" -#: forms_common.py:321 forms_common.py:533 models.py:2581 +#: forms_common.py:321 forms_common.py:533 models.py:2604 #: templates/ishtar/sheet_person.html:27 #: templates/ishtar/wizard/wizard_person.html:33 msgid "Phone" msgstr "" -#: forms_common.py:322 forms_common.py:542 models.py:2593 +#: forms_common.py:322 forms_common.py:542 models.py:2616 #: templates/ishtar/sheet_person.html:45 #: templates/ishtar/wizard/wizard_person.html:54 msgid "Mobile phone" @@ -488,8 +496,8 @@ msgid "Full text search" msgstr "" #: forms_common.py:352 forms_common.py:473 forms_common.py:607 -#: forms_common.py:788 models.py:1089 models.py:2767 models.py:3738 -#: models_imports.py:680 templates/ishtar/blocks/window_image_detail.html:24 +#: forms_common.py:788 models.py:1111 models.py:2790 models.py:3804 +#: models_imports.py:681 templates/ishtar/blocks/window_image_detail.html:24 #: templates/ishtar/blocks/window_tables/documents.html:8 #: templates/ishtar/import_table.html:28 #: templates/ishtar/sheet_organization.html:25 @@ -512,7 +520,7 @@ msgstr "" msgid "Organization to merge" msgstr "" -#: forms_common.py:471 forms_common.py:524 forms_common.py:605 models.py:2934 +#: forms_common.py:471 forms_common.py:524 forms_common.py:605 models.py:2958 #: templates/ishtar/sheet_organization.html:24 msgid "Surname" msgstr "" @@ -529,25 +537,25 @@ msgstr "" msgid "Identity" msgstr "" -#: forms_common.py:521 forms_common.py:1095 forms_common.py:1217 models.py:2928 -#: models.py:2930 models.py:3729 models_imports.py:632 +#: forms_common.py:521 forms_common.py:1095 forms_common.py:1217 models.py:2952 +#: models.py:2954 models.py:3795 models_imports.py:633 #: templates/ishtar/blocks/window_tables/documents.html:7 msgid "Title" msgstr "" -#: forms_common.py:522 models.py:2932 +#: forms_common.py:522 models.py:2956 msgid "Salutation" msgstr "" -#: forms_common.py:528 models.py:2938 +#: forms_common.py:528 models.py:2962 msgid "Raw name" msgstr "" -#: forms_common.py:531 models.py:2582 +#: forms_common.py:531 models.py:2605 msgid "Phone description" msgstr "" -#: forms_common.py:534 models.py:2584 models.py:2586 +#: forms_common.py:534 models.py:2607 models.py:2609 msgid "Phone description 2" msgstr "" @@ -555,11 +563,11 @@ msgstr "" msgid "Phone 2" msgstr "" -#: forms_common.py:538 models.py:2590 +#: forms_common.py:538 models.py:2613 msgid "Phone description 3" msgstr "" -#: forms_common.py:540 models.py:2588 +#: forms_common.py:540 models.py:2611 msgid "Phone 3" msgstr "" @@ -567,23 +575,23 @@ msgstr "" msgid "Current organization" msgstr "" -#: forms_common.py:559 models.py:2571 +#: forms_common.py:559 models.py:2594 msgid "Other address: address" msgstr "" -#: forms_common.py:562 models.py:2574 +#: forms_common.py:562 models.py:2597 msgid "Other address: address complement" msgstr "" -#: forms_common.py:564 models.py:2575 +#: forms_common.py:564 models.py:2598 msgid "Other address: postal code" msgstr "" -#: forms_common.py:566 models.py:2577 +#: forms_common.py:566 models.py:2600 msgid "Other address: town" msgstr "" -#: forms_common.py:568 models.py:2579 +#: forms_common.py:568 models.py:2602 msgid "Other address: country" msgstr "" @@ -591,7 +599,7 @@ msgstr "" msgid "Already has an account" msgstr "" -#: forms_common.py:603 models.py:3293 +#: forms_common.py:603 models.py:3318 msgid "Username" msgstr "Benutzername" @@ -599,7 +607,8 @@ msgstr "Benutzername" msgid "Account search" msgstr "" -#: forms_common.py:669 forms_common.py:709 forms_common.py:713 models.py:2829 +#: forms_common.py:669 forms_common.py:709 forms_common.py:713 models.py:2853 +#: models_imports.py:632 msgid "Person type" msgstr "" @@ -607,7 +616,7 @@ msgstr "" msgid "Account" msgstr "" -#: forms_common.py:734 wizards.py:1639 +#: forms_common.py:734 wizards.py:1651 msgid "New password" msgstr "" @@ -627,7 +636,7 @@ msgstr "" msgid "This username already exists." msgstr "" -#: forms_common.py:789 models.py:3195 models.py:4148 +#: forms_common.py:789 models.py:3219 models.py:4221 msgid "Areas" msgstr "" @@ -635,11 +644,11 @@ msgstr "" msgid "Send the new password by email?" msgstr "" -#: forms_common.py:821 models.py:3197 views.py:968 +#: forms_common.py:821 models.py:3221 views.py:991 msgid "Current profile" msgstr "" -#: forms_common.py:824 models.py:3175 models.py:3194 +#: forms_common.py:824 models.py:3199 models.py:3218 msgid "Profile type" msgstr "" @@ -667,8 +676,8 @@ msgstr "" msgid " (duplicate)" msgstr "" -#: forms_common.py:932 forms_common.py:946 forms_common.py:947 models.py:4021 -#: models.py:4136 +#: forms_common.py:932 forms_common.py:946 forms_common.py:947 models.py:4094 +#: models.py:4209 msgid "Towns" msgstr "" @@ -695,19 +704,19 @@ msgstr "" msgid "Document - General" msgstr "" -#: forms_common.py:1098 forms_common.py:1218 models.py:3543 -#: models_imports.py:633 +#: forms_common.py:1098 forms_common.py:1218 models.py:3609 +#: models_imports.py:634 msgid "Source type" msgstr "" #: forms_common.py:1101 forms_common.py:1152 forms_common.py:1333 -#: forms_common.py:1334 models.py:3504 models.py:3612 models.py:3748 +#: forms_common.py:1334 models.py:3570 models.py:3678 models.py:3814 #: templates/ishtar/blocks/window_image_detail.html:9 #: templates/ishtar/blocks/window_tables/documents.html:9 msgid "Authors" msgstr "" -#: forms_common.py:1105 models.py:3754 +#: forms_common.py:1105 models.py:3820 msgid "Numerical ressource (web address)" msgstr "" @@ -720,7 +729,7 @@ msgctxt "Not directory" msgid "File" msgstr "" -#: forms_common.py:1113 forms_common.py:1219 models.py:4138 +#: forms_common.py:1113 forms_common.py:1219 models.py:4211 msgid "Reference" msgstr "" @@ -728,38 +737,38 @@ msgstr "" msgid "Internal reference" msgstr "" -#: forms_common.py:1118 models.py:3756 +#: forms_common.py:1118 models.py:3822 #: templates/ishtar/blocks/window_image_detail.html:150 msgid "Receipt date" msgstr "" -#: forms_common.py:1120 models.py:3758 models_imports.py:859 +#: forms_common.py:1120 models.py:3824 models_imports.py:860 #: templates/ishtar/blocks/window_image_detail.html:54 msgid "Creation date" msgstr "Gründungsdatum" -#: forms_common.py:1123 models.py:3761 +#: forms_common.py:1123 models.py:3827 #: templates/ishtar/blocks/window_image_detail.html:160 msgid "Receipt date in documentation" msgstr "" -#: forms_common.py:1125 forms_common.py:1222 models.py:473 models.py:2942 -#: models.py:3421 models.py:3764 models_imports.py:483 +#: forms_common.py:1125 forms_common.py:1222 models.py:496 models.py:2966 +#: models.py:3446 models.py:3830 models_imports.py:483 #: templates/ishtar/blocks/window_image_detail.html:170 msgid "Comment" msgstr "" -#: forms_common.py:1127 forms_common.py:1221 models.py:1884 models.py:3763 +#: forms_common.py:1127 forms_common.py:1221 models.py:1902 models.py:3829 #: models_imports.py:125 models_imports.py:372 models_imports.py:446 msgid "Description" msgstr "Beschreibung" -#: forms_common.py:1130 models.py:3765 +#: forms_common.py:1130 models.py:3831 #: templates/ishtar/blocks/window_image_detail.html:182 msgid "Additional information" msgstr "" -#: forms_common.py:1132 forms_common.py:1225 models.py:3767 +#: forms_common.py:1132 forms_common.py:1225 models.py:3833 #: templates/ishtar/blocks/window_image_detail.html:108 msgid "Has a duplicate" msgstr "" @@ -790,11 +799,11 @@ msgid "You should at least fill one of this field: title, url, image or file." msgstr "" #: forms_common.py:1179 -msgid "A document have to attached at least to one item" +msgid "A document has to be attached at least to one item" msgstr "" #: forms_common.py:1214 forms_common.py:1286 forms_common.py:1321 -#: models.py:3503 templates/ishtar/wizard/wizard_person_deletion.html:139 +#: models.py:3569 templates/ishtar/wizard/wizard_person_deletion.html:139 msgid "Author" msgstr "" @@ -822,7 +831,7 @@ msgstr "" msgid "Would you like to delete this documentation?" msgstr "" -#: forms_common.py:1294 models.py:3468 models.py:3497 models_imports.py:634 +#: forms_common.py:1294 models.py:3534 models.py:3563 models_imports.py:635 msgid "Author type" msgstr "" @@ -834,11 +843,11 @@ msgstr "" msgid "There are identical authors." msgstr "" -#: forms_common.py:1339 models.py:1683 +#: forms_common.py:1339 models.py:1700 msgid "Query" msgstr "" -#: forms_common.py:1344 models.py:1687 +#: forms_common.py:1344 models.py:1704 msgid "Is an alert" msgstr "" @@ -878,7 +887,7 @@ msgstr "" msgid "Deletion" msgstr "" -#: ishtar_menu.py:40 models.py:2209 views.py:992 +#: ishtar_menu.py:40 models.py:2231 views.py:1015 msgid "Global variables" msgstr "" @@ -898,7 +907,7 @@ msgid "Creation" msgstr "Gründung" #: ishtar_menu.py:59 ishtar_menu.py:89 ishtar_menu.py:139 -#: templates/ishtar/forms/qa_base.html:29 +#: templates/ishtar/forms/qa_base.html:28 #: templates/ishtar/forms/qa_form.html:16 msgid "Modification" msgstr "" @@ -911,19 +920,19 @@ msgstr "" msgid "Manual merge" msgstr "" -#: ishtar_menu.py:110 models_imports.py:882 +#: ishtar_menu.py:110 models_imports.py:883 msgid "Imports" msgstr "" -#: ishtar_menu.py:113 views.py:1000 +#: ishtar_menu.py:113 views.py:1023 msgid "New import" msgstr "" -#: ishtar_menu.py:117 views.py:1019 +#: ishtar_menu.py:117 views.py:1042 msgid "Current imports" msgstr "" -#: ishtar_menu.py:121 views.py:1468 +#: ishtar_menu.py:121 views.py:1491 msgid "Old imports" msgstr "" @@ -935,35 +944,35 @@ msgstr "" msgid "Not a valid item." msgstr "" -#: models.py:211 +#: models.py:212 msgid "A selected item is not a valid item." msgstr "" -#: models.py:222 +#: models.py:224 msgid "This item already exists." msgstr "" -#: models.py:465 models.py:1682 models.py:2191 models.py:2528 models.py:2544 -#: models.py:3420 models_imports.py:368 +#: models.py:488 models.py:1699 models.py:2213 models.py:2551 models.py:2567 +#: models.py:3445 models_imports.py:368 msgid "Label" msgstr "" -#: models.py:467 +#: models.py:490 msgid "Textual ID" msgstr "" -#: models.py:470 +#: models.py:493 msgid "" "The slug is the standardized version of the name. It contains only lowercase " "letters, numbers and hyphens. Each slug must be unique." msgstr "" -#: models.py:474 models.py:2081 models.py:2437 models.py:3425 +#: models.py:497 models.py:2099 models.py:2460 models.py:3450 #: models_imports.py:139 models_imports.py:542 msgid "Available" msgstr "" -#: models.py:898 models.py:1083 models_imports.py:563 +#: models.py:920 models.py:1105 models_imports.py:563 #: templates/ishtar/formset_import_match.html:21 #: templates/ishtar/import_step_by_step.html:171 #: templates/ishtar/import_step_by_step.html:199 @@ -972,473 +981,473 @@ msgstr "" msgid "Key" msgstr "" -#: models.py:904 +#: models.py:926 msgid "Specific key to an import" msgstr "" -#: models.py:1043 +#: models.py:1065 msgid "Generated relation image (SVG)" msgstr "" -#: models.py:1057 models.py:1091 models.py:1604 models.py:2193 models.py:3465 -#: models.py:4165 models.py:4247 +#: models.py:1079 models.py:1113 models.py:1621 models.py:2215 models.py:3531 +#: models.py:4238 models.py:4320 msgid "Order" msgstr "" -#: models.py:1060 +#: models.py:1082 msgid "Json data - Menu" msgstr "" -#: models.py:1061 +#: models.py:1083 msgid "Json data - Menus" msgstr "" -#: models.py:1069 +#: models.py:1091 msgid "Text" msgstr "" -#: models.py:1070 +#: models.py:1092 msgid "Long text" msgstr "" -#: models.py:1071 models_imports.py:676 +#: models.py:1093 models_imports.py:677 msgid "Integer" msgstr "" -#: models.py:1072 +#: models.py:1094 msgid "Boolean" msgstr "" -#: models.py:1073 models_imports.py:677 +#: models.py:1095 models_imports.py:678 msgid "Float" msgstr "" -#: models.py:1074 models_imports.py:679 +#: models.py:1096 models_imports.py:680 msgid "Date" msgstr "" -#: models.py:1075 +#: models.py:1097 msgid "Choices" msgstr "" -#: models.py:1084 +#: models.py:1106 msgid "" "Value of the key in the JSON schema. For hierarchical key use \"__\" to " "explain it. For instance for the key 'my_subkey' with data such as {'my_key':" " {'my_subkey': 'value'}}, its value will be reached with my_key__my_subkey." msgstr "" -#: models.py:1088 +#: models.py:1110 msgid "Display" msgstr "" -#: models.py:1092 +#: models.py:1114 msgid "Use in search indexes" msgstr "" -#: models.py:1099 +#: models.py:1121 msgid "Json data - Field" msgstr "" -#: models.py:1100 +#: models.py:1122 msgid "Json data - Fields" msgstr "" -#: models.py:1111 +#: models.py:1133 msgid "Content types of the field and of the menu do not match" msgstr "" -#: models.py:1171 +#: models.py:1193 msgid "Search vector" msgstr "" -#: models.py:1172 +#: models.py:1194 msgid "Auto filled at save" msgstr "" -#: models.py:1392 +#: models.py:1409 msgid "Add document/image" msgstr "" -#: models.py:1394 +#: models.py:1411 msgid "doc./image" msgstr "" -#: models.py:1413 +#: models.py:1430 msgid "Last editor" msgstr "" -#: models.py:1416 +#: models.py:1433 msgid "Creator" msgstr "" -#: models.py:1597 +#: models.py:1614 msgid "Above" msgstr "" -#: models.py:1598 +#: models.py:1615 msgid "Bellow" msgstr "" -#: models.py:1599 +#: models.py:1616 msgid "Equal" msgstr "" -#: models.py:1605 +#: models.py:1622 msgid "Symmetrical" msgstr "" -#: models.py:1606 +#: models.py:1623 msgid "Tiny label" msgstr "" -#: models.py:1609 +#: models.py:1626 msgid "Inverse relation" msgstr "" -#: models.py:1612 +#: models.py:1629 msgid "Logical relation" msgstr "" -#: models.py:1622 +#: models.py:1639 msgid "Cannot have symmetrical and an inverse_relation" msgstr "" -#: models.py:1685 +#: models.py:1702 msgid "Content type" msgstr "" -#: models.py:1690 +#: models.py:1707 msgid "Search query" msgstr "" -#: models.py:1691 +#: models.py:1708 msgid "Search queries" msgstr "" -#: models.py:1855 +#: models.py:1873 msgid "Euro" msgstr "" -#: models.py:1856 +#: models.py:1874 msgid "US dollar" msgstr "" -#: models.py:1857 views.py:742 views.py:803 +#: models.py:1875 views.py:765 views.py:826 msgid "Operations" msgstr "" -#: models.py:1858 views.py:744 views.py:807 +#: models.py:1876 views.py:767 views.py:830 msgid "Context records" msgstr "" -#: models.py:1859 +#: models.py:1877 msgid "Site" msgstr "" -#: models.py:1859 +#: models.py:1877 msgid "Archaeological entity" msgstr "" -#: models.py:1863 +#: models.py:1881 msgid "Site search" msgstr "" -#: models.py:1864 +#: models.py:1882 msgid "New site" msgstr "" -#: models.py:1865 +#: models.py:1883 msgid "Site modification" msgstr "" -#: models.py:1866 +#: models.py:1884 msgid "Site deletion" msgstr "" -#: models.py:1869 +#: models.py:1887 msgid "Archaeological entity search" msgstr "" -#: models.py:1870 +#: models.py:1888 msgid "New archaeological entity" msgstr "" -#: models.py:1871 +#: models.py:1889 msgid "Archaeological entity modification" msgstr "" -#: models.py:1872 +#: models.py:1890 msgid "Archaeological entity deletion" msgstr "" -#: models.py:1880 models.py:2431 models_imports.py:124 +#: models.py:1898 models.py:2454 models_imports.py:124 msgid "Slug" msgstr "" -#: models.py:1881 +#: models.py:1899 msgid "Current active" msgstr "" -#: models.py:1883 +#: models.py:1901 msgid "Activate experimental feature" msgstr "" -#: models.py:1886 +#: models.py:1904 msgid "Alternate configuration" msgstr "" -#: models.py:1888 +#: models.py:1906 msgid "Choose an alternate configuration for label, index management" msgstr "" -#: models.py:1892 +#: models.py:1910 msgid "Files module" msgstr "" -#: models.py:1894 +#: models.py:1912 msgid "Archaeological site module" msgstr "" -#: models.py:1896 +#: models.py:1914 msgid "Archaeological site type" msgstr "" -#: models.py:1900 +#: models.py:1918 msgid "Context records module" msgstr "" -#: models.py:1902 +#: models.py:1920 msgid "Finds module" msgstr "" -#: models.py:1903 +#: models.py:1921 msgid "Need context records module" msgstr "" -#: models.py:1905 +#: models.py:1923 msgid "Find index is based on" msgstr "" -#: models.py:1907 +#: models.py:1925 msgid "" "To prevent irrelevant indexes, change this parameter only if there is no " "find in the database" msgstr "" -#: models.py:1910 +#: models.py:1928 msgid "Warehouses module" msgstr "" -#: models.py:1911 +#: models.py:1929 msgid "Need finds module" msgstr "" -#: models.py:1912 +#: models.py:1930 msgid "Preservation module" msgstr "" -#: models.py:1914 +#: models.py:1932 msgid "Mapping module" msgstr "" -#: models.py:1915 +#: models.py:1933 msgid "Underwater module" msgstr "" -#: models.py:1917 +#: models.py:1935 msgid "Parcel are mandatory for context records" msgstr "" -#: models.py:1919 +#: models.py:1937 msgid "Home page" msgstr "" -#: models.py:1920 +#: models.py:1938 #, python-brace-format msgid "" "Homepage of Ishtar - if not defined a default homepage will appear. Use the " "markdown syntax. {random_image} can be used to display a random image." msgstr "" -#: models.py:1924 +#: models.py:1942 msgid "Main operation code prefix" msgstr "" -#: models.py:1928 +#: models.py:1946 msgid "Default operation code prefix" msgstr "" -#: models.py:1932 +#: models.py:1950 msgid "Operation region code" msgstr "" -#: models.py:1936 +#: models.py:1954 msgid "File external id" msgstr "" -#: models.py:1938 +#: models.py:1956 msgid "" "Formula to manage file external ID. Change this with care. With incorrect " "formula, the application might be unusable and import of external data can " "be destructive." msgstr "" -#: models.py:1943 +#: models.py:1961 msgid "Parcel external id" msgstr "" -#: models.py:1946 +#: models.py:1964 msgid "" "Formula to manage parcel external ID. Change this with care. With incorrect " "formula, the application might be unusable and import of external data can " "be destructive." msgstr "" -#: models.py:1951 +#: models.py:1969 msgid "Context record external id" msgstr "" -#: models.py:1953 +#: models.py:1971 msgid "" "Formula to manage context record external ID. Change this with care. With " "incorrect formula, the application might be unusable and import of external " "data can be destructive." msgstr "" -#: models.py:1958 +#: models.py:1976 msgid "Base find external id" msgstr "" -#: models.py:1960 +#: models.py:1978 msgid "" "Formula to manage base find external ID. Change this with care. With " "incorrect formula, the application might be unusable and import of external " "data can be destructive." msgstr "" -#: models.py:1965 +#: models.py:1983 msgid "Find external id" msgstr "" -#: models.py:1967 +#: models.py:1985 msgid "" "Formula to manage find external ID. Change this with care. With incorrect " "formula, the application might be unusable and import of external data can " "be destructive." msgstr "" -#: models.py:1972 +#: models.py:1990 msgid "Container external id" msgstr "" -#: models.py:1974 +#: models.py:1992 msgid "" "Formula to manage container external ID. Change this with care. With " "incorrect formula, the application might be unusable and import of external " "data can be destructive." msgstr "" -#: models.py:1979 +#: models.py:1997 msgid "Warehouse external id" msgstr "" -#: models.py:1981 +#: models.py:1999 msgid "" "Formula to manage warehouse external ID. Change this with care. With " "incorrect formula, the application might be unusable and import of external " "data can be destructive." msgstr "" -#: models.py:1986 +#: models.py:2004 msgid "Raw name for person" msgstr "" -#: models.py:1988 +#: models.py:2006 msgid "" "Formula to manage person raw_name. Change this with care. With incorrect " "formula, the application might be unusable and import of external data can " "be destructive." msgstr "" -#: models.py:1992 +#: models.py:2010 msgid "Use auto index for finds" msgstr "" -#: models.py:1994 +#: models.py:2012 msgid "Currency" msgstr "" -#: models.py:1998 +#: models.py:2016 msgid "Ishtar site profile" msgstr "" -#: models.py:1999 +#: models.py:2017 msgid "Ishtar site profiles" msgstr "" -#: models.py:2083 +#: models.py:2101 msgid "Enable this form" msgstr "" -#: models.py:2084 +#: models.py:2102 msgid "" "Disable with caution: disabling a form with mandatory fields may lead to " "database errors." msgstr "" -#: models.py:2087 +#: models.py:2105 msgid "Apply to all" msgstr "" -#: models.py:2088 +#: models.py:2106 msgid "" "Apply this form to all users. If set to True, selecting user and user type " "is useless." msgstr "" -#: models.py:2094 +#: models.py:2112 msgid "Custom form" msgstr "" -#: models.py:2095 +#: models.py:2113 msgid "Custom forms" msgstr "" -#: models.py:2111 +#: models.py:2129 msgid "User types" msgstr "" -#: models.py:2183 +#: models.py:2205 msgid "Excluded field" msgstr "" -#: models.py:2184 +#: models.py:2206 msgid "Excluded fields" msgstr "" -#: models.py:2194 templates/blocks/form_flex_snippet.html:18 +#: models.py:2216 templates/blocks/form_flex_snippet.html:18 #: templates/blocks/table_form_snippet.html:9 msgid "Help" msgstr "" -#: models.py:2197 +#: models.py:2219 msgid "Custom form - Json data field" msgstr "" -#: models.py:2198 +#: models.py:2220 msgid "Custom form - Json data fields" msgstr "" -#: models.py:2202 +#: models.py:2224 msgid "Variable name" msgstr "" -#: models.py:2203 +#: models.py:2225 msgid "Description of the variable" msgstr "" -#: models.py:2205 models_imports.py:564 +#: models.py:2227 models_imports.py:564 #: templates/ishtar/formset_import_match.html:22 #: templates/ishtar/import_step_by_step.html:172 #: templates/ishtar/import_step_by_step.html:200 @@ -1446,560 +1455,564 @@ msgstr "" msgid "Value" msgstr "" -#: models.py:2208 +#: models.py:2230 msgid "Global variable" msgstr "" -#: models.py:2335 models.py:2365 +#: models.py:2358 models.py:2388 msgid "Total" msgstr "" -#: models.py:2342 models.py:2529 models.py:2545 +#: models.py:2365 models.py:2552 models.py:2568 #: templates/ishtar/dashboards/dashboard_main_detail.html:211 #: templates/ishtar/dashboards/dashboard_main_detail_users.html:5 #: templates/ishtar/sheet_person.html:30 msgid "Number" msgstr "" -#: models.py:2429 +#: models.py:2452 msgid "Administrative Act" msgstr "" -#: models.py:2436 +#: models.py:2459 msgid "Associated object" msgstr "" -#: models.py:2441 +#: models.py:2464 msgid "Document template" msgstr "" -#: models.py:2442 +#: models.py:2465 msgid "Document templates" msgstr "" -#: models.py:2533 models.py:2546 models.py:4285 models_imports.py:853 +#: models.py:2556 models.py:2569 models.py:4360 models_imports.py:854 msgid "State" msgstr "" -#: models.py:2551 models.py:4007 templates/blocks/JQueryAdvancedTown.html:12 +#: models.py:2574 models.py:4080 templates/blocks/JQueryAdvancedTown.html:12 msgid "Department" msgstr "" -#: models.py:2552 +#: models.py:2575 msgid "Departments" msgstr "" -#: models.py:2592 +#: models.py:2615 msgid "Raw phone" msgstr "" -#: models.py:2598 +#: models.py:2621 msgid "Alternative address is prefered" msgstr "" -#: models.py:2637 +#: models.py:2660 msgid "Tel: " msgstr "" -#: models.py:2641 +#: models.py:2664 msgid "Mobile: " msgstr "" -#: models.py:2645 +#: models.py:2668 msgid "Email: " msgstr "E-Mail-Adresse:" -#: models.py:2650 +#: models.py:2673 msgid "Merge key" msgstr "" -#: models.py:2722 +#: models.py:2745 msgid "Organization types" msgstr "" -#: models.py:2749 models.py:2896 models.py:3303 +#: models.py:2772 models.py:2920 models.py:3328 msgctxt "key for text search" msgid "name" msgstr "" -#: models.py:2753 models.py:2908 models.py:3315 models.py:3639 +#: models.py:2776 models.py:2932 models.py:3340 models.py:3705 msgctxt "key for text search" msgid "type" msgstr "" -#: models.py:2768 models.py:2947 models.py:3498 models.py:4015 +#: models.py:2791 models.py:2971 models.py:3564 models.py:4088 msgid "Cached name" msgstr "" -#: models.py:2774 +#: models.py:2797 msgid "Organizations" msgstr "" -#: models.py:2804 +#: models.py:2828 msgid "unknown organization" msgstr "" -#: models.py:2830 +#: models.py:2854 msgid "Person types" msgstr "" -#: models.py:2843 models_imports.py:670 +#: models.py:2867 models_imports.py:671 msgid "Title type" msgstr "" -#: models.py:2844 +#: models.py:2868 msgid "Title types" msgstr "" -#: models.py:2868 +#: models.py:2892 msgid "Mr" msgstr "" -#: models.py:2869 +#: models.py:2893 msgid "Miss" msgstr "" -#: models.py:2870 +#: models.py:2894 msgid "Mr and Mrs" msgstr "" -#: models.py:2871 +#: models.py:2895 msgid "Mrs" msgstr "" -#: models.py:2872 +#: models.py:2896 msgid "Doctor" msgstr "" -#: models.py:2900 models.py:3307 +#: models.py:2924 models.py:3332 msgctxt "key for text search" msgid "surname" msgstr "" -#: models.py:2904 models.py:3311 +#: models.py:2928 models.py:3336 msgctxt "key for text search" msgid "email" msgstr "" -#: models.py:2912 models.py:3319 +#: models.py:2936 models.py:3344 msgctxt "key for text search" msgid "organization" msgstr "" -#: models.py:2916 +#: models.py:2940 msgctxt "key for text search" msgid "has-account" msgstr "" -#: models.py:2940 +#: models.py:2964 msgid "Contact type" msgstr "" -#: models.py:2943 models.py:3033 +#: models.py:2967 models.py:3057 msgid "Types" msgstr "" -#: models.py:2946 +#: models.py:2970 msgid "Is attached to" msgstr "" -#: models.py:2953 +#: models.py:2977 msgid "Persons" msgstr "" -#: models.py:3171 +#: models.py:3195 msgid "Groups" msgstr "" -#: models.py:3176 +#: models.py:3200 msgid "Profile types" msgstr "" -#: models.py:3187 +#: models.py:3211 msgid "Profile type summary" msgstr "" -#: models.py:3188 +#: models.py:3212 msgid "Profile types summary" msgstr "" -#: models.py:3199 +#: models.py:3223 msgid "Show field number" msgstr "" -#: models.py:3200 +#: models.py:3224 msgid "Automatically pin" msgstr "" -#: models.py:3201 +#: models.py:3225 msgid "Display pin menu" msgstr "" -#: models.py:3207 +#: models.py:3231 msgid "User profile" msgstr "" -#: models.py:3208 +#: models.py:3232 msgid "User profiles" msgstr "" -#: models.py:3243 +#: models.py:3267 models.py:3522 msgid " - duplicate" msgstr "" -#: models.py:3299 +#: models.py:3324 msgctxt "key for text search" msgid "username" msgstr "" -#: models.py:3335 +#: models.py:3360 msgid "Advanced shortcut menu" msgstr "" -#: models.py:3338 +#: models.py:3363 msgid "Ishtar user" msgstr "" -#: models.py:3339 +#: models.py:3364 msgid "Ishtar users" msgstr "" -#: models.py:3424 +#: models.py:3449 msgid "Owner" msgstr "" -#: models.py:3427 -msgid "Shared with" +#: models.py:3452 +msgid "Shared (read) with" +msgstr "" + +#: models.py:3456 +msgid "Shared (read/edit) with" msgstr "" -#: models.py:3469 +#: models.py:3535 msgid "Author types" msgstr "" -#: models.py:3544 +#: models.py:3610 msgid "Source types" msgstr "" -#: models.py:3554 models_imports.py:669 +#: models.py:3620 models_imports.py:670 msgid "Support type" msgstr "" -#: models.py:3555 +#: models.py:3621 msgid "Support types" msgstr "" -#: models.py:3564 +#: models.py:3630 msgid "Format type" msgstr "" -#: models.py:3565 +#: models.py:3631 msgid "Format types" msgstr "" -#: models.py:3574 +#: models.py:3640 msgid "URL" msgstr "" -#: models.py:3577 +#: models.py:3643 msgid "License type" msgstr "" -#: models.py:3578 +#: models.py:3644 msgid "License types" msgstr "" -#: models.py:3631 +#: models.py:3697 msgctxt "key for text search" msgid "author" msgstr "" -#: models.py:3635 +#: models.py:3701 msgctxt "key for text search" msgid "title" msgstr "" -#: models.py:3643 +#: models.py:3709 msgctxt "key for text search" msgid "reference" msgstr "" -#: models.py:3647 +#: models.py:3713 msgctxt "key for text search" msgid "internal-reference" msgstr "" -#: models.py:3651 +#: models.py:3717 msgctxt "key for text search" msgid "description" msgstr "" -#: models.py:3655 +#: models.py:3721 msgctxt "key for text search" msgid "comment" msgstr "" -#: models.py:3659 +#: models.py:3725 msgctxt "key for text search" msgid "additional-information" msgstr "" -#: models.py:3663 +#: models.py:3729 msgctxt "key for text search" msgid "has-duplicate" msgstr "" -#: models.py:3667 models.py:3714 +#: models.py:3733 models.py:3780 msgctxt "key for text search" msgid "operation" msgstr "" -#: models.py:3671 models.py:3717 +#: models.py:3737 models.py:3783 msgctxt "key for text search" msgid "context-record" msgstr "" -#: models.py:3675 models.py:3719 +#: models.py:3741 models.py:3785 msgctxt "key for text search" msgid "find" msgstr "" -#: models.py:3679 models.py:3718 +#: models.py:3745 models.py:3784 msgctxt "key for text search" msgid "file" msgstr "" -#: models.py:3683 models.py:3720 +#: models.py:3749 models.py:3786 msgctxt "key for text search" msgid "site" msgstr "" -#: models.py:3687 models.py:3721 +#: models.py:3753 models.py:3787 msgctxt "key for text search" msgid "warehouse" msgstr "" -#: models.py:3723 +#: models.py:3789 msgctxt "key for text search" msgid "treatment" msgstr "" -#: models.py:3726 +#: models.py:3792 msgctxt "key for text search" msgid "treatment-file" msgstr "" -#: models.py:3732 +#: models.py:3798 msgid "Index" msgstr "" -#: models.py:3734 +#: models.py:3800 msgid "External ID" msgstr "" -#: models.py:3735 templates/ishtar/blocks/window_image_detail.html:34 +#: models.py:3801 templates/ishtar/blocks/window_image_detail.html:34 msgid "Ref." msgstr "" -#: models.py:3736 templates/ishtar/blocks/window_image_detail.html:44 +#: models.py:3802 templates/ishtar/blocks/window_image_detail.html:44 msgid "Internal ref." msgstr "" -#: models.py:3740 +#: models.py:3806 msgid "License" msgstr "" -#: models.py:3742 templates/ishtar/blocks/window_image_detail.html:78 +#: models.py:3808 templates/ishtar/blocks/window_image_detail.html:78 msgid "Support" msgstr "" -#: models.py:3744 models_imports.py:635 +#: models.py:3810 models_imports.py:636 #: templates/ishtar/blocks/window_image_detail.html:88 msgid "Format" msgstr "" -#: models.py:3746 templates/ishtar/blocks/window_image_detail.html:98 +#: models.py:3812 templates/ishtar/blocks/window_image_detail.html:98 msgid "Scale" msgstr "" -#: models.py:3750 +#: models.py:3816 msgid "Authors (raw)" msgstr "" -#: models.py:3762 templates/ishtar/blocks/window_image_detail.html:118 +#: models.py:3828 templates/ishtar/blocks/window_image_detail.html:118 msgid "Number of items" msgstr "" -#: models.py:3769 +#: models.py:3835 msgid "Symbolic links" msgstr "" -#: models.py:3772 +#: models.py:3838 msgid "Related" msgstr "" -#: models.py:3773 +#: models.py:3839 msgid "Cached value - do not edit" msgstr "" -#: models.py:3776 templates/ishtar/sheet_document.html:4 +#: models.py:3842 templates/ishtar/sheet_document.html:4 msgid "Document" msgstr "" -#: models.py:3777 templates/ishtar/sheet_person.html:113 +#: models.py:3843 templates/ishtar/sheet_person.html:113 msgid "Documents" msgstr "" -#: models.py:3781 +#: models.py:3847 msgid "Can view all Documents" msgstr "" -#: models.py:3783 +#: models.py:3849 msgid "Can view own Document" msgstr "" -#: models.py:3785 +#: models.py:3851 msgid "Can add own Document" msgstr "" -#: models.py:3787 +#: models.py:3853 msgid "Can change own Document" msgstr "" -#: models.py:3789 +#: models.py:3855 msgid "Can delete own Document" msgstr "" -#: models.py:4000 +#: models.py:4073 msgid "Surface (m2)" msgstr "" -#: models.py:4001 +#: models.py:4074 msgid "Localisation" msgstr "Lokalisierung" -#: models.py:4009 +#: models.py:4082 msgid "Year of creation" msgstr "" -#: models.py:4010 +#: models.py:4083 msgid "" "Filling this field is relevant to distinguish old towns from new towns." msgstr "" -#: models.py:4142 +#: models.py:4215 msgid "Only four level of parent are managed." msgstr "" -#: models.py:4147 +#: models.py:4220 msgid "Area" msgstr "" -#: models.py:4166 +#: models.py:4239 msgid "Is preventive" msgstr "" -#: models.py:4167 +#: models.py:4240 msgid "Is judiciary" msgstr "" -#: models.py:4170 models_imports.py:636 +#: models.py:4243 models_imports.py:637 msgid "Operation type" msgstr "" -#: models.py:4171 +#: models.py:4244 msgid "Operation types" msgstr "" -#: models.py:4210 +#: models.py:4283 msgid "Judiciary" msgstr "" -#: models.py:4212 +#: models.py:4285 msgid "Preventive" msgstr "" -#: models.py:4214 +#: models.py:4287 msgid "Research" msgstr "" -#: models.py:4249 +#: models.py:4322 msgid "Authority name" msgstr "" -#: models.py:4250 +#: models.py:4323 msgid "Authority SRID" msgstr "" -#: models.py:4253 models_imports.py:668 +#: models.py:4326 models_imports.py:669 msgid "Spatial reference system" msgstr "" -#: models.py:4254 +#: models.py:4327 msgid "Spatial reference systems" msgstr "" -#: models.py:4261 +#: models.py:4336 msgid "Filename" msgstr "" -#: models.py:4266 +#: models.py:4341 msgid "Administration script" msgstr "" -#: models.py:4267 +#: models.py:4342 msgid "Administration scripts" msgstr "" -#: models.py:4274 +#: models.py:4349 msgid "Scheduled" msgstr "" -#: models.py:4275 +#: models.py:4350 msgid "In progress" msgstr "" -#: models.py:4276 models_imports.py:792 +#: models.py:4351 models_imports.py:793 msgid "Finished with errors" msgstr "" -#: models.py:4277 models_imports.py:793 +#: models.py:4352 models_imports.py:794 msgid "Finished" msgstr "" -#: models.py:4290 +#: models.py:4365 msgid "Result" msgstr "" -#: models.py:4293 +#: models.py:4368 msgid "Administration task" msgstr "" -#: models.py:4294 +#: models.py:4369 msgid "Administration tasks" msgstr "" -#: models.py:4298 +#: models.py:4373 msgid "Unknown" msgstr "" -#: models.py:4313 +#: models.py:4388 msgid "" "ISHTAR_SCRIPT_DIR is not set in your local_settings. Contact your " "administrator." msgstr "" -#: models.py:4322 +#: models.py:4397 msgid "" "Your ISHTAR_SCRIPT_DIR is containing dots \"..\". As it can refer to " "relative paths, it can be a security issue and this is not allowed. Only put " "a full path." msgstr "" -#: models.py:4333 +#: models.py:4408 msgid "Your ISHTAR_SCRIPT_DIR: \"{}\" is not a valid directory." msgstr "" -#: models.py:4349 +#: models.py:4424 msgid "" "Script \"{}\" is not available in your script directory. Check your " "configuration." @@ -2030,7 +2043,7 @@ msgid "Leave blank for no restrictions" msgstr "" #: models_imports.py:136 -msgid "Is template" +msgid "Can be exported" msgstr "" #: models_imports.py:137 @@ -2138,11 +2151,11 @@ msgstr "" msgid "Importer - Targets" msgstr "" -#: models_imports.py:525 views_item.py:847 +#: models_imports.py:525 views_item.py:346 views_item.py:950 msgid "True" msgstr "" -#: models_imports.py:526 views_item.py:849 +#: models_imports.py:526 views_item.py:952 msgid "False" msgstr "" @@ -2174,327 +2187,327 @@ msgstr "" msgid "Importer - Targets keys" msgstr "" -#: models_imports.py:637 +#: models_imports.py:638 msgid "Period" msgstr "" -#: models_imports.py:638 +#: models_imports.py:639 msgid "Report state" msgstr "" -#: models_imports.py:639 +#: models_imports.py:640 msgid "Remain type" msgstr "" -#: models_imports.py:640 +#: models_imports.py:641 msgid "Unit" msgstr "" -#: models_imports.py:642 +#: models_imports.py:643 msgid "Activity type" msgstr "" -#: models_imports.py:644 +#: models_imports.py:645 msgid "Documentation type" msgstr "" -#: models_imports.py:645 +#: models_imports.py:646 msgid "Material" msgstr "" -#: models_imports.py:647 +#: models_imports.py:648 msgid "Conservatory state" msgstr "" -#: models_imports.py:648 +#: models_imports.py:649 msgid "Container type" msgstr "" -#: models_imports.py:650 +#: models_imports.py:651 msgid "Warehouse division" msgstr "" -#: models_imports.py:651 +#: models_imports.py:652 msgid "Warehouse type" msgstr "" -#: models_imports.py:652 +#: models_imports.py:653 msgid "Treatment type" msgstr "" -#: models_imports.py:654 +#: models_imports.py:655 msgid "Treatment emergency type" msgstr "" -#: models_imports.py:655 +#: models_imports.py:656 msgid "Object type" msgstr "" -#: models_imports.py:656 +#: models_imports.py:657 msgid "Integrity type" msgstr "" -#: models_imports.py:658 +#: models_imports.py:659 msgid "Remarkability type" msgstr "" -#: models_imports.py:659 +#: models_imports.py:660 msgid "Alteration type" msgstr "" -#: models_imports.py:661 +#: models_imports.py:662 msgid "Alteration cause type" msgstr "" -#: models_imports.py:662 +#: models_imports.py:663 msgid "Batch type" msgstr "" -#: models_imports.py:663 +#: models_imports.py:664 msgid "Checked type" msgstr "" -#: models_imports.py:665 +#: models_imports.py:666 msgid "Identification type" msgstr "" -#: models_imports.py:667 +#: models_imports.py:668 msgid "Context record relation type" msgstr "" -#: models_imports.py:678 +#: models_imports.py:679 msgid "String" msgstr "" -#: models_imports.py:681 +#: models_imports.py:682 #: templates/ishtar/dashboards/dashboard_main_detail.html:196 msgid "Year" msgstr "" -#: models_imports.py:682 +#: models_imports.py:683 msgid "INSEE code" msgstr "" -#: models_imports.py:683 +#: models_imports.py:684 msgid "String to boolean" msgstr "" -#: models_imports.py:684 +#: models_imports.py:685 msgctxt "filesystem" msgid "File" msgstr "" -#: models_imports.py:685 +#: models_imports.py:686 msgid "Unknow type" msgstr "" -#: models_imports.py:702 +#: models_imports.py:703 msgid "4 digit year. e.g.: \"2015\"" msgstr "" -#: models_imports.py:703 +#: models_imports.py:704 msgid "4 digit year/month/day. e.g.: \"2015/02/04\"" msgstr "" -#: models_imports.py:704 +#: models_imports.py:705 msgid "Day/month/4 digit year. e.g.: \"04/02/2015\"" msgstr "" -#: models_imports.py:720 +#: models_imports.py:721 msgid "Options" msgstr "" -#: models_imports.py:722 +#: models_imports.py:723 msgid "Split character(s)" msgstr "" -#: models_imports.py:727 +#: models_imports.py:728 msgid "Importer - Formater type" msgstr "" -#: models_imports.py:728 +#: models_imports.py:729 msgid "Importer - Formater types" msgstr "" -#: models_imports.py:784 +#: models_imports.py:785 #: templates/ishtar/dashboards/dashboard_main_detail.html:132 msgid "Created" msgstr "" -#: models_imports.py:785 +#: models_imports.py:786 msgid "Analyse in progress" msgstr "" -#: models_imports.py:786 +#: models_imports.py:787 msgid "Analysed" msgstr "" -#: models_imports.py:787 +#: models_imports.py:788 msgid "Check modified in queue" msgstr "" -#: models_imports.py:788 +#: models_imports.py:789 msgid "Import in queue" msgstr "" -#: models_imports.py:789 +#: models_imports.py:790 msgid "Check modified in progress" msgstr "" -#: models_imports.py:790 +#: models_imports.py:791 msgid "Import in progress" msgstr "" -#: models_imports.py:791 +#: models_imports.py:792 msgid "Partially imported" msgstr "" -#: models_imports.py:794 +#: models_imports.py:795 msgid "Archived" msgstr "" -#: models_imports.py:830 +#: models_imports.py:831 msgid "Imported file" msgstr "" -#: models_imports.py:832 +#: models_imports.py:833 msgid "Associated images (zip file)" msgstr "" -#: models_imports.py:836 +#: models_imports.py:837 msgid "If a group is selected, target key saved in this group will be used." msgstr "" -#: models_imports.py:839 +#: models_imports.py:840 msgid "Encoding" msgstr "" -#: models_imports.py:842 +#: models_imports.py:843 msgid "Skip lines" msgstr "" -#: models_imports.py:843 +#: models_imports.py:844 msgid "Number of header lines in your file (can be 0)." msgstr "" -#: models_imports.py:844 +#: models_imports.py:845 msgid "Error file" msgstr "" -#: models_imports.py:847 +#: models_imports.py:848 msgid "Result file" msgstr "" -#: models_imports.py:850 +#: models_imports.py:851 msgid "Match file" msgstr "" -#: models_imports.py:856 +#: models_imports.py:857 msgid "Conservative import" msgstr "" -#: models_imports.py:857 +#: models_imports.py:858 msgid "If set to true, do not overload existing values." msgstr "" -#: models_imports.py:860 +#: models_imports.py:861 msgid "End date" msgstr "" -#: models_imports.py:863 +#: models_imports.py:864 msgid "Remaining seconds" msgstr "" -#: models_imports.py:865 +#: models_imports.py:866 msgid "Current line" msgstr "" -#: models_imports.py:867 +#: models_imports.py:868 msgid "Number of line" msgstr "" -#: models_imports.py:870 +#: models_imports.py:871 msgid "Imported line numbers" msgstr "" -#: models_imports.py:873 +#: models_imports.py:874 msgid "Changed have been checked" msgstr "" -#: models_imports.py:876 +#: models_imports.py:877 msgid "Changed line numbers" msgstr "" -#: models_imports.py:881 +#: models_imports.py:882 msgid "Import" msgstr "" -#: models_imports.py:970 +#: models_imports.py:971 msgid "Analyse" msgstr "" -#: models_imports.py:972 models_imports.py:981 +#: models_imports.py:973 models_imports.py:982 msgid "Re-analyse" msgstr "" -#: models_imports.py:973 +#: models_imports.py:974 msgid "Launch import" msgstr "" -#: models_imports.py:976 +#: models_imports.py:977 msgid "Step by step import" msgstr "" -#: models_imports.py:977 models_imports.py:986 +#: models_imports.py:978 models_imports.py:987 msgid "Re-check for changes" msgstr "" -#: models_imports.py:979 models_imports.py:988 +#: models_imports.py:980 models_imports.py:989 msgid "Check for changes" msgstr "" -#: models_imports.py:982 +#: models_imports.py:983 msgid "Re-import" msgstr "" -#: models_imports.py:985 +#: models_imports.py:986 msgid "Step by step re-import" msgstr "" -#: models_imports.py:989 +#: models_imports.py:990 msgid "Archive" msgstr "" -#: models_imports.py:991 +#: models_imports.py:992 msgid "Unarchive" msgstr "" -#: models_imports.py:992 templates/ishtar/form_delete.html:11 views.py:1847 -#: widgets.py:371 widgets.py:403 +#: models_imports.py:993 templates/ishtar/form_delete.html:11 views.py:1896 +#: widgets.py:379 widgets.py:411 msgid "Delete" msgstr "" -#: models_imports.py:1042 +#: models_imports.py:1043 msgid "Error in the CSV file." msgstr "" -#: models_imports.py:1070 +#: models_imports.py:1071 msgid "Modification check {} added to the queue" msgstr "" -#: models_imports.py:1140 +#: models_imports.py:1141 msgid "Import {} added to the queue" msgstr "" -#: models_imports.py:1158 +#: models_imports.py:1159 msgid "Error on imported file: {}" msgstr "" -#: models_imports.py:1193 +#: models_imports.py:1194 msgid "Import {} finished with errors" msgstr "" -#: models_imports.py:1202 +#: models_imports.py:1203 msgid "Import {} finished with no errors" msgstr "" @@ -2546,12 +2559,12 @@ msgid "View on site" msgstr "" #: templates/admin/change_form.html:24 templates/admin/change_form.html:27 -#: views.py:1231 views.py:1236 +#: views.py:1254 views.py:1259 msgid "Previous" msgstr "" #: templates/admin/change_form.html:32 templates/admin/change_form.html:35 -#: views.py:1239 views.py:1242 +#: views.py:1262 views.py:1265 msgid "Next" msgstr "" @@ -2585,49 +2598,53 @@ msgid " items added." msgstr "" #: templates/base.html:47 -msgid "yes" +msgid "Select only one item." msgstr "" #: templates/base.html:48 -msgid "no" +msgid "yes" msgstr "" #: templates/base.html:49 -msgid "Autorefresh start. The form is disabled." +msgid "no" msgstr "" #: templates/base.html:50 +msgid "Autorefresh start. The form is disabled." +msgstr "" + +#: templates/base.html:51 msgid "Autorefresh end. The form is re-enabled." msgstr "" -#: templates/base.html:81 +#: templates/base.html:82 msgid "Current items" msgstr "" -#: templates/base.html:83 templates/ishtar/forms/qa_base.html:34 +#: templates/base.html:84 templates/ishtar/forms/qa_base.html:33 #: templates/ishtar/forms/qa_form.html:21 templates/ishtar/manage_basket.html:4 #: templates/welcome.html:11 templates/welcome.html:12 -#: templates/welcome.html:13 templates/welcome.html:14 wizards.py:423 +#: templates/welcome.html:13 templates/welcome.html:14 wizards.py:435 msgid ":" msgstr "" -#: templates/base.html:96 +#: templates/base.html:97 msgid "Sheets" msgstr "" -#: templates/base.html:146 +#: templates/base.html:158 msgid "Processing..." msgstr "" -#: templates/base.html:148 +#: templates/base.html:160 msgid "This can be long." msgstr "" -#: templates/base.html:150 +#: templates/base.html:162 msgid "Time to take a coffee?" msgstr "" -#: templates/base.html:152 +#: templates/base.html:164 msgid "Time to take another coffee?" msgstr "" @@ -2637,7 +2654,8 @@ msgid "Expand table" msgstr "" #: templates/blocks/DataTables.html:53 templates/blocks/JQueryJqGrid.html:26 -#: templates/ishtar/blocks/window_nav.html:59 +#: templates/ishtar/blocks/window_nav.html:62 +#: templates/ishtar/blocks/window_nav.html:68 #: templates/ishtar/blocks/window_tables/dynamic_documents.html:45 msgid "Export" msgstr "" @@ -2808,8 +2826,8 @@ msgstr "" #: templates/ishtar/blocks/modify_toolbar.html:1 #: templates/ishtar/blocks/window_image.html:11 -#: templates/ishtar/blocks/window_nav.html:47 -#: templates/ishtar/forms/qa_base.html:57 +#: templates/ishtar/blocks/window_nav.html:49 +#: templates/ishtar/forms/qa_base.html:56 #: templates/ishtar/organization_form.html:37 #: templates/ishtar/organization_person_form.html:32 #: templates/ishtar/person_form.html:43 @@ -2834,13 +2852,17 @@ msgstr "" msgid "Data" msgstr "" +#: templates/ishtar/blocks/sheet_json.html:9 +msgid "No data" +msgstr "" + #: templates/ishtar/blocks/window_image_detail.html:64 msgid "Licenses" msgstr "" #: templates/ishtar/blocks/window_image_detail.html:111 #: templates/ishtar/import_delete.html:20 templatetags/window_field.py:17 -#: views_item.py:486 wizards.py:393 +#: views_item.py:548 wizards.py:405 msgid "Yes" msgstr "" @@ -2853,6 +2875,11 @@ msgstr "" msgid "Web" msgstr "" +#: templates/ishtar/blocks/window_image_detail.html:193 +#: templates/ishtar/blocks/window_tables/documents.html:10 +msgid "Related to" +msgstr "" + #: templates/ishtar/blocks/window_nav.html:17 msgid "" "Are you sure to restore to this version? All changes made since this version " @@ -2872,26 +2899,22 @@ msgstr "" msgid "Item pined in your shortcut menu." msgstr "" -#: templates/ishtar/blocks/window_nav.html:43 +#: templates/ishtar/blocks/window_nav.html:45 msgid "Actions" msgstr "" -#: templates/ishtar/blocks/window_nav.html:61 +#: templates/ishtar/blocks/window_nav.html:73 msgid "Export as OpenOffice.org file" msgstr "" -#: templates/ishtar/blocks/window_nav.html:64 +#: templates/ishtar/blocks/window_nav.html:77 msgid "Export as PDF file" msgstr "" -#: templates/ishtar/blocks/window_nav.html:72 +#: templates/ishtar/blocks/window_nav.html:92 msgid "Relation between items are not historized." msgstr "" -#: templates/ishtar/blocks/window_tables/documents.html:10 -msgid "Related to" -msgstr "" - #: templates/ishtar/blocks/window_tables/documents.html:11 #: templates/ishtar/blocks/window_tables/documents.html:19 msgid "Link" @@ -2978,12 +3001,12 @@ msgstr "" msgid "User type" msgstr "" -#: templates/ishtar/form.html:20 templates/ishtar/forms/document.html:24 +#: templates/ishtar/form.html:23 templates/ishtar/forms/document.html:24 #: templates/ishtar/wizard/default_wizard.html:43 msgid "Search and select an item in the table" msgstr "" -#: templates/ishtar/form.html:26 templates/ishtar/forms/document.html:30 +#: templates/ishtar/form.html:29 templates/ishtar/forms/document.html:30 #: templates/ishtar/forms/search_query.html:77 templates/ishtar/formset.html:8 #: templates/ishtar/formset_import_match.html:51 #: templates/ishtar/import_list.html:30 templates/ishtar/merge.html:30 @@ -2996,12 +3019,12 @@ msgstr "" msgid "Are you sure you want to delete: " msgstr "" -#: templates/ishtar/forms/qa_base.html:25 +#: templates/ishtar/forms/qa_base.html:24 #: templates/ishtar/forms/qa_form.html:12 msgid "Modified items" msgstr "" -#: templates/ishtar/forms/qa_base.html:62 +#: templates/ishtar/forms/qa_base.html:61 #: templates/ishtar/import_step_by_step.html:126 #: templates/ishtar/import_step_by_step.html:305 #: templates/ishtar/organization_form.html:40 @@ -3083,7 +3106,7 @@ msgstr "" msgid "Go" msgstr "" -#: templates/ishtar/import_step_by_step.html:63 views.py:1081 +#: templates/ishtar/import_step_by_step.html:63 views.py:1104 msgid "Import step by step" msgstr "" @@ -3344,12 +3367,12 @@ msgstr "" msgid "Responsible for planning service of archaeological files" msgstr "" -#: templates/ishtar/wizard/confirm_wizard.html:12 +#: templates/ishtar/wizard/confirm_wizard.html:14 #: templates/ishtar/wizard/wizard_done_summary.html:6 msgid "You have entered the following informations:" msgstr "" -#: templates/ishtar/wizard/confirm_wizard.html:50 +#: templates/ishtar/wizard/confirm_wizard.html:56 msgid "Would you like to save them?" msgstr "" @@ -3648,15 +3671,15 @@ msgstr "" msgid "Bookmarks" msgstr "" -#: templatetags/window_field.py:22 wizards.py:395 +#: templatetags/window_field.py:22 wizards.py:407 msgid "No" msgstr "" -#: templatetags/window_tables.py:88 widgets.py:1065 +#: templatetags/window_tables.py:88 widgets.py:1102 msgid "No results" msgstr "" -#: templatetags/window_tables.py:89 widgets.py:1066 +#: templatetags/window_tables.py:89 widgets.py:1103 msgid "Loading..." msgstr "" @@ -3664,15 +3687,15 @@ msgstr "" msgid "You don't have sufficient permissions to do this action." msgstr "" -#: utils.py:338 +#: utils.py:344 msgid " (...)" msgstr "" -#: utils.py:418 +#: utils.py:424 msgid "Information" msgstr "" -#: utils.py:419 +#: utils.py:425 msgid "Load another random image?" msgstr "" @@ -3736,116 +3759,125 @@ msgstr "" msgid "Treatment" msgstr "" -#: views.py:724 views_item.py:103 +#: views.py:747 views_item.py:117 msgid "Operation not permitted." msgstr "" -#: views.py:741 views.py:799 +#: views.py:764 views.py:822 msgid "Archaeological files" msgstr "" -#: views.py:746 views.py:810 +#: views.py:769 views.py:833 msgid "Finds" msgstr "" -#: views.py:748 views.py:815 +#: views.py:771 views.py:838 msgid "Treatment requests" msgstr "" -#: views.py:749 views.py:821 +#: views.py:772 views.py:844 msgid "Treatments" msgstr "" -#: views.py:1423 +#: views.py:1446 msgid "Col. " msgstr "" -#: views.py:1429 views.py:1441 +#: views.py:1452 views.py:1464 msgid "* empty *" msgstr "" -#: views.py:1482 +#: views.py:1505 msgid "Link unmatched items" msgstr "" -#: views.py:1503 +#: views.py:1526 msgid "Delete import" msgstr "" -#: views.py:1542 +#: views.py:1565 msgid "Merge persons" msgstr "" -#: views.py:1566 +#: views.py:1589 msgid "Select the main person" msgstr "" -#: views.py:1575 +#: views.py:1598 msgid "Merge organization" msgstr "" -#: views.py:1585 +#: views.py:1608 msgid "Select the main organization" msgstr "" -#: views.py:1625 views.py:1641 +#: views.py:1648 views.py:1664 msgid "Corporation manager" msgstr "" -#: views.py:1662 +#: views.py:1685 msgid "Document: search" msgstr "" -#: views.py:1677 +#: views.py:1700 msgid "Document creation" msgstr "" -#: views.py:1710 +#: views.py:1733 msgid "Document modification" msgstr "" -#: views.py:1740 +#: views.py:1763 msgid "Document deletion" msgstr "" -#: views.py:1823 +#: views.py:1872 msgid "Delete bookmark" msgstr "" -#: views.py:1846 +#: views.py:1895 msgid "Bookmark - Delete" msgstr "" -#: views_item.py:105 +#: views_item.py:119 #, python-format msgid "New %s" msgstr "" +#: views_item.py:570 +msgctxt "key for text search" +msgid "today" +msgstr "" + #: widgets.py:174 msgid "The character \" is not accepted." msgstr "" -#: widgets.py:517 +#: widgets.py:555 msgid "{} is not a valid key for {}" msgstr "" -#: widgets.py:618 widgets.py:752 widgets.py:867 +#: widgets.py:656 widgets.py:790 widgets.py:905 msgid "Search..." msgstr "" -#: widgets.py:687 +#: widgets.py:725 msgid "Previous value:" msgstr "" -#: widgets.py:1067 +#: widgets.py:1104 msgid "Remove" msgstr "" -#: wizards.py:431 +#: wizards.py:171 +msgid "Permission error: you cannot do this action." +msgstr "" + +#: wizards.py:443 msgid "Deleted" msgstr "" -#: wizards.py:1757 +#: wizards.py:1769 #, python-format msgid "[%(app_name)s] Account creation/modification" msgstr "" diff --git a/translations/fr/archaeological_context_records.po b/translations/fr/archaeological_context_records.po index d20a86c19..74188a0fb 100644 --- a/translations/fr/archaeological_context_records.po +++ b/translations/fr/archaeological_context_records.po @@ -11,7 +11,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Content-Type: text/plain; charset=UTF-8\n" -"PO-Revision-Date: 2018-11-12 09:32+0000\n" +"PO-Revision-Date: 2018-12-04 12:48+0000\n" "Last-Translator: Étienne Loks <etienne.loks@iggdrasil.net>\n" "Language-Team: \n" "Language: fr\n" @@ -22,242 +22,242 @@ msgstr "" msgid "Point" msgstr "Point" -#: admin.py:51 models.py:410 +#: admin.py:51 models.py:427 msgid "Multi polygon" msgstr "Polygones multi-parties" -#: forms.py:47 forms.py:53 models.py:352 wizards.py:81 +#: forms.py:48 forms.py:54 models.py:369 wizards.py:81 msgid "Operation" msgstr "Opération" -#: forms.py:48 +#: forms.py:49 msgid "Context record - 010 - Operation choice" msgstr "Unité d'enregistrement - 010 - Choix de l'opération" -#: forms.py:63 +#: forms.py:64 msgid "Context record - 001 - Search" msgstr "Unité d'enregistrement - 001 - Recherche" -#: forms.py:66 +#: forms.py:67 msgid "Full text search" msgstr "Recherche en texte intégral" -#: forms.py:69 forms.py:155 models.py:357 models.py:737 +#: forms.py:70 forms.py:156 forms.py:386 models.py:374 models.py:754 msgid "ID" msgstr "Identifiant" -#: forms.py:75 +#: forms.py:76 msgid "Code PATRIARCHE" msgstr "Code PATRIARCHE" -#: forms.py:76 +#: forms.py:77 msgid "Operation's year" msgstr "Année de l'opération" -#: forms.py:78 +#: forms.py:79 msgid "Operation's number (index by year)" msgstr "Numéro de l'opération (index par année)" -#: forms.py:80 models.py:355 +#: forms.py:81 models.py:372 msgid "Archaeological site" msgstr "Entité archéologique" -#: forms.py:86 +#: forms.py:87 msgid "Search within related operations" msgstr "Rechercher parmi les opérations liées" -#: forms.py:87 forms.py:288 models.py:66 +#: forms.py:88 forms.py:289 models.py:66 msgid "Period" msgstr "Période" -#: forms.py:88 +#: forms.py:89 msgid "Unit type" msgstr "Type d'unité" -#: forms.py:89 forms.py:148 models.py:231 models.py:232 models.py:347 -#: models.py:739 +#: forms.py:90 forms.py:149 models.py:248 models.py:249 models.py:364 +#: models.py:756 msgid "Parcel" msgstr "Parcelle" -#: forms.py:91 +#: forms.py:92 msgid "Search within relations" msgstr "Rechercher parmi les relations" -#: forms.py:115 views.py:95 +#: forms.py:116 views.py:99 msgid "Context record search" msgstr "Rechercher une Unité d'Enregistrement" -#: forms.py:130 +#: forms.py:131 msgid "You should at least select one context record." msgstr "Vous devez sélectionner au moins une Unité d'Enregistrement." -#: forms.py:136 +#: forms.py:137 msgid "General" msgstr "Général" -#: forms.py:137 +#: forms.py:138 msgid "Context record - 020 - General" msgstr "Unité d'enregistrement - 020 - Général" -#: forms.py:149 models.py:228 models.py:229 models.py:350 +#: forms.py:150 forms.py:380 models.py:245 models.py:246 models.py:367 msgid "Town" msgstr "Commune" -#: forms.py:152 +#: forms.py:153 forms.py:383 msgid "Only the items associated to the operation can be selected." msgstr "Seuls les éléments associés à l'opération peuvent être sélectionnés." -#: forms.py:157 models.py:358 models.py:740 +#: forms.py:158 forms.py:388 models.py:396 models.py:755 +msgid "Context record type" +msgstr "Type d'Unité d'Enregistrement" + +#: forms.py:160 models.py:375 models.py:757 #: templates/ishtar/sheet_contextrecord.html:45 msgid "Description" msgstr "Description" -#: forms.py:159 models.py:359 +#: forms.py:162 models.py:376 msgid "General comment" msgstr "Commentaire général" -#: forms.py:162 models.py:405 +#: forms.py:165 models.py:422 msgid "Excavation technique" msgstr "Méthode de fouille" -#: forms.py:163 models.py:363 +#: forms.py:166 models.py:380 msgid "Length (m)" msgstr "Taille (m)" -#: forms.py:164 models.py:364 +#: forms.py:167 models.py:381 msgid "Width (m)" msgstr "Largeur (m)" -#: forms.py:165 models.py:365 +#: forms.py:168 models.py:382 msgid "Thickness (m)" msgstr "Épaisseur (m)" -#: forms.py:166 models.py:367 +#: forms.py:169 models.py:384 msgid "Diameter (m)" msgstr "Diamètre (m)" -#: forms.py:167 models.py:368 +#: forms.py:170 models.py:385 msgid "Depth (m)" msgstr "Profondeur (m)" -#: forms.py:169 models.py:370 +#: forms.py:172 models.py:387 msgid "Depth of appearance (m)" msgstr "Profondeur d'apparition (m)" -#: forms.py:170 models.py:379 models.py:738 -msgid "Context record type" -msgstr "Type d'Unité d'Enregistrement" - -#: forms.py:172 models.py:360 +#: forms.py:173 models.py:377 msgid "Opening date" msgstr "Date d'ouverture" -#: forms.py:174 models.py:362 templates/ishtar/sheet_contextrecord.html:140 +#: forms.py:175 models.py:379 templates/ishtar/sheet_contextrecord.html:140 msgid "Closing date" msgstr "Date de clôture" -#: forms.py:177 +#: forms.py:178 msgid "Documentation" msgstr "Documentation" -#: forms.py:180 models.py:372 +#: forms.py:181 models.py:389 msgid "Location" msgstr "Localisation" -#: forms.py:273 +#: forms.py:274 msgid "This ID already exists for this operation." msgstr "Cet identifiant existe déjà pour cette opération." -#: forms.py:277 +#: forms.py:278 msgid "You have to choose a town or a parcel." msgstr "Vous devez choisir une commune ou une parcelle." -#: forms.py:283 forms.py:304 models.py:77 +#: forms.py:284 forms.py:305 models.py:77 msgid "Dating" msgstr "Datation" -#: forms.py:289 models.py:67 +#: forms.py:290 models.py:67 msgid "Start date" msgstr "Date de début" -#: forms.py:290 models.py:68 +#: forms.py:291 models.py:68 msgid "End date" msgstr "Date de fin" -#: forms.py:291 models.py:71 +#: forms.py:292 models.py:71 msgid "Quality" msgstr "Qualité" -#: forms.py:292 models.py:45 models.py:69 +#: forms.py:293 models.py:45 models.py:69 msgid "Dating type" msgstr "Type de datation" -#: forms.py:305 +#: forms.py:306 msgid "Context record - 030 - Dating" msgstr "Unité d'enregistrement - 030 - Datation" -#: forms.py:315 ishtar_menu.py:29 models.py:91 +#: forms.py:316 ishtar_menu.py:29 models.py:108 views.py:185 msgid "Context record" msgstr "Unité d'Enregistrement" -#: forms.py:331 +#: forms.py:332 msgid "Relations" msgstr "Relations" -#: forms.py:332 +#: forms.py:333 msgid "Context record - 050 - Relations" msgstr "Unité d'enregistrement - 050 - Relations" -#: forms.py:337 forms.py:348 models.py:382 +#: forms.py:338 forms.py:349 models.py:399 #: templates/ishtar/sheet_contextrecord.html:64 msgid "Interpretation" msgstr "Interprétation" -#: forms.py:338 +#: forms.py:339 msgid "Context record - 040 - Interpretation" msgstr "Unité d'enregistrement - 040 - Interprétation" -#: forms.py:344 +#: forms.py:345 msgid "Comments on dating" msgstr "Commentaire relatif à la datation" -#: forms.py:346 models.py:381 +#: forms.py:347 models.py:398 msgid "Filling" msgstr "Remplissage" -#: forms.py:350 models.py:402 +#: forms.py:351 models.py:419 msgid "Activity" msgstr "Activité" -#: forms.py:352 models.py:400 +#: forms.py:353 models.py:417 msgid "Identification" msgstr "Identification" -#: forms.py:354 models.py:385 +#: forms.py:355 models.py:402 msgid "TAQ" msgstr "TAQ" -#: forms.py:355 models.py:389 +#: forms.py:356 models.py:406 msgid "Estimated TAQ" msgstr "TAQ estimé" -#: forms.py:357 models.py:392 +#: forms.py:358 models.py:409 msgid "TPQ" msgstr "TPQ" -#: forms.py:358 models.py:396 +#: forms.py:359 models.py:413 msgid "Estimated TPQ" msgstr "TPQ estimé" -#: forms.py:368 +#: forms.py:369 msgid "Operation search" msgstr "Rechercher une opération" -#: forms.py:370 +#: forms.py:371 msgid "You should select an operation." msgstr "Vous devez sélectionner une Opération." -#: forms.py:375 +#: forms.py:376 msgid "Would you like to delete this context record?" msgstr "Voulez-vous supprimer cette Unité d'Enregistrement ?" @@ -297,163 +297,163 @@ msgstr "Datation précise" msgid "Datings" msgstr "Datations" -#: models.py:98 +#: models.py:115 msgid "Find" msgstr "Mobilier" -#: models.py:117 models.py:136 models.py:152 +#: models.py:134 models.py:153 models.py:169 msgid "Order" msgstr "Ordre" -#: models.py:119 +#: models.py:136 msgid "Parent context record type" msgstr "Type d'UE parent" -#: models.py:123 +#: models.py:140 msgid "Context record Type" msgstr "Type d'Unité d'Enregistrement" -#: models.py:124 +#: models.py:141 msgid "Context record Types" msgstr "Types d'Unité d'Enregistrement" -#: models.py:139 +#: models.py:156 msgid "Activity Type" msgstr "Type d'activité" -#: models.py:140 +#: models.py:157 msgid "Activity Types" msgstr "Types d'activité" -#: models.py:155 +#: models.py:172 msgid "Identification Type" msgstr "Type d'identification" -#: models.py:156 +#: models.py:173 msgid "Identification Types" msgstr "Types d'identification" -#: models.py:169 +#: models.py:186 msgid "Excavation technique type" msgstr "Type de méthode de fouille" -#: models.py:170 +#: models.py:187 msgid "Excavation technique types" msgstr "Types de méthode de fouille" -#: models.py:180 +#: models.py:197 msgid "Documentation type" msgstr "Type de documentation" -#: models.py:181 +#: models.py:198 msgid "Documentation types" msgstr "Types de documentation" -#: models.py:222 models.py:741 +#: models.py:239 models.py:758 msgid "Periods" msgstr "Périodes" -#: models.py:223 +#: models.py:240 msgid "Datings (period)" msgstr "Datations (période)" -#: models.py:224 +#: models.py:241 msgid "Related context records" msgstr "Unités d'Enregistrement liées" -#: models.py:225 +#: models.py:242 msgid "Operation (Patriarche code)" msgstr "Opération (code Patriarche)" -#: models.py:226 +#: models.py:243 msgid "Operation (name)" msgstr "Opération (nom)" -#: models.py:227 +#: models.py:244 msgid "Parcel (external ID)" msgstr "Parcelle (identifiant)" -#: models.py:230 +#: models.py:247 msgid "Parcel (year)" msgstr "Parcelle (année)" -#: models.py:265 +#: models.py:282 msgctxt "key for text search" msgid "id" msgstr "id" -#: models.py:269 +#: models.py:286 msgctxt "key for text search" msgid "town" msgstr "commune" -#: models.py:273 +#: models.py:290 msgctxt "key for text search" msgid "operation-year" msgstr "operation-annee" -#: models.py:277 +#: models.py:294 msgctxt "key for text search" msgid "patriarche" msgstr "patriarche" -#: models.py:281 +#: models.py:298 msgctxt "key for text search" msgid "operation-code" msgstr "operation-code" -#: models.py:285 models.py:327 +#: models.py:302 models.py:344 msgctxt "key for text search" msgid "operation" msgstr "operation" -#: models.py:289 models.py:330 +#: models.py:306 models.py:347 msgctxt "key for text search" msgid "site" msgstr "site" -#: models.py:293 +#: models.py:310 msgctxt "key for text search" msgid "operation-relation-type" msgstr "operation-type-relation" -#: models.py:297 +#: models.py:314 msgctxt "key for text search" msgid "period" msgstr "periode" -#: models.py:301 +#: models.py:318 msgctxt "key for text search" msgid "unit-type" msgstr "type" -#: models.py:305 +#: models.py:322 msgctxt "key for text search" msgid "parcel" msgstr "parcelle" -#: models.py:309 +#: models.py:326 msgctxt "key for text search" msgid "record-relation-type" msgstr "ue-type-relation" -#: models.py:343 +#: models.py:360 msgid "External ID" msgstr "Identifiant" -#: models.py:345 +#: models.py:362 msgid "External ID is set automatically" msgstr "L'identifiant est attribué automatiquement" -#: models.py:373 +#: models.py:390 msgid "A short description of the location of the context record" msgstr "Une courte description de la localisation de l'Unité d'Enregistrement" -#: models.py:377 +#: models.py:394 msgid "Comment on datings" msgstr "Commentaire relatif aux datations" -#: models.py:386 +#: models.py:403 msgid "" "\"Terminus Ante Quem\" the context record can't have been created after this " "date" @@ -461,11 +461,11 @@ msgstr "" "« Terminus Ante Quem ». L'Unité d'Enregistrement ne peut avoir été créée " "après cette date." -#: models.py:390 +#: models.py:407 msgid "Estimation of a \"Terminus Ante Quem\"" msgstr "Estimation d'un « Terminus Ante Quem »." -#: models.py:393 +#: models.py:410 msgid "" "\"Terminus Post Quem\" the context record can't have been created before " "this date" @@ -473,91 +473,103 @@ msgstr "" "« Terminus Post Quem ». L'Unité d'Enregistrement ne peut avoir été créée " "avant cette date." -#: models.py:397 +#: models.py:414 msgid "Estimation of a \"Terminus Post Quem\"" msgstr "Estimation d'un « Terminus Post Quem »." -#: models.py:408 +#: models.py:425 msgid "Point (2D)" msgstr "Point (2D)" -#: models.py:409 +#: models.py:426 msgid "Point (3D)" msgstr "Point (3D)" -#: models.py:413 +#: models.py:430 msgid "Documents" msgstr "Documents" -#: models.py:415 +#: models.py:432 msgid "Cached name" msgstr "Nom en cache" -#: models.py:419 models.py:420 templates/ishtar/sheet_contextrecord.html:4 +#: models.py:436 models.py:437 templates/ishtar/sheet_contextrecord.html:4 msgid "Context Record" msgstr "Unité d'Enregistrement" -#: models.py:439 +#: models.py:456 msgctxt "short" msgid "Context record" msgstr "UE" -#: models.py:668 models.py:691 models.py:736 +#: models.py:685 models.py:708 models.py:753 msgid "Relation type" msgstr "Type de relation" -#: models.py:669 +#: models.py:686 msgid "Relation types" msgstr "Types de relation" -#: models.py:686 +#: models.py:703 msgid "ID (left)" msgstr "Identifiant (gauche)" -#: models.py:687 +#: models.py:704 msgid "Context record type (left)" msgstr "Type d'UE (gauche)" -#: models.py:688 +#: models.py:705 msgid "Parcel (left)" msgstr "Parcelle (gauche)" -#: models.py:689 +#: models.py:706 msgid "Description (left)" msgstr "Description (gauche)" -#: models.py:690 +#: models.py:707 msgid "Periods (left)" msgstr "Périodes (gauche)" -#: models.py:692 +#: models.py:709 msgid "ID (right)" msgstr "Identifiant (droit)" -#: models.py:693 +#: models.py:710 msgid "Context record type (right)" msgstr "Type d'UE (droite)" -#: models.py:694 +#: models.py:711 msgid "Parcel (right)" msgstr "Parcelle (droite)" -#: models.py:695 +#: models.py:712 msgid "Description (right)" msgstr "Description (droite)" -#: models.py:696 +#: models.py:713 msgid "Periods (right)" msgstr "Périodes (droite)" -#: models.py:705 +#: models.py:722 msgid "Record relation" msgstr "Relation entre Unités d'Enregistrement" -#: models.py:706 +#: models.py:723 msgid "Record relations" msgstr "Relations entre Unités d'Enregistrement" +#: templates/ishtar/forms/qa_operation_contextrecord.html:11 +msgid "Quick add context record" +msgstr "Ajouter rapide d'Unité d'enregistrement" + +#: templates/ishtar/forms/qa_operation_contextrecord.html:25 +msgid "" +"To put more information to the context record use the full form on the top " +"menu: \\" +msgstr "" +"Pour ajouter plus d'information à l'Unité d'enregistrement utilisez le " +"formulaire complet depuis le menu en haut : \\" + #: templates/ishtar/sheet_contextrecord.html:75 msgid "Datations" msgstr "Datations" @@ -626,19 +638,23 @@ msgstr "Mobilier" msgid "Documents from associated finds" msgstr "Documents du mobilier associé" -#: views.py:109 +#: views.py:113 msgid "New context record" msgstr "Ajouter une Unité d'Enregistrement" -#: views.py:125 +#: views.py:129 msgid "Context record modification" msgstr "Modifier une Unité d'Enregistrement" -#: views.py:136 +#: views.py:140 msgid "You don't have sufficient permissions to do this action." msgstr "" "Vous n'avez pas les permissions suffisantes pour effectuer cette action." -#: views.py:149 +#: views.py:153 msgid "Context record deletion" msgstr "Supprimer une Unité d'Enregistrement" + +#: views.py:190 +msgid "Add context record" +msgstr "Ajouter Unité d'enregistrement" diff --git a/translations/fr/archaeological_files.po b/translations/fr/archaeological_files.po index f86f274a3..d6256f8a2 100644 --- a/translations/fr/archaeological_files.po +++ b/translations/fr/archaeological_files.po @@ -6,13 +6,12 @@ # Étienne Loks <etienne.loks@iggdrasil.net>, 2016. #zanata # Valérie-Emma Leroux <emma@iggdrasil.net>, 2017. #zanata # Valérie-Emma Leroux <emma@iggdrasil.net>, 2018. #zanata -# Étienne Loks <etienne.loks@iggdrasil.net>, 2018. #zanata msgid "" msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Content-Type: text/plain; charset=UTF-8\n" -"PO-Revision-Date: 2018-08-15 03:30+0000\n" +"PO-Revision-Date: 2018-11-30 09:08+0000\n" "Last-Translator: Étienne Loks <etienne.loks@iggdrasil.net>\n" "Language-Team: \n" "Language: fr\n" @@ -307,19 +306,15 @@ msgstr "Suppression" msgid "Administrative act" msgstr "Acte administratif" -#: ishtar_menu.py:77 models.py:321 -msgid "Documents" -msgstr "Documents" - -#: ishtar_menu.py:83 +#: ishtar_menu.py:79 msgid "Dashboard" msgstr "Tableau de bord" -#: ishtar_menu.py:86 +#: ishtar_menu.py:82 msgid "General informations" msgstr "Informations générales" -#: ishtar_menu.py:89 models.py:339 +#: ishtar_menu.py:85 models.py:339 #: templates/ishtar/dashboards/dashboard_file.html:7 msgid "Archaeological files" msgstr "Dossiers archéologiques" @@ -397,7 +392,7 @@ msgstr "type-saisine" #: models.py:177 msgctxt "key for text search" msgid "permit-type" -msgstr "type-permit" +msgstr "type-permis" #: models.py:181 msgctxt "key for text search" @@ -490,6 +485,10 @@ msgstr "Organisation" msgid "Research archaeology comment" msgstr "Commentaire relatif à l'archéologie programmée" +#: models.py:321 +msgid "Documents" +msgstr "Documents" + #: models.py:324 msgid "Cached name" msgstr "Nom en cache" diff --git a/translations/fr/archaeological_finds.po b/translations/fr/archaeological_finds.po index 996b61dca..d0332d11d 100644 --- a/translations/fr/archaeological_finds.po +++ b/translations/fr/archaeological_finds.po @@ -11,249 +11,266 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Content-Type: text/plain; charset=UTF-8\n" -"PO-Revision-Date: 2018-11-12 03:35+0000\n" +"PO-Revision-Date: 2018-12-13 05:53+0000\n" "Last-Translator: Étienne Loks <etienne.loks@iggdrasil.net>\n" "Language-Team: \n" "Language: fr\n" "Plural-Forms: nplurals=2; plural=n>1;\n" "X-Generator: Zanata 4.6.2\n" -#: admin.py:39 models_finds.py:288 +#: admin.py:39 models_finds.py:303 msgid "Point (2D)" msgstr "Point (2D)" -#: admin.py:41 models_finds.py:290 +#: admin.py:41 models_finds.py:305 msgid "Line" msgstr "Ligne" -#: admin.py:43 models_finds.py:291 +#: admin.py:43 models_finds.py:306 msgid "Multi polygon" msgstr "Polygones multi-parties" -#: forms.py:91 forms.py:97 forms.py:340 forms.py:353 forms.py:631 -#: models_finds.py:660 models_finds.py:1213 wizards.py:75 +#: forms.py:96 forms.py:102 forms.py:556 forms.py:569 forms.py:876 +#: models_finds.py:722 models_finds.py:1337 wizards.py:86 msgid "Context record" msgstr "Unité d'Enregistrement" -#: forms.py:92 +#: forms.py:97 msgid "Find - 010 - Context record choice" msgstr "Mobilier - 010 - Choix de l'unité d'enregistrement" -#: forms.py:126 ishtar_menu.py:32 models_finds.py:1089 models_finds.py:1717 -#: models_treatments.py:349 templates/ishtar/sheet_find.html:4 +#: forms.py:134 forms.py:268 ishtar_menu.py:32 models_finds.py:1192 +#: models_finds.py:1959 models_treatments.py:585 +#: templates/ishtar/sheet_find.html:4 msgid "Find" msgstr "Mobilier" -#: forms.py:127 -msgid "Find - 020 - General" -msgstr "Mobilier - 020 - Général" +#: forms.py:135 +msgid "Simple find - 020 - General" +msgstr "Mobilier simple - 020 - Général" -#: forms.py:142 forms.py:341 templates/ishtar/sheet_find.html:40 +#: forms.py:157 forms.py:409 forms.py:557 templates/ishtar/sheet_find.html:110 msgid "Identification" msgstr "Identification" -#: forms.py:145 forms.py:360 forms.py:600 forms.py:889 models_finds.py:253 -#: models_finds.py:968 +#: forms.py:160 forms.py:412 forms.py:576 forms.py:845 forms.py:1155 +#: models_finds.py:268 models_finds.py:1060 msgid "Free ID" msgstr "Identifiant libre" -#: forms.py:147 forms.py:362 forms.py:601 forms.py:932 models_finds.py:969 +#: forms.py:162 forms.py:414 forms.py:578 forms.py:846 forms.py:1220 +#: models_finds.py:1061 msgid "Denomination" msgstr "Dénomination" -#: forms.py:148 forms.py:363 models_finds.py:1042 +#: forms.py:163 forms.py:579 models_finds.py:1141 msgid "Previous ID" msgstr "Identifiant précédent" -#: forms.py:150 forms.py:365 models_finds.py:257 -msgid "Excavation ID" -msgstr "Identifiant fouille" - -#: forms.py:151 forms.py:366 models_finds.py:970 +#: forms.py:164 forms.py:582 models_finds.py:1062 msgid "Museum ID" msgstr "Identifiant musée" -#: forms.py:152 forms.py:367 models_finds.py:965 +#: forms.py:165 forms.py:583 models_finds.py:1057 msgid "Seal number" msgstr "Numéro de scellé" -#: forms.py:153 forms.py:368 models_finds.py:1038 +#: forms.py:166 forms.py:584 models_finds.py:1137 msgid "Mark" msgstr "Marquage" -#: forms.py:155 forms.py:156 forms.py:342 forms.py:371 forms.py:652 -#: forms_treatments.py:139 models_finds.py:258 models_finds.py:971 -#: models_treatments.py:146 templates/ishtar/sheet_find.html:58 +#: forms.py:168 forms.py:169 forms.py:417 forms.py:419 forms.py:558 +#: forms.py:587 forms.py:897 forms_treatments.py:141 models_finds.py:273 +#: models_finds.py:1063 models_treatments.py:164 +#: templates/ishtar/sheet_find.html:128 msgid "Description" msgstr "Description" -#: forms.py:159 models_finds.py:265 -msgid "Discovery date (exact or TPQ)" -msgstr "Date de découverte (exacte ou TPQ)" - -#: forms.py:162 models_finds.py:267 templates/ishtar/sheet_basefind.html:29 -msgid "Discovery date (TAQ)" -msgstr "Date de découverte (TAQ)" - -#: forms.py:164 forms.py:654 models_finds.py:269 -msgid "Batch/object" -msgstr "Lot/objet" - -#: forms.py:166 models_finds.py:1003 +#: forms.py:171 forms.py:421 models_finds.py:1100 msgid "Is complete?" msgstr "Est complet ?" -#: forms.py:169 forms.py:373 models_finds.py:57 models_finds.py:685 -#: models_finds.py:977 +#: forms.py:174 forms.py:423 forms.py:589 models_finds.py:57 +#: models_finds.py:748 models_finds.py:1069 msgid "Material types" msgstr "Types de matériau" -#: forms.py:172 models_finds.py:982 +#: forms.py:177 forms.py:426 models_finds.py:1074 msgid "Material type quality" msgstr "Qualité du type de matériaux" -#: forms.py:174 forms.py:376 models_finds.py:152 models_finds.py:686 -#: models_finds.py:1006 +#: forms.py:179 forms.py:428 forms.py:592 models_finds.py:167 +#: models_finds.py:749 models_finds.py:1103 msgid "Object types" msgstr "Types d'objet" -#: forms.py:177 models_finds.py:1011 +#: forms.py:182 forms.py:431 models_finds.py:1108 msgid "Object type quality" msgstr "Qualité du type d'objet" -#: forms.py:178 forms.py:896 models_finds.py:989 +#: forms.py:183 forms.py:433 forms.py:1162 models_finds.py:1081 msgid "Find number" msgstr "Mobilier (en nombre)" -#: forms.py:180 models_finds.py:1024 +#: forms.py:185 forms.py:435 models_finds.py:1121 msgid "Minimum number of individuals (MNI)" msgstr "Nombre minimum d'individus (NMI)" -#: forms.py:182 models_finds.py:972 +#: forms.py:187 forms.py:438 models_finds.py:1064 msgid "Decoration" msgstr "Décor" -#: forms.py:184 models_finds.py:973 +#: forms.py:189 forms.py:440 models_finds.py:1065 msgid "Inscription" msgstr "Inscription" -#: forms.py:187 forms.py:379 models_finds.py:975 +#: forms.py:192 forms.py:442 forms.py:595 models_finds.py:1067 msgid "Manufacturing place" msgstr "Lieu de fabrication" -#: forms.py:189 forms.py:381 models_finds.py:1021 +#: forms.py:194 forms.py:444 forms.py:597 models_finds.py:1118 msgid "Communicability" msgstr "Communicabilité" -#: forms.py:191 forms.py:384 forms.py:955 forms_treatments.py:141 -#: forms_treatments.py:578 models_finds.py:259 models_finds.py:1039 -#: models_treatments.py:145 models_treatments.py:609 +#: forms.py:196 forms.py:446 forms.py:600 forms.py:1260 forms_treatments.py:143 +#: forms_treatments.py:657 models_finds.py:274 models_finds.py:1138 +#: models_treatments.py:163 models_treatments.py:847 msgid "Comment" msgstr "Commentaire général" -#: forms.py:194 forms.py:394 models_finds.py:1040 +#: forms.py:199 forms.py:449 forms.py:610 models_finds.py:1139 msgid "Comment on dating" msgstr "Commentaire relatif aux datations" -#: forms.py:196 templates/ishtar/sheet_find.html:76 +#: forms.py:201 forms.py:451 templates/ishtar/sheet_find.html:146 msgid "Dimensions" msgstr "Dimensions" -#: forms.py:197 models_finds.py:1025 +#: forms.py:202 forms.py:452 models_finds.py:1122 msgid "Length (cm)" msgstr "Longueur (cm)" -#: forms.py:198 models_finds.py:1026 +#: forms.py:204 forms.py:453 models_finds.py:1123 msgid "Width (cm)" msgstr "Largeur (cm)" -#: forms.py:199 models_finds.py:1027 +#: forms.py:206 forms.py:454 models_finds.py:1124 msgid "Height (cm)" msgstr "Hauteur (cm)" -#: forms.py:200 models_finds.py:1028 +#: forms.py:208 forms.py:458 models_finds.py:1128 +msgid "Thickness (cm)" +msgstr "Épaisseur (cm)" + +#: forms.py:210 forms.py:455 models_finds.py:1125 msgid "Diameter (cm)" msgstr "Diamètre (cm)" -#: forms.py:201 models_finds.py:1029 -msgid "Thickness (cm)" -msgstr "Épaisseur (cm)" +#: forms.py:213 forms.py:456 models_finds.py:1126 +msgid "Circumference (cm)" +msgstr "Circonférence (cm)" -#: forms.py:202 forms.py:894 models_finds.py:985 +#: forms.py:215 forms.py:459 forms.py:1160 models_finds.py:1077 msgid "Volume (l)" msgstr "Volume (l)" -#: forms.py:203 forms.py:895 templates/ishtar/sheet_find.html:84 +#: forms.py:216 forms.py:460 forms.py:1161 templates/ishtar/sheet_find.html:155 msgid "Weight (g)" msgstr "Poids (g)" -#: forms.py:205 +#: forms.py:219 forms.py:462 msgid "Clutter long side (cm)" msgstr "Encombrement grand côté (cm)" -#: forms.py:207 +#: forms.py:222 forms.py:464 msgid "Clutter short side (cm)" msgstr "Encombrement petit côté (cm)" -#: forms.py:209 +#: forms.py:225 forms.py:466 msgid "Clutter height (cm)" msgstr "Encombrement hauteur (cm)" -#: forms.py:211 models_finds.py:1036 +#: forms.py:228 forms.py:468 models_finds.py:1135 msgid "Dimensions comment" msgstr "Commentaire relatif aux dimensions" -#: forms.py:214 templates/ishtar/sheet_basefind.html:46 -#: templates/ishtar/sheet_basefind.html:50 +#: forms.py:230 forms.py:470 forms.py:559 +#: templates/ishtar/sheet_basefind.html:70 templates/ishtar/sheet_find.html:164 +msgid "Sheet" +msgstr "Fiche" + +#: forms.py:231 forms.py:471 forms.py:603 forms.py:900 models_finds.py:1143 +msgid "Check" +msgstr "Vérification" + +#: forms.py:233 forms.py:474 forms.py:605 models_finds.py:1145 +msgid "Check date" +msgstr "Date de vérification" + +#: forms.py:260 +msgid "Clutter: short side cannot be bigger than the long side." +msgstr "" +"Encombrement : le petit côté court ne peut pas être plus grand que le grand " +"côté." + +#: forms.py:269 +msgid "Find - 020 - General" +msgstr "Mobilier - 020 - Général" + +#: forms.py:299 forms.py:581 models_finds.py:272 +msgid "Excavation ID" +msgstr "Identifiant fouille" + +#: forms.py:302 models_finds.py:280 +msgid "Discovery date (exact or TPQ)" +msgstr "Date de découverte (exacte ou TPQ)" + +#: forms.py:305 models_finds.py:282 templates/ishtar/sheet_basefind.html:33 +msgid "Discovery date (TAQ)" +msgstr "Date de découverte (TAQ)" + +#: forms.py:307 forms.py:899 models_finds.py:284 +msgid "Batch/object" +msgstr "Lot/objet" + +#: forms.py:310 templates/ishtar/sheet_basefind.html:50 +#: templates/ishtar/sheet_basefind.html:54 msgid "Coordinates" msgstr "Coordonnées" -#: forms.py:215 models_finds.py:276 +#: forms.py:311 models_finds.py:291 msgid "X" -msgstr "X" +msgstr "X/Long" -#: forms.py:217 models_finds.py:279 +#: forms.py:313 models_finds.py:294 msgid "Estimated error for X" msgstr "Erreur estimée pour X" -#: forms.py:218 models_finds.py:277 +#: forms.py:314 models_finds.py:292 msgid "Y" -msgstr "Y" +msgstr "Y/Lat" -#: forms.py:220 models_finds.py:281 +#: forms.py:316 models_finds.py:296 msgid "Estimated error for Y" msgstr "Erreur estimée pour Y" -#: forms.py:221 models_finds.py:278 +#: forms.py:317 models_finds.py:293 msgid "Z" msgstr "Z" -#: forms.py:223 models_finds.py:283 +#: forms.py:319 models_finds.py:298 msgid "Estimated error for Z" msgstr "Erreur estimée pour Z" -#: forms.py:225 models_finds.py:286 +#: forms.py:321 models_finds.py:301 msgid "Spatial Reference System" msgstr "Système de référence spatiale" -#: forms.py:228 models_finds.py:274 +#: forms.py:324 models_finds.py:289 msgid "Point of topographic reference" msgstr "Point topographique" -#: forms.py:232 forms.py:343 templates/ishtar/sheet_basefind.html:66 -#: templates/ishtar/sheet_find.html:93 -msgid "Sheet" -msgstr "Fiche" - -#: forms.py:233 forms.py:387 forms.py:655 models_finds.py:1044 -msgid "Check" -msgstr "Vérification" - -#: forms.py:235 forms.py:389 models_finds.py:1046 -msgid "Check date" -msgstr "Date de vérification" - -#: forms.py:274 +#: forms.py:352 msgid "" "Discovery date: if a TAQ date is provided a TPQ date has to be informed. If " "you have a precise date fill only the TPQ - discovery date field." @@ -262,434 +279,508 @@ msgstr "" "renseignée. Si vous avez une date précise, remplissez seulement le champ « " "date de découverte (exacte ou TPQ) »." -#: forms.py:280 +#: forms.py:358 msgid "Discovery date: TAQ date must be older than TPQ date." msgstr "Date de découverte : la date TAQ doit être postérieure à la date TPQ." -#: forms.py:290 -msgid "Clutter: short side cannot be bigger than the long side." -msgstr "" -"Encombrement : le petit côté court ne peut pas être plus grand que le grand " -"côté." - -#: forms.py:307 +#: forms.py:374 msgid "" "You should at least provide X, Y and the spatial reference system used." msgstr "" "Vous devez au minimum fournir X, Y et le système de référence spatiale " "utilisé." -#: forms.py:316 +#: forms.py:383 msgid "" "Coordinates are not relevant for the spatial reference system used: {}." msgstr "" "Les coordonnées ne sont pas pertinentes pour le système de référence " "spatiale utilisé : {}." -#: forms.py:322 +#: forms.py:396 forms.py:1152 +msgid "Resulting find" +msgstr "Mobilier résultant" + +#: forms.py:397 +msgid "Treatment n-1 - 030 - Resulting find" +msgstr "Traitement n-1 - 030 - Mobilier résultant" + +#: forms.py:493 forms.py:1171 +msgid "Resulting finds" +msgstr "Mobiliers résultants" + +#: forms.py:494 +msgid "Treatment 1-n - 030 - Resulting finds" +msgstr "Traitement 1-n - 030 - Mobiliers résultants" + +#: forms.py:499 +msgid "Number of resulting finds" +msgstr "Nombre de mobiliers résultants" + +#: forms.py:503 +msgid "Prefix label for resulting finds" +msgstr "Préfixe du libellé des mobiliers résultants" + +#: forms.py:506 +msgid "" +"E.g.: with a prefix \"item-\", each resulting item will be named \"item-1\", " +"\"item-2\", \"item-3\"" +msgstr "" +"Par exemple : avec un préfixe « élément- », chaque élément résultant sera " +"nommé « élément-1 », « élément-2 », « élément-3 »..." + +#: forms.py:510 +msgid "Numbering starting from" +msgstr "Numérotation commençant depuis" + +#: forms.py:513 +msgid "Name of the new basket containing the resulting items" +msgstr "Nom du nouveau panier contenant les éléments résultants" + +#: forms.py:531 forms.py:697 forms.py:733 +msgid "A basket with this label already exists." +msgstr "Un panier avec ce libellé existe déjà ." + +#: forms.py:537 msgid "Find - Quick action - Modify" msgstr "Mobilier - Action rapide - Modification" -#: forms.py:344 +#: forms.py:560 msgid "Datation" msgstr "Datation" -#: forms.py:392 forms.py:565 forms.py:641 templates/ishtar/sheet_find.html:123 +#: forms.py:608 forms.py:810 forms.py:886 templates/ishtar/sheet_find.html:196 msgid "Period" msgstr "Période" -#: forms.py:436 +#: forms.py:652 msgid "Find - Quick action - Modify single" -msgstr "Mobilier - Action rapide - Modification simpe" +msgstr "Mobilier - Action rapide - Modification simple" -#: forms.py:449 +#: forms.py:665 msgid "Create" msgstr "Création" -#: forms.py:450 +#: forms.py:666 msgid "Update" msgstr "Mise à jour" -#: forms.py:452 forms.py:636 forms.py:982 forms.py:986 forms_treatments.py:180 -#: ishtar_menu.py:57 models_finds.py:926 -#: templates/ishtar/sheet_findbasket.html:4 views.py:646 +#: forms.py:668 forms.py:881 forms.py:1308 forms.py:1312 ishtar_menu.py:57 +#: models_finds.py:605 models_finds.py:1018 +#: templates/ishtar/sheet_findbasket.html:4 views.py:824 wizards.py:360 msgid "Basket" msgstr "Panier" -#: forms.py:474 +#: forms.py:690 msgid "On update, you have to select a basket." msgstr "Pour la mise à jour, vous avez à sélectionner un panier." -#: forms.py:478 +#: forms.py:694 forms.py:730 msgid "A label is required." msgstr "Un libellé est obligatoire" -#: forms.py:481 -msgid "A basket with this label already exists." -msgstr "Un panier avec ce libellé existe déjà ." +#: forms.py:725 +msgid " - duplicate" +msgstr " - copie" -#: forms.py:498 templates/ishtar/sheet_find.html:102 +#: forms.py:743 templates/ishtar/sheet_find.html:175 msgid "Preservation" msgstr "Conservation" -#: forms.py:499 +#: forms.py:744 msgid "Find - 030 - Preservation" msgstr "Mobilier - 030 - Conservation" -#: forms.py:513 forms.py:648 models_finds.py:1015 +#: forms.py:758 forms.py:893 models_finds.py:1112 msgid "Integrity / interest" msgstr "Intégrité / intérêt" -#: forms.py:516 forms.py:650 models_finds.py:1018 +#: forms.py:761 forms.py:895 models_finds.py:1115 msgid "Remarkability" msgstr "Remarquabilité" -#: forms.py:518 forms.py:646 models_finds.py:1056 +#: forms.py:763 forms.py:891 models_finds.py:1155 msgid "Conservatory state" msgstr "État sanitaire" -#: forms.py:521 models_finds.py:1065 +#: forms.py:766 models_finds.py:1164 msgid "Alteration" msgstr "Altération" -#: forms.py:524 models_finds.py:1069 +#: forms.py:769 models_finds.py:1168 msgid "Alteration cause" msgstr "Cause d'altération" -#: forms.py:527 models_finds.py:1062 +#: forms.py:772 models_finds.py:1161 msgid "Recommended treatments" msgstr "Traitements recommandés" -#: forms.py:529 models_finds.py:1073 +#: forms.py:774 models_finds.py:1172 msgid "Treatment emergency" msgstr "Urgence du traitement" -#: forms.py:531 models_finds.py:1048 +#: forms.py:776 models_finds.py:1147 msgid "Estimated value" msgstr "Valeur estimée" -#: forms.py:532 models_finds.py:1076 +#: forms.py:777 models_finds.py:1175 msgid "Insurance value" msgstr "Valeur d'assurance" -#: forms.py:534 models_finds.py:1078 +#: forms.py:779 models_finds.py:1177 msgid "Appraisal date" msgstr "Date d'évaluation" -#: forms.py:536 models_finds.py:1058 +#: forms.py:781 models_finds.py:1157 msgid "Conservatory comment" msgstr "Commentaire relatif à la conservation" -#: forms.py:560 forms.py:584 models_finds.py:997 -#: templates/ishtar/sheet_find.html:119 +#: forms.py:805 forms.py:829 models_finds.py:1089 +#: templates/ishtar/sheet_find.html:192 msgid "Dating" msgstr "Datation" -#: forms.py:566 forms_treatments.py:143 forms_treatments.py:370 -#: forms_treatments.py:580 models_finds.py:1722 models_treatments.py:148 -#: models_treatments.py:360 templates/ishtar/sheet_find.html:124 -#: templates/ishtar/sheet_find.html:185 templates/ishtar/sheet_find.html:223 +#: forms.py:811 forms_treatments.py:128 forms_treatments.py:442 +#: forms_treatments.py:659 models_finds.py:1964 models_treatments.py:166 +#: models_treatments.py:596 templates/ishtar/sheet_find.html:197 +#: templates/ishtar/sheet_find.html:265 templates/ishtar/sheet_find.html:302 +#: templates/ishtar/sheet_find.html:340 msgid "Start date" msgstr "Date de début" -#: forms.py:568 models_finds.py:1723 models_treatments.py:361 -#: templates/ishtar/sheet_find.html:125 templates/ishtar/sheet_find.html:186 -#: templates/ishtar/sheet_find.html:224 +#: forms.py:813 models_finds.py:1965 models_treatments.py:597 +#: templates/ishtar/sheet_find.html:198 templates/ishtar/sheet_find.html:266 +#: templates/ishtar/sheet_find.html:303 templates/ishtar/sheet_find.html:341 msgid "End date" msgstr "Date de fin" -#: forms.py:569 templates/ishtar/sheet_find.html:127 +#: forms.py:814 templates/ishtar/sheet_find.html:200 msgid "Quality" msgstr "Qualité" -#: forms.py:571 templates/ishtar/sheet_find.html:126 +#: forms.py:816 templates/ishtar/sheet_find.html:199 msgid "Dating type" msgstr "Type de datation" -#: forms.py:573 templates/ishtar/sheet_find.html:128 +#: forms.py:818 templates/ishtar/sheet_find.html:201 msgid "Precise dating" msgstr "Datation précise" -#: forms.py:585 +#: forms.py:830 msgid "Find - 040 - Dating" msgstr "Mobilier - 040 - Datation" -#: forms.py:592 +#: forms.py:837 msgid "Find - 001 - Search" msgstr "Mobilier - 001 - Recherche" -#: forms.py:595 forms.py:928 forms_treatments.py:50 forms_treatments.py:419 -#: forms_treatments.py:493 forms_treatments.py:686 +#: forms.py:840 forms.py:1216 forms_treatments.py:49 forms_treatments.py:491 +#: forms_treatments.py:565 forms_treatments.py:765 msgid "Full text search" msgstr "Recherche en texte intégral" -#: forms.py:598 models_finds.py:294 +#: forms.py:843 models_finds.py:309 msgid "Short ID" msgstr "Identifiant court" -#: forms.py:599 models_finds.py:297 +#: forms.py:844 models_finds.py:312 msgid "Complete ID" msgstr "Identifiant complet" -#: forms.py:604 forms_treatments.py:56 forms_treatments.py:101 -#: forms_treatments.py:295 forms_treatments.py:423 forms_treatments.py:498 -#: forms_treatments.py:550 forms_treatments.py:690 models_treatments.py:122 -#: models_treatments.py:582 +#: forms.py:849 forms_treatments.py:55 forms_treatments.py:100 +#: forms_treatments.py:363 forms_treatments.py:495 forms_treatments.py:570 +#: forms_treatments.py:624 forms_treatments.py:769 models_treatments.py:137 +#: models_treatments.py:820 msgid "Year" msgstr "Année" -#: forms.py:606 +#: forms.py:851 msgid "Operation's number (index by year)" msgstr "Numéro de l'opération (index par année)" -#: forms.py:609 +#: forms.py:854 msgid "Code PATRIARCHE" msgstr "Code PATRIARCHE" -#: forms.py:613 +#: forms.py:858 msgid "Operation type" msgstr "Type d'opération" -#: forms.py:616 +#: forms.py:861 msgid "Areas" msgstr "Zones" -#: forms.py:619 +#: forms.py:864 msgid "Archaeological site (attached to the operation)" msgstr "Site archéologique (attaché à l'opération)" -#: forms.py:625 +#: forms.py:870 msgid "Archaeological site (attached to the context record)" msgstr "Site archéologique (attaché à l'UE)" -#: forms.py:638 +#: forms.py:883 msgid "Search within related operations" msgstr "Rechercher parmi les opérations liées" -#: forms.py:640 +#: forms.py:885 msgid "Search within related context records" msgstr "Recherche parmi les Unités d'Enregistrement associées" -#: forms.py:642 forms.py:893 models_finds.py:56 +#: forms.py:887 forms.py:1159 models_finds.py:56 msgid "Material type" msgstr "Type de matériau" -#: forms.py:643 models_finds.py:151 +#: forms.py:888 models_finds.py:166 msgid "Object type" msgstr "Type d'objet" -#: forms.py:645 +#: forms.py:890 msgid "Preservation type" msgstr "Type de conservation" -#: forms.py:656 forms_treatments.py:59 +#: forms.py:901 forms_treatments.py:58 msgid "Has an image?" msgstr "Dispose d'une image ?" -#: forms.py:703 -msgid "Warehouse (location)" -msgstr "Lieu de conservation (localisation)" +#: forms.py:902 +msgid "Loan?" +msgstr "Prêt ?" -#: forms.py:709 -msgid "Warehouse (responsible)" -msgstr "Lieu de conservation (responsable)" +#: forms.py:904 +msgid "Treatment file end date before" +msgstr "Dossier de traitement - date de clotûre avant" -#: forms.py:714 -msgid "Container ID" -msgstr "Identifiant du contenant" +#: forms.py:953 +msgid "Reference container - Warehouse (location)" +msgstr "Contenant de référence - Lieu de conservation (localisation)" -#: forms.py:715 -msgid "Container ref." -msgstr "Réf. contenant" +#: forms.py:959 +msgid "Reference container - Warehouse (responsible)" +msgstr "Contenant de référence - Lieu de conservation (responsable)" -#: forms.py:720 forms.py:744 views.py:185 +#: forms.py:965 +msgid "Reference container ID" +msgstr "Identifiant du contenant de référence" + +#: forms.py:967 +msgid "Reference container ref." +msgstr "Réf. du contenant de référence" + +#: forms.py:969 +msgid "Current container - Warehouse (location)" +msgstr "Contenant actuel - Lieu de conservation (localisation)" + +#: forms.py:975 +msgid "Current container - Warehouse (responsible)" +msgstr "Contenant actuel - Lieu de conservation (responsable)" + +#: forms.py:980 +msgid "Current container ID" +msgstr "Identifiant du contenant actuel" + +#: forms.py:981 +msgid "Current container ref." +msgstr "Réf. du contenant actuel" + +#: forms.py:986 forms.py:1010 views.py:241 msgid "Find search" msgstr "Rechercher un mobilier" -#: forms.py:769 models_treatments.py:258 -#: templates/ishtar/sheet_treatment.html:56 +#: forms.py:1035 forms.py:1180 models_treatments.py:280 +#: templates/ishtar/sheet_treatment.html:102 msgid "Upstream finds" msgstr "Mobilier amont" -#: forms.py:771 models_finds.py:1090 +#: forms.py:1037 models_finds.py:1193 #: templates/ishtar/forms/qa_find_treatment.html:11 +#: templates/ishtar/sheet_treatment.html:24 msgid "Finds" msgstr "Mobilier" -#: forms.py:783 +#: forms.py:1049 msgid "You should at least select one archaeological find." msgstr "Vous devez sélectionner au moins un mobilier archéologique." -#: forms.py:886 -msgid "Resulting find" -msgstr "Mobilier résultant" - -#: forms.py:891 +#: forms.py:1157 msgid "Precise description" msgstr "Description précise" -#: forms.py:905 -msgid "Resulting finds" -msgstr "Mobiliers résultants" - -#: forms.py:910 +#: forms.py:1176 msgid "Would you like to delete this find?" msgstr "Voulez-vous supprimer ce mobilier ?" -#: forms.py:914 models_treatments.py:68 -msgid "Upstream find" -msgstr "Mobilier amont" - -#: forms.py:925 +#: forms.py:1213 msgid "Find basket - 001 - Search" msgstr "Panier mobilier - 001 - Recherche" -#: forms.py:937 views.py:122 +#: forms.py:1225 forms.py:1240 views.py:164 msgid "Basket search" msgstr "Recherche de panier" -#: forms.py:951 +#: forms.py:1254 msgid "Find basket" msgstr "Panier de mobilier" -#: forms.py:953 forms_treatments.py:54 forms_treatments.py:97 -#: models_treatments.py:118 templates/ishtar/sheet_find.html:179 -#: templates/ishtar/sheet_find.html:217 +#: forms.py:1258 forms_treatments.py:53 forms_treatments.py:122 +#: models_treatments.py:133 +#: templates/ishtar/forms/qa_findbasket_duplicate.html:15 +#: templates/ishtar/sheet_find.html:259 templates/ishtar/sheet_find.html:296 +#: templates/ishtar/sheet_find.html:334 msgid "Label" msgstr "Dénomination" -#: forms.py:972 +#: forms.py:1264 forms.py:1277 +msgid "Shared (read) with" +msgstr "Partagé (lecture) avec" + +#: forms.py:1269 forms.py:1282 +msgid "Shared (read/edit) with" +msgstr "Partagé (lecture/édition) avec" + +#: forms.py:1298 msgid "Another basket already exists with this name." msgstr "Un autre panier existant utilise déjà ce nom." -#: forms_treatments.py:55 forms_treatments.py:100 models_treatments.py:120 +#: forms_treatments.py:54 forms_treatments.py:125 models_treatments.py:135 msgid "Other ref." msgstr "Autre réf." -#: forms_treatments.py:57 forms_treatments.py:232 forms_treatments.py:424 -#: forms_treatments.py:486 forms_treatments.py:499 forms_treatments.py:603 -#: forms_treatments.py:691 forms_treatments.py:758 models_treatments.py:123 -#: models_treatments.py:583 +#: forms_treatments.py:56 forms_treatments.py:295 forms_treatments.py:496 +#: forms_treatments.py:558 forms_treatments.py:571 forms_treatments.py:682 +#: forms_treatments.py:770 forms_treatments.py:837 models_treatments.py:138 +#: models_treatments.py:821 msgid "Index" msgstr "Index" -#: forms_treatments.py:58 forms_treatments.py:106 forms_treatments.py:378 -#: forms_treatments.py:440 models_finds.py:106 models_treatments.py:128 -#: models_treatments.py:359 +#: forms_treatments.py:57 forms_treatments.py:97 forms_treatments.py:450 +#: forms_treatments.py:512 models_finds.py:121 models_treatments.py:143 +#: models_treatments.py:595 msgid "Treatment type" msgstr "Type de traitement" -#: forms_treatments.py:71 views.py:420 +#: forms_treatments.py:70 views.py:479 msgid "Treatment search" msgstr "Rechercher un traitement" -#: forms_treatments.py:83 -msgid "Base treatment" -msgstr "Traitement de base" +#: forms_treatments.py:82 ishtar_menu.py:143 models_treatments.py:187 +#: models_treatments.py:587 templates/ishtar/sheet_treatment.html:4 +#: templates/ishtar/sheet_treatment.html:17 +msgid "Treatment" +msgstr "Traitement" -#: forms_treatments.py:84 +#: forms_treatments.py:83 msgid "Treatment - 020 - General" msgstr "Traitement - 020 - Général" -#: forms_treatments.py:108 models_treatments.py:70 models_treatments.py:130 -#: templates/ishtar/sheet_find.html:181 templates/ishtar/sheet_find.html:219 +#: forms_treatments.py:99 models_treatments.py:83 models_treatments.py:145 +#: templates/ishtar/sheet_find.html:261 templates/ishtar/sheet_find.html:298 +#: templates/ishtar/sheet_find.html:336 msgid "State" msgstr "État" -#: forms_treatments.py:110 -msgid "Target" -msgstr "Destination" +#: forms_treatments.py:105 models_treatments.py:151 models_treatments.py:598 +msgid "Location" +msgstr "Localisation" -#: forms_treatments.py:112 forms_treatments.py:301 forms_treatments.py:561 -#: models_treatments.py:71 models_treatments.py:138 +#: forms_treatments.py:111 forms_treatments.py:369 forms_treatments.py:635 +#: models_treatments.py:84 models_treatments.py:156 msgid "Responsible" msgstr "Responsable" -#: forms_treatments.py:118 forms_treatments.py:307 models_treatments.py:141 +#: forms_treatments.py:117 forms_treatments.py:375 models_treatments.py:159 msgid "Organization" msgstr "Organisation" -#: forms_treatments.py:124 models_treatments.py:133 models_treatments.py:362 -msgid "Location" -msgstr "Localisation" - -#: forms_treatments.py:130 -msgid "Container (relevant for packaging)" -msgstr "Contenant (pertinent dans le cadre du conditionnement)" +#: forms_treatments.py:130 forms_treatments.py:442 forms_treatments.py:665 +#: forms_treatments.py:718 models_treatments.py:167 models_treatments.py:841 +msgid "Closing date" +msgstr "Date de clôture" -#: forms_treatments.py:136 forms_treatments.py:557 -msgid "External ref." -msgstr "Référence" +#: forms_treatments.py:133 +msgid "Destination container (relevant for treatment that change location)" +msgstr "" +"Contenant de destination (pertinent pour des traitements changeant la " +"localisation)" -#: forms_treatments.py:137 models_treatments.py:147 +#: forms_treatments.py:139 models_treatments.py:165 msgid "Goal" msgstr "But" -#: forms_treatments.py:145 forms_treatments.py:370 forms_treatments.py:586 -#: forms_treatments.py:639 models_treatments.py:149 models_treatments.py:603 -msgid "Closing date" -msgstr "Date de clôture" - -#: forms_treatments.py:147 +#: forms_treatments.py:145 #, python-brace-format msgid "Estimated cost ({currency})" msgstr "Coût estimé ({currency})" -#: forms_treatments.py:149 +#: forms_treatments.py:147 #, python-brace-format msgid "Quoted cost ({currency})" msgstr "Coût devisé ({currency})" -#: forms_treatments.py:151 +#: forms_treatments.py:149 #, python-brace-format msgid "Realized cost ({currency})" msgstr "Coût réalisé ({currency})" -#: forms_treatments.py:153 +#: forms_treatments.py:151 #, python-brace-format msgid "Insurance cost ({currency})" msgstr "Coût d''assurance ({currency})" -#: forms_treatments.py:180 -msgid "Single find" -msgstr "Mobilier isolé" +#: forms_treatments.py:212 +msgid "Unknow treatment type" +msgstr "Type de traitement inconnu" + +#: forms_treatments.py:233 forms_treatments.py:242 +msgid "{} is not compatible with {} treatment(s)." +msgstr "{} n'est pas compatible avec le(s) traitement(s) {}." -#: forms_treatments.py:204 +#: forms_treatments.py:253 msgid "" -"The container field is attached to the treatment. If no packaging treatment " -"is done it is not relevant." +"The container field is attached to the treatment but no treatment with " +"container change is defined." msgstr "" -"Le champ concernant le contenant est rattaché au traitement. Si aucun " -"conditionnement n'est réalisé, il n'est pas pertinent." +"Le champ concernant le contenant est rattaché au traitement mais aucun " +"traitement changeant le contenant n'est sélectionné." -#: forms_treatments.py:209 -msgid "If a packaging treatment is done, the container field must be filled." +#: forms_treatments.py:258 +msgid "" +"A treatment with location change is defined, the container field must be " +"filled." msgstr "" -"Si un conditionnement est fait, le champ du contenant doit être rempli." +"Un traitement avec un changement de localisation est défini, le champ " +"contenant doit être rempli." -#: forms_treatments.py:213 +#: forms_treatments.py:262 msgid "A responsible or an organization must be defined." msgstr "Un responsable ou une organisation doit être défini." -#: forms_treatments.py:256 +#: forms_treatments.py:267 +msgid "Treatment n-1 - 020 - General" +msgstr "Traitement n-1 - 020 - Général" + +#: forms_treatments.py:281 +msgid "Treatment 1-n - 020 - General" +msgstr "Traitement 1-n - 020 - Général" + +#: forms_treatments.py:319 msgid "Another treatment with this index exists for {}." msgstr "Un autre traitement avec cet index existe pour {}." -#: forms_treatments.py:262 models_treatments.py:126 +#: forms_treatments.py:325 models_treatments.py:141 msgid "Associated request" msgstr "Demande associée" -#: forms_treatments.py:263 +#: forms_treatments.py:326 msgid "Treatment - 010 - Request choice" msgstr "Traitement - 010 - Choix de la demande de traitement" -#: forms_treatments.py:268 forms_treatments.py:541 ishtar_menu.py:95 -#: models_treatments.py:618 models_treatments.py:646 -#: templates/ishtar/sheet_treatmentfile.html:4 wizards.py:207 +#: forms_treatments.py:331 forms_treatments.py:613 ishtar_menu.py:95 +#: models_treatments.py:860 models_treatments.py:882 +#: templates/ishtar/sheet_treatmentfile.html:4 wizards.py:465 msgid "Treatment request" msgstr "Demande de traitement" -#: forms_treatments.py:277 +#: forms_treatments.py:340 msgid "" "Are you sure you want to delete this treatment? All changes made to the " "associated finds since this treatment record will be lost!" @@ -698,190 +789,212 @@ msgstr "" "sur le mobilier associé réalisées depuis l'enregistrement de ce traitement " "seront perdues !" -#: forms_treatments.py:280 +#: forms_treatments.py:343 msgid "Would you like to delete this treatment?" msgstr "Voulez-vous supprimer ce traitement ?" -#: forms_treatments.py:285 models_finds.py:683 models_finds.py:1000 -#: models_treatments.py:150 models_treatments.py:363 -#: templates/ishtar/sheet_find.html:184 templates/ishtar/sheet_find.html:222 +#: forms_treatments.py:348 models_finds.py:1092 models_treatments.py:169 +#: models_treatments.py:599 templates/ishtar/sheet_find.html:264 +#: templates/ishtar/sheet_find.html:301 templates/ishtar/sheet_find.html:339 msgid "Container" msgstr "Contenant" -#: forms_treatments.py:291 +#: forms_treatments.py:354 templates/ishtar/forms/qa_find_treatment.html:31 +msgid "Change the reference container" +msgstr "Changer le contenant de référence" + +#: forms_treatments.py:356 +msgid "If unchecked the current container will be changed" +msgstr "Si c'est décoché, le contenant actuel va être changé" + +#: forms_treatments.py:359 msgid "Create a treatment" msgstr "Créer un traitement" -#: forms_treatments.py:298 +#: forms_treatments.py:366 msgid "Precise date" msgstr "Date précise" -#: forms_treatments.py:340 +#: forms_treatments.py:408 msgid "At least a year is required." msgstr "Au minimum une année doit être précisée." -#: forms_treatments.py:369 +#: forms_treatments.py:416 models_finds.py:1022 models_finds.py:1304 +#: templates/ishtar/forms/qa_find_treatment.html:16 views.py:844 +msgid "Packaging" +msgstr "Conditionnement" + +#: forms_treatments.py:441 msgid "months" msgstr "mois" -#: forms_treatments.py:369 +#: forms_treatments.py:441 msgid "years" msgstr "années" -#: forms_treatments.py:374 forms_treatments.py:643 +#: forms_treatments.py:446 forms_treatments.py:722 msgid "Slicing" msgstr "Découpage" -#: forms_treatments.py:377 forms_treatments.py:646 +#: forms_treatments.py:449 forms_treatments.py:725 msgid "Date get from" msgstr "Date utilisée" -#: forms_treatments.py:380 forms_treatments.py:649 +#: forms_treatments.py:452 forms_treatments.py:728 msgid "Date after" msgstr "Date après" -#: forms_treatments.py:382 forms_treatments.py:651 +#: forms_treatments.py:454 forms_treatments.py:730 msgid "Date before" msgstr "Date avant" -#: forms_treatments.py:425 forms_treatments.py:475 forms_treatments.py:692 -#: forms_treatments.py:747 +#: forms_treatments.py:497 forms_treatments.py:547 forms_treatments.py:771 +#: forms_treatments.py:826 msgid "Act type" msgstr "Type d'acte" -#: forms_treatments.py:426 forms_treatments.py:693 +#: forms_treatments.py:498 forms_treatments.py:772 msgid "Indexed?" msgstr "Indexé ?" -#: forms_treatments.py:427 forms_treatments.py:694 +#: forms_treatments.py:499 forms_treatments.py:773 msgid "Object" msgstr "Objet" -#: forms_treatments.py:431 forms_treatments.py:698 +#: forms_treatments.py:503 forms_treatments.py:777 msgid "Signature date after" msgstr "Date de signature après" -#: forms_treatments.py:433 forms_treatments.py:700 +#: forms_treatments.py:505 forms_treatments.py:779 msgid "Signature date before" msgstr "Date de signature avant" -#: forms_treatments.py:435 +#: forms_treatments.py:507 msgid "Treatment name" msgstr "Nom du traitement" -#: forms_treatments.py:436 +#: forms_treatments.py:508 msgid "Treatment year" msgstr "Année du traitement" -#: forms_treatments.py:437 +#: forms_treatments.py:509 msgid "Treatment index" msgstr "Index du traitement" -#: forms_treatments.py:439 +#: forms_treatments.py:511 msgid "Treatment internal reference" msgstr "Référence interne du traitement" -#: forms_treatments.py:443 forms_treatments.py:714 +#: forms_treatments.py:515 forms_treatments.py:793 msgid "Modified by" msgstr "Modifié par" -#: forms_treatments.py:473 +#: forms_treatments.py:545 msgid "Treatment - Administrative act - General" msgstr "Traitement - Acte administratif - Général" -#: forms_treatments.py:496 forms_treatments.py:548 models_treatments.py:588 +#: forms_treatments.py:568 forms_treatments.py:622 models_treatments.py:826 msgid "Name" msgstr "Nom" -#: forms_treatments.py:497 forms_treatments.py:555 +#: forms_treatments.py:569 forms_treatments.py:629 msgid "Internal ref." msgstr "Réf. interne" -#: forms_treatments.py:500 forms_treatments.py:559 models_treatments.py:69 -#: templates/ishtar/sheet_find.html:180 templates/ishtar/sheet_find.html:218 +#: forms_treatments.py:572 forms_treatments.py:633 models_treatments.py:82 +#: templates/ishtar/sheet_find.html:260 templates/ishtar/sheet_find.html:297 +#: templates/ishtar/sheet_find.html:335 msgid "Type" msgstr "Type" -#: forms_treatments.py:503 +#: forms_treatments.py:575 msgid "In charge" msgstr "Responsable" -#: forms_treatments.py:509 forms_treatments.py:567 models_treatments.py:597 -#: templates/ishtar/sheet_treatmentfile.html:45 +#: forms_treatments.py:581 forms_treatments.py:641 models_treatments.py:835 +#: templates/ishtar/sheet_treatmentfile.html:46 msgid "Applicant" msgstr "Demandeur" -#: forms_treatments.py:515 forms_treatments.py:573 models_treatments.py:601 -#: templates/ishtar/sheet_treatmentfile.html:53 +#: forms_treatments.py:587 forms_treatments.py:647 models_treatments.py:839 +#: templates/ishtar/sheet_treatmentfile.html:54 msgid "Applicant organisation" msgstr "Organisation du demandeur" -#: forms_treatments.py:529 views.py:524 +#: forms_treatments.py:601 views.py:681 msgid "Treatment request search" msgstr "Rechercher une demande de traitement" -#: forms_treatments.py:584 forms_treatments.py:638 models_treatments.py:607 +#: forms_treatments.py:631 +msgid "External ref." +msgstr "Référence" + +#: forms_treatments.py:653 +msgid "Associated basket" +msgstr "Panier associé" + +#: forms_treatments.py:663 forms_treatments.py:717 models_treatments.py:845 msgid "Reception date" msgstr "Date de réception" -#: forms_treatments.py:626 +#: forms_treatments.py:705 msgid "Another treatment request with this index exists for {}." msgstr "Une autre demande de traitement avec cet index existe pour {}." -#: forms_treatments.py:632 +#: forms_treatments.py:711 msgid "Are you sure you want to delete this treatment request?" msgstr "Êtes-vous sûr de vouloir supprimer cette demande de traitement ? " -#: forms_treatments.py:633 +#: forms_treatments.py:712 msgid "Would you like to delete this treatment request?" msgstr "Voulez-vous supprimer cette demande de traitement ?" -#: forms_treatments.py:637 models_treatments.py:605 +#: forms_treatments.py:716 models_treatments.py:843 msgid "Creation date" msgstr "Date de création" -#: forms_treatments.py:647 forms_treatments.py:711 models_treatments.py:519 -#: models_treatments.py:590 +#: forms_treatments.py:726 forms_treatments.py:790 models_treatments.py:757 +#: models_treatments.py:828 msgid "Treatment request type" msgstr "Type de demande de traitement" -#: forms_treatments.py:703 +#: forms_treatments.py:782 msgid "Treatment request name" msgstr "Nom du dossier de traitement" -#: forms_treatments.py:705 +#: forms_treatments.py:784 msgid "Treatment request year" msgstr "Année du dossier de traitement" -#: forms_treatments.py:707 +#: forms_treatments.py:786 msgid "Treatment request index" msgstr "Index de la demande de traitement" -#: forms_treatments.py:709 +#: forms_treatments.py:788 msgid "Treatment request internal reference" msgstr "Référence interne de la demande de traitement" -#: forms_treatments.py:745 +#: forms_treatments.py:824 msgid "Treatment request - Administrative act - General" msgstr "Demande de traitement - Acte administratif - Général" #: ishtar_menu.py:37 ishtar_menu.py:60 ishtar_menu.py:100 ishtar_menu.py:123 -#: ishtar_menu.py:155 ishtar_menu.py:179 +#: ishtar_menu.py:148 ishtar_menu.py:181 msgid "Search" msgstr "Recherche" #: ishtar_menu.py:42 ishtar_menu.py:65 ishtar_menu.py:105 ishtar_menu.py:127 -#: ishtar_menu.py:160 ishtar_menu.py:183 +#: ishtar_menu.py:185 msgid "Creation" msgstr "Ajout" #: ishtar_menu.py:47 ishtar_menu.py:70 ishtar_menu.py:110 ishtar_menu.py:131 -#: ishtar_menu.py:165 ishtar_menu.py:188 +#: ishtar_menu.py:168 ishtar_menu.py:190 msgid "Modification" msgstr "Modification" #: ishtar_menu.py:52 ishtar_menu.py:82 ishtar_menu.py:115 ishtar_menu.py:134 -#: ishtar_menu.py:170 ishtar_menu.py:191 +#: ishtar_menu.py:173 ishtar_menu.py:193 msgid "Deletion" msgstr "Suppression" @@ -889,23 +1002,21 @@ msgstr "Suppression" msgid "Manage items" msgstr "Gestion des éléments" -#: ishtar_menu.py:120 ishtar_menu.py:176 models_finds.py:1719 +#: ishtar_menu.py:120 ishtar_menu.py:178 models_finds.py:1961 msgid "Administrative act" msgstr "Acte administratif" -#: ishtar_menu.py:138 ishtar_menu.py:195 models_finds.py:1081 -#: models_treatments.py:163 models_treatments.py:611 -msgid "Documents" -msgstr "Documents" +#: ishtar_menu.py:154 +msgid "Simple treatment - creation" +msgstr "Traitement simple - création" -#: ishtar_menu.py:147 models_treatments.py:170 models_treatments.py:351 -#: templates/ishtar/sheet_treatment.html:4 -msgid "Treatment" -msgstr "Traitement" +#: ishtar_menu.py:159 +msgid "Treatment many to one - creation" +msgstr "Traitement de plusieurs à un - création" -#: ishtar_menu.py:152 -msgid "Simple treatments" -msgstr "Traitements simples" +#: ishtar_menu.py:164 +msgid "Treatment one to many - creation" +msgstr "Traitement de un à plusieurs - création" #: models_finds.py:51 msgid "Code" @@ -915,9 +1026,9 @@ msgstr "Code" msgid "Recommendation" msgstr "Recommandation" -#: models_finds.py:66 models_finds.py:79 models_finds.py:92 models_finds.py:138 -#: models_finds.py:161 models_finds.py:218 models_finds.py:967 -#: models_treatments.py:355 +#: models_finds.py:66 models_finds.py:79 models_finds.py:92 models_finds.py:153 +#: models_finds.py:176 models_finds.py:233 models_finds.py:1059 +#: models_treatments.py:45 models_treatments.py:591 msgid "Order" msgstr "Ordre" @@ -941,581 +1052,712 @@ msgstr "Types d'état de conservation" msgid "Virtual" msgstr "Virtuel" -#: models_finds.py:95 +#: models_finds.py:94 +msgid "Destructive" +msgstr "Destructif" + +#: models_finds.py:96 +msgid "Create a new find" +msgstr "Créer un nouvel élément" + +#: models_finds.py:97 +msgid "" +"If True when this treatment is applied a new version of the object will be " +"created." +msgstr "" +"Si mis à Vrai quand le traitement est appliqué une nouvelle version de " +"l'objet sera créée." + +#: models_finds.py:100 msgid "Upstream is many" msgstr "Les éléments amont sont multiples" -#: models_finds.py:97 +#: models_finds.py:102 msgid "Check this if for this treatment from many finds you'll get one." msgstr "" "Cochez cela si, pour ce traitement, à partir de plusieurs éléments vous en " "obtenez un seul." -#: models_finds.py:100 +#: models_finds.py:105 msgid "Downstream is many" msgstr "Les éléments aval sont multiples" -#: models_finds.py:102 +#: models_finds.py:107 msgid "Check this if for this treatment from one find you'll get many." msgstr "" "Cochez cela si, pour ce traitement, à partir d'un seul élément vous en " "obtenez plusieurs." -#: models_finds.py:107 models_treatments.py:240 +#: models_finds.py:110 +msgid "Change reference location" +msgstr "Change la localisation de référence" + +#: models_finds.py:111 +msgid "The treatment change the reference location." +msgstr "Le traitement change la localisation de référence." + +#: models_finds.py:113 +msgid "Change current location" +msgstr "Change la localisation actuelle" + +#: models_finds.py:114 +msgid "The treatment change the current location." +msgstr "Le traitement change la localisation actuelle." + +#: models_finds.py:116 +msgid "Restore the reference location" +msgstr "Restaure la localisation de référence" + +#: models_finds.py:117 +msgid "" +"The treatment change restore reference location to the current location." +msgstr "" +"Le traitement restaure la localisation de référence sur la localisation " +"actuelle." + +#: models_finds.py:122 models_treatments.py:262 msgid "Treatment types" msgstr "Types de traitement" -#: models_finds.py:117 +#: models_finds.py:132 msgid "Integrity / interest type" msgstr "Type d'intégrité / intérêt" -#: models_finds.py:118 +#: models_finds.py:133 msgid "Integrity / interest types" msgstr "Types d'intégrité / intérêt" -#: models_finds.py:128 +#: models_finds.py:143 msgid "Remarkability type" msgstr "Type de remarquabilité" -#: models_finds.py:129 +#: models_finds.py:144 msgid "Remarkability types" msgstr "Types de remarquabilité" -#: models_finds.py:140 +#: models_finds.py:155 msgid "Batch type" msgstr "Type de lot" -#: models_finds.py:141 +#: models_finds.py:156 msgid "Batch types" msgstr "Types de lot" -#: models_finds.py:164 +#: models_finds.py:179 msgid "Object type quality type" msgstr "Type de qualité du type d'objet" -#: models_finds.py:165 +#: models_finds.py:180 msgid "Object type quality types" msgstr "Types de qualité du type d'objet" -#: models_finds.py:175 +#: models_finds.py:190 msgid "Alteration type" msgstr "Type d'altération" -#: models_finds.py:176 +#: models_finds.py:191 msgid "Alteration types" msgstr "Types d'altération" -#: models_finds.py:186 +#: models_finds.py:201 msgid "Alteration cause type" msgstr "Type de cause d'altération" -#: models_finds.py:187 +#: models_finds.py:202 msgid "Alteration cause types" msgstr "Types de cause d'altération" -#: models_finds.py:197 +#: models_finds.py:212 msgid "Treatment emergency type" msgstr "Type d'urgence du traitement" -#: models_finds.py:198 +#: models_finds.py:213 msgid "Treatment emergency types" msgstr "Types d'urgence du traitement" -#: models_finds.py:208 +#: models_finds.py:223 msgid "Communicability type" msgstr "Type de communicabilité" -#: models_finds.py:209 +#: models_finds.py:224 msgid "Communicability types" msgstr "Types de communicabilité" -#: models_finds.py:221 +#: models_finds.py:236 msgid "Checked type" msgstr "Type de vérification" -#: models_finds.py:222 +#: models_finds.py:237 msgid "Checked types" msgstr "Types de vérification" -#: models_finds.py:254 models_finds.py:960 models_treatments.py:143 -#: models_treatments.py:586 +#: models_finds.py:269 models_finds.py:1052 models_treatments.py:161 +#: models_treatments.py:824 msgid "External ID" msgstr "Identifiant" -#: models_finds.py:256 models_finds.py:962 +#: models_finds.py:271 models_finds.py:1054 msgid "External ID is set automatically" msgstr "L'identifiant est attribué automatiquement" -#: models_finds.py:260 +#: models_finds.py:275 msgid "Special interest" msgstr "Intérêt spécifique" -#: models_finds.py:264 +#: models_finds.py:279 msgid "Context Record" msgstr "Unité d'Enregistrement" -#: models_finds.py:272 +#: models_finds.py:287 msgid "Material index" msgstr "Index matériel" -#: models_finds.py:289 +#: models_finds.py:304 msgid "Point (3D)" msgstr "Point (3D)" -#: models_finds.py:295 models_finds.py:298 +#: models_finds.py:310 models_finds.py:313 msgid "Cached value - do not edit" msgstr "Valeur en cache - ne pas éditer" -#: models_finds.py:308 models_finds.py:958 +#: models_finds.py:323 models_finds.py:1050 msgid "Base find" msgstr "Mobilier d'origine" -#: models_finds.py:309 +#: models_finds.py:324 msgid "Base finds" msgstr "Mobilier d'origine" -#: models_finds.py:565 +#: models_finds.py:589 msgid "g" msgstr "g" -#: models_finds.py:566 +#: models_finds.py:590 msgid "kg" msgstr "kg" -#: models_finds.py:592 views.py:301 +#: models_finds.py:600 views.py:863 views.py:882 +msgid "Duplicate" +msgstr "Dupliquer" + +#: models_finds.py:626 views.py:379 msgid "Manage basket" msgstr "Gérer un panier" -#: models_finds.py:661 +#: models_finds.py:633 models_finds.py:1299 +msgid "Add treatment" +msgstr "Ajouter un traitement" + +#: models_finds.py:723 msgid "Base find - Short ID" msgstr "Mobilier d'origine - ID court" -#: models_finds.py:662 +#: models_finds.py:724 msgid "Base find - Complete ID" msgstr "Mobilier d'origine - ID complet" -#: models_finds.py:664 +#: models_finds.py:726 msgid "Operation (code)" msgstr "Opération (code)" -#: models_finds.py:666 +#: models_finds.py:728 msgid "Town" msgstr "Ville" -#: models_finds.py:668 +#: models_finds.py:730 msgid "Operation (name)" msgstr "Opération (nom)" -#: models_finds.py:672 +#: models_finds.py:734 msgid "Parcel" msgstr "Parcelle" -#: models_finds.py:673 +#: models_finds.py:735 msgid "Batch" msgstr "Lot" -#: models_finds.py:674 +#: models_finds.py:736 msgid "Base find - Comment" msgstr "Mobilier d'origine - Commentaires" -#: models_finds.py:675 +#: models_finds.py:737 msgid "Base find - Description" msgstr "Mobilier d'origine - Description" -#: models_finds.py:676 +#: models_finds.py:738 msgid "Base find - Topographic localisation" msgstr "Mobilier d'origine - Localisation topographique" -#: models_finds.py:678 +#: models_finds.py:740 msgid "Base find - Special interest" msgstr "Mobilier d'origine - Intérêt spécifique" -#: models_finds.py:680 +#: models_finds.py:742 msgid "Base find - Discovery date (exact or TPQ)" msgstr "Mobilier d'origine - Date de découverte (exacte ou TPQ)" -#: models_finds.py:682 +#: models_finds.py:744 msgid "Base find - Discovery date (TAQ)" msgstr "Mobilier d'origine - Date de découverte (TAQ)" -#: models_finds.py:684 +#: models_finds.py:745 +msgid "Current container" +msgstr "Contenant actuel" + +#: models_finds.py:746 models_finds.py:1097 +msgid "Reference container" +msgstr "Contenant de référence" + +#: models_finds.py:747 msgid "Periods" msgstr "Périodes" -#: models_finds.py:760 +#: models_finds.py:823 msgctxt "key for text search" msgid "short-id" msgstr "id-court" -#: models_finds.py:764 +#: models_finds.py:827 msgctxt "key for text search" msgid "complete-id" msgstr "id-complet" -#: models_finds.py:768 +#: models_finds.py:831 msgctxt "key for text search" msgid "free-id" msgstr "id-libre" -#: models_finds.py:772 +#: models_finds.py:835 msgctxt "key for text search" msgid "denomination" msgstr "denomination" -#: models_finds.py:776 +#: models_finds.py:839 msgctxt "key for text search" msgid "town" msgstr "commune" -#: models_finds.py:780 models_treatments.py:87 models_treatments.py:551 +#: models_finds.py:843 models_treatments.py:102 models_treatments.py:789 msgctxt "key for text search" msgid "year" msgstr "annee" -#: models_finds.py:784 +#: models_finds.py:847 msgctxt "key for text search" msgid "operation-code" msgstr "operation-code" -#: models_finds.py:788 +#: models_finds.py:851 msgctxt "key for text search" msgid "code-patriarche" msgstr "code-patriarche" -#: models_finds.py:792 +#: models_finds.py:855 msgctxt "key for text search" msgid "operation-type" msgstr "operation-type" -#: models_finds.py:797 +#: models_finds.py:860 msgctxt "key for text search" msgid "area" msgstr "zone" -#: models_finds.py:801 +#: models_finds.py:864 msgctxt "key for text search" msgid "site" msgstr "site" -#: models_finds.py:806 models_finds.py:945 +#: models_finds.py:869 models_finds.py:1037 msgctxt "key for text search" msgid "context-record-site" msgstr "ue-site" -#: models_finds.py:811 models_finds.py:939 +#: models_finds.py:874 models_finds.py:1031 msgctxt "key for text search" msgid "context-record" msgstr "ue" -#: models_finds.py:815 +#: models_finds.py:878 msgctxt "key for text search" msgid "operation-relation-type" msgstr "operation-type-relation" -#: models_finds.py:819 +#: models_finds.py:882 msgctxt "key for text search" msgid "context-record-relation-type" msgstr "ue-type-relation" -#: models_finds.py:823 +#: models_finds.py:886 msgctxt "key for text search" msgid "period" msgstr "periode" -#: models_finds.py:827 +#: models_finds.py:890 msgctxt "key for text search" msgid "material" msgstr "materiau" -#: models_finds.py:831 +#: models_finds.py:894 msgctxt "key for text search" msgid "object-type" msgstr "type-objet" -#: models_finds.py:835 +#: models_finds.py:898 msgctxt "key for text search" msgid "preservation" msgstr "preservation" -#: models_finds.py:839 +#: models_finds.py:902 msgctxt "key for text search" msgid "conservatory" msgstr "conservation" -#: models_finds.py:843 +#: models_finds.py:906 msgctxt "key for text search" msgid "integrity" msgstr "integrite" -#: models_finds.py:847 +#: models_finds.py:910 msgctxt "key for text search" msgid "remarkability" msgstr "remarquabilite" -#: models_finds.py:851 +#: models_finds.py:914 msgctxt "key for text search" msgid "description" msgstr "description" -#: models_finds.py:855 +#: models_finds.py:918 msgctxt "key for text search" msgid "batch" msgstr "lot" -#: models_finds.py:859 +#: models_finds.py:922 msgctxt "key for text search" msgid "checked" msgstr "verifie" -#: models_finds.py:863 models_treatments.py:95 +#: models_finds.py:926 models_treatments.py:110 msgctxt "key for text search" msgid "has-image" msgstr "a-une-image" -#: models_finds.py:867 models_finds.py:942 +#: models_finds.py:930 models_finds.py:1034 msgctxt "key for text search" msgid "location" msgstr "localisation" -#: models_finds.py:871 +#: models_finds.py:934 msgctxt "key for text search" msgid "warehouse" msgstr "depot" -#: models_finds.py:875 +#: models_finds.py:938 msgctxt "key for text search" msgid "container-index" msgstr "contenant-index" -#: models_finds.py:879 +#: models_finds.py:942 msgctxt "key for text search" msgid "container-ref" msgstr "contenant-ref" -#: models_finds.py:883 +#: models_finds.py:946 +msgctxt "key for text search" +msgid "current-location" +msgstr "localisation-actuelle" + +#: models_finds.py:950 +msgctxt "key for text search" +msgid "current-warehouse" +msgstr "depot-actuel" + +#: models_finds.py:954 +msgctxt "key for text search" +msgid "current-container-index" +msgstr "contenant-actuel-index" + +#: models_finds.py:958 +msgctxt "key for text search" +msgid "current-container-ref" +msgstr "contenant-actuel-ref" + +#: models_finds.py:962 wizards.py:399 msgctxt "key for text search" msgid "basket" msgstr "panier" -#: models_finds.py:887 models_finds.py:936 +#: models_finds.py:966 models_finds.py:1028 msgctxt "key for text search" msgid "operation" msgstr "operation" -#: models_finds.py:891 +#: models_finds.py:970 msgctxt "key for text search" msgid "last-modified-by" msgstr "modifie-en-dernier-par" -#: models_finds.py:895 +#: models_finds.py:974 msgctxt "key for text search" msgid "modified-since" msgstr "modifie-depuis" -#: models_finds.py:919 -msgid "Bulk update" -msgstr "Mise à jour multiple" +#: models_finds.py:978 +msgctxt "key for text search" +msgid "created-by" +msgstr "cree-par" -#: models_finds.py:930 models_finds.py:1180 -#: templates/ishtar/forms/qa_find_treatment.html:16 views.py:666 -msgid "Packaging" -msgstr "Conditionnement" +#: models_finds.py:982 +msgctxt "key for text search" +msgid "loan" +msgstr "pret" #: models_finds.py:986 +msgctxt "key for text search" +msgid "treatment-end-date-before" +msgstr "fin-de-traitement-avant" + +#: models_finds.py:1011 +msgid "Bulk update" +msgstr "Mise à jour multiple" + +#: models_finds.py:1078 msgid "Weight" msgstr "Poids" -#: models_finds.py:987 +#: models_finds.py:1079 msgid "Weight unit" msgstr "Unité de poids" -#: models_finds.py:993 templates/ishtar/sheet_find.html:174 +#: models_finds.py:1085 templates/ishtar/sheet_find.html:291 msgid "Upstream treatment" msgstr "Traitement amont" -#: models_finds.py:996 templates/ishtar/sheet_find.html:212 +#: models_finds.py:1088 templates/ishtar/sheet_find.html:329 msgid "Downstream treatment" msgstr "Traitement aval" -#: models_finds.py:1031 +#: models_finds.py:1130 msgid "Clutter - long side (cm)" msgstr "Encombrement - grand côté (cm)" -#: models_finds.py:1033 +#: models_finds.py:1132 msgid "Clutter - short side (cm)" msgstr "Encombrement - petit côté (cm)" -#: models_finds.py:1035 +#: models_finds.py:1134 msgid "Clutter - height (cm)" msgstr "Encombrement - hauteur (cm)" -#: models_finds.py:1051 +#: models_finds.py:1150 msgid "Collection" msgstr "Collection" -#: models_finds.py:1083 models_treatments.py:165 models_treatments.py:613 +#: models_finds.py:1180 models_treatments.py:180 models_treatments.py:849 +#: templates/ishtar/sheet_find.html:56 templates/ishtar/sheet_treatment.html:32 +msgid "Documents" +msgstr "Documents" + +#: models_finds.py:1183 models_treatments.py:188 +#: templates/ishtar/sheet_find.html:254 +#: templates/ishtar/sheet_treatmentfile.html:62 +msgid "Treatments" +msgstr "Traitements" + +#: models_finds.py:1185 +msgid "Related treatments when no new find is created" +msgstr "" +"Traitements associés quand il n'y a pas de création de nouveau mobilier" + +#: models_finds.py:1186 models_treatments.py:182 models_treatments.py:855 msgid "Cached name" msgstr "Nom en cache" -#: models_finds.py:1105 +#: models_finds.py:1208 msgid "FIND" msgstr "MOBILIER" -#: models_finds.py:1174 +#: models_finds.py:1296 msgid "Add to basket" msgstr "Ajouter au panier" -#: models_finds.py:1222 wizards.py:74 wizards.py:219 +#: models_finds.py:1346 wizards.py:85 wizards.py:477 msgid "Operation" msgstr "Opération (OA)" -#: models_finds.py:1544 +#: models_finds.py:1738 +msgid "No reference container have been set - the localisation cannot be set." +msgstr "" +"Aucun contenant de référence n'a été défini - la localisation ne peut être " +"paramétrée." + +#: models_finds.py:1742 msgid "No container have been set - the localisation cannot be set." msgstr "" "Aucun contenant n'a été défini - la localisation ne peut être définie." -#: models_finds.py:1550 +#: models_finds.py:1748 msgid "The division number {} have not been set for the warehouse {}." msgstr "" "La division numéro {} n'a pas été définie pour le lieu de conservation {}." -#: models_finds.py:1720 +#: models_finds.py:1962 msgid "Person" msgstr "Individu" -#: models_finds.py:1726 +#: models_finds.py:1968 msgid "Property" msgstr "Propriété" -#: models_finds.py:1727 +#: models_finds.py:1969 msgid "Properties" msgstr "Propriétés" -#: models_treatments.py:42 +#: models_treatments.py:44 +msgid "Treatment is executed" +msgstr "Le traitement est réalisé" + +#: models_treatments.py:48 msgid "Treatment state type" msgstr "Type d'état de traitement" -#: models_treatments.py:43 +#: models_treatments.py:49 msgid "Treatment state types" msgstr "Types d'état de traitement" -#: models_treatments.py:67 +#: models_treatments.py:80 msgid "Downstream find" msgstr "Mobilier aval" -#: models_treatments.py:79 +#: models_treatments.py:81 +msgid "Upstream find" +msgstr "Mobilier amont" + +#: models_treatments.py:94 msgctxt "key for text search" msgid "label" msgstr "libelle" -#: models_treatments.py:83 +#: models_treatments.py:98 msgctxt "key for text search" msgid "other-reference" msgstr "autre-reference" -#: models_treatments.py:91 models_treatments.py:555 +#: models_treatments.py:106 models_treatments.py:793 msgctxt "key for text search" msgid "index" msgstr "index" -#: models_treatments.py:99 models_treatments.py:559 +#: models_treatments.py:114 models_treatments.py:797 msgctxt "key for text search" msgid "type" msgstr "type" -#: models_treatments.py:135 +#: models_treatments.py:149 +msgid "Treatment have been executed" +msgstr "Le traitement a été réalisé" + +#: models_treatments.py:153 msgid "Location where the treatment is done. Target warehouse for a move." msgstr "" "Endroit où le traitement est réalisé. Renseignez le lieu de conservation de " "destination pour un déplacement." -#: models_treatments.py:152 +#: models_treatments.py:171 msgid "Estimated cost" msgstr "Coût estimé" -#: models_treatments.py:154 +#: models_treatments.py:173 msgid "Quoted cost" msgstr "Coût devisé" -#: models_treatments.py:156 +#: models_treatments.py:175 msgid "Realized cost" msgstr "Coût réalisé" -#: models_treatments.py:158 +#: models_treatments.py:177 msgid "Insurance cost" msgstr "Coût d'assurance" -#: models_treatments.py:160 -msgid "Target a basket" -msgstr "Appliquer à un panier" - -#: models_treatments.py:171 templates/ishtar/sheet_find.html:171 -#: templates/ishtar/sheet_treatmentfile.html:61 -msgid "Treatments" -msgstr "Traitements" - -#: models_treatments.py:190 +#: models_treatments.py:208 msgid "TREATMENT" msgstr "TRAITEMENT" -#: models_treatments.py:249 templates/ishtar/sheet_treatment.html:61 +#: models_treatments.py:271 templates/ishtar/sheet_treatment.html:107 msgid "Downstream finds" msgstr "Mobilier aval" -#: models_treatments.py:364 templates/ishtar/sheet_find.html:183 -#: templates/ishtar/sheet_find.html:221 +#: models_treatments.py:289 models_treatments.py:911 +msgid "Add associated administrative act" +msgstr "Ajouter un acte administratif associé" + +#: models_treatments.py:290 models_treatments.py:912 +msgid "admin. act" +msgstr "acte admin." + +#: models_treatments.py:600 templates/ishtar/sheet_find.html:263 +#: templates/ishtar/sheet_find.html:300 templates/ishtar/sheet_find.html:338 msgid "Doer" msgstr "Opérateur" -#: models_treatments.py:365 models_treatments.py:366 +#: models_treatments.py:601 models_treatments.py:602 +#: templates/ishtar/sheet_treatment.html:97 msgid "Related finds" msgstr "Mobilier associé" -#: models_treatments.py:508 +#: models_treatments.py:744 msgid "Is upstream" msgstr "Est en amont" -#: models_treatments.py:520 +#: models_treatments.py:758 msgid "Treatment request types" msgstr "Types de demande de traitement" -#: models_treatments.py:543 +#: models_treatments.py:781 msgctxt "key for text search" msgid "name" msgstr "nom" -#: models_treatments.py:547 +#: models_treatments.py:785 msgctxt "key for text search" msgid "reference" msgstr "reference" -#: models_treatments.py:563 +#: models_treatments.py:801 msgctxt "key for text search" msgid "in-charge" msgstr "responsable" -#: models_treatments.py:567 +#: models_treatments.py:805 msgctxt "key for text search" msgid "applicant" msgstr "demandeur" -#: models_treatments.py:571 +#: models_treatments.py:809 msgctxt "key for text search" msgid "applicant-organisation" msgstr "demandeur-organisation" -#: models_treatments.py:584 +#: models_treatments.py:822 msgid "Internal reference" msgstr "Référence interne" -#: models_treatments.py:593 +#: models_treatments.py:831 msgid "Person in charge" msgstr "Personne responsable" -#: models_treatments.py:619 +#: models_treatments.py:861 msgid "Treatment requests" msgstr "Demandes de traitement" +#: models_treatments.py:924 +msgid "Add associated treatment" +msgstr "Ajouter un traitement associé" + +#: templates/ishtar/blocks/window_find_nav.html:9 +msgid "Baskets" +msgstr "Paniers" + #: templates/ishtar/forms/qa_find_basket.html:22 msgid "New" msgstr "Nouveau" @@ -1524,49 +1766,56 @@ msgstr "Nouveau" msgid "Add" msgstr "Ajout" -#: templates/ishtar/forms/qa_find_treatment.html:31 +#: templates/ishtar/forms/qa_find_treatment.html:37 msgid "Associate a treatment" msgstr "Associer un traitement" -#: templates/ishtar/sheet_basefind.html:6 +#: templates/ishtar/forms/qa_findbasket_duplicate.html:6 +msgid "" +"Items of the basket will be attached to the new basket but not the shares." +msgstr "" +"Les éléments du panier vont être rattachés au nouveau panier mais pas les " +"partages." + +#: templates/ishtar/sheet_basefind.html:10 msgid "Internal ID" msgstr "ID interne" -#: templates/ishtar/sheet_basefind.html:21 +#: templates/ishtar/sheet_basefind.html:25 msgid "Discovery date" msgstr "Date de découverte" -#: templates/ishtar/sheet_basefind.html:24 +#: templates/ishtar/sheet_basefind.html:28 msgid "Discovery year" msgstr "Date de découverte" -#: templates/ishtar/sheet_basefind.html:27 +#: templates/ishtar/sheet_basefind.html:31 msgid "Discovery date (TPQ)" msgstr "Date de découverte (TPQ)" -#: templates/ishtar/sheet_basefind.html:52 +#: templates/ishtar/sheet_basefind.html:56 msgid "X:" msgstr "X :" -#: templates/ishtar/sheet_basefind.html:53 -#: templates/ishtar/sheet_basefind.html:55 #: templates/ishtar/sheet_basefind.html:57 +#: templates/ishtar/sheet_basefind.html:59 +#: templates/ishtar/sheet_basefind.html:61 msgid "error:" msgstr "erreur :" -#: templates/ishtar/sheet_basefind.html:54 +#: templates/ishtar/sheet_basefind.html:58 msgid "Y:" msgstr "Y :" -#: templates/ishtar/sheet_basefind.html:56 +#: templates/ishtar/sheet_basefind.html:60 msgid "Z:" msgstr "Z :" -#: templates/ishtar/sheet_basefind.html:60 +#: templates/ishtar/sheet_basefind.html:64 msgid "SRID" msgstr "SRID" -#: templates/ishtar/sheet_basefind.html:75 +#: templates/ishtar/sheet_basefind.html:79 msgid "Last modified by" msgstr "Modifié en dernier par" @@ -1578,65 +1827,86 @@ msgstr "" "Cette fiche a un traitement aval associé, elle concerne une vieille version " "de ce mobilier." -#: templates/ishtar/sheet_find.html:29 -msgid "Associated base finds" -msgstr "Mobilier d'origine associé" +#: templates/ishtar/sheet_find.html:23 +msgid "Image / Base find" +msgstr "Image / Mobilier d'origine" -#: templates/ishtar/sheet_find.html:53 +#: templates/ishtar/sheet_find.html:30 +msgid "Identification / Description / Dimensions" +msgstr "Identification / Description / Dimensions" + +#: templates/ishtar/sheet_find.html:38 +#, fuzzy +msgid "Datings / Preservation" +msgstr "Datations / Conservation" + +#: templates/ishtar/sheet_find.html:47 +msgid "Warehouse / Treatments" +msgstr "Lieu de conservation / Traitements" + +#: templates/ishtar/sheet_find.html:64 +msgid "Custom fields" +msgstr "Champs personnalisés" + +#: templates/ishtar/sheet_find.html:123 msgid "Administrative index" msgstr "Index administratif" -#: templates/ishtar/sheet_find.html:95 +#: templates/ishtar/sheet_find.html:166 msgid "Checked" msgstr "Vérifié" -#: templates/ishtar/sheet_find.html:160 -msgid "Warehouse" -msgstr "Lieu de conservation" +#: templates/ishtar/sheet_find.html:233 +msgid "Warehouse - reference container" +msgstr "Lieu de conservation - Contenant de référence" + +#: templates/ishtar/sheet_find.html:243 +msgid "Warehouse - current container" +msgstr "Lieu de conservation - Contenant actuel" -#: templates/ishtar/sheet_find.html:178 templates/ishtar/sheet_find.html:216 +#: templates/ishtar/sheet_find.html:258 templates/ishtar/sheet_find.html:295 +#: templates/ishtar/sheet_find.html:333 msgid "Year - index" msgstr "Année - index" -#: templates/ishtar/sheet_find.html:182 templates/ishtar/sheet_find.html:220 +#: templates/ishtar/sheet_find.html:262 templates/ishtar/sheet_find.html:299 +#: templates/ishtar/sheet_find.html:337 msgid "Related finds (max. 15 displayed)" msgstr "Mobilier associé (max. 15 affichés)" -#: templates/ishtar/sheet_find.html:208 +#: templates/ishtar/sheet_find.html:325 msgid "Export as CSV" msgstr "Export en CSV" -#: templates/ishtar/sheet_find.html:208 templates/ishtar/sheet_find.html:247 +#: templates/ishtar/sheet_find.html:325 templates/ishtar/sheet_find.html:364 msgid "CSV" msgstr "CSV" -#: templates/ishtar/sheet_find.html:252 +#: templates/ishtar/sheet_find.html:371 +#: templates/ishtar/sheet_treatment.html:124 msgid "Associated documents" msgstr "Documents associés" -#: templates/ishtar/sheet_findbasket.html:19 +#: templates/ishtar/sheet_findbasket.html:20 msgid "Content" msgstr "Contenu" -#: templates/ishtar/sheet_treatment.html:25 +#: templates/ishtar/sheet_treatment.html:41 +#: templates/ishtar/sheet_treatment.html:132 +#: templates/ishtar/sheet_treatmentfile.html:74 +msgid "Administrative acts" +msgstr "Actes administratifs" + +#: templates/ishtar/sheet_treatment.html:63 msgctxt "Treatment" msgid "Closed" msgstr "Close" -#: templates/ishtar/sheet_treatment.html:27 +#: templates/ishtar/sheet_treatment.html:65 msgctxt "Treatment" msgid "Active" msgstr "Actif" -#: templates/ishtar/sheet_treatment.html:66 -msgid "Related operations" -msgstr "Opérations associées" - -#: templates/ishtar/sheet_treatment.html:77 -#: templates/ishtar/sheet_treatmentfile.html:73 -msgid "Administrative acts" -msgstr "Actes administratifs" - #: templates/ishtar/sheet_treatmentfile.html:24 msgctxt "Treatment request" msgid "Closed" @@ -1647,86 +1917,142 @@ msgctxt "Treatment request" msgid "Active" msgstr "Active" -#: views.py:132 +#: templates/ishtar/wizard/wizard_findbasket_deletion.html:8 +msgid "This basket is attached to treatments requests:" +msgstr "Ce panier est attaché à des demandes de traitements :" + +#: templates/ishtar/wizard/wizard_findbasket_deletion.html:12 +msgid "Are you sure you want to delete this basket?" +msgstr "Êtes vous sûr de vouloir supprimer ce panier ?" + +#: templates/ishtar/wizard/wizard_findbasket_deletion.html:16 +msgid "Items inside the basket (these items will not be deleted):" +msgstr "" +"Éléments à l'intérieur du panier (ces éléments ne seront pas effacés) :" + +#: templates/ishtar/wizard/wizard_findbasket_deletion.html:23 +msgid "Basket informations:" +msgstr "Informations sur le panier :" + +#: templates/ishtar/wizard/wizard_simplefind.html:6 +msgid "" +"This find is related to many base finds. To edit field related to base finds " +"edit the corresponding find between theses:" +msgstr "" +"Ce mobilier est associé à plusieurs mobiliers d'origine. Pour modifier les " +"champs associés aux mobiliers d'origines, modifiez le mobilier correspondant " +"parmi ceux-ci :" + +#: templates/ishtar/wizard/wizard_treatement_deletion.html:8 +msgid "Are you sure you want to delete this treatment?" +msgstr "Êtes-vous sûr de vouloir supprimer ce traitement ? " + +#: templates/ishtar/wizard/wizard_treatement_deletion.html:10 +msgid "" +"The following finds will be deleted and restored to a previous version." +msgstr "" +"Le mobilier suivant sera supprimé et restauré à une version précédente." + +#: templates/ishtar/wizard/wizard_treatement_deletion.html:16 +msgid "" +"All changes made to the associated finds since this treatment record will be " +"lost!" +msgstr "" +"Toutes les modifications sur le mobilier associé réalisées depuis " +"l'enregistrement de ce traitement seront perdues !" + +#: templates/ishtar/wizard/wizard_treatement_deletion.html:21 +msgid "Treatment informations:" +msgstr "Informations sur le traitement :" + +#: views.py:175 msgid "Basket modify" msgstr "Modification de panier" -#: views.py:173 +#: views.py:198 +msgid "Basket deletion" +msgstr "Suppression du panier" + +#: views.py:229 msgid "New find" msgstr "Ajouter un mobilier" -#: views.py:209 +#: views.py:281 msgid "Find modification" msgstr "Modifier un mobilier" -#: views.py:238 +#: views.py:316 msgid "Find deletion" msgstr "Supprimer un mobilier" -#: views.py:251 +#: views.py:329 msgid "New basket" msgstr "Ajouter un panier" -#: views.py:280 +#: views.py:358 msgid "Manage items in basket" msgstr "Gérer les éléments dans un panier" -#: views.py:389 -msgid "Delete basket" -msgstr "Supprimer un panier" - -#: views.py:441 +#: views.py:484 views.py:497 views.py:510 msgid "New treatment" msgstr "Ajouter un traitement" -#: views.py:449 +#: views.py:518 msgid "Treatment modification" msgstr "Modifier un traitement" -#: views.py:466 +#: views.py:609 msgid "Treatment deletion" msgstr "Supprimer un traitement" -#: views.py:473 +#: views.py:616 msgid "Treatment: search administrative act" msgstr "Traitement : rechercher un acte administratif" -#: views.py:482 +#: views.py:625 msgid "Treatment: new administrative act" msgstr "Traitement : ajouter un acte administratif" -#: views.py:492 +#: views.py:635 msgid "Treatment: administrative act modification" msgstr "Traitement : modifier un acte administratif" -#: views.py:501 +#: views.py:644 msgid "Treatment: administrative act deletion" msgstr "Traitement : supprimer un acte administratif" -#: views.py:534 +#: views.py:691 msgid "New treatment request" msgstr "Ajouter une demande de traitement" -#: views.py:541 +#: views.py:700 msgid "Treatment request modification" msgstr "Modifier une demande de traitement" -#: views.py:557 +#: views.py:716 msgid "Treatment request deletion" msgstr "Supprimer une demande de traitement" -#: views.py:564 +#: views.py:723 msgid "Treatment request: search administrative act" msgstr "Demande de traitement : rechercher un acte administratif" -#: views.py:574 +#: views.py:734 msgid "Treatment request: new administrative act" msgstr "Demande de traitement : ajouter un acte administratif" -#: views.py:584 +#: views.py:744 msgid "Treatment request: administrative act modification" msgstr "Demande de traitement : modifier un acte administratif" -#: views.py:593 +#: views.py:753 msgid "Treatment request: administrative act deletion" msgstr "Demande de traitement : supprimer un acte administratif" + +#: wizards.py:394 +msgid "" +"The new basket: \"{}\" have been created with the resulting items. This " +"search have been pinned." +msgstr "" +"Le nouveau panier « {} » a été créé avec les éléments résultants. Cette " +"recherche a été épinglée." diff --git a/translations/fr/archaeological_operations.po b/translations/fr/archaeological_operations.po index 5d4bd0631..266eede4d 100644 --- a/translations/fr/archaeological_operations.po +++ b/translations/fr/archaeological_operations.po @@ -11,28 +11,28 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Content-Type: text/plain; charset=UTF-8\n" -"PO-Revision-Date: 2018-11-12 09:43+0000\n" +"PO-Revision-Date: 2018-12-11 06:13+0000\n" "Last-Translator: Étienne Loks <etienne.loks@iggdrasil.net>\n" "Language-Team: \n" "Language: fr\n" "Plural-Forms: nplurals=2; plural=n>1;\n" "X-Generator: Zanata 4.6.2\n" -#: admin.py:91 models.py:244 models.py:836 +#: admin.py:91 models.py:263 models.py:880 msgid "Point" msgstr "Point" -#: admin.py:93 models.py:245 models.py:837 +#: admin.py:93 models.py:264 models.py:881 msgid "Multi polygon" msgstr "Polygones multi-parties" -#: forms.py:64 forms.py:1061 forms.py:1077 forms.py:1083 models.py:1931 +#: forms.py:64 forms.py:1068 forms.py:1084 forms.py:1090 models.py:2014 #: templates/ishtar/blocks/window_tables/parcels.html:9 -#: templates/ishtar/sheet_operation.html:250 +#: templates/ishtar/sheet_operation.html:257 msgid "Parcels" msgstr "Parcelles" -#: forms.py:67 forms.py:200 forms.py:1036 models.py:1915 +#: forms.py:67 forms.py:200 forms.py:1043 models.py:1998 #: templates/ishtar/blocks/window_tables/parcels.html:6 #: templates/ishtar/dashboards/dashboard_operation.html:432 #: templates/ishtar/dashboards/dashboard_operation.html:446 @@ -41,22 +41,22 @@ msgstr "Parcelles" msgid "Town" msgstr "Commune" -#: forms.py:69 forms.py:480 forms.py:763 forms.py:1400 models.py:734 -#: models.py:1489 models.py:1696 models.py:1913 +#: forms.py:69 forms.py:480 forms.py:768 forms.py:1426 models.py:774 +#: models.py:1562 models.py:1769 models.py:1996 #: templates/ishtar/blocks/window_tables/parcels.html:7 msgid "Year" msgstr "Année" -#: forms.py:72 models.py:1916 +#: forms.py:72 models.py:1999 #: templates/ishtar/blocks/window_tables/parcels.html:8 msgid "Section" msgstr "Section" -#: forms.py:75 models.py:1918 +#: forms.py:75 models.py:2001 msgid "Parcel number" msgstr "Numéro de parcelle" -#: forms.py:77 models.py:1920 models.py:1939 models.py:2000 +#: forms.py:77 models.py:2003 models.py:2022 models.py:2083 msgid "Public domain" msgstr "Domaine public" @@ -92,8 +92,8 @@ msgstr "Il y a des parcelles identiques." msgid "Relation type" msgstr "Type de relation" -#: forms.py:373 forms.py:1254 ishtar_menu.py:32 models.py:842 models.py:1394 -#: models.py:1405 models.py:1491 models.py:1678 models.py:1912 +#: forms.py:373 forms.py:1261 ishtar_menu.py:32 models.py:886 models.py:1466 +#: models.py:1477 models.py:1564 models.py:1751 models.py:1995 #: templates/ishtar/sheet_operation.html:4 wizards.py:320 wizards.py:331 msgid "Operation" msgstr "Opération (OA)" @@ -102,7 +102,7 @@ msgstr "Opération (OA)" msgid ":" msgstr ": " -#: forms.py:404 forms.py:608 +#: forms.py:404 forms.py:612 msgid "You should select an operation." msgstr "Vous devez sélectionner une opération." @@ -122,7 +122,7 @@ msgstr "Relations actuelles" msgid "Deleted relations" msgstr "Relations supprimées" -#: forms.py:469 templates/ishtar/sheet_operation.html:169 +#: forms.py:469 templates/ishtar/sheet_operation.html:170 msgid "Relations" msgstr "Relations" @@ -130,19 +130,23 @@ msgstr "Relations" msgid "Operation - 080 - Relations" msgstr "Opération - 080 - Relations" -#: forms.py:478 forms.py:1237 forms.py:1396 +#: forms.py:478 forms.py:1244 forms.py:1422 msgid "Full text search" msgstr "Recherche en texte intégral" -#: forms.py:481 models.py:735 +#: forms.py:481 models.py:775 msgid "Numeric reference" msgstr "Identifiant numérique" -#: forms.py:488 forms.py:1064 forms.py:1412 models.py:1930 models.py:2142 +#: forms.py:487 forms.py:761 models.py:870 +msgid "DRASSM code" +msgstr "Code DRASSM" + +#: forms.py:489 forms.py:1071 forms.py:1438 models.py:2013 models.py:2225 msgid "Parcel" msgstr "Parcelle" -#: forms.py:491 forms.py:1415 models.py:1395 +#: forms.py:492 forms.py:1441 models.py:1467 #: templates/ishtar/dashboards/dashboard_operation.html:390 #: templates/ishtar/dashboards/dashboard_operation.html:411 #: templates/ishtar/dashboards/dashboard_operation.html:643 @@ -151,273 +155,273 @@ msgstr "Parcelle" msgid "Department" msgstr "Département" -#: forms.py:492 forms.py:1148 forms.py:1241 forms.py:1325 models.py:213 +#: forms.py:493 forms.py:1155 forms.py:1248 forms.py:1340 models.py:224 #: templates/ishtar/blocks/window_tables/archaeologicalsites.html:7 #: templates/ishtar/sheet_operation.html:29 msgid "Name" msgstr "Nom" -#: forms.py:493 forms.py:761 models.py:797 +#: forms.py:494 forms.py:766 models.py:838 msgid "Address / Locality" msgstr "Adresse / Lieu-dit" -#: forms.py:494 forms.py:678 forms.py:757 models.py:742 +#: forms.py:495 forms.py:682 forms.py:762 models.py:782 msgid "Operation type" msgstr "Type d'opération" -#: forms.py:495 +#: forms.py:496 msgid "Is open?" msgstr "Est ouvert ?" -#: forms.py:503 forms.py:793 models.py:727 +#: forms.py:504 forms.py:798 models.py:767 msgid "In charge" msgstr "Responsable du suivi scientifique" -#: forms.py:510 models.py:1672 +#: forms.py:511 models.py:1745 msgid "Scientist in charge" msgstr "Responsable scientifique" -#: forms.py:512 forms.py:680 forms.py:783 models.py:725 +#: forms.py:513 forms.py:684 forms.py:788 models.py:765 msgid "Operator" msgstr "Opérateur" -#: forms.py:521 forms.py:1153 forms.py:1243 forms.py:1330 models.py:217 -#: models.py:744 +#: forms.py:522 forms.py:1160 forms.py:1250 forms.py:1345 models.py:228 +#: models.py:784 #: templates/ishtar/blocks/window_tables/archaeologicalsites.html:9 msgid "Remains" msgstr "Vestiges" -#: forms.py:522 forms.py:1131 forms.py:1150 forms.py:1242 forms.py:1327 -#: models.py:215 models.py:750 +#: forms.py:523 forms.py:1138 forms.py:1157 forms.py:1249 forms.py:1342 +#: models.py:226 models.py:790 #: templates/ishtar/blocks/window_tables/archaeologicalsites.html:8 msgid "Periods" msgstr "Périodes" -#: forms.py:523 +#: forms.py:524 msgid "Started before" msgstr "Commencé avant" -#: forms.py:524 +#: forms.py:525 msgid "Started after" msgstr "Commencé après" -#: forms.py:525 +#: forms.py:526 msgid "Ended before" msgstr "Terminé avant" -#: forms.py:526 +#: forms.py:527 msgid "Ended after" msgstr "Terminé après" -#: forms.py:528 +#: forms.py:529 msgid "Search within relations" msgstr "Rechercher parmi les relations" -#: forms.py:529 forms.py:841 forms.py:1245 forms.py:1340 models.py:221 -#: models.py:798 +#: forms.py:530 forms.py:846 forms.py:1252 forms.py:1357 models.py:232 +#: models.py:839 msgid "Comment" msgstr "Commentaire" -#: forms.py:530 +#: forms.py:531 msgid "Abstract (full text search)" msgstr "Résumé (recherche en texte intégral)" -#: forms.py:532 forms.py:844 models.py:800 +#: forms.py:533 forms.py:849 models.py:841 msgid "Comment about scientific documentation" msgstr "Commentaire relatif à la documentation scientifique" -#: forms.py:533 forms.py:846 models.py:815 +#: forms.py:534 forms.py:851 models.py:856 msgid "Record quality" msgstr "Qualité d'enregistrement" -#: forms.py:534 forms.py:812 models.py:762 +#: forms.py:535 forms.py:817 models.py:802 msgid "Report processing" msgstr "Traitement du rapport" -#: forms.py:536 forms.py:849 models.py:810 +#: forms.py:537 forms.py:854 models.py:851 msgid "Virtual operation" msgstr "Opération virtuelle" -#: forms.py:538 forms.py:1188 forms.py:1192 models.py:257 +#: forms.py:539 forms.py:1195 forms.py:1199 models.py:276 msgid "Archaeological site" msgstr "Entité (EA)" -#: forms.py:544 forms.py:1419 +#: forms.py:545 forms.py:1445 msgid "Created by" msgstr "Créé par" -#: forms.py:550 forms.py:1425 +#: forms.py:551 forms.py:1451 msgid "Modified by" msgstr "Modifié par" -#: forms.py:557 forms.py:834 models.py:822 +#: forms.py:558 forms.py:839 models.py:863 msgid "Documentation received" msgstr "Documentation reçue" -#: forms.py:559 +#: forms.py:560 msgid "Documentation deadline before" msgstr "Date limite de versement de la documentation avant" -#: forms.py:561 +#: forms.py:562 msgid "Documentation deadline after" msgstr "Date limite de versement de la documentation après" -#: forms.py:563 forms.py:839 models.py:826 +#: forms.py:564 forms.py:844 models.py:867 msgid "Finds received" msgstr "Mobilier reçu" -#: forms.py:565 +#: forms.py:566 msgid "Finds deadline before" msgstr "Date limite de versement du mobilier avant" -#: forms.py:567 +#: forms.py:568 msgid "Finds deadline after" msgstr "Date limite de versement du mobilier après" -#: forms.py:595 views.py:182 +#: forms.py:599 views.py:183 msgid "Operation search" msgstr "Rechercher une opération" -#: forms.py:639 +#: forms.py:643 msgid "Associated file" msgstr "Dossier associé" -#: forms.py:643 forms.py:937 models.py:1023 models.py:1404 models.py:1490 -#: models.py:1683 wizards.py:83 +#: forms.py:647 forms.py:944 models.py:1083 models.py:1476 models.py:1563 +#: models.py:1756 wizards.py:83 msgid "Archaeological file" msgstr "Dossier archéologique" -#: forms.py:650 forms.py:654 models.py:817 +#: forms.py:654 forms.py:658 models.py:858 msgid "Abstract" msgstr "Résumé" -#: forms.py:651 +#: forms.py:655 msgid "Operation - 090 - Abstract" msgstr "Opération - 090 - Résumé" -#: forms.py:658 +#: forms.py:662 msgid "months" msgstr "mois" -#: forms.py:658 +#: forms.py:662 msgid "years" msgstr "années" -#: forms.py:660 models.py:711 +#: forms.py:664 models.py:751 msgid "Creation date" msgstr "Date de création" -#: forms.py:661 +#: forms.py:665 msgid "Start of field work" msgstr "Début du travail de terrain" -#: forms.py:663 +#: forms.py:667 msgid "All" msgstr "Tout" -#: forms.py:664 +#: forms.py:668 msgid "Preventive" msgstr "Préventif" -#: forms.py:665 +#: forms.py:669 msgid "Research" msgstr "Programmé" -#: forms.py:669 +#: forms.py:673 msgid "Slicing" msgstr "Découpage" -#: forms.py:672 +#: forms.py:676 msgid "Department detail" msgstr "Détail par département" -#: forms.py:674 +#: forms.py:678 msgid "Date get from" msgstr "Date obtenue depuis" -#: forms.py:676 +#: forms.py:680 msgid "Preventive/Research" msgstr "Préventif/Programmé" -#: forms.py:682 +#: forms.py:686 msgid "Date after" msgstr "Date après" -#: forms.py:683 +#: forms.py:687 msgid "Date before" msgstr "Date avant" -#: forms.py:684 +#: forms.py:688 msgid "With reports" msgstr "Avec un rapport" -#: forms.py:685 +#: forms.py:689 msgid "With finds" msgstr "Avec du mobilier" -#: forms.py:737 forms.py:1317 forms.py:1466 +#: forms.py:741 forms.py:1331 forms.py:1492 #: templates/ishtar/sheet_administrativeact.html:23 #: templates/ishtar/sheet_operation.html:12 templates/ishtar/sheet_site.html:33 msgid "General" msgstr "Général" -#: forms.py:738 +#: forms.py:742 msgid "Operation - 010 - General" msgstr "Opération - 010 - Général" -#: forms.py:759 models.py:796 +#: forms.py:764 models.py:837 msgid "Generic name" msgstr "Nom générique" -#: forms.py:768 models.py:764 +#: forms.py:773 models.py:804 msgid "Old code" msgstr "Ancien code" -#: forms.py:771 +#: forms.py:776 msgid "Head scientist" msgstr "Responsable scientifique" -#: forms.py:790 models.py:795 +#: forms.py:795 models.py:836 msgid "Operator reference" msgstr "Référence de l'opérateur" -#: forms.py:804 +#: forms.py:809 msgid "Total surface (m2)" msgstr "Surface totale (m2)" -#: forms.py:807 models.py:57 models.py:714 models.py:2144 +#: forms.py:812 models.py:57 models.py:754 models.py:2227 msgid "Start date" msgstr "Date de début" -#: forms.py:808 models.py:716 +#: forms.py:813 models.py:756 msgid "Excavation end date" msgstr "Date de fin de chantier" -#: forms.py:810 models.py:717 +#: forms.py:815 models.py:757 msgid "Report delivery date" msgstr "Date de livraison du rapport" -#: forms.py:831 models.py:819 +#: forms.py:836 models.py:860 msgid "Deadline for submission of the documentation" msgstr "Date limite de versement de la documentation" -#: forms.py:836 models.py:824 +#: forms.py:841 models.py:865 msgid "Deadline for submission of the finds" msgstr "Date limite de versement du mobilier" -#: forms.py:888 +#: forms.py:895 msgid "" "If you want to set an excavation end date you have to provide a start date." msgstr "" "Avant de renseigner la date de fin de chantier, il est nécessaire de " "renseigner une date de début." -#: forms.py:893 +#: forms.py:900 msgid "The excavation end date cannot be before the start date." msgstr "" "La date de fin de chantier ne peut être antérieure à la date de début." -#: forms.py:923 +#: forms.py:930 #, python-format msgid "" "Operation code already exists for year: %(year)d - use a value bigger than " @@ -426,248 +430,256 @@ msgstr "" "Ce code d'opération existe déjà pour l'année %(year)d - utilisez une valeur " "plus grande que %(last_val)d" -#: forms.py:927 +#: forms.py:934 msgid "Bad operation code" msgstr "Mauvais code d'opération" -#: forms.py:933 models.py:1038 +#: forms.py:940 models.py:1098 msgid "Operation code" msgstr "Code de l'opération" -#: forms.py:968 templates/ishtar/sheet_operation.html:149 +#: forms.py:975 templates/ishtar/sheet_operation.html:150 msgid "Court-ordered seizure" msgstr "Saisie judiciaire" -#: forms.py:969 +#: forms.py:976 msgid "Operation - 015 - Court-ordered seizure" msgstr "Opération - 015 - Saisie judiciaire" -#: forms.py:973 models.py:829 +#: forms.py:980 models.py:873 msgid "Seizure name" msgstr "Nom de la saisie" -#: forms.py:976 models.py:830 +#: forms.py:983 models.py:874 msgid "Official report number" msgstr "Numéro de procès-verbal" -#: forms.py:979 models.py:832 +#: forms.py:986 models.py:876 msgid "Name of the protagonist" msgstr "Nom du protagoniste" -#: forms.py:984 forms.py:991 models.py:731 +#: forms.py:991 forms.py:998 forms.py:1356 models.py:243 models.py:771 msgid "Collaborators" msgstr "Collaborateurs" -#: forms.py:985 +#: forms.py:992 msgid "Operation - 020 - Collaborators" msgstr "Opération - 020 - Collaborateurs" -#: forms.py:1000 +#: forms.py:1007 msgid "Preventive informations - excavation" msgstr "Information archéologie préventive - fouille" -#: forms.py:1001 +#: forms.py:1008 msgid "Operation - 033 - Preventive - Excavation" msgstr "Opération - 033 - Préventif - Fouille" -#: forms.py:1004 models.py:748 +#: forms.py:1011 models.py:788 #: templates/ishtar/dashboards/dashboard_operation.html:701 msgid "Cost (euros)" msgstr "Coût (euros)" -#: forms.py:1005 models.py:753 +#: forms.py:1012 models.py:793 msgid "Scheduled man-days" msgstr "Jours-hommes prévus" -#: forms.py:1007 models.py:756 +#: forms.py:1014 models.py:796 msgid "Optional man-days" msgstr "Jours-hommes optionnels" -#: forms.py:1009 models.py:759 +#: forms.py:1016 models.py:799 msgid "Effective man-days" msgstr "Jours-hommes effectifs" -#: forms.py:1019 +#: forms.py:1026 msgid "Preventive informations - diagnostic" msgstr "Information archéologie préventive - diagnostic" -#: forms.py:1020 +#: forms.py:1027 msgid "Operation - 037 - Preventive - Diagnostic" msgstr "Opération - 037 - Préventif - Diagnostic" -#: forms.py:1025 models.py:779 +#: forms.py:1032 models.py:819 msgid "Prescription on zoning" msgstr "Prescription sur zonage" -#: forms.py:1027 models.py:782 +#: forms.py:1034 models.py:822 msgid "Prescription on large area" msgstr "Prescription sur une vaste surface" -#: forms.py:1030 models.py:784 +#: forms.py:1037 models.py:824 msgid "Prescription on geoarchaeological context" msgstr "Prescription sur un contexte géoarchéologique" -#: forms.py:1034 forms.py:1050 forms.py:1055 forms.py:1359 models.py:128 -#: models.py:219 models.py:506 models.py:746 models.py:1706 +#: forms.py:1041 forms.py:1057 forms.py:1062 forms.py:1381 models.py:131 +#: models.py:230 models.py:541 models.py:786 models.py:1779 msgid "Towns" msgstr "Communes" -#: forms.py:1051 +#: forms.py:1058 msgid "Operation - 040 - Towns" msgstr "Opération - 040 - Communes" -#: forms.py:1056 +#: forms.py:1063 msgid "Operation - 040 - Towns (2)" msgstr "Opération - 040 - Communes (2)" -#: forms.py:1078 +#: forms.py:1085 msgid "Operation - 050 - Parcels" msgstr "Opération - 050 - Parcelles" -#: forms.py:1085 +#: forms.py:1092 msgid "Operation - 050 - Parcels (2)" msgstr "Opération - 050 - Parcelles (2)" -#: forms.py:1115 models.py:47 +#: forms.py:1122 models.py:47 msgid "Remain types" msgstr "Types de vestige" -#: forms.py:1116 +#: forms.py:1123 msgid "Operation - 060 - Remains" msgstr "Opération - 060 - Vestiges" -#: forms.py:1122 models.py:46 +#: forms.py:1129 models.py:46 msgid "Remain type" msgstr "Type de vestige" -#: forms.py:1132 +#: forms.py:1139 msgid "Operation - 070 - Periods" msgstr "Opération - 070 - Périodes" -#: forms.py:1138 templates/ishtar/sheet_operation.html:273 -#: templates/ishtar/sheet_operation.html:310 +#: forms.py:1145 templates/ishtar/sheet_operation.html:280 +#: templates/ishtar/sheet_operation.html:317 msgid "Period" msgstr "Période" -#: forms.py:1147 forms.py:1239 forms.py:1324 models.py:212 +#: forms.py:1154 forms.py:1246 forms.py:1339 models.py:223 msgid "Reference" msgstr "Référence" -#: forms.py:1171 forms.py:1353 +#: forms.py:1178 forms.py:1375 msgid "This reference already exists." msgstr "Cette référence existe déjà ." -#: forms.py:1203 models.py:258 models.py:807 -#: templates/ishtar/sheet_operation.html:194 +#: forms.py:1210 models.py:277 models.py:848 +#: templates/ishtar/sheet_operation.html:195 msgid "Archaeological sites" msgstr "Entités archéologiques" -#: forms.py:1205 +#: forms.py:1212 msgid "Operation - 030 - Archaeological sites" msgstr "Opération - 030 - Sites archéologiques" -#: forms.py:1210 +#: forms.py:1217 msgid "Associated archaeological sites" msgstr "Entités archéologiques associées" -#: forms.py:1216 ishtar_menu.py:36 ishtar_menu.py:66 ishtar_menu.py:113 +#: forms.py:1223 ishtar_menu.py:36 ishtar_menu.py:66 ishtar_menu.py:108 msgid "Search" msgstr "Recherche" -#: forms.py:1221 +#: forms.py:1228 msgid "Would you like to close this operation?" msgstr "Voulez-vous clore cette opération ?" -#: forms.py:1226 +#: forms.py:1233 msgid "Would you like to delete this operation?" msgstr "Voulez-vous supprimer cette opération ?" -#: forms.py:1248 models.py:223 +#: forms.py:1255 models.py:234 msgid "Top operation" msgstr "Opération chapeau" -#: forms.py:1260 forms.py:1333 models.py:226 +#: forms.py:1267 forms.py:1348 models.py:237 msgid "National Geographic Institute locality" msgstr "Lieu-dit IGN" -#: forms.py:1263 forms.py:1337 models.py:229 +#: forms.py:1270 forms.py:1352 models.py:240 msgid "Cadastral locality" msgstr "Lieu-dit cadastre" -#: forms.py:1266 forms.py:1374 models.py:233 +#: forms.py:1274 forms.py:1396 models.py:257 +msgid "AffMar number" +msgstr "Numéro AffMar" + +#: forms.py:1276 forms.py:1398 models.py:259 +msgid "DRASSM number" +msgstr "Numéro DRASSM" + +#: forms.py:1278 forms.py:1400 models.py:248 msgid "Shipwreck name" msgstr "Nom de l'épave" -#: forms.py:1269 forms.py:1382 models.py:235 +#: forms.py:1281 forms.py:1408 models.py:250 msgid "Oceanographic service localisation" msgstr "Localisation SHOM" -#: forms.py:1272 forms.py:1376 models.py:237 +#: forms.py:1284 forms.py:1402 models.py:252 msgid "Shipwreck code" msgstr "Code épave" -#: forms.py:1274 forms.py:1378 models.py:239 +#: forms.py:1286 forms.py:1404 models.py:254 msgid "Sinking date" msgstr "Date de naufrage" -#: forms.py:1276 forms.py:1380 models.py:241 +#: forms.py:1288 forms.py:1406 models.py:256 msgid "Discovery area" msgstr "Zone de découverte" -#: forms.py:1312 +#: forms.py:1326 msgid "You should select an item." msgstr "Vous devez sélectionner un élément." -#: forms.py:1318 +#: forms.py:1332 msgid "Archaeological site - 010 - General" msgstr "Site archéologique - 010 - Général" -#: forms.py:1360 +#: forms.py:1382 msgid "Archaeological site - 020 - Towns" msgstr "Site archéologique - 020 - Villes" -#: forms.py:1369 templates/ishtar/sheet_site.html:52 +#: forms.py:1391 templates/ishtar/sheet_site.html:53 msgid "Underwater" msgstr "Sous-marin / subaquatique" -#: forms.py:1370 +#: forms.py:1392 msgid "Archaeological site - 030 - Underwater" msgstr "Site archéologique - 030 - Sous-marin / subaquatique" -#: forms.py:1401 forms.py:1535 models.py:1663 +#: forms.py:1427 forms.py:1561 models.py:1736 msgid "Index" msgstr "Index" -#: forms.py:1409 forms.py:1469 models.py:1418 models.py:1657 +#: forms.py:1435 forms.py:1495 models.py:1490 models.py:1730 msgid "Act type" msgstr "Type d'acte" -#: forms.py:1410 forms.py:1605 +#: forms.py:1436 forms.py:1631 msgid "Indexed?" msgstr "Indexé ?" -#: forms.py:1416 forms.py:1474 models.py:1697 +#: forms.py:1442 forms.py:1500 models.py:1770 #: templates/ishtar/blocks/window_tables/administrativacts.html:9 msgid "Object" msgstr "Objet" -#: forms.py:1446 views.py:412 +#: forms.py:1472 views.py:413 msgid "Administrative act search" msgstr "Rechercher un acte administratif" -#: forms.py:1461 forms.py:1563 forms.py:1630 +#: forms.py:1487 forms.py:1589 forms.py:1656 msgid "You should select an administrative act." msgstr "Vous devez sélectionner un acte administratif." -#: forms.py:1477 models.py:1694 +#: forms.py:1503 models.py:1767 msgid "Signature date" msgstr "Date de signature" -#: forms.py:1489 +#: forms.py:1515 msgid "Operation - Administrative act - General" msgstr "Opération - Acte administratif - Général" -#: forms.py:1523 +#: forms.py:1549 #, python-format msgid "" "This index already exists for year: %(year)d - use a value bigger than " @@ -676,40 +688,40 @@ msgstr "" "Cet index existe déjà pour l'année : %(year)d, utilisez une valeur plus " "grande que %(last_val)d" -#: forms.py:1527 +#: forms.py:1553 msgid "Bad index" msgstr "Mauvais index" -#: forms.py:1540 +#: forms.py:1566 msgid "Would you like to delete this administrative act?" msgstr "Voulez-vous supprimer cet acte administratif ?" -#: forms.py:1545 +#: forms.py:1571 msgid "Template" msgstr "Patron" -#: forms.py:1569 forms.py:1573 +#: forms.py:1595 forms.py:1599 msgid "This document is not intended for this type of act." msgstr "Ce document n'est pas destiné à ce type d'acte." -#: forms.py:1591 +#: forms.py:1617 msgid "Doc generation" msgstr "Génération de document" -#: forms.py:1593 +#: forms.py:1619 msgid "Generate the associated doc?" msgstr "Générer le document associé ?" -#: forms.py:1614 ishtar_menu.py:101 views.py:465 +#: forms.py:1640 ishtar_menu.py:96 views.py:466 msgctxt "admin act register" msgid "Register" msgstr "Registre" -#: ishtar_menu.py:41 ishtar_menu.py:72 ishtar_menu.py:118 +#: ishtar_menu.py:41 ishtar_menu.py:72 ishtar_menu.py:113 msgid "Creation" msgstr "Ajout" -#: ishtar_menu.py:46 ishtar_menu.py:77 ishtar_menu.py:123 +#: ishtar_menu.py:46 ishtar_menu.py:77 ishtar_menu.py:118 msgid "Modification" msgstr "Modification" @@ -717,42 +729,38 @@ msgstr "Modification" msgid "Closing" msgstr "Clôture" -#: ishtar_menu.py:55 ishtar_menu.py:82 ishtar_menu.py:128 +#: ishtar_menu.py:55 ishtar_menu.py:82 ishtar_menu.py:123 msgid "Deletion" msgstr "Suppression" -#: ishtar_menu.py:61 models.py:1713 +#: ishtar_menu.py:61 models.py:1786 #: templates/ishtar/sheet_administrativeact.html:4 msgid "Administrative act" msgstr "Acte administratif" -#: ishtar_menu.py:87 models.py:249 models.py:802 -msgid "Documents" -msgstr "Documents" - -#: ishtar_menu.py:95 +#: ishtar_menu.py:90 msgid "Administrative Act" msgstr "Acte administratif" -#: ishtar_menu.py:135 +#: ishtar_menu.py:130 msgid "Dashboard" msgstr "Tableau de bord" -#: ishtar_menu.py:139 +#: ishtar_menu.py:134 msgid "General informations" msgstr "Informations générales" -#: ishtar_menu.py:143 models.py:843 +#: ishtar_menu.py:138 models.py:887 #: templates/ishtar/dashboards/dashboard_operation.html:8 -#: templates/ishtar/sheet_site.html:65 +#: templates/ishtar/sheet_site.html:68 msgid "Operations" msgstr "Opérations" -#: models.py:56 models.py:76 models.py:94 models.py:2622 +#: models.py:56 models.py:76 models.py:94 models.py:2705 msgid "Order" msgstr "Ordre" -#: models.py:58 models.py:2145 +#: models.py:58 models.py:2228 msgid "End date" msgstr "Date de fin" @@ -784,667 +792,694 @@ msgstr "Type de qualité d'enregistrement" msgid "Types of record quality" msgstr "Types de qualité d'enregistrement" -#: models.py:135 +#: models.py:138 msgctxt "key for text search" msgid "reference" msgstr "reference" -#: models.py:139 models.py:569 +#: models.py:142 models.py:605 msgctxt "key for text search" msgid "name" msgstr "nom" -#: models.py:143 models.py:601 tests.py:1625 +#: models.py:146 models.py:637 tests.py:1625 msgctxt "key for text search" msgid "period" msgstr "periode" -#: models.py:147 models.py:597 tests.py:1656 +#: models.py:150 models.py:633 tests.py:1656 msgctxt "key for text search" msgid "remain" msgstr "vestige" -#: models.py:151 models.py:557 tests.py:1633 +#: models.py:154 models.py:593 tests.py:1633 msgctxt "key for text search" msgid "town" msgstr "commune" -#: models.py:155 models.py:625 +#: models.py:158 models.py:661 msgctxt "key for text search" msgid "comment" msgstr "commentaire" -#: models.py:159 +#: models.py:162 msgctxt "key for text search" msgid "locality-ngi" msgstr "lieu-dit-ign" -#: models.py:163 +#: models.py:166 msgctxt "key for text search" msgid "locality-cadastral" msgstr "lieu-dit-cadastre" -#: models.py:167 +#: models.py:170 msgctxt "key for text search" msgid "shipwreck-name" msgstr "nom-epave" -#: models.py:172 +#: models.py:175 msgctxt "key for text search" msgid "oceanographic-service-localisation" msgstr "localisation-shom" -#: models.py:176 +#: models.py:179 msgctxt "key for text search" msgid "shipwreck-code" msgstr "code-epave" -#: models.py:180 +#: models.py:183 msgctxt "key for text search" msgid "sinking-date" msgstr "date-naufrage" -#: models.py:184 +#: models.py:187 msgctxt "key for text search" msgid "discovery-area" msgstr "zone-decouverte" -#: models.py:188 models.py:203 +#: models.py:191 models.py:214 msgctxt "key for text search" msgid "operation" msgstr "operation" -#: models.py:192 +#: models.py:195 msgctxt "key for text search" msgid "top-operation" msgstr "operation-chapeau" -#: models.py:251 models.py:804 models.py:1926 +#: models.py:199 +msgctxt "key for text search" +msgid "numero-drassm" +msgstr "numero-drassm" + +#: models.py:203 +msgctxt "key for text search" +msgid "numero-affmar" +msgstr "numero-affmar" + +#: models.py:268 models.py:843 +msgid "Documents" +msgstr "Documents" + +#: models.py:270 models.py:845 models.py:2009 msgid "Cached name" msgstr "Nom en cache" -#: models.py:280 +#: models.py:299 msgid "SITE" msgstr "SITE" -#: models.py:345 +#: models.py:380 msgid "Unknown" msgstr "Inconnu" -#: models.py:348 +#: models.py:383 msgid "Virtual operation of site: {}" msgstr "Opération virtuelle du site : {}" -#: models.py:488 +#: models.py:523 msgid "Associated file (label)" msgstr "Dossier associé (nom)" -#: models.py:489 +#: models.py:524 msgid "Operator name" msgstr "Nom de l'opérateur" -#: models.py:490 +#: models.py:525 msgid "Scientist (full name)" msgstr "Responsable scientifique (nom complet)" -#: models.py:491 +#: models.py:526 msgid "Associated file (external ID)" msgstr "Dossier associé (identifiant)" -#: models.py:492 +#: models.py:527 msgid "Scientist (title)" msgstr "Responsable scientifique (titre)" -#: models.py:493 +#: models.py:528 msgid "Scientist (surname)" msgstr "Responsable scientifique (nom)" -#: models.py:494 +#: models.py:529 msgid "Scientist (name)" msgstr "Scientifique (nom)" -#: models.py:495 +#: models.py:530 msgid "Scientist - Organization (name)" msgstr "Scientifique - Organisation (nom)" -#: models.py:496 +#: models.py:531 msgid "In charge (title)" msgstr "Responsable du suivi scientifique (titre)" -#: models.py:497 +#: models.py:532 msgid "In charge (surname)" msgstr "Responsable du suivi scientifique (prénom)" -#: models.py:498 +#: models.py:533 msgid "In charge (name)" msgstr "Responsable du suivi scientifique (nom)" -#: models.py:499 +#: models.py:534 msgid "In charge - Organization (name)" msgstr "Responsable du suivi scientifique - Organisation (nom)" -#: models.py:504 +#: models.py:539 msgid "Archaeological sites (reference)" msgstr "Entités archéologiques (référence)" -#: models.py:545 models.py:1502 tests.py:1628 tests.py:1673 +#: models.py:581 models.py:1575 tests.py:1628 tests.py:1673 msgctxt "key for text search" msgid "year" msgstr "annee" -#: models.py:549 +#: models.py:585 msgctxt "key for text search" msgid "operation-code" msgstr "code-operation" -#: models.py:553 models.py:1514 +#: models.py:589 models.py:1587 msgctxt "key for text search" msgid "patriarche" msgstr "patriarche" -#: models.py:561 models.py:1534 +#: models.py:597 models.py:1607 msgctxt "key for text search" msgid "parcel" msgstr "parcelle" -#: models.py:565 +#: models.py:601 msgctxt "key for text search" msgid "department" msgstr "departement" -#: models.py:573 +#: models.py:609 msgctxt "key for text search" msgid "address" msgstr "adresse" -#: models.py:577 models.py:1518 +#: models.py:613 models.py:1591 msgctxt "key for text search" msgid "type" msgstr "type" -#: models.py:581 tests.py:1661 +#: models.py:617 tests.py:1661 msgctxt "key for text search" msgid "is-open" msgstr "est-ouvert" -#: models.py:585 +#: models.py:621 msgctxt "key for text search" msgid "in-charge" msgstr "responsable-suivi" -#: models.py:589 +#: models.py:625 msgctxt "key for text search" msgid "scientist" msgstr "scientifique" -#: models.py:593 +#: models.py:629 msgctxt "key for text search" msgid "operator" msgstr "operateur" -#: models.py:605 +#: models.py:641 msgctxt "key for text search" msgid "start-before" msgstr "commence-avant" -#: models.py:609 +#: models.py:645 msgctxt "key for text search" msgid "start-after" msgstr "commence-apres" -#: models.py:613 +#: models.py:649 msgctxt "key for text search" msgid "end-before" msgstr "fini-apres" -#: models.py:617 +#: models.py:653 msgctxt "key for text search" msgid "end-after" msgstr "fini-avant" -#: models.py:621 +#: models.py:657 msgctxt "key for text search" msgid "relation-types" msgstr "type-relation" -#: models.py:629 +#: models.py:665 msgctxt "key for text search" msgid "abstract" msgstr "resume" -#: models.py:634 +#: models.py:670 msgctxt "key for text search" msgid "scientific-documentation-comment" msgstr "commentaire-documentation-scientifique" -#: models.py:638 +#: models.py:674 msgctxt "key for text search" msgid "record-quality" msgstr "qualite-enregistrement" -#: models.py:643 +#: models.py:679 msgctxt "key for text search" msgid "report-processing" msgstr "traitement-rapport" -#: models.py:648 +#: models.py:684 msgctxt "key for text search" msgid "virtual-operation" msgstr "operation-virtuelle" -#: models.py:653 models.py:696 +#: models.py:689 models.py:736 msgctxt "key for text search" msgid "site" msgstr "site" -#: models.py:657 models.py:1552 +#: models.py:693 models.py:1625 msgctxt "key for text search" msgid "created-by" msgstr "cree-par" -#: models.py:661 models.py:1556 +#: models.py:697 models.py:1629 msgctxt "key for text search" msgid "modified-by" msgstr "modifie-par" -#: models.py:665 +#: models.py:701 msgctxt "key for text search" msgid "documentation-received" msgstr "documentation-recue" -#: models.py:669 +#: models.py:705 msgctxt "key for text search" msgid "documentation-deadline-before" msgstr "documentation-date-limite-avant" -#: models.py:673 +#: models.py:709 msgctxt "key for text search" msgid "documentation-deadline-after" msgstr "documentation-date-limite-après" -#: models.py:677 +#: models.py:713 msgctxt "key for text search" msgid "finds-received" msgstr "mobilier-recu" -#: models.py:681 +#: models.py:717 msgctxt "key for text search" msgid "finds-deadline-before" msgstr "mobilier-date-limite-avant" -#: models.py:685 +#: models.py:721 msgctxt "key for text search" msgid "finds-deadline-after" msgstr "mobilier-date-limite-apres" -#: models.py:698 +#: models.py:725 +msgctxt "key for text search" +msgid "code-drassm" +msgstr "code-drassm" + +#: models.py:738 msgctxt "key for text search" msgid "file" msgstr "dossier" -#: models.py:713 templates/ishtar/sheet_operation.html:60 +#: models.py:753 templates/ishtar/sheet_operation.html:61 msgid "Closing date" msgstr "Date de clôture" -#: models.py:720 +#: models.py:760 msgid "In charge scientist" msgstr "Responsable du suivi scientifique" -#: models.py:739 models.py:1908 +#: models.py:779 models.py:1991 msgid "File" msgstr "Dossier" -#: models.py:743 +#: models.py:783 msgid "Surface (m2)" msgstr "Surface (m2)" -#: models.py:812 +#: models.py:853 msgid "" "If checked, it means that this operation have not been officialy registered." msgstr "" "Si coché, cela signifie que cette opération n'a pas été officiellement " "enregistrée." -#: models.py:891 +#: models.py:935 msgid "OPE" msgstr "OPE" -#: models.py:988 +#: models.py:1032 msgid "Intercommunal" msgstr "Intercommunal" -#: models.py:1024 +#: models.py:1078 +msgid "Add context record" +msgstr "Ajouter une unité d'enregistrement" + +#: models.py:1079 +msgid "context record" +msgstr "UE" + +#: models.py:1084 msgid "Code patriarche" msgstr "Code patriarche" -#: models.py:1066 +#: models.py:1126 msgid "This operation code already exists for this year" msgstr "Ce code d'opération existe déjà pour cette année." -#: models.py:1111 +#: models.py:1183 msgid "Number of parcels" msgstr "Nombre de parcelles" -#: models.py:1121 +#: models.py:1193 msgid "Number of administrative acts" msgstr "Nombre d'actes administratifs" -#: models.py:1129 +#: models.py:1201 msgid "Number of indexed administrative acts" msgstr "Nombre d'actes administratifs indexés" -#: models.py:1137 +#: models.py:1209 msgid "Number of context records" msgstr "Nombre d'Unités d'Enregistrement" -#: models.py:1173 +#: models.py:1245 msgid "Number of finds" msgstr "Nombre d'éléments de mobilier" -#: models.py:1218 +#: models.py:1290 msgid "No type" msgstr "Pas de type" -#: models.py:1249 +#: models.py:1321 msgid "Number of sources" msgstr "Nombre de documents" -#: models.py:1287 templates/ishtar/dashboards/dashboard_operation.html:309 +#: models.py:1359 templates/ishtar/dashboards/dashboard_operation.html:309 #: templates/ishtar/dashboards/dashboard_operation.html:575 #: templates/ishtar/dashboards/dashboard_operation.html:611 msgid "Mean" msgstr "Moyenne" -#: models.py:1349 +#: models.py:1421 msgid "Operation relation type" msgstr "Type de relation entre opérations" -#: models.py:1350 +#: models.py:1422 msgid "Operation relation types" msgstr "Types de relation entre opérations" -#: models.py:1363 +#: models.py:1435 msgid "Operation record relation" msgstr "Relation entre opérations" -#: models.py:1364 +#: models.py:1436 msgid "Operation record relations" msgstr "Relations entre opérations" -#: models.py:1406 models.py:1688 +#: models.py:1478 models.py:1761 msgid "Treatment request" msgstr "Demande de traitement" -#: models.py:1407 models.py:1693 +#: models.py:1479 models.py:1766 msgid "Treatment" msgstr "Traitement" -#: models.py:1409 +#: models.py:1481 msgid "Intended to" msgstr "Destiné à " -#: models.py:1411 +#: models.py:1483 msgid "Code" msgstr "Code" -#: models.py:1414 +#: models.py:1486 msgid "Associated template" msgstr "Patron associé" -#: models.py:1415 +#: models.py:1487 msgid "Indexed" msgstr "Indexé" -#: models.py:1419 +#: models.py:1491 msgid "Act types" msgstr "Types d'acte" -#: models.py:1489 models.py:1734 +#: models.py:1562 models.py:1807 #: templates/ishtar/blocks/window_tables/administrativacts.html:6 #: templates/ishtar/blocks/window_tables/archaeologicalsites.html:6 msgid "Ref." msgstr "Réf." -#: models.py:1506 +#: models.py:1579 msgctxt "key for text search" msgid "index" msgstr "index" -#: models.py:1510 +#: models.py:1583 msgctxt "key for text search" msgid "other-ref" msgstr "autre-ref" -#: models.py:1522 +#: models.py:1595 msgctxt "key for text search" msgid "indexed" msgstr "indexe" -#: models.py:1526 +#: models.py:1599 msgctxt "key for text search" msgid "operation-town" msgstr "operation-commune" -#: models.py:1530 +#: models.py:1603 msgctxt "key for text search" msgid "file-town" msgstr "dossier-commune" -#: models.py:1540 +#: models.py:1613 msgctxt "key for text search" msgid "operation-department" msgstr "operation-departement" -#: models.py:1544 +#: models.py:1617 msgctxt "key for text search" msgid "file-department" msgstr "dossier-departement" -#: models.py:1548 +#: models.py:1621 msgctxt "key for text search" msgid "object" msgstr "objet" -#: models.py:1560 +#: models.py:1633 msgctxt "key for text search" msgid "signature-before" msgstr "signature-avant" -#: models.py:1564 +#: models.py:1637 msgctxt "key for text search" msgid "signature-after" msgstr "signature-apres" -#: models.py:1568 +#: models.py:1641 msgctxt "key for text search" msgid "file-name" msgstr "dossier-nom" -#: models.py:1572 +#: models.py:1645 msgctxt "key for text search" msgid "general-contractor" msgstr "amenageur" -#: models.py:1577 +#: models.py:1650 msgctxt "key for text search" msgid "general-contractor-organization" msgstr "amenageur-organisation" -#: models.py:1582 +#: models.py:1655 msgctxt "key for text search" msgid "file-reference" msgstr "dossier-reference" -#: models.py:1586 +#: models.py:1659 msgctxt "key for text search" msgid "file-year" msgstr "dossier-annee" -#: models.py:1590 +#: models.py:1663 msgctxt "key for text search" msgid "file-other-reference" msgstr "dossier-autre-reference" -#: models.py:1594 +#: models.py:1667 msgctxt "key for text search" msgid "file-in-charge" msgstr "dossier-responsable" -#: models.py:1598 +#: models.py:1671 msgctxt "key for text search" msgid "file-permit-reference" msgstr "dossier-ref-permis" -#: models.py:1602 +#: models.py:1675 msgctxt "key for text search" msgid "treatment-name" msgstr "traitement-nom" -#: models.py:1606 +#: models.py:1679 msgctxt "key for text search" msgid "treatment-reference" msgstr "traitement-reference" -#: models.py:1610 +#: models.py:1683 msgctxt "key for text search" msgid "treatment-year" msgstr "traitement-annee" -#: models.py:1614 +#: models.py:1687 msgctxt "key for text search" msgid "treatment-index" msgstr "traitement-index" -#: models.py:1618 +#: models.py:1691 msgctxt "key for text search" msgid "treatment-type" msgstr "traitement-type" -#: models.py:1622 +#: models.py:1695 msgctxt "key for text search" msgid "treatment-file-name" msgstr "dossier-traitement-nom" -#: models.py:1626 +#: models.py:1699 msgctxt "key for text search" msgid "treatment-file-reference" msgstr "dossier-traitement-reference" -#: models.py:1630 +#: models.py:1703 msgctxt "key for text search" msgid "treatment-file-year" msgstr "dossier-traitement-annee" -#: models.py:1634 +#: models.py:1707 msgctxt "key for text search" msgid "treatment-file-index" msgstr "dossier-traitement-index" -#: models.py:1638 +#: models.py:1711 msgctxt "key for text search" msgid "treatment-file-type" msgstr "dossier-traitement-type" -#: models.py:1661 +#: models.py:1734 msgid "Person in charge of the operation" msgstr "Responsable d'opération" -#: models.py:1667 +#: models.py:1740 msgid "Archaeological preventive operator" msgstr "Opérateur d'archéologie préventive" -#: models.py:1675 +#: models.py:1748 msgid "Signatory" msgstr "Signataire" -#: models.py:1703 +#: models.py:1776 msgid "Departments" msgstr "Départements" -#: models.py:1704 +#: models.py:1777 msgid "Cached values get from associated departments" msgstr "Valeur en cache des départements associés" -#: models.py:1707 +#: models.py:1780 msgid "Cached values get from associated towns" msgstr "Valeur en cache des communes associées" -#: models.py:1714 templates/ishtar/sheet_operation.html:202 -#: templates/ishtar/sheet_operation.html:244 +#: models.py:1787 templates/ishtar/sheet_operation.html:205 +#: templates/ishtar/sheet_operation.html:251 msgid "Administrative acts" msgstr "Actes administratifs" -#: models.py:1837 +#: models.py:1920 msgid "This index already exists for this year" msgstr "Cet index existe déjà pour cette année." -#: models.py:1921 +#: models.py:2004 msgid "External ID" msgstr "Identifiant" -#: models.py:1924 +#: models.py:2007 msgid "External ID is set automatically" msgstr "L'identifiant est attribué automatiquement" -#: models.py:1925 +#: models.py:2008 msgid "Address - Locality" msgstr "Adresse - Lieu-dit" -#: models.py:2140 +#: models.py:2223 msgid "Owner" msgstr "Propriétaire" -#: models.py:2148 +#: models.py:2231 msgid "Parcel owner" msgstr "Propriétaire de parcelle" -#: models.py:2149 +#: models.py:2232 msgid "Parcel owners" msgstr "Propriétaires de parcelle" -#: models.py:2183 +#: models.py:2266 msgid "Recorded" msgstr "Enregistré" -#: models.py:2184 +#: models.py:2267 msgid "Effective" msgstr "Effectif" -#: models.py:2185 +#: models.py:2268 msgid "Active" msgstr "Actif" -#: models.py:2186 +#: models.py:2269 msgid "Field completed" msgstr "Terrain achevé" -#: models.py:2187 +#: models.py:2270 msgid "Associated report" msgstr "Rapport associé" -#: models.py:2188 +#: models.py:2271 msgid "Closed" msgstr "Clos" -#: models.py:2189 +#: models.py:2272 msgid "Documented and closed" msgstr "Documenté et clos" -#: models.py:2623 +#: models.py:2706 msgid "Is preventive" msgstr "Préventif" -#: models.py:2626 +#: models.py:2709 msgid "Operation type old" msgstr "Type d'opération - ancien" -#: models.py:2627 +#: models.py:2710 msgid "Operation types old" msgstr "Types d'opération - ancien" #: templates/ishtar/blocks/window_tables/administrativacts.html:7 -#: templates/ishtar/sheet_operation.html:263 -#: templates/ishtar/sheet_operation.html:327 +#: templates/ishtar/sheet_operation.html:270 +#: templates/ishtar/sheet_operation.html:334 msgid "Type" msgstr "Type" @@ -1488,12 +1523,12 @@ msgstr "État" #: templates/ishtar/dashboards/dashboard_operation.html:432 #: templates/ishtar/dashboards/dashboard_operation.html:463 #: templates/ishtar/dashboards/dashboard_operation.html:687 -#: templates/ishtar/sheet_operation.html:263 -#: templates/ishtar/sheet_operation.html:273 -#: templates/ishtar/sheet_operation.html:290 -#: templates/ishtar/sheet_operation.html:300 -#: templates/ishtar/sheet_operation.html:310 -#: templates/ishtar/sheet_operation.html:327 +#: templates/ishtar/sheet_operation.html:270 +#: templates/ishtar/sheet_operation.html:280 +#: templates/ishtar/sheet_operation.html:297 +#: templates/ishtar/sheet_operation.html:307 +#: templates/ishtar/sheet_operation.html:317 +#: templates/ishtar/sheet_operation.html:334 msgid "Number" msgstr "Nombre" @@ -1519,7 +1554,7 @@ msgstr "par types" #: templates/ishtar/dashboards/dashboard_operation.html:479 #: templates/ishtar/dashboards/dashboard_operation.html:499 #: templates/ishtar/dashboards/dashboard_operation.html:623 -#: templates/ishtar/sheet_operation.html:52 +#: templates/ishtar/sheet_operation.html:53 msgid "State" msgstr "État" @@ -1684,7 +1719,7 @@ msgid "area by organization by realisation year" msgstr "surface par organisation et par année de réalisation" #: templates/ishtar/dashboards/dashboard_operation.html:670 -#: templates/ishtar/sheet_operation.html:77 +#: templates/ishtar/sheet_operation.html:78 msgid "Cost" msgstr "Coût" @@ -1697,7 +1732,7 @@ msgid "main towns by cost" msgstr "communes principales par coût" #: templates/ishtar/sheet_administrativeact.html:40 -#: templates/ishtar/sheet_operation.html:69 +#: templates/ishtar/sheet_operation.html:70 msgid "Surface" msgstr "Surface" @@ -1705,103 +1740,103 @@ msgstr "Surface" msgid "Address" msgstr "Adresse" -#: templates/ishtar/sheet_operation.html:37 +#: templates/ishtar/sheet_operation.html:38 msgid "Begining date" msgstr "Date de début" -#: templates/ishtar/sheet_operation.html:54 +#: templates/ishtar/sheet_operation.html:55 msgid "Active file" msgstr "Dossier actif" -#: templates/ishtar/sheet_operation.html:55 +#: templates/ishtar/sheet_operation.html:56 msgid "Closed operation" msgstr "Opération close" -#: templates/ishtar/sheet_operation.html:62 +#: templates/ishtar/sheet_operation.html:63 msgid "by" msgstr "par" -#: templates/ishtar/sheet_operation.html:85 +#: templates/ishtar/sheet_operation.html:86 msgid "Duration" msgstr "Durée" -#: templates/ishtar/sheet_operation.html:87 +#: templates/ishtar/sheet_operation.html:88 msgid "days" msgstr "jours" -#: templates/ishtar/sheet_operation.html:129 +#: templates/ishtar/sheet_operation.html:130 msgid "Sheet" msgstr "Fiche" -#: templates/ishtar/sheet_operation.html:138 +#: templates/ishtar/sheet_operation.html:139 msgid "This operation is virtual." msgstr "Cette opération est virtuelle." -#: templates/ishtar/sheet_operation.html:144 +#: templates/ishtar/sheet_operation.html:145 msgid "Patriarche OA code not yet recorded!" msgstr "Code d'opération Patriarche non renseigné !" -#: templates/ishtar/sheet_operation.html:159 -#: templates/ishtar/sheet_site.html:43 +#: templates/ishtar/sheet_operation.html:160 +#: templates/ishtar/sheet_site.html:44 msgid "Localisation" msgstr "Localisation" -#: templates/ishtar/sheet_operation.html:198 +#: templates/ishtar/sheet_operation.html:200 msgid "Associated parcels" msgstr "Parcelles associées" -#: templates/ishtar/sheet_operation.html:206 +#: templates/ishtar/sheet_operation.html:209 msgid "Document from this operation" msgstr "Documents de cette opération" -#: templates/ishtar/sheet_operation.html:212 -#: templates/ishtar/sheet_operation.html:255 +#: templates/ishtar/sheet_operation.html:216 +#: templates/ishtar/sheet_operation.html:262 msgid "Context records" msgstr "Unités d'Enregistrement" -#: templates/ishtar/sheet_operation.html:217 +#: templates/ishtar/sheet_operation.html:221 msgid "Context record relations" msgstr "Relations entre Unités d'Enregistrement" -#: templates/ishtar/sheet_operation.html:222 +#: templates/ishtar/sheet_operation.html:226 msgid "Documents from associated context records" msgstr "Documents des Unités d'Enregistrement associées" -#: templates/ishtar/sheet_operation.html:227 -#: templates/ishtar/sheet_operation.html:282 -#: templates/ishtar/sheet_site.html:70 +#: templates/ishtar/sheet_operation.html:232 +#: templates/ishtar/sheet_operation.html:289 +#: templates/ishtar/sheet_site.html:73 msgid "Finds" msgstr "Mobilier" -#: templates/ishtar/sheet_operation.html:232 +#: templates/ishtar/sheet_operation.html:237 msgid "Documents from associated finds" msgstr "Documents du mobilier associé" -#: templates/ishtar/sheet_operation.html:237 +#: templates/ishtar/sheet_operation.html:243 msgid "Associated containers" msgstr "Contenants associés" -#: templates/ishtar/sheet_operation.html:241 +#: templates/ishtar/sheet_operation.html:248 msgid "Statistics" msgstr "Statistiques" -#: templates/ishtar/sheet_operation.html:242 +#: templates/ishtar/sheet_operation.html:249 msgid "These numbers are updated hourly" msgstr "Ces chiffres sont mis à jour toutes les heures" -#: templates/ishtar/sheet_operation.html:290 +#: templates/ishtar/sheet_operation.html:297 msgid "Material type" msgstr "Type de matériau" -#: templates/ishtar/sheet_operation.html:300 +#: templates/ishtar/sheet_operation.html:307 msgid "Object type" msgstr "Type d'objet" -#: templates/ishtar/sheet_operation.html:319 +#: templates/ishtar/sheet_operation.html:326 msgid "Sources" msgstr "Documents" -#: templates/ishtar/sheet_operation.html:337 +#: templates/ishtar/sheet_operation.html:344 msgid "Finds by context records" msgstr "Mobilier par Unités d'Enregistrement" @@ -1824,44 +1859,44 @@ msgstr "" "Le(s) erreur(s) suivante(s) ont été rencontrées lors de l'analyse du fichier " "source :" -#: views.py:244 +#: views.py:245 msgid "New operation" msgstr "Ajouter une opération" -#: views.py:293 +#: views.py:294 msgid "Operation modification" msgstr "Modifier une opération" -#: views.py:304 +#: views.py:305 msgid "You don't have sufficient permissions to do this action." msgstr "" "Vous n'avez pas les permissions suffisantes pour effectuer cette action." -#: views.py:329 +#: views.py:330 msgid "Operation closing" msgstr "Clôturer une opération" -#: views.py:340 +#: views.py:341 msgid "Operation deletion" msgstr "Supprimer une opération" -#: views.py:406 +#: views.py:407 msgid "Site deletion" msgstr "Suppression du site" -#: views.py:425 +#: views.py:426 msgid "Operation: new administrative act" msgstr "Opération : ajouter un acte administratif" -#: views.py:435 +#: views.py:436 msgid "Operation: administrative act modification" msgstr "Opération : modification d'un acte administratif" -#: views.py:459 +#: views.py:460 msgid "Operation: administrative act deletion" msgstr "Opération : supprimer un acte administratif" -#: views.py:552 +#: views.py:530 msgid "" "Syntax error on the source template \"{}\" - contact your administrator and " "ask him to check the syntax of this document." diff --git a/translations/fr/archaeological_warehouse.po b/translations/fr/archaeological_warehouse.po index 6b2c7ae8e..1f4e35014 100644 --- a/translations/fr/archaeological_warehouse.po +++ b/translations/fr/archaeological_warehouse.po @@ -11,322 +11,322 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Content-Type: text/plain; charset=UTF-8\n" -"PO-Revision-Date: 2018-11-12 10:09+0000\n" +"PO-Revision-Date: 2018-12-04 01:07+0000\n" "Last-Translator: Étienne Loks <etienne.loks@iggdrasil.net>\n" "Language-Team: \n" "Language: fr\n" "Plural-Forms: nplurals=2; plural=n>1;\n" "X-Generator: Zanata 4.6.2\n" -#: forms.py:41 forms.py:113 ishtar_menu.py:40 models.py:94 models.py:258 +#: forms.py:42 forms.py:114 ishtar_menu.py:32 models.py:95 models.py:259 #: templates/ishtar/sheet_warehouse.html:4 msgid "Warehouse" msgstr "Lieu de conservation" -#: forms.py:50 forms.py:55 models.py:622 +#: forms.py:51 forms.py:56 models.py:638 msgid "Division" msgstr "Division" -#: forms.py:57 models.py:286 +#: forms.py:58 models.py:287 msgid "Order" msgstr "Ordre" -#: forms.py:71 +#: forms.py:72 msgid "There are identical divisions." msgstr "Il y a des divisions identiques" -#: forms.py:76 models.py:83 +#: forms.py:77 models.py:84 msgid "Divisions" msgstr "Divisions" -#: forms.py:77 +#: forms.py:78 msgid "Warehouse - 020 - Divisions" msgstr "Lieu de conservation - 020 - Divisions" -#: forms.py:85 forms.py:254 +#: forms.py:86 forms.py:255 msgid "Full text search" msgstr "Recherche en texte intégral" -#: forms.py:88 forms.py:119 models.py:75 models.py:255 +#: forms.py:89 forms.py:120 models.py:76 models.py:256 msgid "Name" msgstr "Nom" -#: forms.py:89 forms.py:121 models.py:39 models.py:77 +#: forms.py:90 forms.py:122 models.py:40 models.py:78 msgid "Warehouse type" msgstr "Type de lieu de conservation" -#: forms.py:101 views.py:108 +#: forms.py:102 views.py:120 msgid "Warehouse search" msgstr "Rechercher un lieu de conservation" -#: forms.py:114 +#: forms.py:115 msgid "Warehouse - 010 - General" msgstr "Lieu de conservation - 010 - Général" -#: forms.py:124 models.py:80 +#: forms.py:125 models.py:81 msgid "Person in charge" msgstr "Responsable" -#: forms.py:130 forms.py:198 models.py:81 models.py:381 +#: forms.py:131 forms.py:199 models.py:82 models.py:383 msgid "Comment" msgstr "Commentaire" -#: forms.py:132 +#: forms.py:133 msgid "Address" msgstr "Adresse" -#: forms.py:134 +#: forms.py:135 msgid "Address complement" msgstr "Complément d'adresse" -#: forms.py:136 +#: forms.py:137 msgid "Postal code" msgstr "Code postal" -#: forms.py:138 +#: forms.py:139 msgid "Town" msgstr "Commune" -#: forms.py:139 +#: forms.py:140 msgid "Country" msgstr "Pays" -#: forms.py:141 +#: forms.py:142 msgid "Phone" msgstr "Téléphone" -#: forms.py:142 +#: forms.py:143 msgid "Mobile phone" msgstr "Téléphone mobile" -#: forms.py:167 forms.py:168 +#: forms.py:168 forms.py:169 msgid "Would you like to delete this warehouse?" msgstr "Voulez-vous supprimer ce lieu de conservation?" -#: forms.py:172 models.py:395 models.py:619 +#: forms.py:173 models.py:397 models.py:635 #: templates/ishtar/sheet_container.html:4 msgid "Container" msgstr "Contenant" -#: forms.py:173 +#: forms.py:174 msgid "Container - 010 - General" msgstr "Contenant - 010 - Général" -#: forms.py:179 forms.py:261 models.py:301 +#: forms.py:180 forms.py:262 models.py:302 msgid "Ref." msgstr "Réf." -#: forms.py:180 models.py:389 +#: forms.py:181 models.py:391 msgid "Old reference" msgstr "Ancienne référence" -#: forms.py:182 forms.py:260 models.py:304 models.py:379 +#: forms.py:183 forms.py:261 models.py:306 models.py:381 msgid "Container type" msgstr "Type de contenant" -#: forms.py:184 forms.py:258 +#: forms.py:185 forms.py:259 msgid "Current location (warehouse)" msgstr "Localisation actuelle (lieu de conservation)" -#: forms.py:190 forms.py:259 models.py:376 +#: forms.py:191 forms.py:260 models.py:378 msgid "Responsible warehouse" msgstr "Lieu de conservation responsable" -#: forms.py:196 +#: forms.py:197 msgid "Image" msgstr "Image" -#: forms.py:223 +#: forms.py:224 msgid "ID" msgstr "Identifiant" -#: forms.py:245 +#: forms.py:246 msgid "This ID already exists for this warehouse." msgstr "Cet identifiant existe déjà pour ce lieu de conservation." -#: forms.py:272 forms.py:278 views.py:150 +#: forms.py:273 forms.py:279 views.py:162 msgid "Container search" msgstr "Rechercher un contenant" -#: forms.py:274 forms.py:280 +#: forms.py:275 forms.py:281 msgid "You should select a container." msgstr "Vous devez sélectionner un contenant." -#: forms.py:275 +#: forms.py:276 msgid "Add a new container" msgstr "Ajouter un nouveau contenant" -#: forms.py:285 ishtar_menu.py:36 views.py:103 +#: forms.py:286 views.py:115 msgid "Packaging" msgstr "Conditionnement" -#: forms.py:291 +#: forms.py:292 msgid "Packager" msgstr "Personne assurant le conditionnement" -#: forms.py:297 +#: forms.py:298 msgid "Date" msgstr "Date" -#: forms.py:301 +#: forms.py:304 msgid "Packaged finds" msgstr "Mobilier conditionné" -#: forms.py:305 +#: forms.py:308 msgid "Container - 020 - Localisation" msgstr "Contenant - 020 - Localisation" -#: forms.py:307 models.py:382 +#: forms.py:310 models.py:384 msgid "Localisation" msgstr "Localisation" -#: forms.py:331 forms.py:332 +#: forms.py:334 forms.py:335 msgid "Would you like to delete this container?" msgstr "Voulez-vous supprimer ce contenant ?" -#: ishtar_menu.py:32 -msgid "Treatment" -msgstr "Traitement" - -#: ishtar_menu.py:44 ishtar_menu.py:59 +#: ishtar_menu.py:36 ishtar_menu.py:51 msgid "Search" msgstr "Recherche" -#: ishtar_menu.py:47 ishtar_menu.py:63 +#: ishtar_menu.py:39 ishtar_menu.py:55 msgid "Creation" msgstr "Ajout" -#: ishtar_menu.py:50 ishtar_menu.py:67 +#: ishtar_menu.py:42 ishtar_menu.py:59 msgid "Modification" msgstr "Modification" -#: ishtar_menu.py:53 ishtar_menu.py:71 +#: ishtar_menu.py:45 ishtar_menu.py:63 msgid "Deletion" msgstr "Suppression" -#: ishtar_menu.py:57 models.py:396 templates/ishtar/sheet_warehouse.html:42 +#: ishtar_menu.py:49 models.py:398 templates/ishtar/sheet_warehouse.html:42 #: templates/ishtar/sheet_warehouse.html:87 msgid "Containers" msgstr "Contenants" -#: models.py:40 +#: models.py:41 msgid "Warehouse types" msgstr "Types de lieu de conservation" -#: models.py:60 +#: models.py:61 msgctxt "key for text search" msgid "name" msgstr "nom" -#: models.py:64 models.py:356 +#: models.py:65 models.py:358 msgctxt "key for text search" msgid "type" msgstr "type" -#: models.py:87 +#: models.py:88 msgid "Documents" msgstr "Documents" -#: models.py:89 models.py:390 +#: models.py:90 models.py:392 msgid "External ID" msgstr "Identifiant" -#: models.py:91 models.py:392 +#: models.py:92 models.py:394 msgid "External ID is set automatically" msgstr "L'identifiant est attribué automatiquement" -#: models.py:95 +#: models.py:96 msgid "Warehouses" msgstr "Lieux de conservation" -#: models.py:257 +#: models.py:258 msgid "Description" msgstr "Description" -#: models.py:262 models.py:263 +#: models.py:263 models.py:264 msgid "Collection" msgstr "Collection" -#: models.py:272 +#: models.py:273 msgid "Warehouse division type" msgstr "Type de division de lieu de conservation" -#: models.py:273 +#: models.py:274 msgid "Warehouse division types" msgstr "Types de division de lieu de conservation" -#: models.py:297 +#: models.py:298 msgid "Length (mm)" msgstr "Longueur (mm)" -#: models.py:298 +#: models.py:299 msgid "Width (mm)" msgstr "Largeur (mm)" -#: models.py:299 +#: models.py:300 msgid "Height (mm)" msgstr "Hauteur (mm)" -#: models.py:300 +#: models.py:301 msgid "Volume (l)" msgstr "Volume (l)" -#: models.py:305 +#: models.py:307 msgid "Container types" msgstr "Types de contenant" -#: models.py:339 +#: models.py:341 msgid "Location - index" msgstr "Localisation - index" -#: models.py:340 +#: models.py:342 msgid "Precise localisation" msgstr "Localisation précise" -#: models.py:341 +#: models.py:343 msgid "Type" msgstr "Type" -#: models.py:348 +#: models.py:350 msgctxt "key for text search" msgid "location" msgstr "localisation" -#: models.py:352 +#: models.py:354 msgctxt "key for text search" msgid "responsible-warehouse" msgstr "lieu-de-conservation-responsable" -#: models.py:360 +#: models.py:362 msgctxt "key for text search" msgid "reference" msgstr "reference" -#: models.py:373 +#: models.py:375 msgid "Location (warehouse)" msgstr "Localisation (lieu de conservation)" -#: models.py:380 +#: models.py:382 msgid "Container ref." msgstr "Réf. du contenant" -#: models.py:384 +#: models.py:386 msgid "Cached location" msgstr "Localisation - en cache" -#: models.py:386 +#: models.py:388 msgid "Cached division" msgstr "Division mise en cache" -#: models.py:623 +#: models.py:584 +msgid "Add treatment" +msgstr "Ajouter un traitement" + +#: models.py:639 msgid "Reference" msgstr "Référence" -#: models.py:626 +#: models.py:642 msgid "Container localisation" msgstr "Localisation de contenant" -#: models.py:627 +#: models.py:643 msgid "Container localisations" msgstr "Localisations de contenant" @@ -391,26 +391,26 @@ msgstr "" "Des contenants localisés sont associés à ce lieu de conservation. Vous ne " "pouvez pas modifier les divisions." -#: views.py:120 +#: views.py:132 msgid "Warehouse creation" msgstr "Ajouter un lieu de conservation" -#: views.py:129 +#: views.py:141 msgid "Warehouse modification" msgstr "Modifier un lieu de conservation" -#: views.py:145 +#: views.py:157 msgid "Warehouse deletion" msgstr "Supprimer un lieu de conservation" -#: views.py:161 +#: views.py:173 msgid "Container creation" msgstr "Ajouter un contenant" -#: views.py:170 +#: views.py:182 msgid "Container modification" msgstr "Modifier un contenant" -#: views.py:185 +#: views.py:197 msgid "Container deletion" msgstr "Supprimer un contenant" diff --git a/translations/fr/ishtar_common.po b/translations/fr/ishtar_common.po index 0c15c6cf7..11b5f6aa2 100644 --- a/translations/fr/ishtar_common.po +++ b/translations/fr/ishtar_common.po @@ -12,7 +12,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Content-Type: text/plain; charset=UTF-8\n" -"PO-Revision-Date: 2018-11-12 10:08+0000\n" +"PO-Revision-Date: 2018-12-04 01:09+0000\n" "Last-Translator: Étienne Loks <etienne.loks@iggdrasil.net>\n" "Language-Team: \n" "Language: fr\n" @@ -43,12 +43,12 @@ msgstr "Seul l'unicode est géré - convertissez votre fichier d'abord" msgid "Export selected as CSV file" msgstr "Exporter la sélection en fichier CSV" -#: admin.py:207 models.py:1686 templates/navbar.html:31 +#: admin.py:207 models.py:1703 templates/navbar.html:31 msgid "Profile" msgstr "Profil" #: admin.py:208 forms_common.py:782 forms_common.py:801 forms_common.py:802 -#: models.py:3039 +#: models.py:3063 msgid "Profiles" msgstr "Profils" @@ -70,7 +70,7 @@ msgstr "%d élément(s) mis à jour." msgid "These parents are missing: {}" msgstr "Ces parents sont manquants : {}" -#: admin.py:386 admin.py:405 models.py:883 models.py:4141 +#: admin.py:386 admin.py:405 models.py:905 models.py:4214 msgid "Parent" msgstr "Parent" @@ -78,11 +78,11 @@ msgstr "Parent" msgid "Center" msgstr "Centre" -#: admin.py:395 models.py:4003 +#: admin.py:395 models.py:4076 msgid "Limit" msgstr "Limite" -#: admin.py:398 models.py:4013 +#: admin.py:398 models.py:4086 msgid "Town children" msgstr "Communes enfants" @@ -131,16 +131,16 @@ msgstr "Afficher les éléments sélectionnés" msgid "Hide selected" msgstr "Cacher les éléments sélectionnés" -#: admin.py:931 models.py:2080 +#: admin.py:931 models.py:2098 msgid "Form" msgstr "Formulaire" -#: admin.py:933 models.py:2105 models_imports.py:127 +#: admin.py:933 models.py:2123 models_imports.py:127 #: templates/ishtar/dashboards/dashboard_main.html:39 msgid "Users" msgstr "Utilisateurs" -#: admin.py:953 models.py:2180 +#: admin.py:953 models.py:2202 msgid "Field" msgstr "Champ" @@ -239,7 +239,7 @@ msgstr "" msgid "Too many cols (%(user_col)d) when maximum is %(ref_col)d" msgstr "Trop de colonnes (%(user_col)d). Le maximum est %(ref_col)d" -#: data_importer.py:730 views.py:1177 +#: data_importer.py:730 views.py:1200 msgid "No data provided" msgstr "Aucune donnée fournie" @@ -272,7 +272,7 @@ msgstr "" "L'élément {} avec les valeurs {} n'existe pas dans la base de données. Créez-" "le d'abord ou corrigez votre fichier source." -#: data_importer.py:1236 views.py:1255 views.py:1265 +#: data_importer.py:1236 views.py:1278 views.py:1288 msgid "Not imported" msgstr "Non importé" @@ -339,7 +339,7 @@ msgstr "\"%(value)s\" n'est pas dans %(values)s" msgid "Enter a valid name consisting of letters, spaces and hyphens." msgstr "Entrez un nom correct composé de lettres, espaces et tirets." -#: forms.py:96 forms_common.py:808 views.py:1968 +#: forms.py:96 forms_common.py:808 views.py:2017 msgid "Confirm" msgstr "Confirmer" @@ -347,36 +347,44 @@ msgstr "Confirmer" msgid "Are you sure you want to delete?" msgstr "Êtes-vous sûr de vouloir supprimer ?" -#: forms.py:379 +#: forms.py:410 msgid "There are identical items." msgstr "Il y a des éléments identiques." -#: forms.py:535 +#: forms.py:566 msgid "Last modified by" msgstr "Modifié en dernier par" -#: forms.py:541 +#: forms.py:572 msgid "Modified since" msgstr "Modifié depuis" -#: forms.py:565 forms.py:566 +#: forms.py:596 forms.py:597 msgid "Closing date" msgstr "Date de clôture" -#: forms.py:578 forms_common.py:1272 +#: forms.py:609 forms_common.py:1272 msgid "You should select an item." msgstr "Vous devez sélectionner un élément." -#: forms.py:579 +#: forms.py:610 msgid "Add a new item" msgstr "Ajouter un nouvel élément" -#: forms.py:769 models.py:2434 +#: forms.py:757 +msgid " - append to existing" +msgstr " - ajouter à l'existant" + +#: forms.py:760 +msgid " - replace" +msgstr " - remplacer" + +#: forms.py:803 models.py:2457 msgid "Template" msgstr "Patron" #: forms_common.py:54 forms_common.py:72 forms_common.py:317 -#: forms_common.py:556 models.py:2568 models.py:4020 +#: forms_common.py:556 models.py:2591 models.py:4093 #: templates/blocks/JQueryAdvancedTown.html:19 msgid "Town" msgstr "Commune" @@ -398,8 +406,8 @@ msgstr "" "<p class='example'>Par exemple tapez « saint denis 93 » pour obtenir la " "commune Saint-Denis dans le département français de Seine-Saint-Denis.</p>" -#: forms_common.py:81 forms_common.py:1293 ishtar_menu.py:48 models.py:2952 -#: models.py:3204 models.py:3332 models.py:3495 +#: forms_common.py:81 forms_common.py:1293 ishtar_menu.py:48 models.py:2976 +#: models.py:3228 models.py:3357 models.py:3561 #: templates/ishtar/sheet_person.html:4 msgid "Person" msgstr "Personne" @@ -455,17 +463,17 @@ msgid "all users" msgstr "tous les utilisateurs" #: forms_common.py:305 forms_common.py:475 forms_common.py:609 -#: ishtar_menu.py:76 models.py:2773 models.py:2890 models.py:3292 +#: ishtar_menu.py:76 models.py:2796 models.py:2914 models.py:3317 #: templates/ishtar/sheet_organization.html:4 msgid "Organization" msgstr "Organisation" #: forms_common.py:308 forms_common.py:351 forms_common.py:470 #: forms_common.py:526 forms_common.py:604 forms_common.py:790 -#: forms_common.py:823 models.py:1056 models.py:1080 models.py:1879 -#: models.py:2079 models.py:2430 models.py:2765 models.py:2936 models.py:3192 -#: models.py:3999 models.py:4262 models_imports.py:98 models_imports.py:123 -#: models_imports.py:445 models_imports.py:537 models_imports.py:827 +#: forms_common.py:823 models.py:1078 models.py:1102 models.py:1897 +#: models.py:2097 models.py:2453 models.py:2788 models.py:2960 models.py:3216 +#: models.py:4072 models.py:4337 models_imports.py:98 models_imports.py:123 +#: models_imports.py:445 models_imports.py:537 models_imports.py:828 #: templates/ishtar/import_step_by_step.html:102 #: templates/ishtar/import_step_by_step.html:270 #: templates/ishtar/import_table.html:27 @@ -473,40 +481,40 @@ msgstr "Organisation" msgid "Name" msgstr "Nom" -#: forms_common.py:309 models.py:2721 models_imports.py:630 +#: forms_common.py:309 models.py:2744 models_imports.py:630 #: models_imports.py:631 msgid "Organization type" msgstr "Type d'organisation" -#: forms_common.py:311 forms_common.py:550 models.py:2563 +#: forms_common.py:311 forms_common.py:550 models.py:2586 #: templates/ishtar/blocks/sheet_address_section.html:4 msgid "Address" msgstr "Adresse" -#: forms_common.py:313 forms_common.py:553 models.py:2564 +#: forms_common.py:313 forms_common.py:553 models.py:2587 msgid "Address complement" msgstr "Complément d'adresse" -#: forms_common.py:315 forms_common.py:554 models.py:2566 +#: forms_common.py:315 forms_common.py:554 models.py:2589 msgid "Postal code" msgstr "Code postal" -#: forms_common.py:318 forms_common.py:557 models.py:2569 +#: forms_common.py:318 forms_common.py:557 models.py:2592 msgid "Country" msgstr "Pays" #: forms_common.py:320 forms_common.py:472 forms_common.py:530 -#: forms_common.py:606 forms_common.py:731 models.py:2596 +#: forms_common.py:606 forms_common.py:731 models.py:2619 msgid "Email" msgstr "Courriel" -#: forms_common.py:321 forms_common.py:533 models.py:2581 +#: forms_common.py:321 forms_common.py:533 models.py:2604 #: templates/ishtar/sheet_person.html:27 #: templates/ishtar/wizard/wizard_person.html:33 msgid "Phone" msgstr "Téléphone" -#: forms_common.py:322 forms_common.py:542 models.py:2593 +#: forms_common.py:322 forms_common.py:542 models.py:2616 #: templates/ishtar/sheet_person.html:45 #: templates/ishtar/wizard/wizard_person.html:54 msgid "Mobile phone" @@ -518,8 +526,8 @@ msgid "Full text search" msgstr "Recherche en texte intégral" #: forms_common.py:352 forms_common.py:473 forms_common.py:607 -#: forms_common.py:788 models.py:1089 models.py:2767 models.py:3738 -#: models_imports.py:680 templates/ishtar/blocks/window_image_detail.html:24 +#: forms_common.py:788 models.py:1111 models.py:2790 models.py:3804 +#: models_imports.py:681 templates/ishtar/blocks/window_image_detail.html:24 #: templates/ishtar/blocks/window_tables/documents.html:8 #: templates/ishtar/import_table.html:28 #: templates/ishtar/sheet_organization.html:25 @@ -542,7 +550,7 @@ msgstr "Fusionner tous les éléments dans" msgid "Organization to merge" msgstr "Organisation à fusionner" -#: forms_common.py:471 forms_common.py:524 forms_common.py:605 models.py:2934 +#: forms_common.py:471 forms_common.py:524 forms_common.py:605 models.py:2958 #: templates/ishtar/sheet_organization.html:24 msgid "Surname" msgstr "Prénom" @@ -559,25 +567,25 @@ msgstr "Personne à fusionner" msgid "Identity" msgstr "Identité" -#: forms_common.py:521 forms_common.py:1095 forms_common.py:1217 models.py:2928 -#: models.py:2930 models.py:3729 models_imports.py:632 +#: forms_common.py:521 forms_common.py:1095 forms_common.py:1217 models.py:2952 +#: models.py:2954 models.py:3795 models_imports.py:633 #: templates/ishtar/blocks/window_tables/documents.html:7 msgid "Title" msgstr "Titre" -#: forms_common.py:522 models.py:2932 +#: forms_common.py:522 models.py:2956 msgid "Salutation" msgstr "Formule d'appel" -#: forms_common.py:528 models.py:2938 +#: forms_common.py:528 models.py:2962 msgid "Raw name" msgstr "Nom brut" -#: forms_common.py:531 models.py:2582 +#: forms_common.py:531 models.py:2605 msgid "Phone description" msgstr "Type de téléphone" -#: forms_common.py:534 models.py:2584 models.py:2586 +#: forms_common.py:534 models.py:2607 models.py:2609 msgid "Phone description 2" msgstr "Type de téléphone 2" @@ -585,11 +593,11 @@ msgstr "Type de téléphone 2" msgid "Phone 2" msgstr "Téléphone 2" -#: forms_common.py:538 models.py:2590 +#: forms_common.py:538 models.py:2613 msgid "Phone description 3" msgstr "Type de téléphone 3" -#: forms_common.py:540 models.py:2588 +#: forms_common.py:540 models.py:2611 msgid "Phone 3" msgstr "Téléphone 3" @@ -597,23 +605,23 @@ msgstr "Téléphone 3" msgid "Current organization" msgstr "Organisation actuelle" -#: forms_common.py:559 models.py:2571 +#: forms_common.py:559 models.py:2594 msgid "Other address: address" msgstr "Autre adresse : adresse" -#: forms_common.py:562 models.py:2574 +#: forms_common.py:562 models.py:2597 msgid "Other address: address complement" msgstr "Autre adresse : complément d'adresse" -#: forms_common.py:564 models.py:2575 +#: forms_common.py:564 models.py:2598 msgid "Other address: postal code" msgstr "Autre adresse : code postal" -#: forms_common.py:566 models.py:2577 +#: forms_common.py:566 models.py:2600 msgid "Other address: town" msgstr "Autre adresse : ville" -#: forms_common.py:568 models.py:2579 +#: forms_common.py:568 models.py:2602 msgid "Other address: country" msgstr "Autre adresse : pays" @@ -621,7 +629,7 @@ msgstr "Autre adresse : pays" msgid "Already has an account" msgstr "A déjà un compte" -#: forms_common.py:603 models.py:3293 +#: forms_common.py:603 models.py:3318 msgid "Username" msgstr "Nom d'utilisateur" @@ -629,7 +637,8 @@ msgstr "Nom d'utilisateur" msgid "Account search" msgstr "Rechercher un compte" -#: forms_common.py:669 forms_common.py:709 forms_common.py:713 models.py:2829 +#: forms_common.py:669 forms_common.py:709 forms_common.py:713 models.py:2853 +#: models_imports.py:632 msgid "Person type" msgstr "Type de personne" @@ -637,7 +646,7 @@ msgstr "Type de personne" msgid "Account" msgstr "Compte" -#: forms_common.py:734 wizards.py:1639 +#: forms_common.py:734 wizards.py:1651 msgid "New password" msgstr "Nouveau mot de passe" @@ -657,7 +666,7 @@ msgstr "Vous devez fournir un mot de passe correct." msgid "This username already exists." msgstr "Ce nom d'utilisateur existe déjà ." -#: forms_common.py:789 models.py:3195 models.py:4148 +#: forms_common.py:789 models.py:3219 models.py:4221 msgid "Areas" msgstr "Zones" @@ -665,11 +674,11 @@ msgstr "Zones" msgid "Send the new password by email?" msgstr "Envoyer le nouveau mot de passe par courriel ?" -#: forms_common.py:821 models.py:3197 views.py:968 +#: forms_common.py:821 models.py:3221 views.py:991 msgid "Current profile" msgstr "Profil actuel" -#: forms_common.py:824 models.py:3175 models.py:3194 +#: forms_common.py:824 models.py:3199 models.py:3218 msgid "Profile type" msgstr "Type de profil" @@ -698,8 +707,8 @@ msgstr "Un profil avec un nom identique existe" msgid " (duplicate)" msgstr "(copie)" -#: forms_common.py:932 forms_common.py:946 forms_common.py:947 models.py:4021 -#: models.py:4136 +#: forms_common.py:932 forms_common.py:946 forms_common.py:947 models.py:4094 +#: models.py:4209 msgid "Towns" msgstr "Communes" @@ -728,19 +737,19 @@ msgstr "Documentation" msgid "Document - General" msgstr "Document - Général" -#: forms_common.py:1098 forms_common.py:1218 models.py:3543 -#: models_imports.py:633 +#: forms_common.py:1098 forms_common.py:1218 models.py:3609 +#: models_imports.py:634 msgid "Source type" msgstr "Type de document" #: forms_common.py:1101 forms_common.py:1152 forms_common.py:1333 -#: forms_common.py:1334 models.py:3504 models.py:3612 models.py:3748 +#: forms_common.py:1334 models.py:3570 models.py:3678 models.py:3814 #: templates/ishtar/blocks/window_image_detail.html:9 #: templates/ishtar/blocks/window_tables/documents.html:9 msgid "Authors" msgstr "Auteurs" -#: forms_common.py:1105 models.py:3754 +#: forms_common.py:1105 models.py:3820 msgid "Numerical ressource (web address)" msgstr "Ressource numérique (adresse web)" @@ -753,7 +762,7 @@ msgctxt "Not directory" msgid "File" msgstr "Fichier" -#: forms_common.py:1113 forms_common.py:1219 models.py:4138 +#: forms_common.py:1113 forms_common.py:1219 models.py:4211 msgid "Reference" msgstr "Référence" @@ -761,38 +770,38 @@ msgstr "Référence" msgid "Internal reference" msgstr "Référence interne" -#: forms_common.py:1118 models.py:3756 +#: forms_common.py:1118 models.py:3822 #: templates/ishtar/blocks/window_image_detail.html:150 msgid "Receipt date" msgstr "Date de réception" -#: forms_common.py:1120 models.py:3758 models_imports.py:859 +#: forms_common.py:1120 models.py:3824 models_imports.py:860 #: templates/ishtar/blocks/window_image_detail.html:54 msgid "Creation date" msgstr "Date de création" -#: forms_common.py:1123 models.py:3761 +#: forms_common.py:1123 models.py:3827 #: templates/ishtar/blocks/window_image_detail.html:160 msgid "Receipt date in documentation" msgstr "Date de réception en documentation" -#: forms_common.py:1125 forms_common.py:1222 models.py:473 models.py:2942 -#: models.py:3421 models.py:3764 models_imports.py:483 +#: forms_common.py:1125 forms_common.py:1222 models.py:496 models.py:2966 +#: models.py:3446 models.py:3830 models_imports.py:483 #: templates/ishtar/blocks/window_image_detail.html:170 msgid "Comment" msgstr "Commentaire" -#: forms_common.py:1127 forms_common.py:1221 models.py:1884 models.py:3763 +#: forms_common.py:1127 forms_common.py:1221 models.py:1902 models.py:3829 #: models_imports.py:125 models_imports.py:372 models_imports.py:446 msgid "Description" msgstr "Description" -#: forms_common.py:1130 models.py:3765 +#: forms_common.py:1130 models.py:3831 #: templates/ishtar/blocks/window_image_detail.html:182 msgid "Additional information" msgstr "Information supplémentaire" -#: forms_common.py:1132 forms_common.py:1225 models.py:3767 +#: forms_common.py:1132 forms_common.py:1225 models.py:3833 #: templates/ishtar/blocks/window_image_detail.html:108 msgid "Has a duplicate" msgstr "Existe en doublon" @@ -821,15 +830,15 @@ msgstr "Éléments reliés" #: forms_common.py:1173 msgid "You should at least fill one of this field: title, url, image or file." msgstr "" -"Vous devez au minimum remplir un de ces champs : titres, url, image ou " -"fichier" +"Vous devez au minimum remplir un de ces champs : titre, url, image ou " +"fichier." #: forms_common.py:1179 -msgid "A document have to attached at least to one item" -msgstr "Un document doit être rattaché au minimum à un élément" +msgid "A document has to be attached at least to one item" +msgstr "Un document doit être attaché au moins à un élément" #: forms_common.py:1214 forms_common.py:1286 forms_common.py:1321 -#: models.py:3503 templates/ishtar/wizard/wizard_person_deletion.html:139 +#: models.py:3569 templates/ishtar/wizard/wizard_person_deletion.html:139 msgid "Author" msgstr "Auteur" @@ -857,7 +866,7 @@ msgstr "Recherche document" msgid "Would you like to delete this documentation?" msgstr "Voulez-vous supprimer ce document ?" -#: forms_common.py:1294 models.py:3468 models.py:3497 models_imports.py:634 +#: forms_common.py:1294 models.py:3534 models.py:3563 models_imports.py:635 msgid "Author type" msgstr "Type d'auteur" @@ -869,11 +878,11 @@ msgstr "Sélection d'auteur" msgid "There are identical authors." msgstr "Il y a des auteurs identiques." -#: forms_common.py:1339 models.py:1683 +#: forms_common.py:1339 models.py:1700 msgid "Query" msgstr "Requête" -#: forms_common.py:1344 models.py:1687 +#: forms_common.py:1344 models.py:1704 msgid "Is an alert" msgstr "Est une alerte" @@ -913,7 +922,7 @@ msgstr "Ajout/modification" msgid "Deletion" msgstr "Suppression" -#: ishtar_menu.py:40 models.py:2209 views.py:992 +#: ishtar_menu.py:40 models.py:2231 views.py:1015 msgid "Global variables" msgstr "Variables globales" @@ -933,7 +942,7 @@ msgid "Creation" msgstr "Ajout" #: ishtar_menu.py:59 ishtar_menu.py:89 ishtar_menu.py:139 -#: templates/ishtar/forms/qa_base.html:29 +#: templates/ishtar/forms/qa_base.html:28 #: templates/ishtar/forms/qa_form.html:16 msgid "Modification" msgstr "Modification" @@ -946,19 +955,19 @@ msgstr "Fusion automatique" msgid "Manual merge" msgstr "Fusion manuelle" -#: ishtar_menu.py:110 models_imports.py:882 +#: ishtar_menu.py:110 models_imports.py:883 msgid "Imports" msgstr "Imports" -#: ishtar_menu.py:113 views.py:1000 +#: ishtar_menu.py:113 views.py:1023 msgid "New import" msgstr "Nouvel import" -#: ishtar_menu.py:117 views.py:1019 +#: ishtar_menu.py:117 views.py:1042 msgid "Current imports" msgstr "Imports en cours" -#: ishtar_menu.py:121 views.py:1468 +#: ishtar_menu.py:121 views.py:1491 msgid "Old imports" msgstr "Anciens imports" @@ -970,24 +979,24 @@ msgstr "Documentation / Images" msgid "Not a valid item." msgstr "Élément invalide." -#: models.py:211 +#: models.py:212 msgid "A selected item is not a valid item." msgstr "Un élément sélectionné n'est pas valide." -#: models.py:222 +#: models.py:224 msgid "This item already exists." msgstr "Cet élément existe déjà ." -#: models.py:465 models.py:1682 models.py:2191 models.py:2528 models.py:2544 -#: models.py:3420 models_imports.py:368 +#: models.py:488 models.py:1699 models.py:2213 models.py:2551 models.py:2567 +#: models.py:3445 models_imports.py:368 msgid "Label" msgstr "Dénomination" -#: models.py:467 +#: models.py:490 msgid "Textual ID" msgstr "Identifiant textuel" -#: models.py:470 +#: models.py:493 msgid "" "The slug is the standardized version of the name. It contains only lowercase " "letters, numbers and hyphens. Each slug must be unique." @@ -996,12 +1005,12 @@ msgstr "" "lettres en minuscule, des nombres et des tirets (-). Chaque \"slug\" doit " "être unique dans la typologie." -#: models.py:474 models.py:2081 models.py:2437 models.py:3425 +#: models.py:497 models.py:2099 models.py:2460 models.py:3450 #: models_imports.py:139 models_imports.py:542 msgid "Available" msgstr "Disponible" -#: models.py:898 models.py:1083 models_imports.py:563 +#: models.py:920 models.py:1105 models_imports.py:563 #: templates/ishtar/formset_import_match.html:21 #: templates/ishtar/import_step_by_step.html:171 #: templates/ishtar/import_step_by_step.html:199 @@ -1010,56 +1019,56 @@ msgstr "Disponible" msgid "Key" msgstr "Clé" -#: models.py:904 +#: models.py:926 msgid "Specific key to an import" msgstr "Clé spécifique à un import" -#: models.py:1043 +#: models.py:1065 msgid "Generated relation image (SVG)" msgstr "Image des relations (SVG généré)" -#: models.py:1057 models.py:1091 models.py:1604 models.py:2193 models.py:3465 -#: models.py:4165 models.py:4247 +#: models.py:1079 models.py:1113 models.py:1621 models.py:2215 models.py:3531 +#: models.py:4238 models.py:4320 msgid "Order" msgstr "Ordre" -#: models.py:1060 +#: models.py:1082 msgid "Json data - Menu" msgstr "Données JSON - Menu" -#: models.py:1061 +#: models.py:1083 msgid "Json data - Menus" msgstr "Données JSON - Menus" -#: models.py:1069 +#: models.py:1091 msgid "Text" msgstr "Texte" -#: models.py:1070 +#: models.py:1092 msgid "Long text" msgstr "Texte long" -#: models.py:1071 models_imports.py:676 +#: models.py:1093 models_imports.py:677 msgid "Integer" msgstr "Entier" -#: models.py:1072 +#: models.py:1094 msgid "Boolean" msgstr "Booléen" -#: models.py:1073 models_imports.py:677 +#: models.py:1095 models_imports.py:678 msgid "Float" msgstr "Nombre à virgule" -#: models.py:1074 models_imports.py:679 +#: models.py:1096 models_imports.py:680 msgid "Date" msgstr "Date" -#: models.py:1075 +#: models.py:1097 msgid "Choices" msgstr "Choix" -#: models.py:1084 +#: models.py:1106 msgid "" "Value of the key in the JSON schema. For hierarchical key use \"__\" to " "explain it. For instance for the key 'my_subkey' with data such as {'my_key':" @@ -1070,200 +1079,200 @@ msgstr "" "{'ma_clef': {'ma_sousclef': 'valeur'}}, sa valeur sera atteinte avec : " "ma_clef__ma_sousclef." -#: models.py:1088 +#: models.py:1110 msgid "Display" msgstr "Afficher" -#: models.py:1092 +#: models.py:1114 msgid "Use in search indexes" msgstr "Utiliser dans les index de recherche" -#: models.py:1099 +#: models.py:1121 msgid "Json data - Field" msgstr "Donnée JSON - Champ" -#: models.py:1100 +#: models.py:1122 msgid "Json data - Fields" msgstr "Donnée JSON - Champs" -#: models.py:1111 +#: models.py:1133 msgid "Content types of the field and of the menu do not match" msgstr "Les types de contenu du champ et du menu ne correspondent pas" -#: models.py:1171 +#: models.py:1193 msgid "Search vector" msgstr "Vecteur de recherche" -#: models.py:1172 +#: models.py:1194 msgid "Auto filled at save" msgstr "Auto-rempli à la sauvegarde" -#: models.py:1392 +#: models.py:1409 msgid "Add document/image" msgstr "Ajouter un document / une image" -#: models.py:1394 +#: models.py:1411 msgid "doc./image" msgstr "doc./image" -#: models.py:1413 +#: models.py:1430 msgid "Last editor" msgstr "Dernier éditeur" -#: models.py:1416 +#: models.py:1433 msgid "Creator" msgstr "Créateur" -#: models.py:1597 +#: models.py:1614 msgid "Above" msgstr "Au-dessus" -#: models.py:1598 +#: models.py:1615 msgid "Bellow" msgstr "En dessous" -#: models.py:1599 +#: models.py:1616 msgid "Equal" msgstr "Égal" -#: models.py:1605 +#: models.py:1622 msgid "Symmetrical" msgstr "Symétrique" -#: models.py:1606 +#: models.py:1623 msgid "Tiny label" msgstr "Dénomination courte" -#: models.py:1609 +#: models.py:1626 msgid "Inverse relation" msgstr "Relation inverse" -#: models.py:1612 +#: models.py:1629 msgid "Logical relation" msgstr "Relation logique" -#: models.py:1622 +#: models.py:1639 msgid "Cannot have symmetrical and an inverse_relation" msgstr "Ne peut pas être symétrique et avoir une relation inverse" -#: models.py:1685 +#: models.py:1702 msgid "Content type" msgstr "Type de contenu" -#: models.py:1690 +#: models.py:1707 msgid "Search query" msgstr "Requête de recherche" -#: models.py:1691 +#: models.py:1708 msgid "Search queries" msgstr "Requêtes de recherche" -#: models.py:1855 +#: models.py:1873 msgid "Euro" msgstr "Euro" -#: models.py:1856 +#: models.py:1874 msgid "US dollar" msgstr "Dollar US" -#: models.py:1857 views.py:742 views.py:803 +#: models.py:1875 views.py:765 views.py:826 msgid "Operations" msgstr "Opérations" -#: models.py:1858 views.py:744 views.py:807 +#: models.py:1876 views.py:767 views.py:830 msgid "Context records" msgstr "Unités d'Enregistrement" -#: models.py:1859 +#: models.py:1877 msgid "Site" msgstr "Site" -#: models.py:1859 +#: models.py:1877 msgid "Archaeological entity" msgstr "Entité (EA)" -#: models.py:1863 +#: models.py:1881 msgid "Site search" msgstr "Rechercher un site" -#: models.py:1864 +#: models.py:1882 msgid "New site" msgstr "Ajouter un site" -#: models.py:1865 +#: models.py:1883 msgid "Site modification" msgstr "Modifier un site" -#: models.py:1866 +#: models.py:1884 msgid "Site deletion" msgstr "Supprimer un site" -#: models.py:1869 +#: models.py:1887 msgid "Archaeological entity search" msgstr "Rechercher une entité archéologique" -#: models.py:1870 +#: models.py:1888 msgid "New archaeological entity" msgstr "Nouvelle entité archéologique" -#: models.py:1871 +#: models.py:1889 msgid "Archaeological entity modification" msgstr "Modifier une entité archéologique" -#: models.py:1872 +#: models.py:1890 msgid "Archaeological entity deletion" msgstr "Supprimer une entité archéologique" -#: models.py:1880 models.py:2431 models_imports.py:124 +#: models.py:1898 models.py:2454 models_imports.py:124 msgid "Slug" msgstr "Identifiant texte" -#: models.py:1881 +#: models.py:1899 msgid "Current active" msgstr "Actuellement utilisé" -#: models.py:1883 +#: models.py:1901 msgid "Activate experimental feature" msgstr "Activer les fonctionnalités expérimentales" -#: models.py:1886 +#: models.py:1904 msgid "Alternate configuration" msgstr "Configuration alternative" -#: models.py:1888 +#: models.py:1906 msgid "Choose an alternate configuration for label, index management" msgstr "" -"Choisir une configuration alternative pour les libellés, gestion des indexes" +"Choisir une configuration alternative pour les libellés, gestion des index" -#: models.py:1892 +#: models.py:1910 msgid "Files module" msgstr "Module Dossiers" -#: models.py:1894 +#: models.py:1912 msgid "Archaeological site module" msgstr "Module Site archéologique" -#: models.py:1896 +#: models.py:1914 msgid "Archaeological site type" msgstr "Type de site archéologique" -#: models.py:1900 +#: models.py:1918 msgid "Context records module" msgstr "Module Unités d'Enregistrement" -#: models.py:1902 +#: models.py:1920 msgid "Finds module" msgstr "Module Mobilier" -#: models.py:1903 +#: models.py:1921 msgid "Need context records module" msgstr "Nécessite le module Unités d'Enregistrement" -#: models.py:1905 +#: models.py:1923 msgid "Find index is based on" msgstr "Index mobilier basé sur" -#: models.py:1907 +#: models.py:1925 msgid "" "To prevent irrelevant indexes, change this parameter only if there is no " "find in the database" @@ -1271,35 +1280,35 @@ msgstr "" "Pour éviter des index non pertinents, ne changer ce paramètre que s'il n'y a " "pas encore de mobilier dans cette base de données" -#: models.py:1910 +#: models.py:1928 msgid "Warehouses module" msgstr "Module Lieu de conservation" -#: models.py:1911 +#: models.py:1929 msgid "Need finds module" msgstr "Nécessite le module mobilier" -#: models.py:1912 +#: models.py:1930 msgid "Preservation module" msgstr "Module de conservation" -#: models.py:1914 +#: models.py:1932 msgid "Mapping module" msgstr "Module cartographique" -#: models.py:1915 +#: models.py:1933 msgid "Underwater module" msgstr "Module sous-marin / subaquatique" -#: models.py:1917 +#: models.py:1935 msgid "Parcel are mandatory for context records" msgstr "Parcelles cadastrales obligatoires pour les Unités d'Enregistrement" -#: models.py:1919 +#: models.py:1937 msgid "Home page" msgstr "Page d'accueil" -#: models.py:1920 +#: models.py:1938 #, python-brace-format msgid "" "Homepage of Ishtar - if not defined a default homepage will appear. Use the " @@ -1309,23 +1318,23 @@ msgstr "" "défaut apparaît. Utiliser la syntaxe Markdown. {random_image} peut être " "utilisé pour afficher une image au hasard." -#: models.py:1924 +#: models.py:1942 msgid "Main operation code prefix" msgstr "Préfixe principal pour le code opération" -#: models.py:1928 +#: models.py:1946 msgid "Default operation code prefix" msgstr "Préfixe par défaut pour le code opération" -#: models.py:1932 +#: models.py:1950 msgid "Operation region code" msgstr "Code région des opérations" -#: models.py:1936 +#: models.py:1954 msgid "File external id" msgstr "Identifiant de fichier" -#: models.py:1938 +#: models.py:1956 msgid "" "Formula to manage file external ID. Change this with care. With incorrect " "formula, the application might be unusable and import of external data can " @@ -1335,11 +1344,11 @@ msgstr "" " Une formule incorrecte peut rendre l'application inutilisable et l'import " "de données externes peut alors être destructif." -#: models.py:1943 +#: models.py:1961 msgid "Parcel external id" msgstr "Identifiant de parcelle" -#: models.py:1946 +#: models.py:1964 msgid "" "Formula to manage parcel external ID. Change this with care. With incorrect " "formula, the application might be unusable and import of external data can " @@ -1349,11 +1358,11 @@ msgstr "" "précaution. Une formule incorrecte peut rendre l'application inutilisable et " "l'import de données externes peut alors être destructif." -#: models.py:1951 +#: models.py:1969 msgid "Context record external id" msgstr "Identifiant d'unité d'enregistrement" -#: models.py:1953 +#: models.py:1971 msgid "" "Formula to manage context record external ID. Change this with care. With " "incorrect formula, the application might be unusable and import of external " @@ -1363,11 +1372,11 @@ msgstr "" "avec précaution. Une formule incorrecte peut rendre l'application " "inutilisable et l'import de données externes peut alors être destructif." -#: models.py:1958 +#: models.py:1976 msgid "Base find external id" msgstr "Identifiant de mobilier d'origine" -#: models.py:1960 +#: models.py:1978 msgid "" "Formula to manage base find external ID. Change this with care. With " "incorrect formula, the application might be unusable and import of external " @@ -1377,11 +1386,11 @@ msgstr "" "précaution. Une formule incorrecte peut rendre l'application inutilisable et " "l'import de données externes peut alors être destructif." -#: models.py:1965 +#: models.py:1983 msgid "Find external id" msgstr "Identifiant de mobilier" -#: models.py:1967 +#: models.py:1985 msgid "" "Formula to manage find external ID. Change this with care. With incorrect " "formula, the application might be unusable and import of external data can " @@ -1391,11 +1400,11 @@ msgstr "" " Une formule incorrecte peut rendre l'application inutilisable et l'import " "de données externes peut alors être destructif." -#: models.py:1972 +#: models.py:1990 msgid "Container external id" msgstr "ID du contenant" -#: models.py:1974 +#: models.py:1992 msgid "" "Formula to manage container external ID. Change this with care. With " "incorrect formula, the application might be unusable and import of external " @@ -1405,11 +1414,11 @@ msgstr "" "précaution. Une formule incorrecte peut rendre l'application inutilisable et " "l'import de données externes peut alors être destructif." -#: models.py:1979 +#: models.py:1997 msgid "Warehouse external id" msgstr "Identifiant du lieu de conservation" -#: models.py:1981 +#: models.py:1999 msgid "" "Formula to manage warehouse external ID. Change this with care. With " "incorrect formula, the application might be unusable and import of external " @@ -1419,11 +1428,11 @@ msgstr "" "avec précaution. Une formule incorrecte peut rendre l'application " "inutilisable et l'import de données externes peut alors être destructif." -#: models.py:1986 +#: models.py:2004 msgid "Raw name for person" msgstr "Nom brut pour une personne" -#: models.py:1988 +#: models.py:2006 msgid "" "Formula to manage person raw_name. Change this with care. With incorrect " "formula, the application might be unusable and import of external data can " @@ -1433,27 +1442,27 @@ msgstr "" "Une formule incorrecte peut rendre l'application inutilisable et l'import de " "données externes peut alors être destructif." -#: models.py:1992 +#: models.py:2010 msgid "Use auto index for finds" -msgstr "Utiliser les indexes automatique pour le mobilier" +msgstr "Utiliser les index automatiques pour le mobilier" -#: models.py:1994 +#: models.py:2012 msgid "Currency" msgstr "Devise" -#: models.py:1998 +#: models.py:2016 msgid "Ishtar site profile" msgstr "Profil d'instance Ishtar" -#: models.py:1999 +#: models.py:2017 msgid "Ishtar site profiles" msgstr "Profils d'instance Ishtar" -#: models.py:2083 +#: models.py:2101 msgid "Enable this form" msgstr "Activer ce formulaire" -#: models.py:2084 +#: models.py:2102 msgid "" "Disable with caution: disabling a form with mandatory fields may lead to " "database errors." @@ -1461,11 +1470,11 @@ msgstr "" "Désactiver avec précaution : désactiver un formulaire avec des champs " "obligatoires peut entraîner des erreurs dans la base de données." -#: models.py:2087 +#: models.py:2105 msgid "Apply to all" msgstr "S'applique à tous" -#: models.py:2088 +#: models.py:2106 msgid "" "Apply this form to all users. If set to True, selecting user and user type " "is useless." @@ -1473,48 +1482,48 @@ msgstr "" "Activer ce formulaire pour tous les utilisateurs. Si mis à Vrai, " "sélectionner des utilisateurs ou des types d'utilisateurs est inutile." -#: models.py:2094 +#: models.py:2112 msgid "Custom form" msgstr "Formulaire personnalisé" -#: models.py:2095 +#: models.py:2113 msgid "Custom forms" msgstr "Formulaires personnalisés" -#: models.py:2111 +#: models.py:2129 msgid "User types" msgstr "Types d'utilisateur" -#: models.py:2183 +#: models.py:2205 msgid "Excluded field" msgstr "Champ exclus" -#: models.py:2184 +#: models.py:2206 msgid "Excluded fields" msgstr "Champs exclus" -#: models.py:2194 templates/blocks/form_flex_snippet.html:18 +#: models.py:2216 templates/blocks/form_flex_snippet.html:18 #: templates/blocks/table_form_snippet.html:9 msgid "Help" msgstr "Aide" -#: models.py:2197 +#: models.py:2219 msgid "Custom form - Json data field" msgstr "Formulaire personnalisé - Champ de donnée Json" -#: models.py:2198 +#: models.py:2220 msgid "Custom form - Json data fields" msgstr "Formulaire personnalisé - Champs de donnée Json" -#: models.py:2202 +#: models.py:2224 msgid "Variable name" msgstr "Nom de la variable" -#: models.py:2203 +#: models.py:2225 msgid "Description of the variable" msgstr "Description de la variable" -#: models.py:2205 models_imports.py:564 +#: models.py:2227 models_imports.py:564 #: templates/ishtar/formset_import_match.html:22 #: templates/ishtar/import_step_by_step.html:172 #: templates/ishtar/import_step_by_step.html:200 @@ -1522,545 +1531,549 @@ msgstr "Description de la variable" msgid "Value" msgstr "Valeur" -#: models.py:2208 +#: models.py:2230 msgid "Global variable" msgstr "Variable globale" -#: models.py:2335 models.py:2365 +#: models.py:2358 models.py:2388 msgid "Total" msgstr "Total" -#: models.py:2342 models.py:2529 models.py:2545 +#: models.py:2365 models.py:2552 models.py:2568 #: templates/ishtar/dashboards/dashboard_main_detail.html:211 #: templates/ishtar/dashboards/dashboard_main_detail_users.html:5 #: templates/ishtar/sheet_person.html:30 msgid "Number" msgstr "Nombre" -#: models.py:2429 +#: models.py:2452 msgid "Administrative Act" msgstr "Acte administratif" -#: models.py:2436 +#: models.py:2459 msgid "Associated object" msgstr "Objet associé" -#: models.py:2441 +#: models.py:2464 msgid "Document template" msgstr "Patron de document" -#: models.py:2442 +#: models.py:2465 msgid "Document templates" msgstr "Patrons de document" -#: models.py:2533 models.py:2546 models.py:4285 models_imports.py:853 +#: models.py:2556 models.py:2569 models.py:4360 models_imports.py:854 msgid "State" msgstr "État" -#: models.py:2551 models.py:4007 templates/blocks/JQueryAdvancedTown.html:12 +#: models.py:2574 models.py:4080 templates/blocks/JQueryAdvancedTown.html:12 msgid "Department" msgstr "Département" -#: models.py:2552 +#: models.py:2575 msgid "Departments" msgstr "Départements" -#: models.py:2592 +#: models.py:2615 msgid "Raw phone" msgstr "Téléphone brut" -#: models.py:2598 +#: models.py:2621 msgid "Alternative address is prefered" msgstr "L'adresse alternative est préférée" -#: models.py:2637 +#: models.py:2660 msgid "Tel: " msgstr "Tél :" -#: models.py:2641 +#: models.py:2664 msgid "Mobile: " msgstr "Mobile :" -#: models.py:2645 +#: models.py:2668 msgid "Email: " msgstr "Courriel :" -#: models.py:2650 +#: models.py:2673 msgid "Merge key" msgstr "Clé de fusion" -#: models.py:2722 +#: models.py:2745 msgid "Organization types" msgstr "Types d'organisation" -#: models.py:2749 models.py:2896 models.py:3303 +#: models.py:2772 models.py:2920 models.py:3328 msgctxt "key for text search" msgid "name" msgstr "nom" -#: models.py:2753 models.py:2908 models.py:3315 models.py:3639 +#: models.py:2776 models.py:2932 models.py:3340 models.py:3705 msgctxt "key for text search" msgid "type" msgstr "type" -#: models.py:2768 models.py:2947 models.py:3498 models.py:4015 +#: models.py:2791 models.py:2971 models.py:3564 models.py:4088 msgid "Cached name" msgstr "Nom en cache" -#: models.py:2774 +#: models.py:2797 msgid "Organizations" msgstr "Organisations" -#: models.py:2804 +#: models.py:2828 msgid "unknown organization" msgstr "organisation inconnue" -#: models.py:2830 +#: models.py:2854 msgid "Person types" msgstr "Types de personne" -#: models.py:2843 models_imports.py:670 +#: models.py:2867 models_imports.py:671 msgid "Title type" msgstr "Type de titre" -#: models.py:2844 +#: models.py:2868 msgid "Title types" msgstr "Types de titre" -#: models.py:2868 +#: models.py:2892 msgid "Mr" msgstr "M." -#: models.py:2869 +#: models.py:2893 msgid "Miss" msgstr "Mlle" -#: models.py:2870 +#: models.py:2894 msgid "Mr and Mrs" msgstr "M. et Mme" -#: models.py:2871 +#: models.py:2895 msgid "Mrs" msgstr "Mme" -#: models.py:2872 +#: models.py:2896 msgid "Doctor" msgstr "Dr." -#: models.py:2900 models.py:3307 +#: models.py:2924 models.py:3332 msgctxt "key for text search" msgid "surname" msgstr "prenom" -#: models.py:2904 models.py:3311 +#: models.py:2928 models.py:3336 msgctxt "key for text search" msgid "email" msgstr "courriel" -#: models.py:2912 models.py:3319 +#: models.py:2936 models.py:3344 msgctxt "key for text search" msgid "organization" msgstr "organisation" -#: models.py:2916 +#: models.py:2940 msgctxt "key for text search" msgid "has-account" msgstr "a-un-compte" -#: models.py:2940 +#: models.py:2964 msgid "Contact type" msgstr "Type de contact" -#: models.py:2943 models.py:3033 +#: models.py:2967 models.py:3057 msgid "Types" msgstr "Types" -#: models.py:2946 +#: models.py:2970 msgid "Is attached to" msgstr "Est rattaché à " -#: models.py:2953 +#: models.py:2977 msgid "Persons" msgstr "Personnes" -#: models.py:3171 +#: models.py:3195 msgid "Groups" msgstr "Groupes" -#: models.py:3176 +#: models.py:3200 msgid "Profile types" msgstr "Types de profil" -#: models.py:3187 +#: models.py:3211 msgid "Profile type summary" msgstr "Résumé du type de profil" -#: models.py:3188 +#: models.py:3212 msgid "Profile types summary" msgstr "Résumés des types de profil" -#: models.py:3199 +#: models.py:3223 msgid "Show field number" msgstr "Afficher les numéros des champs" -#: models.py:3200 +#: models.py:3224 msgid "Automatically pin" msgstr "Épingler automatiquement" -#: models.py:3201 +#: models.py:3225 msgid "Display pin menu" msgstr "Montrer le menu d'épinglage" -#: models.py:3207 +#: models.py:3231 msgid "User profile" msgstr "Profil d'utilisateur" -#: models.py:3208 +#: models.py:3232 msgid "User profiles" msgstr "Profils d'utilisateurs" -#: models.py:3243 +#: models.py:3267 models.py:3522 msgid " - duplicate" -msgstr "- copie" +msgstr " - copie" -#: models.py:3299 +#: models.py:3324 msgctxt "key for text search" msgid "username" msgstr "nom-utilisateur" -#: models.py:3335 +#: models.py:3360 msgid "Advanced shortcut menu" msgstr "Menu de raccourci (avancé)" -#: models.py:3338 +#: models.py:3363 msgid "Ishtar user" msgstr "Utilisateur d'Ishtar" -#: models.py:3339 +#: models.py:3364 msgid "Ishtar users" msgstr "Utilisateurs d'Ishtar" -#: models.py:3424 +#: models.py:3449 msgid "Owner" msgstr "Propriétaire" -#: models.py:3427 -msgid "Shared with" -msgstr "Partagé avec" +#: models.py:3452 +msgid "Shared (read) with" +msgstr "Partagé (lecture) avec" -#: models.py:3469 +#: models.py:3456 +msgid "Shared (read/edit) with" +msgstr "Partagé (lecture/édition) avec" + +#: models.py:3535 msgid "Author types" msgstr "Types d'auteur" -#: models.py:3544 +#: models.py:3610 msgid "Source types" msgstr "Types de document" -#: models.py:3554 models_imports.py:669 +#: models.py:3620 models_imports.py:670 msgid "Support type" msgstr "Type de support" -#: models.py:3555 +#: models.py:3621 msgid "Support types" msgstr "Types de support" -#: models.py:3564 +#: models.py:3630 msgid "Format type" msgstr "Type de format" -#: models.py:3565 +#: models.py:3631 msgid "Format types" msgstr "Types de format" -#: models.py:3574 +#: models.py:3640 msgid "URL" msgstr "URL" -#: models.py:3577 +#: models.py:3643 msgid "License type" msgstr "Type de licence" -#: models.py:3578 +#: models.py:3644 msgid "License types" msgstr "Types de licence" -#: models.py:3631 +#: models.py:3697 msgctxt "key for text search" msgid "author" msgstr "auteur" -#: models.py:3635 +#: models.py:3701 msgctxt "key for text search" msgid "title" msgstr "titre" -#: models.py:3643 +#: models.py:3709 msgctxt "key for text search" msgid "reference" msgstr "reference" -#: models.py:3647 +#: models.py:3713 msgctxt "key for text search" msgid "internal-reference" msgstr "reference-interne" -#: models.py:3651 +#: models.py:3717 msgctxt "key for text search" msgid "description" msgstr "description" -#: models.py:3655 +#: models.py:3721 msgctxt "key for text search" msgid "comment" msgstr "commentaire" -#: models.py:3659 +#: models.py:3725 msgctxt "key for text search" msgid "additional-information" msgstr "informations-supplementaires" -#: models.py:3663 +#: models.py:3729 msgctxt "key for text search" msgid "has-duplicate" msgstr "existe-en-doublon" -#: models.py:3667 models.py:3714 +#: models.py:3733 models.py:3780 msgctxt "key for text search" msgid "operation" msgstr "operation" -#: models.py:3671 models.py:3717 +#: models.py:3737 models.py:3783 msgctxt "key for text search" msgid "context-record" msgstr "ue" -#: models.py:3675 models.py:3719 +#: models.py:3741 models.py:3785 msgctxt "key for text search" msgid "find" msgstr "mobilier" -#: models.py:3679 models.py:3718 +#: models.py:3745 models.py:3784 msgctxt "key for text search" msgid "file" msgstr "dossier" -#: models.py:3683 models.py:3720 +#: models.py:3749 models.py:3786 msgctxt "key for text search" msgid "site" msgstr "site" -#: models.py:3687 models.py:3721 +#: models.py:3753 models.py:3787 msgctxt "key for text search" msgid "warehouse" msgstr "depot" -#: models.py:3723 +#: models.py:3789 msgctxt "key for text search" msgid "treatment" msgstr "traitement" -#: models.py:3726 +#: models.py:3792 msgctxt "key for text search" msgid "treatment-file" msgstr "dossier-traitement" -#: models.py:3732 +#: models.py:3798 msgid "Index" msgstr "Index" -#: models.py:3734 +#: models.py:3800 msgid "External ID" msgstr "Identifiant" -#: models.py:3735 templates/ishtar/blocks/window_image_detail.html:34 +#: models.py:3801 templates/ishtar/blocks/window_image_detail.html:34 msgid "Ref." msgstr "Réf." -#: models.py:3736 templates/ishtar/blocks/window_image_detail.html:44 +#: models.py:3802 templates/ishtar/blocks/window_image_detail.html:44 msgid "Internal ref." msgstr "Réf. interne" -#: models.py:3740 +#: models.py:3806 msgid "License" msgstr "Licence" -#: models.py:3742 templates/ishtar/blocks/window_image_detail.html:78 +#: models.py:3808 templates/ishtar/blocks/window_image_detail.html:78 msgid "Support" msgstr "Support" -#: models.py:3744 models_imports.py:635 +#: models.py:3810 models_imports.py:636 #: templates/ishtar/blocks/window_image_detail.html:88 msgid "Format" msgstr "Format" -#: models.py:3746 templates/ishtar/blocks/window_image_detail.html:98 +#: models.py:3812 templates/ishtar/blocks/window_image_detail.html:98 msgid "Scale" msgstr "Échelle" -#: models.py:3750 +#: models.py:3816 msgid "Authors (raw)" msgstr "Auteurs (brut)" -#: models.py:3762 templates/ishtar/blocks/window_image_detail.html:118 +#: models.py:3828 templates/ishtar/blocks/window_image_detail.html:118 msgid "Number of items" msgstr "Nombre d'éléments" -#: models.py:3769 +#: models.py:3835 msgid "Symbolic links" msgstr "Liens symboliques" -#: models.py:3772 +#: models.py:3838 msgid "Related" msgstr "Lié" -#: models.py:3773 +#: models.py:3839 msgid "Cached value - do not edit" msgstr "Valeur en cache - ne pas éditer" -#: models.py:3776 templates/ishtar/sheet_document.html:4 +#: models.py:3842 templates/ishtar/sheet_document.html:4 msgid "Document" msgstr "Document" -#: models.py:3777 templates/ishtar/sheet_person.html:113 +#: models.py:3843 templates/ishtar/sheet_person.html:113 msgid "Documents" msgstr "Documents" -#: models.py:3781 +#: models.py:3847 msgid "Can view all Documents" msgstr "Peut voir tous les Documents" -#: models.py:3783 +#: models.py:3849 msgid "Can view own Document" msgstr "Peut voir ses propres Documents" -#: models.py:3785 +#: models.py:3851 msgid "Can add own Document" msgstr "Peut ajouter son propre Document" -#: models.py:3787 +#: models.py:3853 msgid "Can change own Document" -msgstr "Peut modifier ses propres documents" +msgstr "Peut modifier ses propres Documents" -#: models.py:3789 +#: models.py:3855 msgid "Can delete own Document" msgstr "Peut supprimer ses propres Documents" -#: models.py:4000 +#: models.py:4073 msgid "Surface (m2)" msgstr "Surface (m2)" -#: models.py:4001 +#: models.py:4074 msgid "Localisation" msgstr "Localisation" -#: models.py:4009 +#: models.py:4082 msgid "Year of creation" msgstr "Année de création" -#: models.py:4010 +#: models.py:4083 msgid "" "Filling this field is relevant to distinguish old towns from new towns." msgstr "" "Remplir ce champ est nécessaire pour distinguer les anciennes communes des " "nouvelles communes." -#: models.py:4142 +#: models.py:4215 msgid "Only four level of parent are managed." msgstr "Seulement quatre niveaux de parents sont gérés." -#: models.py:4147 +#: models.py:4220 msgid "Area" msgstr "Zone" -#: models.py:4166 +#: models.py:4239 msgid "Is preventive" msgstr "Est du préventif" -#: models.py:4167 +#: models.py:4240 msgid "Is judiciary" msgstr "Est judiciaire" -#: models.py:4170 models_imports.py:636 +#: models.py:4243 models_imports.py:637 msgid "Operation type" msgstr "Type d'opération" -#: models.py:4171 +#: models.py:4244 msgid "Operation types" msgstr "Types d'opération" -#: models.py:4210 +#: models.py:4283 msgid "Judiciary" msgstr "Judiciaire" -#: models.py:4212 +#: models.py:4285 msgid "Preventive" msgstr "Préventif" -#: models.py:4214 +#: models.py:4287 msgid "Research" msgstr "Programmé" -#: models.py:4249 +#: models.py:4322 msgid "Authority name" msgstr "Registre" -#: models.py:4250 +#: models.py:4323 msgid "Authority SRID" msgstr "SRID" -#: models.py:4253 models_imports.py:668 +#: models.py:4326 models_imports.py:669 msgid "Spatial reference system" msgstr "Système de référence spatiale" -#: models.py:4254 +#: models.py:4327 msgid "Spatial reference systems" msgstr "Systèmes de référence spatiale" -#: models.py:4261 +#: models.py:4336 msgid "Filename" msgstr "Nom de fichier" -#: models.py:4266 +#: models.py:4341 msgid "Administration script" msgstr "Script d'administration" -#: models.py:4267 +#: models.py:4342 msgid "Administration scripts" msgstr "Scripts d'administration" -#: models.py:4274 +#: models.py:4349 msgid "Scheduled" msgstr "Planifié" -#: models.py:4275 +#: models.py:4350 msgid "In progress" msgstr "En cours" -#: models.py:4276 models_imports.py:792 +#: models.py:4351 models_imports.py:793 msgid "Finished with errors" msgstr "Terminé avec des erreurs" -#: models.py:4277 models_imports.py:793 +#: models.py:4352 models_imports.py:794 msgid "Finished" msgstr "Terminé" -#: models.py:4290 +#: models.py:4365 msgid "Result" msgstr "Résultat" -#: models.py:4293 +#: models.py:4368 msgid "Administration task" msgstr "Tâche d'administration" -#: models.py:4294 +#: models.py:4369 msgid "Administration tasks" msgstr "Tâches d'administration" -#: models.py:4298 +#: models.py:4373 msgid "Unknown" msgstr "Inconnu" -#: models.py:4313 +#: models.py:4388 msgid "" "ISHTAR_SCRIPT_DIR is not set in your local_settings. Contact your " "administrator." @@ -2068,7 +2081,7 @@ msgstr "" "ISHTAR_SCRIPT_DIR n'est pas défini dans votre fichier local_settings. " "Contactez l'administrateur." -#: models.py:4322 +#: models.py:4397 msgid "" "Your ISHTAR_SCRIPT_DIR is containing dots \"..\". As it can refer to " "relative paths, it can be a security issue and this is not allowed. Only put " @@ -2079,11 +2092,11 @@ msgstr "" "problème de sécurité et cela n'est pas permis. Seul un chemin complet est " "permis." -#: models.py:4333 +#: models.py:4408 msgid "Your ISHTAR_SCRIPT_DIR: \"{}\" is not a valid directory." msgstr "ISHTAR_SCRIPT_DIR: « {} » n'est pas un répertoire valable." -#: models.py:4349 +#: models.py:4424 msgid "" "Script \"{}\" is not available in your script directory. Check your " "configuration." @@ -2116,8 +2129,8 @@ msgid "Leave blank for no restrictions" msgstr "Laissez vide pour aucune restriction" #: models_imports.py:136 -msgid "Is template" -msgstr "Est un patron" +msgid "Can be exported" +msgstr "Peut être exporté" #: models_imports.py:137 msgid "Unicity keys (separator \";\")" @@ -2228,11 +2241,11 @@ msgstr "Importeur - Cible" msgid "Importer - Targets" msgstr "Importeur - Cibles" -#: models_imports.py:525 views_item.py:847 +#: models_imports.py:525 views_item.py:346 views_item.py:950 msgid "True" msgstr "Oui" -#: models_imports.py:526 views_item.py:849 +#: models_imports.py:526 views_item.py:952 msgid "False" msgstr "Non" @@ -2264,329 +2277,329 @@ msgstr "Importeur - Clé de rapprochement" msgid "Importer - Targets keys" msgstr "Importeur - Clés de rapprochement" -#: models_imports.py:637 +#: models_imports.py:638 msgid "Period" msgstr "Période" -#: models_imports.py:638 +#: models_imports.py:639 msgid "Report state" msgstr "État de rapport" -#: models_imports.py:639 +#: models_imports.py:640 msgid "Remain type" msgstr "Type de vestige" -#: models_imports.py:640 +#: models_imports.py:641 msgid "Unit" msgstr "Unité" -#: models_imports.py:642 +#: models_imports.py:643 msgid "Activity type" msgstr "Type d'activité" -#: models_imports.py:644 +#: models_imports.py:645 msgid "Documentation type" msgstr "Type de documentation" -#: models_imports.py:645 +#: models_imports.py:646 msgid "Material" msgstr "Matériau" -#: models_imports.py:647 +#: models_imports.py:648 msgid "Conservatory state" msgstr "État de conservation" -#: models_imports.py:648 +#: models_imports.py:649 msgid "Container type" msgstr "Type de contenant" -#: models_imports.py:650 +#: models_imports.py:651 msgid "Warehouse division" msgstr "Division de lieu de conservation" -#: models_imports.py:651 +#: models_imports.py:652 msgid "Warehouse type" msgstr "Type de lieu de conservation" -#: models_imports.py:652 +#: models_imports.py:653 msgid "Treatment type" msgstr "Type de traitement" -#: models_imports.py:654 +#: models_imports.py:655 msgid "Treatment emergency type" msgstr "Type d'urgence de traitement" -#: models_imports.py:655 +#: models_imports.py:656 msgid "Object type" msgstr "Type d'objet" -#: models_imports.py:656 +#: models_imports.py:657 msgid "Integrity type" msgstr "Type d'intégrité" -#: models_imports.py:658 +#: models_imports.py:659 msgid "Remarkability type" msgstr "Type de remarquabilité" -#: models_imports.py:659 +#: models_imports.py:660 msgid "Alteration type" msgstr "Type d'altération" -#: models_imports.py:661 +#: models_imports.py:662 msgid "Alteration cause type" msgstr "Type de cause d'altération" -#: models_imports.py:662 +#: models_imports.py:663 msgid "Batch type" msgstr "Type de lot" -#: models_imports.py:663 +#: models_imports.py:664 msgid "Checked type" msgstr "Type de vérification" -#: models_imports.py:665 +#: models_imports.py:666 msgid "Identification type" msgstr "Type d'identification" -#: models_imports.py:667 +#: models_imports.py:668 msgid "Context record relation type" msgstr "Type de relations entre Unités d'Enregistrement" -#: models_imports.py:678 +#: models_imports.py:679 msgid "String" msgstr "Chaîne de caractères" -#: models_imports.py:681 +#: models_imports.py:682 #: templates/ishtar/dashboards/dashboard_main_detail.html:196 msgid "Year" msgstr "Année" -#: models_imports.py:682 +#: models_imports.py:683 msgid "INSEE code" msgstr "Code INSEE" -#: models_imports.py:683 +#: models_imports.py:684 msgid "String to boolean" msgstr "Chaîne de caractères vers booléen" -#: models_imports.py:684 +#: models_imports.py:685 msgctxt "filesystem" msgid "File" msgstr "Fichier" -#: models_imports.py:685 +#: models_imports.py:686 msgid "Unknow type" msgstr "Type inconnu" -#: models_imports.py:702 +#: models_imports.py:703 msgid "4 digit year. e.g.: \"2015\"" msgstr "Année sur 4 chiffres. Exemple : « 2015 »" -#: models_imports.py:703 +#: models_imports.py:704 msgid "4 digit year/month/day. e.g.: \"2015/02/04\"" msgstr "Année sur 4 chiffres/mois/jour. Exemple : « 2015/02/04 »" -#: models_imports.py:704 +#: models_imports.py:705 msgid "Day/month/4 digit year. e.g.: \"04/02/2015\"" msgstr "Jour/mois/année sur 4 chiffres. Exemple : « 04/02/2015 »" -#: models_imports.py:720 +#: models_imports.py:721 msgid "Options" msgstr "Options" -#: models_imports.py:722 +#: models_imports.py:723 msgid "Split character(s)" msgstr "Caractère(s) de séparation" -#: models_imports.py:727 +#: models_imports.py:728 msgid "Importer - Formater type" msgstr "Importeur - Type de mise en forme" -#: models_imports.py:728 +#: models_imports.py:729 msgid "Importer - Formater types" msgstr "Importeur - Types de mise en forme" -#: models_imports.py:784 +#: models_imports.py:785 #: templates/ishtar/dashboards/dashboard_main_detail.html:132 msgid "Created" msgstr "Créé" -#: models_imports.py:785 +#: models_imports.py:786 msgid "Analyse in progress" msgstr "Analyse en cours" -#: models_imports.py:786 +#: models_imports.py:787 msgid "Analysed" msgstr "Analysé" -#: models_imports.py:787 +#: models_imports.py:788 msgid "Check modified in queue" msgstr "Vérification des modifications dans la file" -#: models_imports.py:788 +#: models_imports.py:789 msgid "Import in queue" msgstr "Import en file d'attente" -#: models_imports.py:789 +#: models_imports.py:790 msgid "Check modified in progress" msgstr "Vérification des modifications en cours" -#: models_imports.py:790 +#: models_imports.py:791 msgid "Import in progress" msgstr "Import en cours" -#: models_imports.py:791 +#: models_imports.py:792 msgid "Partially imported" msgstr "Importé partiellement" -#: models_imports.py:794 +#: models_imports.py:795 msgid "Archived" msgstr "Archivé" -#: models_imports.py:830 +#: models_imports.py:831 msgid "Imported file" msgstr "Fichier importé" -#: models_imports.py:832 +#: models_imports.py:833 msgid "Associated images (zip file)" msgstr "Images associées (fichier zip)" -#: models_imports.py:836 +#: models_imports.py:837 msgid "If a group is selected, target key saved in this group will be used." msgstr "" "Si un groupe est sélectionné, les clés de rapprochement enregistrées dans ce " "groupe sont utilisées." -#: models_imports.py:839 +#: models_imports.py:840 msgid "Encoding" msgstr "Codage" -#: models_imports.py:842 +#: models_imports.py:843 msgid "Skip lines" msgstr "Nombre de lignes d'entête" -#: models_imports.py:843 +#: models_imports.py:844 msgid "Number of header lines in your file (can be 0)." msgstr "Nombre de ligne d'entête dans votre fichier (peut être égal à zéro)" -#: models_imports.py:844 +#: models_imports.py:845 msgid "Error file" msgstr "Fichier erreur" -#: models_imports.py:847 +#: models_imports.py:848 msgid "Result file" msgstr "Fichier résultant" -#: models_imports.py:850 +#: models_imports.py:851 msgid "Match file" msgstr "Fichier de correspondance" -#: models_imports.py:856 +#: models_imports.py:857 msgid "Conservative import" msgstr "Import conservateur" -#: models_imports.py:857 +#: models_imports.py:858 msgid "If set to true, do not overload existing values." msgstr "Si coché, ne surchargera pas les valeurs existantes." -#: models_imports.py:860 +#: models_imports.py:861 msgid "End date" msgstr "Date de fin" -#: models_imports.py:863 +#: models_imports.py:864 msgid "Remaining seconds" msgstr "Secondes restantes" -#: models_imports.py:865 +#: models_imports.py:866 msgid "Current line" msgstr "Ligne actuelle" -#: models_imports.py:867 +#: models_imports.py:868 msgid "Number of line" msgstr "Nombre de lignes" -#: models_imports.py:870 +#: models_imports.py:871 msgid "Imported line numbers" msgstr "Numéros des lignes importées" -#: models_imports.py:873 +#: models_imports.py:874 msgid "Changed have been checked" msgstr "Les changements ont été vérifiés" -#: models_imports.py:876 +#: models_imports.py:877 msgid "Changed line numbers" msgstr "Numéro des lignes modifiées" -#: models_imports.py:881 +#: models_imports.py:882 msgid "Import" msgstr "Import" -#: models_imports.py:970 +#: models_imports.py:971 msgid "Analyse" msgstr "Analyser" -#: models_imports.py:972 models_imports.py:981 +#: models_imports.py:973 models_imports.py:982 msgid "Re-analyse" msgstr "Analyser de nouveau " -#: models_imports.py:973 +#: models_imports.py:974 msgid "Launch import" msgstr "Lancer l'import" -#: models_imports.py:976 +#: models_imports.py:977 msgid "Step by step import" msgstr "Import pas à pas" -#: models_imports.py:977 models_imports.py:986 +#: models_imports.py:978 models_imports.py:987 msgid "Re-check for changes" msgstr "Re-vérifier les changements" -#: models_imports.py:979 models_imports.py:988 +#: models_imports.py:980 models_imports.py:989 msgid "Check for changes" msgstr "Vérifier les changements" -#: models_imports.py:982 +#: models_imports.py:983 msgid "Re-import" msgstr "Ré-importer" -#: models_imports.py:985 +#: models_imports.py:986 msgid "Step by step re-import" msgstr "Ré-import pas à pas" -#: models_imports.py:989 +#: models_imports.py:990 msgid "Archive" msgstr "Archiver" -#: models_imports.py:991 +#: models_imports.py:992 msgid "Unarchive" msgstr "Désarchiver" -#: models_imports.py:992 templates/ishtar/form_delete.html:11 views.py:1847 -#: widgets.py:371 widgets.py:403 +#: models_imports.py:993 templates/ishtar/form_delete.html:11 views.py:1896 +#: widgets.py:379 widgets.py:411 msgid "Delete" msgstr "Supprimer" -#: models_imports.py:1042 +#: models_imports.py:1043 msgid "Error in the CSV file." msgstr "Erreur dans le fichier CSV." -#: models_imports.py:1070 +#: models_imports.py:1071 msgid "Modification check {} added to the queue" msgstr "Vérification des changements {} ajoutée à la file d'attente" -#: models_imports.py:1140 +#: models_imports.py:1141 msgid "Import {} added to the queue" msgstr "Import {} ajouté à la file d'attente" -#: models_imports.py:1158 +#: models_imports.py:1159 msgid "Error on imported file: {}" msgstr "Erreur sur le fichier d'import : {}" -#: models_imports.py:1193 +#: models_imports.py:1194 msgid "Import {} finished with errors" msgstr "Import {} fini avec des erreurs" -#: models_imports.py:1202 +#: models_imports.py:1203 msgid "Import {} finished with no errors" msgstr "Import {} fini avec aucune erreur" @@ -2638,12 +2651,12 @@ msgid "View on site" msgstr "Voir sur le site" #: templates/admin/change_form.html:24 templates/admin/change_form.html:27 -#: views.py:1231 views.py:1236 +#: views.py:1254 views.py:1259 msgid "Previous" msgstr "Précédent" #: templates/admin/change_form.html:32 templates/admin/change_form.html:35 -#: views.py:1239 views.py:1242 +#: views.py:1262 views.py:1265 msgid "Next" msgstr "Suivant" @@ -2679,49 +2692,53 @@ msgid " items added." msgstr "Éléments ajoutés." #: templates/base.html:47 +msgid "Select only one item." +msgstr "Sélectionnez seulement un seul élément." + +#: templates/base.html:48 msgid "yes" msgstr "oui" -#: templates/base.html:48 +#: templates/base.html:49 msgid "no" msgstr "non" -#: templates/base.html:49 +#: templates/base.html:50 msgid "Autorefresh start. The form is disabled." msgstr "Rafraîchissement automatique activé. Le formulaire est désactivé." -#: templates/base.html:50 +#: templates/base.html:51 msgid "Autorefresh end. The form is re-enabled." msgstr "Rafraîchissement automatique désactivé. Le formulaire est ré-activé." -#: templates/base.html:81 +#: templates/base.html:82 msgid "Current items" msgstr "Éléments courants" -#: templates/base.html:83 templates/ishtar/forms/qa_base.html:34 +#: templates/base.html:84 templates/ishtar/forms/qa_base.html:33 #: templates/ishtar/forms/qa_form.html:21 templates/ishtar/manage_basket.html:4 #: templates/welcome.html:11 templates/welcome.html:12 -#: templates/welcome.html:13 templates/welcome.html:14 wizards.py:423 +#: templates/welcome.html:13 templates/welcome.html:14 wizards.py:435 msgid ":" msgstr " :" -#: templates/base.html:96 +#: templates/base.html:97 msgid "Sheets" msgstr "Fiches" -#: templates/base.html:146 +#: templates/base.html:158 msgid "Processing..." msgstr "En traitement..." -#: templates/base.html:148 +#: templates/base.html:160 msgid "This can be long." msgstr "Cela peut être long." -#: templates/base.html:150 +#: templates/base.html:162 msgid "Time to take a coffee?" msgstr "Il est peut-être temps de prendre un café ?" -#: templates/base.html:152 +#: templates/base.html:164 msgid "Time to take another coffee?" msgstr "Pourquoi pas un autre café ?" @@ -2731,7 +2748,8 @@ msgid "Expand table" msgstr "Agrandir le tableau" #: templates/blocks/DataTables.html:53 templates/blocks/JQueryJqGrid.html:26 -#: templates/ishtar/blocks/window_nav.html:59 +#: templates/ishtar/blocks/window_nav.html:62 +#: templates/ishtar/blocks/window_nav.html:68 #: templates/ishtar/blocks/window_tables/dynamic_documents.html:45 msgid "Export" msgstr "Exporter" @@ -2911,8 +2929,8 @@ msgstr "" #: templates/ishtar/blocks/modify_toolbar.html:1 #: templates/ishtar/blocks/window_image.html:11 -#: templates/ishtar/blocks/window_nav.html:47 -#: templates/ishtar/forms/qa_base.html:57 +#: templates/ishtar/blocks/window_nav.html:49 +#: templates/ishtar/forms/qa_base.html:56 #: templates/ishtar/organization_form.html:37 #: templates/ishtar/organization_person_form.html:32 #: templates/ishtar/person_form.html:43 @@ -2937,13 +2955,17 @@ msgstr "ID interne" msgid "Data" msgstr "Données" +#: templates/ishtar/blocks/sheet_json.html:9 +msgid "No data" +msgstr "Pas de données" + #: templates/ishtar/blocks/window_image_detail.html:64 msgid "Licenses" msgstr "Licences" #: templates/ishtar/blocks/window_image_detail.html:111 #: templates/ishtar/import_delete.html:20 templatetags/window_field.py:17 -#: views_item.py:486 wizards.py:393 +#: views_item.py:548 wizards.py:405 msgid "Yes" msgstr "Oui" @@ -2956,6 +2978,11 @@ msgstr "Fichier" msgid "Web" msgstr "Internet" +#: templates/ishtar/blocks/window_image_detail.html:193 +#: templates/ishtar/blocks/window_tables/documents.html:10 +msgid "Related to" +msgstr "Associé à " + #: templates/ishtar/blocks/window_nav.html:17 msgid "" "Are you sure to restore to this version? All changes made since this version " @@ -2977,26 +3004,22 @@ msgstr "Épingler" msgid "Item pined in your shortcut menu." msgstr "Cet élément a été épinglé dans votre menu de raccourcis." -#: templates/ishtar/blocks/window_nav.html:43 +#: templates/ishtar/blocks/window_nav.html:45 msgid "Actions" msgstr "Actions" -#: templates/ishtar/blocks/window_nav.html:61 +#: templates/ishtar/blocks/window_nav.html:73 msgid "Export as OpenOffice.org file" msgstr "Exporter en fichier OpenOffice.org" -#: templates/ishtar/blocks/window_nav.html:64 +#: templates/ishtar/blocks/window_nav.html:77 msgid "Export as PDF file" msgstr "Exporter en fichier PDF" -#: templates/ishtar/blocks/window_nav.html:72 +#: templates/ishtar/blocks/window_nav.html:92 msgid "Relation between items are not historized." msgstr "Les relations entre éléments ne sont pas historisées." -#: templates/ishtar/blocks/window_tables/documents.html:10 -msgid "Related to" -msgstr "Associé à " - #: templates/ishtar/blocks/window_tables/documents.html:11 #: templates/ishtar/blocks/window_tables/documents.html:19 msgid "Link" @@ -3085,12 +3108,12 @@ msgstr "Mois" msgid "User type" msgstr "Type d'utilisateur" -#: templates/ishtar/form.html:20 templates/ishtar/forms/document.html:24 +#: templates/ishtar/form.html:23 templates/ishtar/forms/document.html:24 #: templates/ishtar/wizard/default_wizard.html:43 msgid "Search and select an item in the table" msgstr "Rechercher et sélectionner un élément dans le tableau" -#: templates/ishtar/form.html:26 templates/ishtar/forms/document.html:30 +#: templates/ishtar/form.html:29 templates/ishtar/forms/document.html:30 #: templates/ishtar/forms/search_query.html:77 templates/ishtar/formset.html:8 #: templates/ishtar/formset_import_match.html:51 #: templates/ishtar/import_list.html:30 templates/ishtar/merge.html:30 @@ -3103,12 +3126,12 @@ msgstr "Valider" msgid "Are you sure you want to delete: " msgstr "Êtes-vous sûr de vouloir supprimer :" -#: templates/ishtar/forms/qa_base.html:25 +#: templates/ishtar/forms/qa_base.html:24 #: templates/ishtar/forms/qa_form.html:12 msgid "Modified items" msgstr "Éléments modifiés" -#: templates/ishtar/forms/qa_base.html:62 +#: templates/ishtar/forms/qa_base.html:61 #: templates/ishtar/import_step_by_step.html:126 #: templates/ishtar/import_step_by_step.html:305 #: templates/ishtar/organization_form.html:40 @@ -3192,7 +3215,7 @@ msgstr "Ligne" msgid "Go" msgstr "Aller" -#: templates/ishtar/import_step_by_step.html:63 views.py:1081 +#: templates/ishtar/import_step_by_step.html:63 views.py:1104 msgid "Import step by step" msgstr "Import pas à pas" @@ -3457,12 +3480,12 @@ msgstr "Aménageur des dossiers" msgid "Responsible for planning service of archaeological files" msgstr "Responsable pour le service instructeur des dossiers" -#: templates/ishtar/wizard/confirm_wizard.html:12 +#: templates/ishtar/wizard/confirm_wizard.html:14 #: templates/ishtar/wizard/wizard_done_summary.html:6 msgid "You have entered the following informations:" msgstr "Vous avez entré les informations suivantes :" -#: templates/ishtar/wizard/confirm_wizard.html:50 +#: templates/ishtar/wizard/confirm_wizard.html:56 msgid "Would you like to save them?" msgstr "Voulez-vous sauvegarder ces informations ?" @@ -3775,15 +3798,15 @@ msgstr "Épingler la recherche actuelle" msgid "Bookmarks" msgstr "Marque-pages" -#: templatetags/window_field.py:22 wizards.py:395 +#: templatetags/window_field.py:22 wizards.py:407 msgid "No" msgstr "Non" -#: templatetags/window_tables.py:88 widgets.py:1065 +#: templatetags/window_tables.py:88 widgets.py:1102 msgid "No results" msgstr "Pas de résultats" -#: templatetags/window_tables.py:89 widgets.py:1066 +#: templatetags/window_tables.py:89 widgets.py:1103 msgid "Loading..." msgstr "Chargement..." @@ -3792,15 +3815,15 @@ msgid "You don't have sufficient permissions to do this action." msgstr "" "Vous n'avez pas les permissions suffisantes pour effectuer cette action." -#: utils.py:338 +#: utils.py:344 msgid " (...)" msgstr " (...)" -#: utils.py:418 +#: utils.py:424 msgid "Information" msgstr "Information" -#: utils.py:419 +#: utils.py:425 msgid "Load another random image?" msgstr "Charger une autre image au hasard ?" @@ -3869,116 +3892,125 @@ msgstr "Demande de traitement" msgid "Treatment" msgstr "Traitement" -#: views.py:724 views_item.py:103 +#: views.py:747 views_item.py:117 msgid "Operation not permitted." msgstr "Opération non permise." -#: views.py:741 views.py:799 +#: views.py:764 views.py:822 msgid "Archaeological files" msgstr "Dossiers" -#: views.py:746 views.py:810 +#: views.py:769 views.py:833 msgid "Finds" msgstr "Mobilier" -#: views.py:748 views.py:815 +#: views.py:771 views.py:838 msgid "Treatment requests" msgstr "Demandes de traitement" -#: views.py:749 views.py:821 +#: views.py:772 views.py:844 msgid "Treatments" msgstr "Traitements" -#: views.py:1423 +#: views.py:1446 msgid "Col. " msgstr "Col." -#: views.py:1429 views.py:1441 +#: views.py:1452 views.py:1464 msgid "* empty *" msgstr "* vide *" -#: views.py:1482 +#: views.py:1505 msgid "Link unmatched items" msgstr "Associer les éléments non rapprochés" -#: views.py:1503 +#: views.py:1526 msgid "Delete import" msgstr "Supprimer un import" -#: views.py:1542 +#: views.py:1565 msgid "Merge persons" msgstr "Fusionner des personnes" -#: views.py:1566 +#: views.py:1589 msgid "Select the main person" msgstr "Choisir la personne principale" -#: views.py:1575 +#: views.py:1598 msgid "Merge organization" msgstr "Fusionner des organisations" -#: views.py:1585 +#: views.py:1608 msgid "Select the main organization" msgstr "Sélectionner l'organisation principale" -#: views.py:1625 views.py:1641 +#: views.py:1648 views.py:1664 msgid "Corporation manager" msgstr "Représentant de la personne morale" -#: views.py:1662 +#: views.py:1685 msgid "Document: search" msgstr "Document : recherche" -#: views.py:1677 +#: views.py:1700 msgid "Document creation" msgstr "Document : création" -#: views.py:1710 +#: views.py:1733 msgid "Document modification" msgstr "Document : modification" -#: views.py:1740 +#: views.py:1763 msgid "Document deletion" msgstr "Document : suppression" -#: views.py:1823 +#: views.py:1872 msgid "Delete bookmark" msgstr "Supprimer le marque page" -#: views.py:1846 +#: views.py:1895 msgid "Bookmark - Delete" msgstr "Marque page - Suppression" -#: views_item.py:105 +#: views_item.py:119 #, python-format msgid "New %s" msgstr "Nouveau %s" +#: views_item.py:570 +msgctxt "key for text search" +msgid "today" +msgstr "aujourdhui" + #: widgets.py:174 msgid "The character \" is not accepted." msgstr "Le caractère \" n'est pas accepté" -#: widgets.py:517 +#: widgets.py:555 msgid "{} is not a valid key for {}" msgstr "{} n’est pas une valeur valide pour {}" -#: widgets.py:618 widgets.py:752 widgets.py:867 +#: widgets.py:656 widgets.py:790 widgets.py:905 msgid "Search..." msgstr "Recherche..." -#: widgets.py:687 +#: widgets.py:725 msgid "Previous value:" msgstr "Valeur précédente :" -#: widgets.py:1067 +#: widgets.py:1104 msgid "Remove" msgstr "Enlever" -#: wizards.py:431 +#: wizards.py:171 +msgid "Permission error: you cannot do this action." +msgstr "Erreur de permission : vous ne pouvez pas faire cette action." + +#: wizards.py:443 msgid "Deleted" msgstr "Supprimé" -#: wizards.py:1757 +#: wizards.py:1769 #, python-format msgid "[%(app_name)s] Account creation/modification" msgstr "[%(app_name)s] Création/modification du compte" diff --git a/version.py b/version.py index 8885edb48..4f00a9ce2 100644 --- a/version.py +++ b/version.py @@ -1,5 +1,5 @@ -# 2.1.dev.17 -VERSION = (2, 1, 'dev', 17) +# 2.1.dev.19 +VERSION = (2, 1, 'dev', 19) def get_version(): |