summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2021-07-22 18:22:54 +0200
committerÉtienne Loks <etienne.loks@iggdrasil.net>2021-07-29 11:56:34 +0200
commit7e1b10f0645539698b3aad3512a5e865dd56522f (patch)
tree272169633833554b81ab51336c3ebe41bb714e8a
parentcc6d9d22d724fb39a5b7d30255e6bab2adc78763 (diff)
downloadIshtar-7e1b10f0645539698b3aad3512a5e865dd56522f.tar.bz2
Ishtar-7e1b10f0645539698b3aad3512a5e865dd56522f.zip
Preventive file: work on inlines - 2
-rw-r--r--archaeological_files/admin.py12
-rw-r--r--archaeological_files/forms.py120
-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.py33
-rw-r--r--archaeological_files/templates/ishtar/forms/preventive_detail.html23
-rw-r--r--archaeological_files/views.py9
-rw-r--r--ishtar_common/admin.py14
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 bbd61f14b..b21503c35 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 (
@@ -575,11 +576,14 @@ class ImportActionAdmin(admin.ModelAdmin):
elif isinstance(field, ForeignKey):
if value:
model = field.rel.to
- 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