diff options
| -rw-r--r-- | archaeological_files/admin.py | 12 | ||||
| -rw-r--r-- | archaeological_files/forms.py | 120 | ||||
| -rw-r--r-- | archaeological_files/migrations/0106_auto_20210726_1230.py (renamed from archaeological_files/migrations/0106_auto_20210720_1203.py) | 13 | ||||
| -rw-r--r-- | archaeological_files/models.py | 33 | ||||
| -rw-r--r-- | archaeological_files/templates/ishtar/forms/preventive_detail.html | 23 | ||||
| -rw-r--r-- | archaeological_files/views.py | 9 | ||||
| -rw-r--r-- | ishtar_common/admin.py | 14 | 
7 files changed, 157 insertions, 67 deletions
diff --git a/archaeological_files/admin.py b/archaeological_files/admin.py index 6ac40a69b..629a0031d 100644 --- a/archaeological_files/admin.py +++ b/archaeological_files/admin.py @@ -20,10 +20,10 @@  from ajax_select import make_ajax_form  from django.conf import settings -from django.contrib import admin  from ishtar_common.apps import admin_site -from ishtar_common.admin import HistorizedObjectAdmin, GeneralTypeAdmin +from ishtar_common.admin import HistorizedObjectAdmin, GeneralTypeAdmin, \ +    export_as_csv_action, serialize_type_action, ImportActionAdmin  from . import models @@ -82,14 +82,16 @@ class EquipmentServiceTypeAdmin(GeneralTypeAdmin):  admin_site.register(models.EquipmentServiceType, EquipmentServiceTypeAdmin) -class EquipmentServiceCostAdmin(admin.ModelAdmin): +class EquipmentServiceCostAdmin(ImportActionAdmin):      search_fields = (          "equipment_service_type__label",          "service_provider",      )      list_filter = ("available",) -    list_display = ["equipment_service_type", "specificity", "unitary_cost", "unit", -                    "flat_rate", "available"] +    list_display = ["equipment_service_type", "specificity", "parent", +                    "unitary_cost", "unit", "flat_rate", "available"] +    actions = [export_as_csv_action(), serialize_type_action] +    model = models.EquipmentServiceCost  admin_site.register(models.EquipmentServiceCost, EquipmentServiceCostAdmin) diff --git a/archaeological_files/forms.py b/archaeological_files/forms.py index 3c113c665..4918fdaaa 100644 --- a/archaeological_files/forms.py +++ b/archaeological_files/forms.py @@ -522,25 +522,37 @@ class FileFormPreventiveDetail(forms.ModelForm, CustomForm, ManageOldType):      class Meta:          model = models.File -        fields = ["start_date", "end_date", "ground_start_date", -                  "ground_end_date", "study_period", "execution_report_date", -                  "total_developed_surface", "total_surface", "linear_meter"] +        fields = [ +            "start_date", +            "end_date", +            "ground_start_date", +            "ground_end_date", +            "study_period", +            "execution_report_date", +            "total_developed_surface", +            "total_surface", +            "linear_meter", +        ]      pk = forms.IntegerField(label="", required=False, widget=forms.HiddenInput)      start_date = forms.DateField( -        label=_("Start date"), required=False, +        label=_("Start date"), +        required=False,          widget=DatePicker(attrs={"bs_col_width": "col-6 col-lg-3"}),      )      end_date = forms.DateField( -        label=_("End date"), required=False, +        label=_("End date"), +        required=False,          widget=DatePicker(attrs={"bs_col_width": "col-6 col-lg-3"}),      )      ground_start_date = forms.DateField( -        label=_("Ground start date"), required=False, +        label=_("Ground start date"), +        required=False,          widget=DatePicker(attrs={"bs_col_width": "col-6 col-lg-3"}),      )      ground_end_date = forms.DateField( -        label=_("Ground end date"), required=False, +        label=_("Ground end date"), +        required=False,          widget=DatePicker(attrs={"bs_col_width": "col-6 col-lg-3"}),      )      study_period = forms.CharField( @@ -549,7 +561,8 @@ class FileFormPreventiveDetail(forms.ModelForm, CustomForm, ManageOldType):          required=False,      )      execution_report_date = forms.DateField( -        label=_("Execution report date"), required=False, +        label=_("Execution report date"), +        required=False,          widget=DatePicker(attrs={"bs_col_width": "col-6 col-lg-3"}),      )      total_developed_surface = forms.FloatField( @@ -571,7 +584,8 @@ class FileFormPreventiveDetail(forms.ModelForm, CustomForm, ManageOldType):          ],      )      linear_meter = forms.IntegerField( -        label=_("Linear meter (m)"), required=False, +        label=_("Linear meter (m)"), +        required=False,          widget=widgets.MeterKilometerWidget(attrs={"bs_col_width": "col-6 col-lg-3"}),      ) @@ -588,24 +602,32 @@ class FileBaseFormset(forms.BaseModelFormSet):          if "instance" in kwargs:              self.instance = kwargs.pop("instance")          super().__init__(*args, **kwargs) -        self.queryset = self.model.objects.filter(pk=None) +        self.queryset = self.get_base_queryset() + +    def get_base_queryset(self): +        queryset = self.model.objects.filter(pk=None)          if self.instance: -            self.queryset = self.model.objects.filter(file_id=self.instance.pk) +            queryset = self.model.objects.filter(file_id=self.instance.pk) +        return queryset      def get_form_kwargs(self, index):          kwargs = super(FileBaseFormset, self).get_form_kwargs(index)          if self.instance: -            kwargs['file_id'] = self.instance.pk +            kwargs["file_id"] = self.instance.pk          return kwargs -INLINE_JOB_FIELDS = ["man_by_day_planned", "days_planned", "man_by_day_worked", -                     "days_worked"] +INLINE_JOB_FIELDS = [ +    "man_by_day_planned", +    "days_planned", +    "man_by_day_worked", +    "days_worked", +]  JOB_WIDGETS = {      "man_by_day_planned": forms.NumberInput(attrs={"class": "w-50 form-planned"}),      "days_planned": forms.NumberInput(attrs={"class": "w-50 form-planned"}),      "man_by_day_worked": forms.NumberInput(attrs={"class": "w-50 form-worked"}), -    "days_worked": forms.NumberInput(attrs={"class": "w-50 form-worked"}) +    "days_worked": forms.NumberInput(attrs={"class": "w-50 form-worked"}),  }  JOB_LABELS = { @@ -613,7 +635,7 @@ JOB_LABELS = {      "days_planned": _("Days"),      "man_by_day_worked": _("Man by day"),      "days_worked": _("Days"), -    "Job": _("Job") +    "Job": _("Job"),  } @@ -645,7 +667,8 @@ class PreventiveFileJobBaseFormSet(FileBaseFormset):  PreventiveFileJobFormSet = formset_factory( -    PreventiveFileJobForm, formset=PreventiveFileJobBaseFormSet, can_delete=True) +    PreventiveFileJobForm, formset=PreventiveFileJobBaseFormSet, can_delete=True +)  PreventiveFileJobFormSet.form_label = _("Post-excavation")  PreventiveFileJobFormSet.form_admin_name = _("Preventive file - 030 - Post-excavation")  PreventiveFileJobFormSet.form_slug = "preventive-030-post-excavation" @@ -665,8 +688,9 @@ class PreventiveFileGroundJobBaseFormSet(FileBaseFormset):  PreventiveFileGroundJobFormSet = formset_factory( -    PreventiveFileGroundJobForm, formset=PreventiveFileGroundJobBaseFormSet, -    can_delete=True +    PreventiveFileGroundJobForm, +    formset=PreventiveFileGroundJobBaseFormSet, +    can_delete=True,  )  PreventiveFileGroundJobFormSet.form_label = _("Ground jobs")  PreventiveFileGroundJobFormSet.form_admin_name = _( @@ -677,23 +701,27 @@ PreventiveFileGroundJobFormSet.dynamic_add = True  COST_LABELS = {      "quantity_by_day_planned": _("Quantity"), -    "days_planned": _("Days / weeks / months"), +    "days_planned": "",      "quantity_by_day_worked": _("Quantity"), -    "days_worked": _("Days / weeks / months"), -    "equipment_service_cost": _("Equipment / service") +    "days_worked": "", +    "equipment_service_cost": _("Equipment / service"),  }  INLINE_COST_FIELDS = [ -    "quantity_by_day_planned", "days_planned", "quantity_by_day_worked", "days_worked"] +    "quantity_by_day_planned", +    "days_planned", +    "quantity_by_day_worked", +    "days_worked", +]  COST_WIDGETS = { -    "quantity_by_day_planned": forms.NumberInput( -        attrs={"class": "w-50 form-planned"}), -    "days_planned": forms.NumberInput(attrs={"class": "w-50 form-planned"}), +    "quantity_by_day_planned": forms.NumberInput(attrs={"class": "w-50 form-planned"}), +    "days_planned": forms.NumberInput(attrs={"class": "w-50 form-planned unit-form"}),      "quantity_by_day_worked": forms.NumberInput(attrs={"class": "w-50 form-worked"}), -    "days_worked": forms.NumberInput(attrs={"class": "w-50 form-worked"}), +    "days_worked": forms.NumberInput(attrs={"class": "w-50 form-worked unit-form"}),      "equipment_service_cost": forms.Select( -        attrs={"class":"form-cost", "bs_col_width": "col-12"}) +        attrs={"class": "form-cost", "bs_col_width": "col-12"} +    ),  } @@ -710,25 +738,55 @@ class PreventiveFileEquipmentServiceForm(PreventiveFileForm):          super(PreventiveFileEquipmentServiceForm, self).__init__(*args, **kwargs)          q = models.EquipmentServiceCost.objects.filter(              available=True, -            equipment_service_type__parent__isnull=True, -            equipment_service_type__generic_equipment_type__txt_idx=self.type_filter +            parent__isnull=True, +            equipment_service_type__generic_equipment_type__txt_idx=self.type_filter,          )          self.unities = {}          unit_dict = dict(models.ES_UNITS)          choices = [("", "--")] -        for cost in q.all(): +        costs = list(q.all()) +        if self.instance and self.instance.equipment_service_cost_id \ +                and self.instance.equipment_service_cost not in costs: +            costs.append(self.instance.equipment_service_cost) +        self.flat_rates = [] +        for cost in costs:              choices.append((cost.pk, str(cost)))              if cost.unit:                  self.unities[cost.pk] = unit_dict[cost.unit] +            if cost.flat_rate: +                self.flat_rates.append(cost.pk)          self.fields["equipment_service_cost"].choices = choices          self.fields["quantity_by_day_planned"].initial = 1          self.fields["days_planned"].unit = "..." +        self.fields["days_worked"].unit = "..." + +    def save(self, commit=True): +        item = super().save(commit=True) +        if not item: +            return +        for child in item.equipment_service_cost.equipment_service_type.children.all(): +            if not self._meta.model.objects.filter( +                    file_id=item.file_id, equipment_service_cost=child).count(): +                self._meta.model.objects.create( +                    file_id=item.file_id, equipment_service_cost=child, +                    quantity_by_day_planned=0 +                ) +        return item  class PreventiveFileEquipmentServiceBaseFormSet(FileBaseFormset):      model = models.PreventiveFileEquipmentServiceCost +    def get_base_queryset(self): +        queryset = super( +            PreventiveFileEquipmentServiceBaseFormSet, self +        ).get_base_queryset() +        queryset = queryset.filter( +            equipment_service_cost__equipment_service_type__generic_equipment_type__txt_idx=self.type_filter +        ) +        return queryset +  class AdministrativeActFileModifySelect(TableSelect):      _model = AdministrativeAct diff --git a/archaeological_files/migrations/0106_auto_20210720_1203.py b/archaeological_files/migrations/0106_auto_20210726_1230.py index 86ff78ec6..5f3163cf9 100644 --- a/archaeological_files/migrations/0106_auto_20210720_1203.py +++ b/archaeological_files/migrations/0106_auto_20210726_1230.py @@ -1,5 +1,5 @@  # -*- coding: utf-8 -*- -# Generated by Django 1.11.27 on 2021-07-20 12:03 +# Generated by Django 1.11.28 on 2021-07-26 12:30  from __future__ import unicode_literals  import django.core.validators @@ -20,6 +20,7 @@ class Migration(migrations.Migration):              name='EquipmentServiceCost',              fields=[                  ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), +                ('slug', models.SlugField(help_text='The slug is the standardized version of the name. It contains only lowercase letters, numbers and hyphens. Each slug must be unique.', max_length=300, unique=True, verbose_name='Textual ID')),                  ('service_provider', models.CharField(blank=True, default='', max_length=200, verbose_name='Service provider')),                  ('flat_rate', models.BooleanField(default=False, verbose_name='Flat rate')),                  ('unitary_cost', models.FloatField(blank=True, null=True, verbose_name='Unitary cost')), @@ -232,13 +233,13 @@ class Migration(migrations.Migration):              field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.GenericEquipmentServiceType', verbose_name='Generic type'),          ),          migrations.AddField( -            model_name='equipmentservicetype', -            name='parent', -            field=models.ForeignKey(blank=True, help_text='Auto-add this cost when a parent is added', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='archaeological_files.EquipmentServiceType', verbose_name='Parent'), -        ), -        migrations.AddField(              model_name='equipmentservicecost',              name='equipment_service_type',              field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.EquipmentServiceType', verbose_name='Equipment/Service'),          ), +        migrations.AddField( +            model_name='equipmentservicecost', +            name='parent', +            field=models.ForeignKey(blank=True, help_text='Auto-add this cost when a parent is added', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='archaeological_files.EquipmentServiceType', verbose_name='Parent'), +        ),      ] diff --git a/archaeological_files/models.py b/archaeological_files/models.py index 334e8faa4..ab84be8cb 100644 --- a/archaeological_files/models.py +++ b/archaeological_files/models.py @@ -104,15 +104,6 @@ class EquipmentServiceType(GeneralType):      generic_equipment_type = models.ForeignKey(          GenericEquipmentServiceType, verbose_name=_("Generic type"))      order = models.IntegerField(_("Order"), default=10) -    parent = models.ForeignKey( -        "self", -        blank=True, -        null=True, -        on_delete=models.CASCADE, -        verbose_name=_("Parent"), -        help_text=_("Auto-add this cost when a parent is added"), -        related_name="children" -    )      class Meta:          verbose_name = _("Equipment/service type") @@ -131,6 +122,16 @@ ES_UNITS = (  class EquipmentServiceCost(models.Model):      equipment_service_type = models.ForeignKey(          EquipmentServiceType, verbose_name=_("Equipment/Service")) +    slug = models.SlugField( +        _("Textual ID"), +        unique=True, +        max_length=300, +        help_text=_( +            "The slug is the standardized version of the name. It contains " +            "only lowercase letters, numbers and hyphens. Each slug must " +            "be unique." +        ), +    )      service_provider = models.CharField(          _("Service provider"), max_length=200, blank=True, default="")      flat_rate = models.BooleanField(_("Flat rate"), default=False) @@ -141,6 +142,15 @@ class EquipmentServiceCost(models.Model):                                     max_length=200, default="")      order = models.IntegerField(_("Order"), default=10)      available = models.BooleanField(_("Available"), default=True) +    parent = models.ForeignKey( +        EquipmentServiceType, +        blank=True, +        null=True, +        on_delete=models.CASCADE, +        verbose_name=_("Parent"), +        help_text=_("Auto-add this cost when a parent is added"), +        related_name="children" +    )      class Meta:          verbose_name = _("Equipment/service cost") @@ -148,7 +158,10 @@ class EquipmentServiceCost(models.Model):          ordering = ("order", "equipment_service_type__label",)      def __str__(self): -        lbl = str(self.equipment_service_type) +        lbl = "" +        if self.parent: +            lbl = self.parent.label + " - " +        lbl += str(self.equipment_service_type)          if self.specificity:              lbl += " - " + self.specificity          if self.service_provider: diff --git a/archaeological_files/templates/ishtar/forms/preventive_detail.html b/archaeological_files/templates/ishtar/forms/preventive_detail.html index 5b6f7f9ed..cc27e26f3 100644 --- a/archaeological_files/templates/ishtar/forms/preventive_detail.html +++ b/archaeological_files/templates/ishtar/forms/preventive_detail.html @@ -16,10 +16,10 @@          </label>        </div>      </div> -    <div class="w-100 pb-3 text-center"> +    <div class="w-100 pb-3 text-center form-group">        <button class="btn btn-secondary btn-sm form-planned" type="button">{% trans "Add default costs" %}</button>      </div> -    <div class="w-100 pb-3 text-center"> +    <div class="w-100 pb-3 text-center form-group">        <button class="btn btn-secondary btn-sm form-worked" type="button">{% trans "Copy planned costs" %}</button>      </div>      {% for inline in inline_forms %} @@ -34,18 +34,21 @@  {% block end_js %}    {{block.super}}    var check_planned_value = function() { -    if (this.value === 'false'){ -      $(".form-planned").parent().hide() -      $(".form-worked").parent().show() +    if ($('#planned-toggle-true').is(":checked") === false){ +      $(".form-planned").closest("div.form-group").hide() +      $(".form-worked").closest("div.form-group").show()      } else { -      $(".form-planned").parent().show() -      $(".form-worked").parent().hide() +      $(".form-planned").closest("div.form-group").show() +      $(".form-worked").closest("div.form-group").hide()      }    };    const cost_units = {{% for unit_pk, value in form_unities %}{% if forloop.counter0 %},{% endif %}      {{unit_pk}}: "{{value}}"{% endfor %}    }; +  const flat_rates = [{% for pk in form_flat_rates %}{% if forloop.counter0 %},{% endif %} +    "{{pk}}"{% endfor %} +  ];    var update_units = function() {      $(".form-cost").each(function(){        var unit = cost_units[$(this).val()]; @@ -53,6 +56,12 @@          unit = "...";        }        $(this).parent().parent().find(".unit-label").html(unit); +      if (flat_rates.indexOf($(this).val()) != -1){ +        $(this).parent().parent().find(".unit-form").prop("disabled", true); +      } else { +        $(this).parent().parent().find(".unit-form").prop("disabled", false); +      } +      check_planned_value();      });    };    $(document).ready(function(){ diff --git a/archaeological_files/views.py b/archaeological_files/views.py index 90d41c68b..805921016 100644 --- a/archaeological_files/views.py +++ b/archaeological_files/views.py @@ -389,14 +389,11 @@ class MixFormFormsetUpdateView(UpdateView):      def form_valid(self, form, inline_forms):          self.object = form.save() -        print("OK")          for inline in inline_forms:              inline.save() -            pass          return HttpResponseRedirect(self.get_success_url())      def form_invalid(self, form, inline_forms): -        print("NOP")          return self.render_to_response(              self.get_context_data(form=form, inlines=inline_forms)          ) @@ -436,6 +433,7 @@ class PreventiveEditView(IshtarMixin, LoginRequiredMixin, MixFormFormsetUpdateVi              formset.form_label = str(inline_type)              formset.form_slug = inline_type.txt_idx              formset.dynamic_add = True +            formset.type_filter = inline_type.txt_idx              inlines.append(formset)          return inlines @@ -468,8 +466,13 @@ class PreventiveEditView(IshtarMixin, LoginRequiredMixin, MixFormFormsetUpdateVi      def get_context_data(self, **kwargs):          context = super(PreventiveEditView, self).get_context_data(**kwargs)          unities = {} +        flat_rates = set()          for inline_formset in context["inline_forms"]:              if inline_formset.forms and hasattr(inline_formset.forms[0], "unities"):                  unities.update(inline_formset.forms[0].unities) +            if inline_formset.forms and hasattr(inline_formset.forms[0], "flat_rates"): +                for form in inline_formset.forms: +                    flat_rates.update(form.flat_rates)          context["form_unities"] = unities.items() +        context["form_flat_rates"] = flat_rates          return context diff --git a/ishtar_common/admin.py b/ishtar_common/admin.py index 99c3b2deb..00e1b8b74 100644 --- a/ishtar_common/admin.py +++ b/ishtar_common/admin.py @@ -46,6 +46,7 @@ from django.contrib.gis.geos import GEOSGeometry, MultiPolygon  from django.contrib.gis.gdal.error import GDALException  from django.contrib.gis.geos.error import GEOSException  from django.core.cache import cache +from django.core.exceptions import FieldError  from django.core.serializers import serialize  from django.core.urlresolvers import reverse  from django.db.models.fields import ( @@ -582,11 +583,14 @@ class ImportActionAdmin(admin.ModelAdmin):                                      value = ContentType.objects.get(app_label=value[0],                                                                      model=value[1])                                  else: -                                    try: -                                        value = model.objects.get(**{slug_col: value}) -                                    except model.DoesNotExist: -                                        missing_parent.append(row.pop(k)) -                                        continue +                                    for slug_col2 in self.import_keys: +                                        try: +                                            value = model.objects.get(**{slug_col2: value}) +                                        except FieldError: +                                            continue +                                        except model.DoesNotExist: +                                            missing_parent.append(row.pop(k)) +                                            break                              else:                                  value = None                          row[k] = value  | 
