From 12fd2be76304653e91fc17390e18e73b6015abb1 Mon Sep 17 00:00:00 2001 From: Étienne Loks Date: Thu, 29 Jul 2021 19:02:32 +0200 Subject: Preventive file: work on inlines - 3 --- archaeological_files/admin.py | 43 +++- archaeological_files/forms.py | 79 +++++-- .../migrations/0106_auto_20210726_1230.py | 245 --------------------- .../migrations/0106_auto_20210729_1616.py | 245 +++++++++++++++++++++ archaeological_files/models.py | 129 ++++++++--- archaeological_files/views.py | 2 +- ishtar_common/static/js/ishtar.js | 1 - .../templates/blocks/bs_formset_snippet.html | 6 +- 8 files changed, 442 insertions(+), 308 deletions(-) delete mode 100644 archaeological_files/migrations/0106_auto_20210726_1230.py create mode 100644 archaeological_files/migrations/0106_auto_20210729_1616.py diff --git a/archaeological_files/admin.py b/archaeological_files/admin.py index 629a0031d..a2834c498 100644 --- a/archaeological_files/admin.py +++ b/archaeological_files/admin.py @@ -22,8 +22,13 @@ from ajax_select import make_ajax_form from django.conf import settings from ishtar_common.apps import admin_site -from ishtar_common.admin import HistorizedObjectAdmin, GeneralTypeAdmin, \ - export_as_csv_action, serialize_type_action, ImportActionAdmin +from ishtar_common.admin import ( + HistorizedObjectAdmin, + GeneralTypeAdmin, + export_as_csv_action, + serialize_type_action, + ImportActionAdmin, +) from . import models @@ -66,7 +71,8 @@ admin_site.register(models.File, FileAdmin) general_models = [ - models.FileType, models.PermitType, models.Job, + models.FileType, + models.PermitType, models.GenericEquipmentServiceType, ] if settings.COUNTRY == "fr": @@ -75,8 +81,26 @@ for model in general_models: admin_site.register(model, GeneralTypeAdmin) +class JobAdmin(GeneralTypeAdmin): + list_filter = ("available", "permanent_contract") + LIST_DISPLAY = [ + "label", + "permanent_contract", + "order", + "ground_daily_cost", + "daily_cost", + "default_daily_need_on_ground", + "default_daily_need", + "child", + "available", + ] + + +admin_site.register(models.Job, JobAdmin) + + class EquipmentServiceTypeAdmin(GeneralTypeAdmin): - list_filter = ("available", 'generic_equipment_type') + list_filter = ("available", "generic_equipment_type") admin_site.register(models.EquipmentServiceType, EquipmentServiceTypeAdmin) @@ -88,8 +112,15 @@ class EquipmentServiceCostAdmin(ImportActionAdmin): "service_provider", ) list_filter = ("available",) - list_display = ["equipment_service_type", "specificity", "parent", - "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 diff --git a/archaeological_files/forms.py b/archaeological_files/forms.py index 4918fdaaa..77d19ce2f 100644 --- a/archaeological_files/forms.py +++ b/archaeological_files/forms.py @@ -624,10 +624,19 @@ INLINE_JOB_FIELDS = [ "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"}), + "job": forms.Select(attrs={"bs_col_width": "col-lg-6 col-12"}), + "man_by_day_planned": forms.NumberInput( + attrs={"class": "w-50 form-planned", "bs_col_width": "col-2"} + ), + "days_planned": forms.NumberInput( + attrs={"class": "w-50 form-planned", "bs_col_width": "col-2"} + ), + "man_by_day_worked": forms.NumberInput( + attrs={"class": "w-50 form-worked", "bs_col_width": "col-2"} + ), + "days_worked": forms.NumberInput( + attrs={"class": "w-50 form-worked", "bs_col_width": "col-2"} + ), } JOB_LABELS = { @@ -653,7 +662,30 @@ class PreventiveFileForm(forms.ModelForm): return super().save(commit=commit) -class PreventiveFileJobForm(PreventiveFileForm): +class PreventiveFileGenJobForm(PreventiveFileForm): + def __init__(self, *args, **kwargs): + super(PreventiveFileGenJobForm, self).__init__(*args, **kwargs) + current_value = None + if hasattr(self.instance, "job") and self.instance.job: + current_value = self.instance.job + self.fields["job"].choices = models.Job.get_choices(current_value) + + def save(self, commit=True): + item = super().save(commit=True) + child = item.job.child + if not item or not child: + return + if not self._meta.model.objects.filter(file_id=item.file_id, job=child).count(): + self._meta.model.objects.create( + file_id=item.file_id, + job=child, + man_by_day_planned=item.man_by_day_planned, + days_planned=item.days_planned, + ) + return item + + +class PreventiveFileJobForm(PreventiveFileGenJobForm): class Meta: model = models.PreventiveFileJob fields = ["job"] + INLINE_JOB_FIELDS @@ -675,7 +707,7 @@ PreventiveFileJobFormSet.form_slug = "preventive-030-post-excavation" PreventiveFileJobFormSet.dynamic_add = True -class PreventiveFileGroundJobForm(PreventiveFileForm): +class PreventiveFileGroundJobForm(PreventiveFileGenJobForm): class Meta: model = models.PreventiveFileGroundJob fields = ["job"] + INLINE_JOB_FIELDS @@ -715,12 +747,20 @@ INLINE_COST_FIELDS = [ ] COST_WIDGETS = { - "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 unit-form"}), + "quantity_by_day_planned": forms.NumberInput( + attrs={"class": "w-50 form-planned", "bs_col_width": "col-2"} + ), + "days_planned": forms.NumberInput( + attrs={"class": "w-50 form-planned unit-form", "bs_col_width": "col-2"} + ), + "quantity_by_day_worked": forms.NumberInput( + attrs={"class": "w-50 form-worked", "bs_col_width": "col-2"} + ), + "days_worked": forms.NumberInput( + attrs={"class": "w-50 form-worked unit-form", "bs_col_width": "col-2"} + ), "equipment_service_cost": forms.Select( - attrs={"class": "form-cost", "bs_col_width": "col-12"} + attrs={"class": "form-cost", "bs_col_width": "col-lg-6 col-12"} ), } @@ -744,10 +784,13 @@ class PreventiveFileEquipmentServiceForm(PreventiveFileForm): self.unities = {} unit_dict = dict(models.ES_UNITS) - choices = [("", "--")] + choices = [("", "-" * 9)] costs = list(q.all()) - if self.instance and self.instance.equipment_service_cost_id \ - and self.instance.equipment_service_cost not in costs: + 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: @@ -767,10 +810,12 @@ class PreventiveFileEquipmentServiceForm(PreventiveFileForm): 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(): + 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 + file_id=item.file_id, + equipment_service_cost=child, + quantity_by_day_planned=0, ) return item diff --git a/archaeological_files/migrations/0106_auto_20210726_1230.py b/archaeological_files/migrations/0106_auto_20210726_1230.py deleted file mode 100644 index 5f3163cf9..000000000 --- a/archaeological_files/migrations/0106_auto_20210726_1230.py +++ /dev/null @@ -1,245 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.11.28 on 2021-07-26 12:30 -from __future__ import unicode_literals - -import django.core.validators -from django.db import migrations, models -import django.db.models.deletion -import ishtar_common.models_common -import re - - -class Migration(migrations.Migration): - - dependencies = [ - ('archaeological_files', '0105_auto_20201204_1442'), - ] - - operations = [ - migrations.CreateModel( - 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')), - ('unit', models.CharField(blank=True, choices=[('D', 'days'), ('W', 'weeks'), ('M', 'months'), ('L', 'linear meter')], max_length=1, null=True, verbose_name='Unit')), - ('specificity', models.CharField(blank=True, default='', max_length=200, verbose_name='Specificity')), - ('order', models.IntegerField(default=10, verbose_name='Order')), - ('available', models.BooleanField(default=True, verbose_name='Available')), - ], - options={ - 'verbose_name': 'Equipment/service cost', - 'verbose_name_plural': 'Equipment/service costs', - 'ordering': ('order', 'equipment_service_type__label'), - }, - ), - migrations.CreateModel( - name='EquipmentServiceType', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('label', models.TextField(verbose_name='Label')), - ('txt_idx', models.TextField(help_text='The slug is the standardized version of the name. It contains only lowercase letters, numbers and hyphens. Each slug must be unique.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z', 32), "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.", 'invalid')], verbose_name='Textual ID')), - ('comment', models.TextField(blank=True, default='', verbose_name='Comment')), - ('available', models.BooleanField(default=True, verbose_name='Available')), - ('order', models.IntegerField(default=10, verbose_name='Order')), - ], - options={ - 'verbose_name': 'Equipment/service type', - 'verbose_name_plural': 'Equipment/service types', - 'ordering': ('order', 'label'), - }, - bases=(ishtar_common.models_common.Cached, models.Model), - ), - migrations.CreateModel( - name='GenericEquipmentServiceType', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('label', models.TextField(verbose_name='Label')), - ('txt_idx', models.TextField(help_text='The slug is the standardized version of the name. It contains only lowercase letters, numbers and hyphens. Each slug must be unique.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z', 32), "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.", 'invalid')], verbose_name='Textual ID')), - ('comment', models.TextField(blank=True, default='', verbose_name='Comment')), - ('available', models.BooleanField(default=True, verbose_name='Available')), - ('order', models.IntegerField(default=10, verbose_name='Order')), - ], - options={ - 'verbose_name': 'Generic equipment type', - 'verbose_name_plural': 'Generic equipment types', - 'ordering': ('order', 'label'), - }, - bases=(ishtar_common.models_common.Cached, models.Model), - ), - migrations.CreateModel( - name='Job', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('label', models.TextField(verbose_name='Label')), - ('txt_idx', models.TextField(help_text='The slug is the standardized version of the name. It contains only lowercase letters, numbers and hyphens. Each slug must be unique.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z', 32), "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.", 'invalid')], verbose_name='Textual ID')), - ('comment', models.TextField(blank=True, default='', verbose_name='Comment')), - ('available', models.BooleanField(default=True, verbose_name='Available')), - ('ground_daily_cost', models.FloatField(blank=True, null=True, verbose_name='Ground daily cost')), - ('daily_cost', models.FloatField(blank=True, null=True, verbose_name='Daily cost')), - ('permanent_contract', models.NullBooleanField(verbose_name='Is a permanent contract')), - ('default_daily_need_on_ground', models.FloatField(default=0, verbose_name='Default daily number needed on the ground')), - ('default_daily_need', models.FloatField(default=0, verbose_name='Default daily number needed')), - ('order', models.IntegerField(default=10, verbose_name='Order')), - ('parents', models.ManyToManyField(blank=True, help_text='Auto-add this job when a parent is added', related_name='_job_parents_+', to='archaeological_files.Job', verbose_name='Parents')), - ], - options={ - 'verbose_name': 'Job', - 'verbose_name_plural': 'Jobs', - 'ordering': ('order', 'label'), - }, - bases=(ishtar_common.models_common.Cached, models.Model), - ), - migrations.CreateModel( - name='PreventiveFileEquipmentServiceCost', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('quantity_by_day_planned', models.FloatField(blank=True, null=True, verbose_name='Quantity by day - planned')), - ('days_planned', models.FloatField(blank=True, null=True, verbose_name='Days - planned')), - ('quantity_by_day_worked', models.FloatField(blank=True, null=True, verbose_name='Quantity by day - worked')), - ('days_worked', models.FloatField(blank=True, null=True, verbose_name='Days - worked')), - ('equipment_service_cost', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.EquipmentServiceCost')), - ], - options={ - 'ordering': ('equipment_service_cost',), - }, - ), - migrations.CreateModel( - name='PreventiveFileGroundJob', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('man_by_day_planned', models.FloatField(blank=True, null=True, verbose_name='Man by day - planned')), - ('days_planned', models.FloatField(blank=True, null=True, verbose_name='Days - planned')), - ('man_by_day_worked', models.FloatField(blank=True, null=True, verbose_name='Man by day - worked')), - ('days_worked', models.FloatField(blank=True, null=True, verbose_name='Days - worked')), - ], - options={ - 'ordering': ('job',), - }, - ), - migrations.CreateModel( - name='PreventiveFileJob', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('man_by_day_planned', models.FloatField(blank=True, null=True, verbose_name='Man by day - planned')), - ('days_planned', models.FloatField(blank=True, null=True, verbose_name='Days - planned')), - ('man_by_day_worked', models.FloatField(blank=True, null=True, verbose_name='Man by day - worked')), - ('days_worked', models.FloatField(blank=True, null=True, verbose_name='Days - worked')), - ], - options={ - 'ordering': ('job',), - }, - ), - migrations.AddField( - model_name='file', - name='execution_report_date', - field=models.DateField(blank=True, null=True, verbose_name='Execution report date'), - ), - migrations.AddField( - model_name='file', - name='ground_end_date', - field=models.DateField(blank=True, null=True, verbose_name='Ground end date'), - ), - migrations.AddField( - model_name='file', - name='ground_start_date', - field=models.DateField(blank=True, null=True, verbose_name='Ground start date'), - ), - migrations.AddField( - model_name='file', - name='linear_meter', - field=models.IntegerField(blank=True, null=True, verbose_name='Linear meter'), - ), - migrations.AddField( - model_name='file', - name='start_date', - field=models.DateField(blank=True, null=True, verbose_name='Start date'), - ), - migrations.AddField( - model_name='file', - name='study_period', - field=models.CharField(blank=True, default='', max_length=200, verbose_name='Study period'), - ), - migrations.AddField( - model_name='historicalfile', - name='execution_report_date', - field=models.DateField(blank=True, null=True, verbose_name='Execution report date'), - ), - migrations.AddField( - model_name='historicalfile', - name='ground_end_date', - field=models.DateField(blank=True, null=True, verbose_name='Ground end date'), - ), - migrations.AddField( - model_name='historicalfile', - name='ground_start_date', - field=models.DateField(blank=True, null=True, verbose_name='Ground start date'), - ), - migrations.AddField( - model_name='historicalfile', - name='linear_meter', - field=models.IntegerField(blank=True, null=True, verbose_name='Linear meter'), - ), - migrations.AddField( - model_name='historicalfile', - name='start_date', - field=models.DateField(blank=True, null=True, verbose_name='Start date'), - ), - migrations.AddField( - model_name='historicalfile', - name='study_period', - field=models.CharField(blank=True, default='', max_length=200, verbose_name='Study period'), - ), - migrations.AlterField( - model_name='file', - name='end_date', - field=models.DateField(blank=True, null=True, verbose_name='End date'), - ), - migrations.AlterField( - model_name='historicalfile', - name='end_date', - field=models.DateField(blank=True, null=True, verbose_name='End date'), - ), - migrations.AddField( - model_name='preventivefilejob', - name='file', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='jobs', to='archaeological_files.File'), - ), - migrations.AddField( - model_name='preventivefilejob', - name='job', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.Job'), - ), - migrations.AddField( - model_name='preventivefilegroundjob', - name='file', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ground_jobs', to='archaeological_files.File'), - ), - migrations.AddField( - model_name='preventivefilegroundjob', - name='job', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.Job'), - ), - migrations.AddField( - model_name='preventivefileequipmentservicecost', - name='file', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='equipment_costs', to='archaeological_files.File'), - ), - migrations.AddField( - model_name='equipmentservicetype', - name='generic_equipment_type', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.GenericEquipmentServiceType', verbose_name='Generic type'), - ), - 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/migrations/0106_auto_20210729_1616.py b/archaeological_files/migrations/0106_auto_20210729_1616.py new file mode 100644 index 000000000..3891b5d30 --- /dev/null +++ b/archaeological_files/migrations/0106_auto_20210729_1616.py @@ -0,0 +1,245 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.28 on 2021-07-29 16:16 +from __future__ import unicode_literals + +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import ishtar_common.models_common +import re + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_files', '0105_auto_20201204_1442'), + ] + + operations = [ + migrations.CreateModel( + 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')), + ('unit', models.CharField(blank=True, choices=[('D', 'days'), ('W', 'weeks'), ('M', 'months'), ('L', 'linear meter')], max_length=1, null=True, verbose_name='Unit')), + ('specificity', models.CharField(blank=True, default='', max_length=200, verbose_name='Specificity')), + ('order', models.IntegerField(default=10, verbose_name='Order')), + ('available', models.BooleanField(default=True, verbose_name='Available')), + ], + options={ + 'verbose_name': 'Equipment/service cost', + 'verbose_name_plural': 'Equipment/service costs', + 'ordering': ('order', 'equipment_service_type__label'), + }, + ), + migrations.CreateModel( + name='EquipmentServiceType', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('label', models.TextField(verbose_name='Label')), + ('txt_idx', models.TextField(help_text='The slug is the standardized version of the name. It contains only lowercase letters, numbers and hyphens. Each slug must be unique.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z', 32), "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.", 'invalid')], verbose_name='Textual ID')), + ('comment', models.TextField(blank=True, default='', verbose_name='Comment')), + ('available', models.BooleanField(default=True, verbose_name='Available')), + ('order', models.IntegerField(default=10, verbose_name='Order')), + ], + options={ + 'verbose_name': 'Equipment/service type', + 'verbose_name_plural': 'Equipment/service types', + 'ordering': ('order', 'label'), + }, + bases=(ishtar_common.models_common.Cached, models.Model), + ), + migrations.CreateModel( + name='GenericEquipmentServiceType', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('label', models.TextField(verbose_name='Label')), + ('txt_idx', models.TextField(help_text='The slug is the standardized version of the name. It contains only lowercase letters, numbers and hyphens. Each slug must be unique.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z', 32), "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.", 'invalid')], verbose_name='Textual ID')), + ('comment', models.TextField(blank=True, default='', verbose_name='Comment')), + ('available', models.BooleanField(default=True, verbose_name='Available')), + ('order', models.IntegerField(default=10, verbose_name='Order')), + ], + options={ + 'verbose_name': 'Generic equipment type', + 'verbose_name_plural': 'Generic equipment types', + 'ordering': ('order', 'label'), + }, + bases=(ishtar_common.models_common.Cached, models.Model), + ), + migrations.CreateModel( + name='Job', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('label', models.TextField(verbose_name='Label')), + ('txt_idx', models.TextField(help_text='The slug is the standardized version of the name. It contains only lowercase letters, numbers and hyphens. Each slug must be unique.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z', 32), "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.", 'invalid')], verbose_name='Textual ID')), + ('comment', models.TextField(blank=True, default='', verbose_name='Comment')), + ('available', models.BooleanField(default=True, verbose_name='Available')), + ('ground_daily_cost', models.FloatField(blank=True, null=True, verbose_name='Ground daily cost')), + ('daily_cost', models.FloatField(blank=True, null=True, verbose_name='Daily cost')), + ('permanent_contract', models.NullBooleanField(verbose_name='Permanent contract')), + ('default_daily_need_on_ground', models.FloatField(default=0, verbose_name='Def. daily number on ground')), + ('default_daily_need', models.FloatField(default=0, verbose_name='Def. daily number')), + ('order', models.IntegerField(default=10, verbose_name='Order')), + ('child', models.ForeignKey(blank=True, help_text='Auto-add this job when a parent is added', null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.Job', verbose_name='Child')), + ], + options={ + 'verbose_name': 'Job', + 'verbose_name_plural': 'Jobs', + 'ordering': ('order', '-permanent_contract', 'label'), + }, + bases=(ishtar_common.models_common.Cached, models.Model), + ), + migrations.CreateModel( + name='PreventiveFileEquipmentServiceCost', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('quantity_by_day_planned', models.FloatField(blank=True, null=True, verbose_name='Quantity by day - planned')), + ('days_planned', models.FloatField(blank=True, null=True, verbose_name='Days - planned')), + ('quantity_by_day_worked', models.FloatField(blank=True, null=True, verbose_name='Quantity by day - worked')), + ('days_worked', models.FloatField(blank=True, null=True, verbose_name='Days - worked')), + ('equipment_service_cost', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.EquipmentServiceCost')), + ], + options={ + 'ordering': ('equipment_service_cost',), + }, + ), + migrations.CreateModel( + name='PreventiveFileGroundJob', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('man_by_day_planned', models.FloatField(blank=True, null=True, verbose_name='Man by day - planned')), + ('days_planned', models.FloatField(blank=True, null=True, verbose_name='Days - planned')), + ('man_by_day_worked', models.FloatField(blank=True, null=True, verbose_name='Man by day - worked')), + ('days_worked', models.FloatField(blank=True, null=True, verbose_name='Days - worked')), + ], + options={ + 'ordering': ('job',), + }, + ), + migrations.CreateModel( + name='PreventiveFileJob', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('man_by_day_planned', models.FloatField(blank=True, null=True, verbose_name='Man by day - planned')), + ('days_planned', models.FloatField(blank=True, null=True, verbose_name='Days - planned')), + ('man_by_day_worked', models.FloatField(blank=True, null=True, verbose_name='Man by day - worked')), + ('days_worked', models.FloatField(blank=True, null=True, verbose_name='Days - worked')), + ], + options={ + 'ordering': ('job',), + }, + ), + migrations.AddField( + model_name='file', + name='execution_report_date', + field=models.DateField(blank=True, null=True, verbose_name='Execution report date'), + ), + migrations.AddField( + model_name='file', + name='ground_end_date', + field=models.DateField(blank=True, null=True, verbose_name='Ground end date'), + ), + migrations.AddField( + model_name='file', + name='ground_start_date', + field=models.DateField(blank=True, null=True, verbose_name='Ground start date'), + ), + migrations.AddField( + model_name='file', + name='linear_meter', + field=models.IntegerField(blank=True, null=True, verbose_name='Linear meter'), + ), + migrations.AddField( + model_name='file', + name='start_date', + field=models.DateField(blank=True, null=True, verbose_name='Start date'), + ), + migrations.AddField( + model_name='file', + name='study_period', + field=models.CharField(blank=True, default='', max_length=200, verbose_name='Study period'), + ), + migrations.AddField( + model_name='historicalfile', + name='execution_report_date', + field=models.DateField(blank=True, null=True, verbose_name='Execution report date'), + ), + migrations.AddField( + model_name='historicalfile', + name='ground_end_date', + field=models.DateField(blank=True, null=True, verbose_name='Ground end date'), + ), + migrations.AddField( + model_name='historicalfile', + name='ground_start_date', + field=models.DateField(blank=True, null=True, verbose_name='Ground start date'), + ), + migrations.AddField( + model_name='historicalfile', + name='linear_meter', + field=models.IntegerField(blank=True, null=True, verbose_name='Linear meter'), + ), + migrations.AddField( + model_name='historicalfile', + name='start_date', + field=models.DateField(blank=True, null=True, verbose_name='Start date'), + ), + migrations.AddField( + model_name='historicalfile', + name='study_period', + field=models.CharField(blank=True, default='', max_length=200, verbose_name='Study period'), + ), + migrations.AlterField( + model_name='file', + name='end_date', + field=models.DateField(blank=True, null=True, verbose_name='End date'), + ), + migrations.AlterField( + model_name='historicalfile', + name='end_date', + field=models.DateField(blank=True, null=True, verbose_name='End date'), + ), + migrations.AddField( + model_name='preventivefilejob', + name='file', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='jobs', to='archaeological_files.File'), + ), + migrations.AddField( + model_name='preventivefilejob', + name='job', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.Job'), + ), + migrations.AddField( + model_name='preventivefilegroundjob', + name='file', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ground_jobs', to='archaeological_files.File'), + ), + migrations.AddField( + model_name='preventivefilegroundjob', + name='job', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.Job'), + ), + migrations.AddField( + model_name='preventivefileequipmentservicecost', + name='file', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='equipment_costs', to='archaeological_files.File'), + ), + migrations.AddField( + model_name='equipmentservicetype', + name='generic_equipment_type', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.GenericEquipmentServiceType', verbose_name='Generic type'), + ), + 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 ab84be8cb..5129189cf 100644 --- a/archaeological_files/models.py +++ b/archaeological_files/models.py @@ -72,23 +72,60 @@ class Job(GeneralType): ground_daily_cost = models.FloatField(_("Ground daily cost"), blank=True, null=True) daily_cost = models.FloatField(_("Daily cost"), blank=True, null=True) permanent_contract = models.NullBooleanField( - _("Is a permanent contract"), blank=True, null=True) + _("Permanent contract"), blank=True, null=True + ) default_daily_need_on_ground = models.FloatField( - _("Default daily number needed on the ground"), default=0) - default_daily_need = models.FloatField( - _("Default daily number needed"), default=0) + _("Def. daily number on ground"), default=0 + ) + default_daily_need = models.FloatField(_("Def. daily number"), default=0) order = models.IntegerField(_("Order"), default=10) - parents = models.ManyToManyField( + child = models.ForeignKey( "self", blank=True, - verbose_name=_("Parents"), - help_text=_("Auto-add this job when a parent is added") + null=True, + verbose_name=_("Child"), + help_text=_("Auto-add this job when a parent is added"), + related_name="parents", ) class Meta: verbose_name = _("Job") verbose_name_plural = _("Jobs") - ordering = ("order", "label",) + ordering = ( + "order", + "-permanent_contract", + "label", + ) + + def __str__(self): + lbl = self.label + if not self.permanent_contract: + lbl += " ({})".format(_("fixed-term contract")) + return lbl + + @classmethod + def get_choices(cls, current_value): + q = cls.objects.filter( + available=True, + parents__isnull=True, + ) + permanent = [(j.pk, str(j)) for j in q.filter(permanent_contract=True).all()] + fixed_term = [(j.pk, str(j)) for j in q.filter(permanent_contract=False).all()] + if current_value: + if current_value.permanent_contract: + permanent.append((current_value.pk, str(current_value))) + else: + fixed_term.append((current_value.pk, str(current_value))) + return [("", "-" * 9)] + [ + ( + _("Permanent contract"), + permanent, + ), + ( + _("Fixed-term contract"), + fixed_term, + ), + ] class GenericEquipmentServiceType(GeneralType): @@ -97,18 +134,25 @@ class GenericEquipmentServiceType(GeneralType): class Meta: verbose_name = _("Generic equipment type") verbose_name_plural = _("Generic equipment types") - ordering = ("order", "label",) + ordering = ( + "order", + "label", + ) class EquipmentServiceType(GeneralType): generic_equipment_type = models.ForeignKey( - GenericEquipmentServiceType, verbose_name=_("Generic type")) + GenericEquipmentServiceType, verbose_name=_("Generic type") + ) order = models.IntegerField(_("Order"), default=10) class Meta: verbose_name = _("Equipment/service type") verbose_name_plural = _("Equipment/service types") - ordering = ("order", "label",) + ordering = ( + "order", + "label", + ) ES_UNITS = ( @@ -118,10 +162,13 @@ ES_UNITS = ( ("L", _("linear meter")), ) +DCT_ES_UNITS = dict(ES_UNITS) + class EquipmentServiceCost(models.Model): equipment_service_type = models.ForeignKey( - EquipmentServiceType, verbose_name=_("Equipment/Service")) + EquipmentServiceType, verbose_name=_("Equipment/Service") + ) slug = models.SlugField( _("Textual ID"), unique=True, @@ -133,13 +180,16 @@ class EquipmentServiceCost(models.Model): ), ) service_provider = models.CharField( - _("Service provider"), max_length=200, blank=True, default="") + _("Service provider"), max_length=200, blank=True, default="" + ) flat_rate = models.BooleanField(_("Flat rate"), default=False) unitary_cost = models.FloatField(_("Unitary cost"), blank=True, null=True) - unit = models.CharField(_("Unit"), max_length=1, choices=ES_UNITS, - blank=True, null=True) - specificity = models.CharField(_("Specificity"), blank=True, - max_length=200, default="") + unit = models.CharField( + _("Unit"), max_length=1, choices=ES_UNITS, blank=True, null=True + ) + specificity = models.CharField( + _("Specificity"), blank=True, max_length=200, default="" + ) order = models.IntegerField(_("Order"), default=10) available = models.BooleanField(_("Available"), default=True) parent = models.ForeignKey( @@ -149,13 +199,16 @@ class EquipmentServiceCost(models.Model): on_delete=models.CASCADE, verbose_name=_("Parent"), help_text=_("Auto-add this cost when a parent is added"), - related_name="children" + related_name="children", ) class Meta: verbose_name = _("Equipment/service cost") verbose_name_plural = _("Equipment/service costs") - ordering = ("order", "equipment_service_type__label",) + ordering = ( + "order", + "equipment_service_type__label", + ) def __str__(self): lbl = "" @@ -166,6 +219,10 @@ class EquipmentServiceCost(models.Model): lbl += " - " + self.specificity if self.service_provider: lbl += f" ({self.service_provider})" + if self.flat_rate: + lbl += " - " + str(_("Flat rate")) + if self.unit and self.unit in DCT_ES_UNITS: + lbl += " - " + str(DCT_ES_UNITS[self.unit]) return lbl @@ -544,14 +601,16 @@ class File( # <-- research archaeology # --> preventive detail - study_period = models.CharField(_("Study period"), max_length=200, - default="", blank=True) + study_period = models.CharField( + _("Study period"), max_length=200, default="", blank=True + ) start_date = models.DateField(_("Start date"), blank=True, null=True) end_date = models.DateField(_("End date"), blank=True, null=True) ground_start_date = models.DateField(_("Ground start date"), blank=True, null=True) ground_end_date = models.DateField(_("Ground end date"), blank=True, null=True) - execution_report_date = models.DateField(_("Execution report date"), blank=True, - null=True) + execution_report_date = models.DateField( + _("Execution report date"), blank=True, null=True + ) linear_meter = models.IntegerField(_("Linear meter"), blank=True, null=True) # <-- preventive detail @@ -1178,13 +1237,13 @@ class FileDashboard: class ManDays(models.Model): man_by_day_planned = models.FloatField( - _("Man by day - planned"), null=True, blank=True) - days_planned = models.FloatField( - _("Days - planned"), null=True, blank=True) + _("Man by day - planned"), null=True, blank=True + ) + days_planned = models.FloatField(_("Days - planned"), null=True, blank=True) man_by_day_worked = models.FloatField( - _("Man by day - worked"), null=True, blank=True) - days_worked = models.FloatField( - _("Days - worked"), null=True, blank=True) + _("Man by day - worked"), null=True, blank=True + ) + days_worked = models.FloatField(_("Days - worked"), null=True, blank=True) class Meta: abstract = True @@ -1220,13 +1279,13 @@ class PreventiveFileJob(ManDays): class TechDays(models.Model): quantity_by_day_planned = models.FloatField( - _("Quantity by day - planned"), null=True, blank=True) - days_planned = models.FloatField( - _("Days - planned"), null=True, blank=True) + _("Quantity by day - planned"), null=True, blank=True + ) + days_planned = models.FloatField(_("Days - planned"), null=True, blank=True) quantity_by_day_worked = models.FloatField( - _("Quantity by day - worked"), null=True, blank=True) - days_worked = models.FloatField( - _("Days - worked"), null=True, blank=True) + _("Quantity by day - worked"), null=True, blank=True + ) + days_worked = models.FloatField(_("Days - worked"), null=True, blank=True) class Meta: abstract = True diff --git a/archaeological_files/views.py b/archaeological_files/views.py index 805921016..4cf3ce390 100644 --- a/archaeological_files/views.py +++ b/archaeological_files/views.py @@ -438,7 +438,7 @@ class PreventiveEditView(IshtarMixin, LoginRequiredMixin, MixFormFormsetUpdateVi return inlines def get_success_url(self): - return reverse("file_modification") + "?open_item={}".format(self.object.pk) + return reverse("file-edit-preventive", args=[self.object.pk]) def get_form_kwargs(self): kwargs = super(PreventiveEditView, self).get_form_kwargs() diff --git a/ishtar_common/static/js/ishtar.js b/ishtar_common/static/js/ishtar.js index 3fa293deb..0fa058cca 100644 --- a/ishtar_common/static/js/ishtar.js +++ b/ishtar_common/static/js/ishtar.js @@ -1890,7 +1890,6 @@ var inline_register_add_button = function(slug){ let form_regex_var = slug + '(\\d){1}-'; let form_regex = new RegExp(form_regex_var, 'g'); inline_form_num++; - console.log(new_form); new_form.innerHTML = new_form.innerHTML.replace( form_regex, slug + `-${inline_form_num}-`); inline_container.insertBefore(new_form, inline_div_add_button); diff --git a/ishtar_common/templates/blocks/bs_formset_snippet.html b/ishtar_common/templates/blocks/bs_formset_snippet.html index 3a7e537d3..cfc9bb37b 100644 --- a/ishtar_common/templates/blocks/bs_formset_snippet.html +++ b/ishtar_common/templates/blocks/bs_formset_snippet.html @@ -19,9 +19,9 @@ {% csrf_token %} {% for field in form.visible_fields %} - {% with bs_col_width='col-3' %} - {% include "blocks/bs_field_snippet.html" %} - {% endwith %} + {% ifequal field.name "DELETE" %}{% with bs_col_width='col-2' %}{% include "blocks/bs_field_snippet.html" %}{% endwith %} + {% else %}{% with bs_col_width='col-3' %}{% include "blocks/bs_field_snippet.html" %}{% endwith %} + {% endifequal %} {% endfor %} {% if form.extra_render %} -- cgit v1.2.3