diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2020-04-10 17:11:20 +0200 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2021-02-28 12:15:20 +0100 |
commit | 1d90e7c7001c21c9e8a5d1f3683c2acd1873973f (patch) | |
tree | 93817496eadc13648680de8c70e7052ce06cb8df | |
parent | 69cf0a7de4b4d842c814e83f28f7d45aec69929c (diff) | |
download | Ishtar-1d90e7c7001c21c9e8a5d1f3683c2acd1873973f.tar.bz2 Ishtar-1d90e7c7001c21c9e8a5d1f3683c2acd1873973f.zip |
Container: adapt forms for the new container management
-rw-r--r-- | archaeological_warehouse/forms.py | 79 | ||||
-rw-r--r-- | archaeological_warehouse/migrations/0102_auto_20200408_1823.py | 9 | ||||
-rw-r--r-- | archaeological_warehouse/models.py | 14 | ||||
-rw-r--r-- | archaeological_warehouse/templates/ishtar/sheet_container.html | 24 | ||||
-rw-r--r-- | archaeological_warehouse/templates/ishtar/wizard/wizard_container.html | 39 | ||||
-rw-r--r-- | archaeological_warehouse/tests.py | 6 | ||||
-rw-r--r-- | archaeological_warehouse/urls.py | 2 | ||||
-rw-r--r-- | archaeological_warehouse/views.py | 16 | ||||
-rw-r--r-- | archaeological_warehouse/wizards.py | 18 | ||||
-rw-r--r-- | ishtar_common/templates/blocks/JQueryAutocomplete.js | 2 | ||||
-rw-r--r-- | ishtar_common/templates/ishtar/wizard/default_wizard.html | 2 | ||||
-rw-r--r-- | ishtar_common/widgets.py | 10 |
12 files changed, 116 insertions, 105 deletions
diff --git a/archaeological_warehouse/forms.py b/archaeological_warehouse/forms.py index 83289819e..3e754b84a 100644 --- a/archaeological_warehouse/forms.py +++ b/archaeological_warehouse/forms.py @@ -61,17 +61,17 @@ def get_warehouse_field(label=_("Warehouse"), required=True): class SelectedDivisionForm(ManageOldType, forms.Form): form_label = _("Division") base_model = 'associated_division' - associated_models = {'division': models.WarehouseDivision, + associated_models = {'division': models.ContainerType, 'associated_division': models.WarehouseDivisionLink} division = forms.ChoiceField( - label=_("Division"), choices=(), - validators=[valid_id(models.WarehouseDivision)]) + label=_("Container type"), choices=(), + validators=[valid_id(models.ContainerType)]) order = forms.IntegerField(label=_("Order"), min_value=0, required=False) def __init__(self, *args, **kwargs): super(SelectedDivisionForm, self).__init__(*args, **kwargs) self.fields['division'].choices = \ - models.WarehouseDivision.get_types( + models.ContainerType.get_types( initial=self.init_data.get('division') ) @@ -263,32 +263,27 @@ class ContainerForm(CustomForm, ManageOldType, forms.Form): extra_form_modals = ["warehouse", "organization", "person", "container"] associated_models = {'container_type': models.ContainerType, 'location': models.Warehouse, - 'parent': models.Container, - 'responsible': models.Warehouse} + 'parent': models.Container} reference = forms.CharField(label=_("Ref."), max_length=200) old_reference = forms.CharField(label=_("Old reference"), required=False, max_length=200) container_type = forms.ChoiceField(label=_("Container type"), choices=[]) + location = forms.IntegerField( + label=_("Current location (warehouse)"), + widget=widgets.JQueryAutoComplete( + reverse_lazy('autocomplete-warehouse'), + associated_model=models.Warehouse, new=True), + validators=[valid_id(models.Warehouse)]) parent = forms.IntegerField( label=_("Parent container"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-container'), - associated_model=models.Container, new=True), + associated_model=models.Container, new=True, + tips="-" + ), validators=[valid_id(models.Container)], required=False ) - responsible = forms.IntegerField( - label=_("Responsible warehouse"), - widget=widgets.JQueryAutoComplete( - reverse_lazy('autocomplete-warehouse'), - associated_model=models.Warehouse, new=True), - validators=[valid_id(models.Warehouse)]) - location = forms.IntegerField( - label=_("Current location (warehouse)"), - widget=widgets.JQueryAutoComplete( - reverse_lazy('autocomplete-warehouse'), - associated_model=models.Warehouse, new=True), - validators=[valid_id(models.Warehouse)]) comment = forms.CharField(label=_("Comment"), widget=forms.Textarea, required=False) TYPES = [ @@ -303,6 +298,18 @@ class ContainerForm(CustomForm, ManageOldType, forms.Form): kwargs.pop('limits') super(ContainerForm, self).__init__(*args, **kwargs) + def _clean_parent(self): + if not self.cleaned_data.get("parent", None): + return + warehouse_id = self.cleaned_data.get("location") + q = models.Container.objects.filter( + pk=self.cleaned_data["parent"], + location_id=warehouse_id) + if not q.count(): + raise forms.ValidationError( + _("The parent container is not attached to the same " + "warehouse.")) + def clean(self): cleaned_data = self.cleaned_data warehouse = cleaned_data.get("location") @@ -324,7 +331,6 @@ class ContainerForm(CustomForm, ManageOldType, forms.Form): dct['container_type'] = models.ContainerType.objects.get( pk=dct['container_type']) dct['location'] = models.Warehouse.objects.get(pk=dct['location']) - dct['responsible'] = models.Warehouse.objects.get(pk=dct['responsible']) new_item = models.Container(**dct) new_item.save() return new_item @@ -340,7 +346,7 @@ class ContainerModifyForm(ContainerForm): idx = self.fields.pop('index') for key, value in self.fields.items(): fields[key] = value - if key == 'location': + if key == 'container_type': fields['index'] = idx self.fields = fields @@ -348,9 +354,9 @@ class ContainerModifyForm(ContainerForm): # manage unique ID cleaned_data = super(ContainerModifyForm, self).clean() index = cleaned_data.get("index", None) - warehouse = cleaned_data.get("responsible") + warehouse = cleaned_data.get("location") if not index: - q = models.Container.objects.filter(responsible__pk=warehouse) + q = models.Container.objects.filter(location__pk=warehouse) if not q.count(): cleaned_data["index"] = 1 else: @@ -539,33 +545,6 @@ class FindPackagingFormSelection(FindMultipleFormSelection): form_label = _("Packaged finds") -class LocalisationForm(CustomForm, forms.Form): - form_admin_name = _("Container - 020 - Localisation") - form_slug = "container-020-localisation" - form_label = _("Localisation") - - def __init__(self, *args, **kwargs): - self.container, self.warehouse = None, None - if 'warehouse' in kwargs: - self.warehouse = kwargs.pop('warehouse') - if 'container' in kwargs: - self.container = kwargs.pop('container') - super(LocalisationForm, self).__init__(*args, **kwargs) - if not self.warehouse: - return - for divlink in self.warehouse.divisions.order_by('order').all(): - initial = "-" - if self.container: - q = models.ContainerLocalisation.objects.filter( - division__division=divlink.division, - container=self.container) - if q.count(): - initial = q.all()[0].reference - self.fields['division_{}'.format(divlink.pk)] = forms.CharField( - label=str(divlink.division), max_length=200, initial=initial, - ) - - class ContainerDeletionForm(FinalForm): confirm_msg = _("Would you like to delete this container?") confirm_end_msg = _("Would you like to delete this container?") diff --git a/archaeological_warehouse/migrations/0102_auto_20200408_1823.py b/archaeological_warehouse/migrations/0102_auto_20200408_1823.py index 6bc7f8f88..6550636dc 100644 --- a/archaeological_warehouse/migrations/0102_auto_20200408_1823.py +++ b/archaeological_warehouse/migrations/0102_auto_20200408_1823.py @@ -142,6 +142,15 @@ class Migration(migrations.Migration): name='stationary', field=models.BooleanField(default=False, help_text='Container that usually will not be moved. Ex: building, room.', verbose_name='Stationary'), ), + migrations.AlterModelOptions( + name='containertype', + options={'ordering': ('order', 'label'), 'verbose_name': 'Container type', 'verbose_name_plural': 'Container types'}, + ), + migrations.AddField( + model_name='containertype', + name='order', + field=models.IntegerField(default=10, verbose_name='Order'), + ), migrations.AddField( model_name='warehousedivisionlink', name='container_type', diff --git a/archaeological_warehouse/models.py b/archaeological_warehouse/models.py index 8d2a3fb71..6de87ee36 100644 --- a/archaeological_warehouse/models.py +++ b/archaeological_warehouse/models.py @@ -370,9 +370,9 @@ post_delete.connect(post_save_cache, sender=WarehouseDivision) class WarehouseDivisionLinkManager(models.Manager): - def get_by_natural_key(self, warehouse, division): + def get_by_natural_key(self, warehouse, container_type): return self.get(warehouse__uuid=warehouse, - division__txt_idx=division) + container_type__txt_idx=container_type) class ContainerType(GeneralType): @@ -386,11 +386,12 @@ class ContainerType(GeneralType): volume = models.FloatField(_("Volume (l)"), blank=True, null=True) reference = models.CharField(_("Ref."), max_length=300, blank=True, null=True) + order = models.IntegerField(_("Order"), default=10) class Meta: verbose_name = _("Container type") verbose_name_plural = _("Container types") - ordering = ('label',) + ordering = ('order', 'label',) post_save.connect(post_save_cache, sender=ContainerType) @@ -414,10 +415,10 @@ class WarehouseDivisionLink(models.Model): unique_together = ('warehouse', 'division') def __str__(self): - return "{} - {}".format(self.warehouse, self.division) + return "{} - {}".format(self.warehouse, self.container_type) def natural_key(self): - return self.warehouse.uuid, self.division.txt_idx + return self.warehouse.uuid, self.container_type.txt_idx class ContainerTree: @@ -1123,6 +1124,7 @@ def container_post_save(sender, **kwargs): if not kwargs.get('instance'): return instance = kwargs.get('instance') + #TODO: to be deleted??? for loca in ContainerLocalisation.objects.filter( container=instance).exclude( division__warehouse=instance.location).all(): @@ -1142,6 +1144,7 @@ m2m_changed.connect(document_attached_changed, class ContainerLocalisationManager(models.Manager): + #TODO: to be deleted.... def get_by_natural_key(self, container, warehouse, division): return self.get(container__uuid=container, division__warehouse__uuid=warehouse, @@ -1149,6 +1152,7 @@ class ContainerLocalisationManager(models.Manager): class ContainerLocalisation(models.Model): + #TODO: to be deleted.... container = models.ForeignKey(Container, verbose_name=_("Container"), related_name='division') division = models.ForeignKey(WarehouseDivisionLink, diff --git a/archaeological_warehouse/templates/ishtar/sheet_container.html b/archaeological_warehouse/templates/ishtar/sheet_container.html index 1bb004071..60f49b7ae 100644 --- a/archaeological_warehouse/templates/ishtar/sheet_container.html +++ b/archaeological_warehouse/templates/ishtar/sheet_container.html @@ -2,8 +2,11 @@ {% load i18n window_header window_field window_tables link_to_window %} {% block head_title %}<strong>{% trans "Container" %}</strong> - -{{ item.container_type|default:"" }} {{ item.reference|default:"" }} - -{{ item.location.name|default:"" }} +{% if item.cached_division %} +{{item.cached_division}} +{% else %} +{{ item.container_type|default:"" }} {{ item.reference|default:"" }} {% endif %} +- {{ item.location.name|default:"" }} {% endblock %} {% block toolbar %} @@ -34,7 +37,7 @@ {% endif %} {% field_flex_detail "Warehouse" item.location %} {% if item.parent %} - <dl class="col-12 col-md-6 flex-wrap"> + <dl class="col-12 col-md-9 flex-wrap"> <dt>{% trans "Location" %}</dt> <dd> <nav aria-label="breadcrumb"> @@ -55,6 +58,21 @@ </div> </div> + +{% with item.container_type as container_type %} +{% if container_type.length or container_type.width or container_type.height or container_type.volume or container_type.reference %} +<h4>{% trans "Container type" %}</h4> +<div class='row'> + {% field_flex "Length (mm)" container_type.length %} + {% field_flex "Width (mm)" container_type.width %} + {% field_flex "Height (mm)" container_type.height %} + {% field_flex "Volume (l)" container_type.volume %} + {% field_flex "Reference" container_type.reference %} +</div> +{% endif %} +{% endwith %} + + {% if item.container_content.count or item.children.count %} <h4>{% trans "Content" %}</h4> diff --git a/archaeological_warehouse/templates/ishtar/wizard/wizard_container.html b/archaeological_warehouse/templates/ishtar/wizard/wizard_container.html index 4d0a63c17..cf9d4122e 100644 --- a/archaeological_warehouse/templates/ishtar/wizard/wizard_container.html +++ b/archaeological_warehouse/templates/ishtar/wizard/wizard_container.html @@ -1,17 +1,26 @@ {% extends "ishtar/wizard/default_wizard.html" %} -{% load i18n %} -{% block form_head %} -{% if not wizard.form.fields %} -<p class="alert"> - <i class="fa fa-exclamation-triangle"></i> - {% trans "No division set for this warehouse. Define at least one division to localise containers in this warehouse." %}<br/> - {{wizard.form.warehouse}} - <a href="{% url 'warehouse_modify' wizard.form.warehouse.pk %}"> - <span class="fa-stack fa-lg"> - <i class="fa fa-circle fa-stack-2x"></i> - <i class="fa fa-pencil fa-stack-1x fa-inverse"></i> - </span> - </a> -</p> -{% endif %} +{% load i18n replace_underscore %} + +{% block "js_extra_generic" %} +var constraint_on_parent = function(){ + var warehouse_location_id = $("#id_{{wizard.steps.current}}-location").val(); + if (!warehouse_location_id) return; + + var parent_search_url = source_{{wizard.steps.current|replace_underscore}}_parent; + parent_search_url += warehouse_location_id; + $("#id_select_{{wizard.steps.current}}-parent").autocomplete( + "option", "source", parent_search_url); + var ctips; + if (current_label_{{wizard.steps.current|replace_underscore}}_location){ + ctips = current_label_{{wizard.steps.current|replace_underscore}}_location; + } else { + ctips = $("#id_{{wizard.steps.current}}-location_previous_label").val(); + } + $("#id_{{wizard.steps.current}}-parent-tips").html(ctips); +} +{% endblock %} +{% block "js_extra_ready" %} + +constraint_on_parent(); +$("#id_{{wizard.steps.current}}-location").change(constraint_on_parent); {% endblock %} diff --git a/archaeological_warehouse/tests.py b/archaeological_warehouse/tests.py index 37babf1b2..2fc492caa 100644 --- a/archaeological_warehouse/tests.py +++ b/archaeological_warehouse/tests.py @@ -439,9 +439,7 @@ class ContainerWizardCreationTest(WizardTest, FindInit, TestCase): 'reference': 'hop-ref', 'container_type': None, 'location': None, - 'responsible': None, }, - 'localisation-container_creation': [] }, ), FormData( @@ -451,9 +449,7 @@ class ContainerWizardCreationTest(WizardTest, FindInit, TestCase): 'reference': 'hop-ref2', 'container_type': None, 'location': None, - 'responsible': None, }, - 'localisation-container_creation': [] }, ), FormData( @@ -463,9 +459,7 @@ class ContainerWizardCreationTest(WizardTest, FindInit, TestCase): 'reference': 'hop-ref3', 'container_type': None, 'location': None, - 'responsible': None, }, - 'localisation-container_creation': [] }, ), ] diff --git a/archaeological_warehouse/urls.py b/archaeological_warehouse/urls.py index 5c08af2ad..56f554edf 100644 --- a/archaeological_warehouse/urls.py +++ b/archaeological_warehouse/urls.py @@ -47,7 +47,7 @@ urlpatterns = [ url(r'get-warehouse-shortcut/(?P<type>.+)?$', views.get_warehouse, name='get-warehouse-shortcut', kwargs={'full': 'shortcut'}), - url(r'autocomplete-container/?$', + url(r'autocomplete-container/(?P<warehouse_id>\d+)?$', views.autocomplete_container, name='autocomplete-container'), url(r'^show-container(?:/(?P<pk>.+))?/(?P<type>.+)?$', views.show_container, name=models.Container.SHOW_URL), diff --git a/archaeological_warehouse/views.py b/archaeological_warehouse/views.py index cb74b49f9..801c2255c 100644 --- a/archaeological_warehouse/views.py +++ b/archaeological_warehouse/views.py @@ -76,7 +76,7 @@ def autocomplete_warehouse(request): return HttpResponse(data, content_type='text/plain') -def autocomplete_container(request): +def autocomplete_container(request, warehouse_id=None): if not request.user.has_perm('ishtar_common.view_warehouse', models.Warehouse)\ and not request.user.has_perm( @@ -86,7 +86,10 @@ def autocomplete_container(request): return HttpResponse(content_type='text/plain') term = request.GET.get('term') limit = 15 - query = Q() + base_query = Q() + if warehouse_id: + base_query = Q(location_id=warehouse_id) + query = base_query for q in term.split(' '): extra = Q(reference__iexact=q) query = query & extra @@ -94,20 +97,21 @@ def autocomplete_container(request): query).values('id', 'cached_label')[:limit]) limit = 15 - len(containers) if limit > 0: - query = Q() + query = base_query for q in term.split(' '): extra = Q(container_type__label__icontains=q) | \ Q(container_type__reference__icontains=q) | \ Q(reference__icontains=q) | \ + Q(cached_division__icontains=q) | \ Q(location__name=q) | \ Q(location__town=q) query = query & extra containers += list( models.Container.objects.filter(query).exclude( pk__in=[c['id'] for c in containers] - ).values('id', 'cached_label')[:limit]) + ).values('id', 'cached_division')[:limit]) data = json.dumps( - [{'id': container['id'], 'value': container['cached_label']} + [{'id': container['id'], 'value': container['cached_division']} for container in containers]) return HttpResponse(data, content_type='text/plain') @@ -188,7 +192,6 @@ container_search_wizard = ContainerSearch.as_view([ container_creation_steps = [ ('container-container_creation', forms.ContainerForm), - ('localisation-container_creation', forms.LocalisationForm), ('final-container_creation', FinalForm)] container_creation_wizard = ContainerWizard.as_view( @@ -200,7 +203,6 @@ container_creation_wizard = ContainerWizard.as_view( container_modification_wizard = ContainerModificationWizard.as_view([ ('selec-container_modification', forms.MainContainerFormSelection), ('container-container_modification', forms.ContainerModifyForm), - ('localisation-container_modification', forms.LocalisationForm), ('final-container_modification', FinalForm)], label=_("Container modification"), url_name='container_modification', diff --git a/archaeological_warehouse/wizards.py b/archaeological_warehouse/wizards.py index 302045e2f..9bce9381b 100644 --- a/archaeological_warehouse/wizards.py +++ b/archaeological_warehouse/wizards.py @@ -102,16 +102,6 @@ class WarehouseModificationWizard(Wizard): } redirect_url = "warehouse_modification" - def get_form_kwargs(self, step=None): - kwargs = super(WarehouseModificationWizard, self).get_form_kwargs(step) - if step == "divisions-warehouse_modification": - current_warehouse = self.get_current_object() - q = models.ContainerLocalisation.objects.filter( - division__warehouse=current_warehouse) - if q.count(): - kwargs['readonly'] = True - return kwargs - class WarehouseDeletionWizard(MultipleDeletionWizard): model = models.Warehouse @@ -121,10 +111,10 @@ class WarehouseDeletionWizard(MultipleDeletionWizard): class ContainerWizard(Wizard): model = models.Container wizard_templates = { - 'localisation-container_creation': - 'ishtar/wizard/wizard_containerlocalisation.html', - 'localisation-container_modification': - 'ishtar/wizard/wizard_containerlocalisation.html', + 'container-container_creation': + 'ishtar/wizard/wizard_container.html', + 'container-container_modification': + 'ishtar/wizard/wizard_container.html', } ignore_init_steps = ['localisation'] wizard_done_window = reverse_lazy('show-container') diff --git a/ishtar_common/templates/blocks/JQueryAutocomplete.js b/ishtar_common/templates/blocks/JQueryAutocomplete.js index aaf493db9..54b0cb645 100644 --- a/ishtar_common/templates/blocks/JQueryAutocomplete.js +++ b/ishtar_common/templates/blocks/JQueryAutocomplete.js @@ -1,6 +1,7 @@ {% load replace_underscore %} var base_source_{{field_id|replace_underscore}} = {{source}}; var source_{{field_id|replace_underscore}} = base_source_{{field_id|replace_underscore}}; +var current_label_{{field_id|replace_underscore}}; $(function() { $("#id_select_{{field_id}}").autocomplete({ @@ -8,6 +9,7 @@ $(function() { select: function( event, ui ) { if(ui.item){ $('#id_{{field_id}}').val(ui.item.id); + current_label_{{field_id|replace_underscore}} = ui.item.label; $('#id_{{field_id}}').change(); } else { $('#id_{{field_id}}').val(null); diff --git a/ishtar_common/templates/ishtar/wizard/default_wizard.html b/ishtar_common/templates/ishtar/wizard/default_wizard.html index cfd17e58f..c279a37e0 100644 --- a/ishtar_common/templates/ishtar/wizard/default_wizard.html +++ b/ishtar_common/templates/ishtar/wizard/default_wizard.html @@ -52,6 +52,8 @@ {% endblock %} <script language="javascript" type="text/javascript"> var form_changed = false; +{% block "js_extra_generic" %} +{% endblock %} $(document).ready(function(){ $('form :input').change(function(){form_changed=true;}); $('.change_step').click(function(){ diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py index 28bd9bdd9..df0d09764 100644 --- a/ishtar_common/widgets.py +++ b/ishtar_common/widgets.py @@ -729,8 +729,10 @@ class JQueryAutoComplete(forms.TextInput): model_name = self.associated_model._meta.object_name.lower() if self.tips: new += """<span class="input-group-append"> - <span class="add-button input-group-text"><em>{}</em></span></span> - """.format(self.tips) + <span class="add-button input-group-text"> + <em id="{}-tips">{}</em> + </span></span> + """.format(attrs_hidden['id'], self.tips) if self.modify: new += """ <span class="input-group-append"> @@ -786,8 +788,8 @@ class JQueryAutoComplete(forms.TextInput): _("Restore previous") ) attrs_hidden_previous = attrs_hidden.copy() - attrs_hidden_previous['name'] += u"_previous" - attrs_hidden_previous['id'] += u"_previous" + attrs_hidden_previous['name'] += "_previous" + attrs_hidden_previous['id'] += "_previous" old_value += u"<input type='hidden'{}>".format( flatatt(attrs_hidden_previous)) pk = None |