From 6ef9750adef894a11001b959ba0f31def1f3fdd4 Mon Sep 17 00:00:00 2001 From: Étienne Loks Date: Wed, 28 Apr 2021 09:55:25 +0200 Subject: WIP: preventive forms --- archaeological_files/forms.py | 188 ++++++++++++++- .../migrations/0106_auto_20210423_1206.py | 194 ---------------- .../migrations/0106_auto_20210622_1456.py | 255 +++++++++++++++++++++ archaeological_files/models.py | 65 +++--- .../templates/ishtar/forms/preventive_detail.html | 2 + archaeological_files/urls.py | 7 + archaeological_files/views.py | 84 ++++++- 7 files changed, 571 insertions(+), 224 deletions(-) delete mode 100644 archaeological_files/migrations/0106_auto_20210423_1206.py create mode 100644 archaeological_files/migrations/0106_auto_20210622_1456.py create mode 100644 archaeological_files/templates/ishtar/forms/preventive_detail.html (limited to 'archaeological_files') diff --git a/archaeological_files/forms.py b/archaeological_files/forms.py index 2cb08b5d7..51d1fdeb0 100644 --- a/archaeological_files/forms.py +++ b/archaeological_files/forms.py @@ -20,12 +20,13 @@ """ Files forms definitions """ + import datetime from django import forms from django.conf import settings from django.core import validators -from django.forms.formsets import formset_factory +from django.forms.formsets import formset_factory, BaseFormSet from django.utils.functional import lazy from django.utils.safestring import mark_safe from ishtar_common.utils import ugettext_lazy as _ @@ -57,6 +58,7 @@ from ishtar_common.forms import ( LockForm, CustomFormSearch, DocumentItemSelect, + FormHeader, ) from ishtar_common.forms_common import get_town_field from archaeological_operations.forms import ( @@ -506,6 +508,190 @@ class FinalFileDeleteForm(FinalForm): confirm_end_msg = _("Would you like to delete this archaeological file ?") +class FileFormPreventiveDetail(forms.ModelForm, CustomForm, ManageOldType): + form_label = _("Preventive file") + form_admin_name = _("Preventive file - 020 - Edition form") + form_slug = "preventive-020-edition-form" + + associated_models = {} + + HEADERS = { + "start_date": FormHeader(_("Dates")), + "total_developed_surface": FormHeader(_("Surfaces")), + } + + 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"] + + pk = forms.IntegerField(label="", required=False, widget=forms.HiddenInput) + start_date = forms.DateField( + label=_("Start date"), widget=DatePicker, required=False + ) + end_date = forms.DateField(label=_("End date"), widget=DatePicker, required=False) + ground_start_date = forms.DateField( + label=_("Ground start date"), widget=DatePicker, required=False + ) + ground_end_date = forms.DateField( + label=_("Ground end date"), widget=DatePicker, required=False + ) + study_period = forms.CharField( + label=_("Study period"), + max_length=200, + required=False, + ) + execution_report_date = forms.DateField( + label=_("Execution report date"), widget=DatePicker, required=False + ) + total_developed_surface = forms.FloatField( + widget=widgets.AreaWidget, + label=_("Total developed surface (m2)"), + required=False, + validators=[ + validators.MinValueValidator(0), + validators.MaxValueValidator(999999999), + ], + ) + total_surface = forms.FloatField( + required=False, + widget=widgets.AreaWidget, + label=_("Total surface (m2)"), + validators=[ + validators.MinValueValidator(0), + validators.MaxValueValidator(999999999), + ], + ) + linear_meter = forms.IntegerField( + label=_("Linear meter (m)"), required=False, + widget=widgets.MeterKilometerWidget, + ) + + def __init__(self, *args, **kwargs): + self.user = None + if kwargs.get("user", None): + self.user = kwargs.pop("user") + super(FileFormPreventiveDetail, self).__init__(*args, **kwargs) + + +class FileBaseFormset(forms.BaseModelFormSet): + def __init__(self, *args, **kwargs): + self.instance = None + if "instance" in kwargs: + self.instance = kwargs.pop("instance") + super().__init__(*args, **kwargs) + self.queryset = self.model.objects.filter(pk=None) + if self.instance: + self.queryset = self.model.objects.filter(file_id=self.instance.pk) + + +class PreventiveFileJobForm(forms.ModelForm): + file_id = forms.IntegerField(widget=forms.HiddenInput) + job = forms.ChoiceField(choices=[]) + man_by_day_planned = forms.FloatField(_("Man by day - planned"), required=False) + days_planned = forms.FloatField(_("Days - planned"), required=False) + man_by_day_worked = forms.FloatField(_("Man by day - worked"), required=False) + days_worked = forms.FloatField(_("Days - worked"), required=False) + + class Meta: + model = models.PreventiveFileJob + exclude = ["file"] + + +class PreventiveFileJobBaseFormSet(FileBaseFormset): + model = models.PreventiveFileJob + + +PreventiveFileJobFormSet = formset_factory( + PreventiveFileJobForm, formset=PreventiveFileJobBaseFormSet, can_delete=True) +PreventiveFileJobFormSet.form_label = _("Preventive - Jobs") +PreventiveFileJobFormSet.form_admin_name = _("Preventive file - 030 - Jobs") +PreventiveFileJobFormSet.form_slug = "preventive-030-jobs" + + +class PreventiveFileGroundJobForm(forms.ModelForm): + file_id = forms.IntegerField(widget=forms.HiddenInput) + ground_job = forms.ChoiceField(choices=[]) + man_by_day_planned = forms.FloatField(_("Man by day - planned"), required=False) + days_planned = forms.FloatField(_("Days - planned"), required=False) + man_by_day_worked = forms.FloatField(_("Man by day - worked"), required=False) + days_worked = forms.FloatField(_("Days - worked"), required=False) + + class Meta: + model = models.PreventiveFileGroundJob + exclude = ["file"] + + +class PreventiveFileGroundJobBaseFormSet(FileBaseFormset): + model = models.PreventiveFileGroundJob + + +PreventiveFileGroundJobFormSet = formset_factory( + PreventiveFileGroundJobForm, formset=PreventiveFileGroundJobBaseFormSet, + can_delete=True +) +PreventiveFileGroundJobFormSet.form_label = _("Preventive - Ground jobs") +PreventiveFileGroundJobFormSet.form_admin_name = _( + "Preventive file - 040 - Ground jobs" +) +PreventiveFileGroundJobFormSet.form_slug = "preventive-040-ground-jobs" + + +class PreventiveFileEquipmentForm(forms.ModelForm): + file_id = forms.IntegerField(widget=forms.HiddenInput) + equipment = forms.ChoiceField(choices=[]) + man_by_day_planned = forms.FloatField(_("Man by day - planned"), required=False) + days_planned = forms.FloatField(_("Days - planned"), required=False) + man_by_day_worked = forms.FloatField(_("Man by day - worked"), required=False) + days_worked = forms.FloatField(_("Days - worked"), required=False) + + class Meta: + model = models.PreventiveFileEquipmentCost + exclude = ["file"] + + +class PreventiveFileEquipmentBaseFormSet(FileBaseFormset): + model = models.PreventiveFileEquipmentCost + + +PreventiveFileEquipmentFormSet = formset_factory( + PreventiveFileEquipmentForm, formset=PreventiveFileEquipmentBaseFormSet, + can_delete=True +) +PreventiveFileEquipmentFormSet.form_label = _("Preventive - Equipment") +PreventiveFileEquipmentFormSet.form_admin_name = _("Preventive file - 050 - Equipments") +PreventiveFileEquipmentFormSet.form_slug = "preventive-050-equipments" + + +class PreventiveFileTechnicalServiceForm(forms.ModelForm): + file_id = forms.IntegerField(widget=forms.HiddenInput) + technical_service = forms.ChoiceField(choices=[]) + man_by_day_planned = forms.FloatField(_("Man by day - planned"), required=False) + days_planned = forms.FloatField(_("Days - planned"), required=False) + man_by_day_worked = forms.FloatField(_("Man by day - worked"), required=False) + days_worked = forms.FloatField(_("Days - worked"), required=False) + + class Meta: + model = models.PreventiveFileTechnicalServiceCost + exclude = ["file"] + + +class PreventiveFileTechnicalServiceBaseFormSet(FileBaseFormset): + model = models.PreventiveFileTechnicalServiceCost + + +PreventiveFileTechnicalServiceFormSet = formset_factory( + PreventiveFileTechnicalServiceForm, + formset=PreventiveFileTechnicalServiceBaseFormSet, can_delete=True +) +PreventiveFileTechnicalServiceFormSet.form_label = _("Preventive - Technical Services") +PreventiveFileTechnicalServiceFormSet.form_admin_name = _( + "Preventive file - 060 - TechnicalServices" +) +PreventiveFileTechnicalServiceFormSet.form_slug = "preventive-060-technical_services" + + class AdministrativeActFileModifySelect(TableSelect): _model = AdministrativeAct diff --git a/archaeological_files/migrations/0106_auto_20210423_1206.py b/archaeological_files/migrations/0106_auto_20210423_1206.py deleted file mode 100644 index 5d147781e..000000000 --- a/archaeological_files/migrations/0106_auto_20210423_1206.py +++ /dev/null @@ -1,194 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.11.27 on 2021-04-23 12:06 -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='EquipmentCost', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('service_provider', models.CharField(default='-', max_length=200, verbose_name='Service provider')), - ('flat_rate', models.BooleanField(default=False, verbose_name='Flat rate')), - ('daily_cost', models.FloatField(blank=True, null=True, verbose_name='Daily cost')), - ('monday', models.BooleanField(default=True, verbose_name='Monday')), - ('tuesday', models.BooleanField(default=True, verbose_name='Tuesday')), - ('wednesday', models.BooleanField(default=True, verbose_name='Wednesday')), - ('thursday', models.BooleanField(default=True, verbose_name='Thursday')), - ('friday', models.BooleanField(default=True, verbose_name='Friday')), - ], - options={ - 'verbose_name': 'Equipment cost', - 'verbose_name_plural': 'Equipment costs', - }, - ), - migrations.CreateModel( - name='EquipmentType', - 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')), - ], - options={ - 'verbose_name': 'Equipment type', - 'verbose_name_plural': 'Equipment types', - 'ordering': ('label',), - }, - bases=(ishtar_common.models_common.Cached, models.Model), - ), - migrations.CreateModel( - name='GenericEquipmentType', - 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')), - ], - options={ - 'verbose_name': 'Generic equipment type', - 'verbose_name_plural': 'Generic equipment types', - 'ordering': ('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')), - ], - options={ - 'verbose_name': 'Job', - 'verbose_name_plural': 'Jobs', - 'ordering': ('label',), - }, - bases=(ishtar_common.models_common.Cached, models.Model), - ), - migrations.CreateModel( - name='PreventiveFile', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('study_period', models.CharField(blank=True, default='', max_length=200, verbose_name='Study period')), - ('start_date', models.DateField(blank=True, null=True, verbose_name='Start date')), - ('end_date', models.DateField(blank=True, null=True, verbose_name='End date')), - ('ground_start_date', models.DateField(blank=True, null=True, verbose_name='Ground start date')), - ('ground_end_date', models.DateField(blank=True, null=True, verbose_name='Ground end date')), - ('execution_report_date', models.DateField(blank=True, null=True, verbose_name='Execution report date')), - ('linear_meter', models.IntegerField(blank=True, null=True, verbose_name='Linear meter')), - ('file', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.File', verbose_name='File')), - ], - options={ - 'verbose_name': 'Preventive file', - 'verbose_name_plural': 'Preventive files', - }, - ), - migrations.CreateModel( - name='PreventiveFileEquipmentCost', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('man_days_planned', models.FloatField(blank=True, null=True, verbose_name='Man-day planned')), - ('man_days_worked', models.FloatField(blank=True, null=True, verbose_name='Man-day worked')), - ('equipment_cost', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.EquipmentCost')), - ('file', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.PreventiveFile')), - ], - options={ - 'abstract': False, - }, - ), - migrations.CreateModel( - name='PreventiveFileJob', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('man_days_planned', models.FloatField(blank=True, null=True, verbose_name='Man-day planned')), - ('man_days_worked', models.FloatField(blank=True, null=True, verbose_name='Man-day worked')), - ('ground_man_days_planned', models.FloatField(blank=True, null=True, verbose_name='Ground man-day planned')), - ('ground_man_days_worked', models.FloatField(blank=True, null=True, verbose_name='Ground man-day worked')), - ('file', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.PreventiveFile')), - ('job', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.Job')), - ], - options={ - 'abstract': False, - }, - ), - migrations.CreateModel( - name='PreventiveFileTechnicalServiceCost', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('man_days_planned', models.FloatField(blank=True, null=True, verbose_name='Man-day planned')), - ('man_days_worked', models.FloatField(blank=True, null=True, verbose_name='Man-day worked')), - ('file', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.PreventiveFile')), - ], - options={ - 'abstract': False, - }, - ), - migrations.CreateModel( - name='TechnicalService', - 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')), - ], - options={ - 'verbose_name': 'Technical service', - 'verbose_name_plural': 'Technical services', - 'ordering': ('label',), - }, - bases=(ishtar_common.models_common.Cached, models.Model), - ), - migrations.CreateModel( - name='TechnicalServiceCost', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('service_provider', models.CharField(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'), ('M', 'Linear meter')], max_length=1, null=True, verbose_name='Unit')), - ('technical_service', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.TechnicalService', verbose_name='Technical service')), - ], - options={ - 'verbose_name': 'Equipment cost', - 'verbose_name_plural': 'Equipment costs', - }, - ), - migrations.AddField( - model_name='preventivefiletechnicalservicecost', - name='technical_service_cost', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.TechnicalServiceCost'), - ), - migrations.AddField( - model_name='equipmenttype', - name='generic_equipment_type', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.GenericEquipmentType', verbose_name='Generic type'), - ), - migrations.AddField( - model_name='equipmentcost', - name='equipment_type', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.EquipmentType', verbose_name='Equipment'), - ), - ] diff --git a/archaeological_files/migrations/0106_auto_20210622_1456.py b/archaeological_files/migrations/0106_auto_20210622_1456.py new file mode 100644 index 000000000..2667a705d --- /dev/null +++ b/archaeological_files/migrations/0106_auto_20210622_1456.py @@ -0,0 +1,255 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.28 on 2021-06-22 14:56 +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='EquipmentCost', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('service_provider', models.CharField(default='-', max_length=200, verbose_name='Service provider')), + ('flat_rate', models.BooleanField(default=False, verbose_name='Flat rate')), + ('daily_cost', models.FloatField(blank=True, null=True, verbose_name='Daily cost')), + ('monday', models.BooleanField(default=True, verbose_name='Monday')), + ('tuesday', models.BooleanField(default=True, verbose_name='Tuesday')), + ('wednesday', models.BooleanField(default=True, verbose_name='Wednesday')), + ('thursday', models.BooleanField(default=True, verbose_name='Thursday')), + ('friday', models.BooleanField(default=True, verbose_name='Friday')), + ], + options={ + 'verbose_name': 'Equipment cost', + 'verbose_name_plural': 'Equipment costs', + }, + ), + migrations.CreateModel( + name='EquipmentType', + 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')), + ], + options={ + 'verbose_name': 'Equipment type', + 'verbose_name_plural': 'Equipment types', + 'ordering': ('label',), + }, + bases=(ishtar_common.models_common.Cached, models.Model), + ), + migrations.CreateModel( + name='GenericEquipmentType', + 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')), + ], + options={ + 'verbose_name': 'Generic equipment type', + 'verbose_name_plural': 'Generic equipment types', + 'ordering': ('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')), + ], + options={ + 'verbose_name': 'Job', + 'verbose_name_plural': 'Jobs', + 'ordering': ('label',), + }, + bases=(ishtar_common.models_common.Cached, models.Model), + ), + migrations.CreateModel( + name='ManDays', + 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')), + ], + ), + migrations.CreateModel( + name='TechnicalService', + 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')), + ], + options={ + 'verbose_name': 'Technical service', + 'verbose_name_plural': 'Technical services', + 'ordering': ('label',), + }, + bases=(ishtar_common.models_common.Cached, models.Model), + ), + migrations.CreateModel( + name='TechnicalServiceCost', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('service_provider', models.CharField(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'), ('M', 'Linear meter')], max_length=1, null=True, verbose_name='Unit')), + ('technical_service', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.TechnicalService', verbose_name='Technical service')), + ], + options={ + 'verbose_name': 'Equipment cost', + 'verbose_name_plural': 'Equipment costs', + }, + ), + 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.CreateModel( + name='PreventiveFileEquipmentCost', + fields=[ + ('mandays_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='archaeological_files.ManDays')), + ], + bases=('archaeological_files.mandays',), + ), + migrations.CreateModel( + name='PreventiveFileGroundJob', + fields=[ + ('mandays_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='archaeological_files.ManDays')), + ('file', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ground_jobs', to='archaeological_files.File')), + ('job', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.Job')), + ], + bases=('archaeological_files.mandays',), + ), + migrations.CreateModel( + name='PreventiveFileJob', + fields=[ + ('mandays_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='archaeological_files.ManDays')), + ('file', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='jobs', to='archaeological_files.File')), + ('job', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.Job')), + ], + bases=('archaeological_files.mandays',), + ), + migrations.CreateModel( + name='PreventiveFileTechnicalServiceCost', + fields=[ + ('mandays_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='archaeological_files.ManDays')), + ('file', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='technical_service_costs', to='archaeological_files.File')), + ('technical_service_cost', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.TechnicalServiceCost')), + ], + bases=('archaeological_files.mandays',), + ), + migrations.AddField( + model_name='equipmenttype', + name='generic_equipment_type', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.GenericEquipmentType', verbose_name='Generic type'), + ), + migrations.AddField( + model_name='equipmentcost', + name='equipment_type', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.EquipmentType', verbose_name='Equipment'), + ), + migrations.AddField( + model_name='preventivefileequipmentcost', + name='equipment_cost', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.EquipmentCost'), + ), + migrations.AddField( + model_name='preventivefileequipmentcost', + name='file', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='equipment_costs', to='archaeological_files.File'), + ), + ] diff --git a/archaeological_files/models.py b/archaeological_files/models.py index db46c1ca7..fde527ae1 100644 --- a/archaeological_files/models.py +++ b/archaeological_files/models.py @@ -521,6 +521,18 @@ class File( ) # <-- research archaeology + # --> preventive detail + 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) + linear_meter = models.IntegerField(_("Linear meter"), blank=True, null=True) + # <-- preventive detail + documents = models.ManyToManyField( Document, related_name="files", verbose_name=_("Documents"), blank=True ) @@ -1142,47 +1154,44 @@ class FileDashboard: ) -class PreventiveFile(models.Model): - file = models.ForeignKey(File, verbose_name=_("File")) - 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) - linear_meter = models.IntegerField(_("Linear meter"), blank=True, null=True) +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_worked = models.FloatField( + _("Man by day - worked"), null=True, blank=True) + days_worked = models.FloatField( + _("Days - worked"), null=True, blank=True) - class Meta: - verbose_name = _("Preventive file") - verbose_name_plural = _("Preventive files") + @property + def man_days_planned(self): + if not self.days_planned or not self.man_by_day_planned: + return 0 + return self.days_planned * self.man_by_day_planned + @property + def man_days_worked(self): + if not self.days_worked or not self.man_by_day_worked: + return 0 + return self.days_worked * self.man_by_day_worked -class ManDays(models.Model): - man_days_planned = models.FloatField( - _("Man-day planned"), null=True, blank=True) - man_days_worked = models.FloatField( - _("Man-day worked"), null=True, blank=True) - class Meta: - abstract = True +class PreventiveFileGroundJob(ManDays): + file = models.ForeignKey(File, related_name="ground_jobs") + job = models.ForeignKey(Job) class PreventiveFileJob(ManDays): - file = models.ForeignKey(PreventiveFile) + file = models.ForeignKey(File, related_name="jobs") job = models.ForeignKey(Job) - ground_man_days_planned = models.FloatField( - _("Ground man-day planned"), null=True, blank=True) - ground_man_days_worked = models.FloatField( - _("Ground man-day worked"), null=True, blank=True) class PreventiveFileEquipmentCost(ManDays): - file = models.ForeignKey(PreventiveFile) + file = models.ForeignKey(File, related_name="equipment_costs") equipment_cost = models.ForeignKey(EquipmentCost) class PreventiveFileTechnicalServiceCost(ManDays): - file = models.ForeignKey(PreventiveFile) + file = models.ForeignKey(File, related_name="technical_service_costs") technical_service_cost = models.ForeignKey(TechnicalServiceCost) diff --git a/archaeological_files/templates/ishtar/forms/preventive_detail.html b/archaeological_files/templates/ishtar/forms/preventive_detail.html new file mode 100644 index 000000000..3cdfb3da0 --- /dev/null +++ b/archaeological_files/templates/ishtar/forms/preventive_detail.html @@ -0,0 +1,2 @@ +{% extends "ishtar/forms/base_form.html" %} +{% load i18n %} diff --git a/archaeological_files/urls.py b/archaeological_files/urls.py index b245b0aea..3fcf9a42c 100644 --- a/archaeological_files/urls.py +++ b/archaeological_files/urls.py @@ -137,4 +137,11 @@ urlpatterns = [ check_rights(["add_operation"])(views.file_add_operation), name="file-add-operation", ), + url( + r'^file/edit-preventive/(?P.+)/$', + check_rights(["change_file", "change_own_file"])( + views.PreventiveEditView.as_view() + ), + name="file-edit-preventive", + ) ] diff --git a/archaeological_files/views.py b/archaeological_files/views.py index 35bd9d7c8..a927a94e6 100644 --- a/archaeological_files/views.py +++ b/archaeological_files/views.py @@ -23,11 +23,12 @@ import re from django.core.urlresolvers import reverse from django.db.models import Q from django.http import HttpResponse, Http404, HttpResponseRedirect +from django.views.generic.edit import UpdateView from django.shortcuts import redirect, render from ishtar_common.utils import ugettext_lazy as _ from ishtar_common.views import wizard_is_available -from ishtar_common.views_item import get_item, show_item, revert_item +from ishtar_common.views_item import get_item, show_item, revert_item, check_permission from archaeological_operations.wizards import ( AdministrativeActDeletionWizard, @@ -45,6 +46,7 @@ from archaeological_files.wizards import ( FileAdministrativeActWizard, FileEditAdministrativeActWizard, ) +from ishtar_common.views import IshtarMixin, LoginRequiredMixin from archaeological_operations.wizards import OperationWizard from archaeological_operations.views import operation_creation_wizard @@ -354,3 +356,83 @@ def reset_wizards(request): (AdministrativeActDeletionWizard, "file_administrativeactfile_deletion_wizard"), ): wizard_class.session_reset(request, url_name) + + +class MixFormFormsetUpdateView(UpdateView): + form_inlines_class = [] + + def get(self, request, *args, **kwargs): + self.object = self.get_object() + self.inline_forms = [ + inline(instance=self.object) for inline in self.form_inlines_class + ] + return super(MixFormFormsetUpdateView, self).get(request, *args, **kwargs) + + def post(self, request, *args, **kwargs): + self.object = self.get_object() + form = self.form_class(data=request.POST, instance=self.object) + inline_forms = [ + inline(instance=self.object, data=request.POST) + for inline in self.form_inlines_class + ] + if form.is_valid() and all((inline.is_valid() for inline in inline_forms)): + return self.form_valid(form, inline_forms) + else: + return self.form_invalid(form, inline_forms) + + def form_valid(self, form, inline_forms): + self.object = form.save() + for inline in inline_forms: + # save inlines... + pass + return HttpResponseRedirect(self.get_success_url()) + + def form_invalid(self, form, inline_forms): + return self.render_to_response( + self.get_context_data(form=form, inlines=inline_forms) + ) + + def get_context_data(self, *args, **kwargs): + data = super(MixFormFormsetUpdateView, self).get_context_data(*args, **kwargs) + data["inline_forms"] = self.inline_forms + return data + + +class PreventiveEditView(IshtarMixin, LoginRequiredMixin, MixFormFormsetUpdateView): + page_name = _("Preventive modification") + form_class = forms.FileFormPreventiveDetail + form_inlines_class = [ + forms.PreventiveFileJobFormSet, + forms.PreventiveFileGroundJobFormSet, + forms.PreventiveFileEquipmentFormSet, + forms.PreventiveFileTechnicalServiceFormSet + ] + template_name = "ishtar/forms/preventive_detail.html" + model = models.File + + + def get_success_url(self): + return reverse("file_modification") + "?open_item={}".format(self.object.pk) + + def get_form_kwargs(self): + kwargs = super(PreventiveEditView, self).get_form_kwargs() + try: + file = models.File.objects.get(pk=self.kwargs.get("pk")) + except models.Document.DoesNotExist: + raise Http404() + if not check_permission(self.request, "file/edit-preventive/", file.pk): + raise Http404() + initial = {} + for k in ( + list(self.form_class.base_fields.keys()) + ): + value = getattr(file, k) + if hasattr(value, "all"): + value = ",".join([str(v.pk) for v in value.all()]) + if hasattr(value, "pk"): + value = value.pk + initial[k] = value + kwargs["initial"] = initial + kwargs["user"] = self.request.user + self.file = file + return kwargs \ No newline at end of file -- cgit v1.2.3