From 1e08db944aa5a2e481e80cf658e76b53c08cf2aa Mon Sep 17 00:00:00 2001 From: Fasand Date: Thu, 4 Jul 2024 12:43:18 +0200 Subject: [PATCH] #679: add parent_contract & description to ContractForm, use autocomplete for contracts --- .gitignore | 1 + Seeder/contracts/forms.py | 8 ++++++- .../migrations/0007_auto_20240704_1041.py | 19 +++++++++++++++ Seeder/contracts/models.py | 1 + Seeder/contracts/urls.py | 1 + Seeder/contracts/views.py | 24 +++++++++++++++++++ 6 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 Seeder/contracts/migrations/0007_auto_20240704_1041.py diff --git a/.gitignore b/.gitignore index 8c2fa20b..e055fd2a 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ var/ *.egg-info/ .installed.cfg *.egg +.cronenv # PyInstaller # Usually these files are written by a python script from a template diff --git a/Seeder/contracts/forms.py b/Seeder/contracts/forms.py index 03bf1b43..851f4e8c 100755 --- a/Seeder/contracts/forms.py +++ b/Seeder/contracts/forms.py @@ -1,6 +1,7 @@ from . import models from contracts.constants import CREATIVE_COMMONS_TYPES_CHOICES +from dal import autocomplete from django import forms @@ -9,10 +10,15 @@ class Meta: model = models.Contract fields = ('state', 'year', 'contract_number', 'valid_from', 'valid_to', 'contract_file', 'creative_commons_type', + 'parent_contract', 'description', 'in_communication') widgets = { 'creative_commons_type': forms.Select( - choices=CREATIVE_COMMONS_TYPES_CHOICES) + choices=CREATIVE_COMMONS_TYPES_CHOICES), + 'description': forms.Textarea(attrs={"rows": 2}), + 'parent_contract': autocomplete.ModelSelect2( + url='contracts:autocomplete', + ), } diff --git a/Seeder/contracts/migrations/0007_auto_20240704_1041.py b/Seeder/contracts/migrations/0007_auto_20240704_1041.py new file mode 100644 index 00000000..0660b886 --- /dev/null +++ b/Seeder/contracts/migrations/0007_auto_20240704_1041.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.28 on 2024-07-04 10:41 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('contracts', '0006_auto_20201207_1653'), + ] + + operations = [ + migrations.AlterField( + model_name='contract', + name='parent_contract', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='sub_contracts', to='contracts.Contract', verbose_name='Parent'), + ), + ] diff --git a/Seeder/contracts/models.py b/Seeder/contracts/models.py index b625def7..1c551377 100755 --- a/Seeder/contracts/models.py +++ b/Seeder/contracts/models.py @@ -107,6 +107,7 @@ class Contract(BaseModel): parent_contract = models.ForeignKey( 'self', + verbose_name=_("Parent"), null=True, blank=True, on_delete=models.DO_NOTHING, diff --git a/Seeder/contracts/urls.py b/Seeder/contracts/urls.py index c77c7231..6260ddd3 100644 --- a/Seeder/contracts/urls.py +++ b/Seeder/contracts/urls.py @@ -3,6 +3,7 @@ urlpatterns = [ path('/detail', Detail.as_view(), name='detail'), + path('autocomplete', ContractAutocomplete.as_view(), name='autocomplete'), path('/create', Create.as_view(), name='create'), path('/assign', Assign.as_view(), name='assign'), path('/edit', Edit.as_view(), name='edit'), diff --git a/Seeder/contracts/views.py b/Seeder/contracts/views.py index 0b67084f..659dfee9 100755 --- a/Seeder/contracts/views.py +++ b/Seeder/contracts/views.py @@ -7,7 +7,10 @@ from . import constants from datetime import timedelta, date +from dal import autocomplete +from django.db.models.functions import Cast +from django.db.models import CharField from django.views.generic import DetailView, FormView from django.utils.translation import ugettext_lazy as _ from django.template.loader import render_to_string @@ -31,6 +34,27 @@ class Detail(ContractView, DetailView, CommentViewGeneric): template_name = 'contract.html' +class ContractAutocomplete(autocomplete.Select2QuerySetView): + + def get_queryset(self): + if not self.request.user.is_authenticated: + return models.Contract.objects.none() + # Annotate as strings so we can use icontains + qs = models.Contract.objects.all().annotate( + contract_number_s=Cast("contract_number", output_field=CharField()), + year_s=Cast("year", output_field=CharField()) + ).order_by("contract_number", "year") + # Allow searching by "{contract_number} / {year}" + if self.q: + q_split = str(self.q or "").replace(" ", "").split("/") + if len(q_split) == 1: + qs = qs.filter(contract_number_s__icontains=q_split[0]) + elif len(q_split) == 2: + qs = qs.filter(contract_number_s__icontains=q_split[0], + year_s__icontains=q_split[1]) + return qs + + class Create(LoginMixin, FormView, ObjectMixinFixed): """ Create contract based on existing source