From b9c259a2cadd9717cb6854ac4931a87d6becc938 Mon Sep 17 00:00:00 2001 From: Étienne Loks Date: Tue, 5 Jul 2022 16:55:49 +0200 Subject: Preventive file - admin: copy job and costs from price agreement --- Makefile.example | 1 + archaeological_files/admin.py | 101 ++++++++++++++++++++- .../migrations/0107_auto_20220630_1519.py | 59 ------------ .../migrations/0107_auto_20220705_1612.py | 69 ++++++++++++++ archaeological_files/models.py | 6 ++ .../templates/admin/copy_price.html | 14 +++ .../templates/admin/copy_price_change_list.html | 14 +++ 7 files changed, 204 insertions(+), 60 deletions(-) delete mode 100644 archaeological_files/migrations/0107_auto_20220630_1519.py create mode 100644 archaeological_files/migrations/0107_auto_20220705_1612.py create mode 100644 archaeological_files/templates/admin/copy_price.html create mode 100644 archaeological_files/templates/admin/copy_price_change_list.html diff --git a/Makefile.example b/Makefile.example index 657b8ecba..947f1edd9 100644 --- a/Makefile.example +++ b/Makefile.example @@ -256,6 +256,7 @@ fixtures_files: archaeological_files.saisinetype \ archaeological_files.filetype \ archaeological_files.permittype \ + archaeological_files.priceagreement \ archaeological_files.job \ archaeological_files.genericequipmentservicetype \ archaeological_files.equipmentservicetype \ diff --git a/archaeological_files/admin.py b/archaeological_files/admin.py index edc6be716..df2afd677 100644 --- a/archaeological_files/admin.py +++ b/archaeological_files/admin.py @@ -19,7 +19,13 @@ from ajax_select import make_ajax_form +from django import forms from django.conf import settings +from django.conf.urls import url +from django.core.urlresolvers import reverse +from django.http import HttpResponseRedirect +from django.shortcuts import get_object_or_404, render +from django.utils.translation import ugettext_lazy as _ from ishtar_common.apps import admin_site from ishtar_common.admin import ( @@ -87,6 +93,7 @@ class JobAdmin(GeneralTypeAdmin): list_filter = ("available", "price_agreement") LIST_DISPLAY = [ "label", + "price_agreement", "permanent_contract", "order", "ground_daily_cost", @@ -116,6 +123,7 @@ class EquipmentServiceCostAdmin(ImportActionAdmin): list_filter = ("available", "price_agreement") list_display = [ "equipment_service_type", + "price_agreement", "specificity", "parent", "unitary_cost", @@ -130,7 +138,98 @@ class EquipmentServiceCostAdmin(ImportActionAdmin): admin_site.register(models.EquipmentServiceCost, EquipmentServiceCostAdmin) -class PriceAgreementAdmin(GeneralTypeAdmin): +class CopyPriceForm(forms.Form): + source = forms.ChoiceField( + label=_("Copy from"), + choices=[], + ) + destination = forms.ChoiceField( + label=_("To"), + choices=[], + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + choices = [ + (idx, label) + for idx, label in models.PriceAgreement.objects.values_list("id", "label") + ] + self.fields["source"].choices = choices + self.fields["destination"].choices = choices + + def clean(self): + if self.cleaned_data.get("source", None) \ + == self.cleaned_data.get("destination", None): + raise forms.ValidationError( + _("Source and destination must be different.") + ) + return self.cleaned_data + + +class CopyPriceAgreementAdmin(GeneralTypeAdmin): + change_list_template = "admin/copy_price_change_list.html" + + def get_urls(self): + urls = super(CopyPriceAgreementAdmin, self).get_urls() + my_urls = [ + url(r"^copy-price-agreement/$", self.copy_price_agreement), + ] + return my_urls + urls + + def copy_price_agreement(self, request): + form = None + + if "apply" in request.POST: + form = CopyPriceForm(request.POST) + if form.is_valid(): + created, already_here = 0, 0 + source = get_object_or_404( + models.PriceAgreement, pk=form.cleaned_data["source"] + ) + destination = get_object_or_404( + models.PriceAgreement, pk=form.cleaned_data["destination"] + ) + for model, slug_name in ((models.Job, "txt_idx"), + (models.EquipmentServiceCost, "slug")): + items = model.objects.filter(price_agreement_id=source.pk).all() + for item in items: + slug = getattr(item, slug_name).split("--")[0] + "--" + \ + str(source.pk) + q = model.objects.filter(**{slug_name: slug}) + if q.count(): + already_here += 1 + continue + new_item = item + new_item.pk = None + setattr(new_item, slug_name, slug) + new_item.price_agreement_id = destination.pk + new_item.save() + created += 1 + if created: + self.message_user( + request, str(_("{} item(s) created.")).format(created) + ) + if already_here: + self.message_user( + request, str(_("{} item(s) already in database.")).format( + already_here) + ) + c_url = reverse( + "admin:{}_{}_changelist".format( + self.model._meta.app_label, self.model._meta.model_name + ) + ) + return HttpResponseRedirect(c_url) + if not form: + form = CopyPriceForm() + return render( + request, + "admin/copy_price.html", + {"file_form": form, "current_action": "import_generic"}, + ) + + +class PriceAgreementAdmin(CopyPriceAgreementAdmin): list_filter = ("available",) extra_list_display = [ "start_date", diff --git a/archaeological_files/migrations/0107_auto_20220630_1519.py b/archaeological_files/migrations/0107_auto_20220630_1519.py deleted file mode 100644 index 4d0331f0c..000000000 --- a/archaeological_files/migrations/0107_auto_20220630_1519.py +++ /dev/null @@ -1,59 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.11.28 on 2022-06-30 15:19 -from __future__ import unicode_literals - -import datetime -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', '0106_auto_20210803_1730'), - ] - - operations = [ - migrations.CreateModel( - name='PriceAgreement', - 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')), - ('start_date', models.DateField(blank=True, null=True, verbose_name='Start date')), - ('end_date', models.DateField(blank=True, null=True, verbose_name='End date')), - ], - options={ - 'verbose_name': 'Price agreement', - 'verbose_name_plural': 'Price agreement', - 'ordering': ('order', 'label'), - }, - bases=(ishtar_common.models_common.Cached, models.Model), - ), - migrations.AlterField( - model_name='file', - name='last_modified', - field=models.DateTimeField(blank=True, default=datetime.datetime.now), - ), - migrations.AlterField( - model_name='historicalfile', - name='last_modified', - field=models.DateTimeField(blank=True, default=datetime.datetime.now), - ), - migrations.AddField( - model_name='equipmentservicecost', - name='price_agreement', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.PriceAgreement', verbose_name='Price agreement'), - ), - migrations.AddField( - model_name='job', - name='price_agreement', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.PriceAgreement', verbose_name='Price agreement'), - ), - ] diff --git a/archaeological_files/migrations/0107_auto_20220705_1612.py b/archaeological_files/migrations/0107_auto_20220705_1612.py new file mode 100644 index 000000000..2589f0a15 --- /dev/null +++ b/archaeological_files/migrations/0107_auto_20220705_1612.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.28 on 2022-07-05 16:12 +from __future__ import unicode_literals + +import datetime +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', '0106_auto_20210803_1730'), + ] + + operations = [ + migrations.CreateModel( + name='PriceAgreement', + 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')), + ('start_date', models.DateField(blank=True, null=True, verbose_name='Start date')), + ('end_date', models.DateField(blank=True, null=True, verbose_name='End date')), + ], + options={ + 'verbose_name': 'Price agreement', + 'verbose_name_plural': 'Price agreement', + 'ordering': ('order', 'label'), + }, + bases=(ishtar_common.models_common.Cached, models.Model), + ), + migrations.AlterField( + model_name='file', + name='last_modified', + field=models.DateTimeField(blank=True, default=datetime.datetime.now), + ), + migrations.AlterField( + model_name='historicalfile', + name='last_modified', + field=models.DateTimeField(blank=True, default=datetime.datetime.now), + ), + migrations.AddField( + model_name='equipmentservicecost', + name='price_agreement', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.PriceAgreement', verbose_name='Price agreement'), + ), + migrations.AddField( + model_name='file', + name='price_agreement', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='archaeological_files.PriceAgreement', verbose_name='Price agreement'), + ), + migrations.AddField( + model_name='historicalfile', + name='price_agreement', + field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='archaeological_files.PriceAgreement', verbose_name='Price agreement'), + ), + migrations.AddField( + model_name='job', + name='price_agreement', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_files.PriceAgreement', verbose_name='Price agreement'), + ), + ] diff --git a/archaeological_files/models.py b/archaeological_files/models.py index 8d3f014da..60f9882fe 100644 --- a/archaeological_files/models.py +++ b/archaeological_files/models.py @@ -80,6 +80,8 @@ class PriceAgreement(GeneralType): verbose_name_plural = _("Price agreement") ordering = ( "order", + "start_date", + "end_date", "label", ) @@ -669,6 +671,10 @@ class File( # <-- research archaeology # --> preventive detail + price_agreement = models.ForeignKey( + PriceAgreement, verbose_name=_("Price agreement"), blank=True, null=True, + on_delete=models.SET_NULL + ) study_period = models.CharField( _("Study period"), max_length=200, default="", blank=True ) diff --git a/archaeological_files/templates/admin/copy_price.html b/archaeological_files/templates/admin/copy_price.html new file mode 100644 index 000000000..f66f9f7a1 --- /dev/null +++ b/archaeological_files/templates/admin/copy_price.html @@ -0,0 +1,14 @@ +{% extends "admin/base_site.html" %} + +{% block content %} + +
+{% csrf_token %} + +{{ file_form }} +
+ + +
+ +{% endblock %} diff --git a/archaeological_files/templates/admin/copy_price_change_list.html b/archaeological_files/templates/admin/copy_price_change_list.html new file mode 100644 index 000000000..1e3ae8585 --- /dev/null +++ b/archaeological_files/templates/admin/copy_price_change_list.html @@ -0,0 +1,14 @@ +{% extends "admin/gen_change_list.html" %} +{% load i18n admin_urls static admin_list %} + + {% block object-tools-items %} + {{ block.super }} + {% if has_add_permission %} +
  • + + {% trans "Copy price agreement" %} + +
  • + {% endif %} + {% endblock %} + -- cgit v1.2.3