From 59229c514bc0a55e9c0ea15c8dfcb794de77f66c Mon Sep 17 00:00:00 2001 From: Claude Paroz Date: Thu, 10 Jan 2019 15:49:20 +0100 Subject: [PATCH] Add a corporation merge form (no link to UI yet) --- common/urls.py | 1 + stages/admin.py | 1 + stages/forms.py | 64 +++++++++++++++++++++++++++++++- stages/views/__init__.py | 23 +++++++++++- templates/corporation_merge.html | 27 ++++++++++++++ 5 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 templates/corporation_merge.html diff --git a/common/urls.py b/common/urls.py index f4a6d12..9e76748 100644 --- a/common/urls.py +++ b/common/urls.py @@ -24,6 +24,7 @@ urlpatterns = [ path('institutions/', views.CorporationListView.as_view(), name='corporations'), path('institutions//', views.CorporationView.as_view(), name='corporation'), + path('institutions/merge/', views.CorporationMergeView.as_view(), name='corporations-merge'), path('institutions/export/', views.export.institutions_export, name='corporations-export'), path('classes/', views.KlassListView.as_view(), name='classes'), diff --git a/stages/admin.py b/stages/admin.py index 0969895..c788474 100644 --- a/stages/admin.py +++ b/stages/admin.py @@ -290,6 +290,7 @@ class AvailabilityInline(admin.StackedInline): formfield_overrides = { models.TextField: {'widget': forms.Textarea(attrs={'rows':2, 'cols':40})}, } + autocomplete_fields = ['corporation'] class PeriodAdmin(admin.ModelAdmin): diff --git a/stages/forms.py b/stages/forms.py index fb41bf9..f68375a 100644 --- a/stages/forms.py +++ b/stages/forms.py @@ -1,8 +1,12 @@ from django import forms +from django.contrib.admin.widgets import AutocompleteSelect +from django.db import transaction +from django.db.models.deletion import Collector +from django.urls import reverse from tabimport import FileFactory, UnsupportedFileFormat -from .models import Section, Period +from .models import Corporation, Section, Period class StudentImportForm(forms.Form): @@ -51,3 +55,61 @@ class EmailBaseForm(forms.Form): cci = forms.CharField(widget=forms.TextInput(attrs={'size': '60'})) subject = forms.CharField(widget=forms.TextInput(attrs={'size': '60'})) message = forms.CharField(widget=forms.Textarea(attrs={'rows': 20, 'cols': 120})) + + + +class CorpAutocompleteSelect(AutocompleteSelect): + model = Corporation + + def __init__(self, **kwargs): + super().__init__(None, None, **kwargs) + + def get_url(self): + return reverse(self.url_name % ('admin', self.model._meta.app_label, self.model._meta.model_name)) + + +class CorporationMergeForm(forms.Form): + corp_merge_from = forms.ModelChoiceField( + label="L'institution", queryset=Corporation.objects.filter(archived=False), + widget=CorpAutocompleteSelect + ) + corp_merge_to = forms.ModelChoiceField( + label="Sera fusionnée dans", queryset=Corporation.objects.filter(archived=False), + widget=CorpAutocompleteSelect + ) + + def merge_corps(self): + def check_no_links(instance): + collector = Collector(using='default') + collector.collect(instance._meta.model.objects.filter(pk=instance.pk)) + if len(collector.data) > 1: + raise Exception(collector.data) + + with transaction.atomic(): + # Try first to merge corpcontacts with same name + merge_to_contacts = { + (cont.last_name, cont.first_name): cont + for cont in self.cleaned_data['corp_merge_to'].corpcontact_set.all() + } + for contact in self.cleaned_data['corp_merge_from'].corpcontact_set.all(): + ckey = (contact.last_name, contact.first_name) + if ckey in merge_to_contacts: + # Merge contacts + for rel in ( + 'availability_set', 'candidate_set', 'rel_expert', 'rel_mentor', + 'rel_supervisor', 'student_set', 'supervisionbill_set'): + relation = getattr(contact, rel) + relation.all().update(**{relation.field.name: merge_to_contacts[ckey]}) + check_no_links(contact) + contact.delete() + # Merge corporation now + self.cleaned_data['corp_merge_from'].corpcontact_set.all( + ).update(corporation=self.cleaned_data['corp_merge_to']) + self.cleaned_data['corp_merge_from'].availability_set.all( + ).update(corporation=self.cleaned_data['corp_merge_to']) + self.cleaned_data['corp_merge_from'].student_set.all( + ).update(corporation=self.cleaned_data['corp_merge_to']) + self.cleaned_data['corp_merge_from'].candidate_set.all( + ).update(corporation=self.cleaned_data['corp_merge_to']) + check_no_links(self.cleaned_data['corp_merge_from']) + self.cleaned_data['corp_merge_from'].delete() diff --git a/stages/views/__init__.py b/stages/views/__init__.py index 7e46ae0..7375ad0 100644 --- a/stages/views/__init__.py +++ b/stages/views/__init__.py @@ -19,7 +19,7 @@ from django.views.generic import DetailView, FormView, TemplateView, ListView from .base import EmailConfirmationBaseView, ZippedFilesBaseView from .export import OpenXMLExport from .imports import HPContactsImportView, HPImportView, ImportReportsView, StudentImportView -from ..forms import EmailBaseForm +from ..forms import CorporationMergeForm, EmailBaseForm from ..models import ( Klass, Section, Student, Teacher, Corporation, CorpContact, Period, Training, Availability @@ -66,6 +66,27 @@ class CorporationView(DetailView): return context +class CorporationMergeView(FormView): + form_class = CorporationMergeForm + template_name = 'corporation_merge.html' + success_url = reverse_lazy('corporations') + + def form_valid(self, form): + if form.data['step'] != '2': + return self.render_to_response(self.get_context_data(form=form)) + form.merge_corps() + return super().form_valid(form) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['step'] = '1' + if context['form'].is_bound and context['form'].is_valid(): + context['step'] = '2' + context['contacts_from'] = context['form'].cleaned_data['corp_merge_from'].corpcontact_set.all() + context['contacts_to'] = context['form'].cleaned_data['corp_merge_to'].corpcontact_set.all() + return context + + class KlassListView(ListView): queryset = Klass.active.order_by('section', 'name') template_name = 'classes.html' diff --git a/templates/corporation_merge.html b/templates/corporation_merge.html new file mode 100644 index 0000000..18b6065 --- /dev/null +++ b/templates/corporation_merge.html @@ -0,0 +1,27 @@ +{% extends "admin/base_site.html" %} + +{% block extrahead %}{{ block.super }} + +{{ form.media }} +{% endblock %} + +{% block content %} +

Fusionner deux institutions

+ +
{% csrf_token %} +
{{ form.corp_merge_from.label_tag }} {{ form.corp_merge_from }} +
    {% for contact in contacts_from %} +
  • {{ contact }}
  • + {% endfor %} +
+
+
{{ form.corp_merge_to.label_tag }} {{ form.corp_merge_to }} +
    {% for contact in contacts_to %} +
  • {{ contact }}
  • + {% endfor %} +
+
+ + +
+{% endblock %}