diff --git a/aula/apps/importaActuacions/__init__.py b/aula/apps/importaActuacions/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/aula/apps/importaActuacions/admin.py b/aula/apps/importaActuacions/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/aula/apps/importaActuacions/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/aula/apps/importaActuacions/apps.py b/aula/apps/importaActuacions/apps.py new file mode 100644 index 00000000..999dffb6 --- /dev/null +++ b/aula/apps/importaActuacions/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ImportaactuacionsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'aula.apps.importaActuacions' diff --git a/aula/apps/importaActuacions/forms.py b/aula/apps/importaActuacions/forms.py new file mode 100644 index 00000000..b8ca772d --- /dev/null +++ b/aula/apps/importaActuacions/forms.py @@ -0,0 +1,6 @@ +from django import forms + +class dades_dboldForm (forms.Form): + nom = forms.CharField(label='Nom de la Base de dades antiga:', max_length=30) + usuari = forms.CharField(label='Usuari per accedir-hi:', max_length=30) + contrasenya = forms.CharField(label="Contrasenya de l'usuari:", max_length=30, widget=forms.PasswordInput) diff --git a/aula/apps/importaActuacions/migrations/__init__.py b/aula/apps/importaActuacions/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/aula/apps/importaActuacions/models.py b/aula/apps/importaActuacions/models.py new file mode 100644 index 00000000..bcd8aee1 --- /dev/null +++ b/aula/apps/importaActuacions/models.py @@ -0,0 +1,3 @@ + +# Create your models here. + diff --git a/aula/apps/importaActuacions/table2_models.py b/aula/apps/importaActuacions/table2_models.py new file mode 100644 index 00000000..442d8d6e --- /dev/null +++ b/aula/apps/importaActuacions/table2_models.py @@ -0,0 +1,43 @@ +# -*- encoding: utf-8 -*- +import django_tables2 as tables +from django_tables2.utils import A + +from aula.apps.tutoria.models import Actuacio + + +class Table2_llista_actuacions(tables.Table): + + id_actuacio = tables.TemplateColumn( + template_code = u"""{{record.id}}""", + order_by=( '-id', ) + ) + + moment_actuacio = tables.TemplateColumn( + template_code = u"""{{record.moment_actuacio}}""", + order_by=( '-moment_actuacio', ) + ) + + alumne = tables.TemplateColumn( + template_code = u"""{{ record.alumne }}""", + order_by=( 'alumne.cognoms', 'alumne.nom', '-moment_actuacio', ) + ) + + + qui = tables.TemplateColumn( + template_code = u"""{{ record.professional }} ( {{record.get_qui_fa_actuacio_display}})""", + order_by=( 'professional', '-moment_actuacio', ), + verbose_name=u"Qui?" + ) + + actuacio = tables.TemplateColumn( + template_code = u"""{{ record.actuacio }}""", + orderable = False + ) + + class Meta: + model = Actuacio + # add class="paleblue" to
Id | +Alumne | +Data | +Professional | +Contingut | +|
---|---|---|---|---|---|
{{ actuacio.id }} | +{{ actuacio.nom_alumne }} {{ actuacio.cognoms_alumne }} | +{{ actuacio.moment_actuacio }} | + {% if actuacio.professional_id %} +{{ actuacio.nom_professional }} {{ actuacio.cognoms_professional }} | + {% else %} +Ja no és al centre. | + {% endif %} +{{ actuacio.actuacio }} | +
Atenció! No hi ha cap actuació a importar.
+Totes les actuacions registrades al curs anterior estan associades a alumnat desmatriculat.
+
+
Revisi les dades que es presenten a sota.
+Atenció! No hi ha cap actuació a importar.
+D'entre totes les actuacions registrades al curs anterior que es podrien importar, unes estan associades a alumnat desmatriculat i d'altres són actuacions que ja s'han importat amb anterioritat.
+
+
Revisi les dades que es presenten a sota.
+Actuacions amb característiques especials
+ +Actuacions associades a alumnat desmatriculat
+ +L'alumnat desmatriculat és aquell que no ha continuat al centre educatiu, és a dir, va estar matriculat però actualment ja no hi és.
+Les actuacions associades a aquest alumnat no s'importaran. Si n'hi hagués es mostraran a continuació a títol informatiu.
+ + + + + {% if not alumnes_desmatriculats %} + No s'ha trobat cap alumne desmatriculat. + {% else %} + ++ {% if alumnes_desmatriculats|length == 1 %} + Només s'ha trobat un alumne desmatriculat + {% else %} + S'han trobat {{ alumnes_desmatriculats|length }} alumnes desmatriculats + {% endif %} +
+ +Nom | +Ralc | +
---|---|
{{ alumne.nom }} {{ alumne.cognoms }} | +{{ alumne.ralc }} | +
+ {% if actuacions_sense_alumne_curs_actual|length == 1 %} + Només s'ha trobat una actuació associades a alumnat desmatriculat. + {% else %} + S'han trobat {{ actuacions_sense_alumne_curs_actual|length }} actuacions associades a alumnat desmatriculat. + {% endif %} +
+ + + +Id | +Professional | +Data | +Alumne | +Contingut | +
---|---|---|---|---|
{{ actuacio.id }} | +{{ actuacio.nom_professional }} {{ actuacio.cognoms_professional }} | +{{ actuacio.moment_actuacio }} | +{{ actuacio.nom_alumne }} {{ actuacio.cognoms_alumne }} | +{{ actuacio.actuacio }} | +
Actuacions creades per professionals que ja no es troben al centre educatiu
+ +S'ofereixen dos llistats. El primer fa referència als professionals que ja no es troben al centre i que van fer actuacions amb alumnat que encara hi és, mentre que el segon presenta les actuacions que van crear.
+
Donat que aquestes actuacions sí que seran importades a l'historial de l'alumnat corresponent, es mostren a continuació per tal de facilitar-ne la revisió. No obstant, degut a aquesta circumstància específica, a l'inici del text de l'actuació afectada s'insertarà una frase que dirà:
+ ++ {% if professionals_foracentre|length == 1 %} + Només s'ha trobat un professional que ja no es al centre educatiu.
+ {% else %} + S'han trobat {{ professionals_foracentre|length }} professionals que ja no són al centre educatiu. + {% endif %} + + +Nom | +Codi intern | +
---|---|
{{ professional.nom }} {{ professional.cognoms }} | +{{ professional.username }} | +
+ {% if actuacions_sense_professional|length == 1 %} + Només s'ha trobat una actuació afectada per un professional que no és al centre educatiu.
+ {% else %} + S'han trobat {{ actuacions_sense_professional|length }} actuacions creades per professionals que ja no són al centre educatiu. + {% endif %} + + + + +Id | +Alumne | +Data | +Contingut | +
---|---|---|---|
{{ actuacio.id }} | +{{ actuacio.nom_alumne }} {{ actuacio.cognoms_alumne }} | +{{ actuacio.moment_actuacio }} | +{{ actuacio.actuacio }} | +
Actuacions que ja es troben al curs actual
+ + {% if not actuacions_ja_importades %} + No s'ha trobat cap actuació duplicada, és a dir, no hi ha cap actuació a importar que ja estigui en el curs actual. + {% else %} + +Atenció! + S'han trobat actuacions en el curs anterior que podria ser que ja hi siguin en el curs actual donat que tenen la mateixa data i hora de creació.
++ {% if actuacions_ja_importades|length == 1 %} + Concretament se n'ha trobat una, d'actuació, que ja existeix al curs actual. Podria ser que ja hagi estat importada amb anterioritat. Aquesta actuació no s'importarà.
+ {% else %} + Concretament se n'han trobat {{ actuacions_ja_importades|length }}, d'actuacions, que ja existeixen al curs actual. És possible que ja hagin estat importades amb anterioritat. Aquestes actuacions no s'importaran. + {% endif %} + + + + +Id | +Alumne | +Data | +Professional | +Contingut | +|
---|---|---|---|---|---|
{{ actuacio.id }} | +{{ actuacio.nom_alumne }} {{ actuacio.cognoms_alumne }} | +{{ actuacio.moment_actuacio }} | + {% if actuacio.professional_id %} +{{ actuacio.nom_professional }} {{ actuacio.cognoms_professional }} | + {% else %} +Ja no és al centre. | + {% endif %} +{{ actuacio.actuacio }} | +
A continuació es mostra el resultat de la importació. En primer lloc un llistat de les actuacions finalment importades, mentre que en segon lloc es mostren totes les actuacions del curs actual després d'haver fet la importació.
+Actuacions importades
+ + + +Llistat final d'actuacions del curs actual
+ + + +Atenció! + S'han detectat repeticions en les assignacions, és a dir, més d'un professional del curs actual assignat a un mateix professional del curs anterior.
+Els noms d'usuari dels professionals repetits en les assignacions són els següents:
+Com a pas previ, cal comprovar que els noms dels usuaris dels professionals
A continuació es mostren els professionals del curs anterior que sembla que no es troben en el curs actual.
+Com és lògic, un usuari del curs actual no es pot associar a més d'un usuari del curs anterior.
+ + + + +Debug: {{ debug }}
+Debug2: {{ debug2 }}
+Debug3: {{ debug3 }}
+ + +{% endblock %} + diff --git a/aula/apps/importaActuacions/tests.py b/aula/apps/importaActuacions/tests.py new file mode 100644 index 00000000..b0a9ee23 --- /dev/null +++ b/aula/apps/importaActuacions/tests.py @@ -0,0 +1,5 @@ +from django.test import TestCase +from django.shortcuts import render +from django.db import connections, OperationalError, DatabaseError + +# Create your tests here. diff --git a/aula/apps/importaActuacions/urls.py b/aula/apps/importaActuacions/urls.py new file mode 100644 index 00000000..154a7cca --- /dev/null +++ b/aula/apps/importaActuacions/urls.py @@ -0,0 +1,13 @@ +from django.urls import re_path +from aula.apps.importaActuacions import views as importaActuacions_views + +urlpatterns = [ + re_path(r'^connexioDB/$', importaActuacions_views.connexioDBold , + name="importaActuacions__connexio__DB"), + re_path(r'^sincronitzaProfessionals/$', importaActuacions_views.sincronitzaProfessionals , + name="importaActuacions__sincronitzaProfessionals"), + re_path(r'^importantActuacions/$', importaActuacions_views.importantActuacions , + name="importaActuacions__importa__actuacions"), + re_path(r'^resultatImportacio/$', importaActuacions_views.importacio , + name="importaActuacions__resultat__importacio"), +] \ No newline at end of file diff --git a/aula/apps/importaActuacions/views.py b/aula/apps/importaActuacions/views.py new file mode 100644 index 00000000..77968cf8 --- /dev/null +++ b/aula/apps/importaActuacions/views.py @@ -0,0 +1,518 @@ +from django.shortcuts import render, redirect, HttpResponse +from django.db import OperationalError, DatabaseError, connections +from django.contrib.auth.models import User +from copy import deepcopy +from aula.utils.my_paginator import DiggPaginator +from django.template.defaulttags import register + +#auth +from django.contrib.auth.decorators import login_required +from aula.utils.decorators import group_required + +#models +from aula.apps.alumnes.models import Alumne +from aula.apps.tutoria.models import Actuacio + +#forms +from aula.apps.importaActuacions.forms import dades_dboldForm + +#tables +from django_tables2.config import RequestConfig +from aula.apps.importaActuacions.table2_models import Table2_llista_actuacions + +# Per afegir i/o eliminar bases de dades a la configuració +from aula import settings_local + + +############################ +# PROCEDIMENT D'IMPORTACIÓ # +############################ + +# 1r PAS. CONNEXIÓ DB OLD. Cal connectar-se a la base de dades del curs anterior per extreure les dades. +# 2n PAS. SINCRONITZAR PROFESSIONALS. Els usernames dels professionals del curs anterior no tenen per què coincidir + # amb els del curs actual, encara que siguin els mateixos professionals. +# 3r PAS. EXTRACCIÓ DE DADES. Lectura de les dades significatives, tant de la BD antiga com de l'actual. +# 4t PAS. 1r CANVI. Amb les dades de la BD antiga: + # 4.1 Substitució de l'identificador del professional pel seu username antic i substitució dels usernames antics dels professionals pels actuals usernames. + # 4.2 Substitució de l'identificador de l'alumne pel RALC, que és universal. + # POSSIBLE MILLORA: Es podria contemplar el cas que un alumne no tinguin RALC? Només en aquest cas, caldria estirar les dades del nom i cognoms, però sempre és molt més insegur i amb confirmació expressa. +# 5é PAS. 2n CANVI. Amb les dades de la BD actual: + # 5.1 Substitució del RALC de l'alumne pel valor de l'identificador. + # 5.2 Substitució de l'username del professional pel seu identificador. +# 6é PAS. PREPARANT LA INSERCIÓ de les dades tractades a la BD actual. +# 7é PAS. INSERCIÓ de les actuacions antigues a la BD actual. + + +# Variables globals per traspassar informació entre funcions +dades_connexio_dbold = {} # Dades de connexió de la DB origen de les actuacions a importar +usernames_oldb_to_usernames_curs_actual_dict = [] # La correspondència dels usernames dels professionals entre bases de dades +actuacions_a_importar = [] # Les actuacions que finalment seran importades +actuacions_pel_bulkcreate = [] + + +def check_database_connection(request): + global dades_connexio_dbold + nom_dbold = dades_connexio_dbold.get('name_dbold') + usuari_dbold = dades_connexio_dbold.get('user_dbold') + + if nom_dbold in settings_local.DATABASES: + db_conn = connections[nom_dbold] + try: + cursor = db_conn.cursor() # Create a cursor object using the database connection + cursor.execute('SELECT 1') # Run a query to check if the connection is working + result = cursor.fetchone()[0] # Fetch the result of the query + cursor.close() + except OperationalError: + return render( + request, + '../templates/errorConnexio.html', + { + 'nom':nom_dbold, + 'usuari':usuari_dbold, + },) + else: + return render(request,'404.html',{},) + return None + +# Per poder renderitzar en un template un diccionario que té clau variable +@register.filter +def get_value(dictionary, key): + return dictionary.get(key) + + +############################ +# 1r PAS # CONNEXIÓ DB OLD # +############################ + +@login_required +@group_required(['direcció','administradors']) +def connexioDBold(request): + + if request.method == 'POST': + + form = dades_dboldForm(request.POST) + if form.is_valid(): + global dades_connexio_dbold + dades_connexio_dbold = { + 'name_dbold':form.cleaned_data['nom'], + 'user_dbold':form.cleaned_data['usuari'], + 'pass_dbold':form.cleaned_data['contrasenya'], + } + + settings_local.DATABASES[dades_connexio_dbold.get('name_dbold')] = { + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'NAME': dades_connexio_dbold.get('name_dbold'), + 'USER': dades_connexio_dbold.get('user_dbold'), + 'PASSWORD': dades_connexio_dbold.get('pass_dbold'), + 'HOST': 'localhost', + 'PORT': '5432', + 'ATOMIC_REQUESTS': False, + 'AUTOCOMMIT': True, + 'CONN_MAX_AGE': 0, + 'OPTIONS': {}, + 'TIME_ZONE': None + } + + connexio = check_database_connection(request) + if connexio is None: + return redirect('/importaActuacions/sincronitzaProfessionals') + else: + return connexio + + else: + head = u"Importació de les actuacions d'un altre curs al curs actual" + titol_formulari =u"Paràmetres de connexió amb la base de dades del curs anterior." + form = dades_dboldForm() + + return render( + request, + 'connexioDBold.html', + { + 'form': form, + 'head': head, + 'titol_formulari':titol_formulari, + }, + ) + +####################################### +# 2n PAS # SINCRONITZAR PROFESSIONALS # +####################################### + +@login_required +@group_required(['direcció','administradors']) +def sincronitzaProfessionals(request): + global dades_connexio_dbold + global usernames_oldb_to_usernames_curs_actual_dict + nom_dbold = dades_connexio_dbold.get('name_dbold') + + # Redirecció si hi ha un accès indegut i conseqüent error en la connexió a la BD antiga + connexio = check_database_connection(request) + if connexio is not None: + return connexio + + head = u"Sincronització entre cursos dels professionals del centre educatiu" + + usuaris_olddb_id_username_firstname_lastname_list = list(User.objects. + using(nom_dbold). + values_list('id', 'username', 'first_name', 'last_name'). + exclude(username__startswith = 'almn'). + exclude(username__startswith = 'admin'). + exclude(username__startswith = 'conser'). + exclude(username = 'TP'). + order_by('username')) + + usuaris_id_username_firstname_lastname_list = list(User.objects. + values_list('id', 'username', 'first_name', 'last_name'). + exclude(username__startswith = 'almn'). + exclude(username__startswith = 'admin'). + exclude(username__startswith = 'conser'). + exclude(username = 'TP'). + order_by('username')) + + actuacions_professionalid_olddb_list_tuples = list(Actuacio.objects. + using(nom_dbold). + values_list('professional_id')) + + actuacions_professionalid_olddb_list = [] + actuacions_professionalid_olddb_list = [actuacio[0] for actuacio in actuacions_professionalid_olddb_list_tuples] + del actuacions_professionalid_olddb_list_tuples + + # Netejar la llista per quedar-se amb els valors únics. + professionals_amb_actuacions_olddb_list = list(set(actuacions_professionalid_olddb_list)) + + for i, identificador_professional in enumerate(professionals_amb_actuacions_olddb_list): + for usuari in usuaris_olddb_id_username_firstname_lastname_list: + if identificador_professional == usuari[0]: + professionals_amb_actuacions_olddb_list[i] = usuari + break + + usernames_usuaris = [] # Llista dels usernames dels usuaris actuals + usernames_usuaris_orfes_oldb = [] # Llista dels useranames dels usuaris antics que no es troben al curs actual + professionals_repetits = [] # Per controlar que no s'associen un professional actual amb més d'un profesional antic + + # Només em quedo els usernames. La resta per renderritzar en el template + usernames_usuaris = [usuari[1] for usuari in usuaris_id_username_firstname_lastname_list] + + # Filtre per trobar els usuaris antics que han quedat sense relacionar + usernames_usuaris_orfes_oldb = [usuari_oldb for usuari_oldb in professionals_amb_actuacions_olddb_list if usuari_oldb[1] not in usernames_usuaris] + + if request.method == 'POST': + + # Es recull la relació entre els professionals antics i actuals, eliminant la primera entrada. + usernames_oldb_to_usernames_curs_actual_dict = dict(request.POST) + usernames_oldb_to_usernames_curs_actual_dict.pop('csrfmiddlewaretoken') + usernames_claus = list(dict.keys(request.POST)) + usernames_claus.pop(0) + + # Si algun professinal s'ha deixat sense relacionar, es millor que mantingui el seu propi username. + # Els valors del diccionari son llistes d'un sol element =:-O Aprofito per eliminar aquestes llistes. + for clau in usernames_claus: + username_associat_list = usernames_oldb_to_usernames_curs_actual_dict.get(clau) + if not username_associat_list[0]: username_associat_list[0] = clau + usernames_oldb_to_usernames_curs_actual_dict[clau] = username_associat_list[0] + + # Únic procediment per trobar associacions duplicades que m'ha funcionat + visited = set() + professionals_repetits = [x for x in list(dict.values(usernames_oldb_to_usernames_curs_actual_dict)) if x in visited or (visited.add(x) or False)] + + if not professionals_repetits: + return redirect('/importaActuacions/importantActuacions') + + return render( + request, + '../templates/sincronitzaProfessionals.html', + { + 'head':head, + 'usuaris_orfes_oldb':usernames_usuaris_orfes_oldb, + 'usuaris_curs_actual':usuaris_id_username_firstname_lastname_list, + 'professionals_repetits':professionals_repetits, + 'assignacio_anterior':usernames_oldb_to_usernames_curs_actual_dict, + },) + + +@login_required +@group_required(['direcció','administradors']) +def importantActuacions(request): + + global dades_connexio_dbold + global usernames_oldb_to_usernames_curs_actual_dict + nom_dbold = dades_connexio_dbold.get('name_dbold') + + # Redirecció si hi ha un accès indegut i conseqüent error en la connexió a la BD antiga + connexio = check_database_connection(request) + if connexio is not None: + return connexio + if not usernames_oldb_to_usernames_curs_actual_dict: # Per evitar un accès amb url directe + return render(request,'404.html',{},) + + head = u"Llistat detallat de les actuacions que s'importaran des d'un altre curs." + + # Informació a mostrar en el template. + actuacions_sense_alumne_curs_actual = [] # Actuacions especials donat que NO s'importaran a la BD del curs actual. + actuacions_sense_professional = [] # actuacions especials donat se'n modificarà el seu text i SÍ que s'importaran a la BD del curs actual. + alumnes_desmatriculats = [] # Alumnat que ja no hi és. + professionals_foracentre = [] # Professionals que ja no hi son. + + ############################### + # 3r PAS # EXTRACCIÓ DE DADES # + ############################### + + # Dades de l'alumnat + alumnes_id_ralc_nom_cognoms_list = list(Alumne.objects. + values_list('id', 'ralc', 'nom', 'cognoms'). + order_by('cognoms')) + + alumnes_olddb_id_ralc_nom_cognoms_list = list(Alumne.objects. + using(nom_dbold). + values_list('id', 'ralc', 'nom', 'cognoms'). + order_by('cognoms')) + + # Dades dels professionals + usuaris_username_id = dict(User.objects. + values_list('username','id'). + exclude(username__startswith = 'almn'). + order_by('username')) + + usuaris_olddb_id_username_firstname_lastname_llista_de_tuples = list(User.objects. + using(nom_dbold). + values_list('id', 'username', 'first_name', 'last_name'). + exclude(username__startswith = 'almn'). + exclude(username__startswith = 'admin'). + exclude(username__startswith = 'conser'). + exclude(username = 'TP'). + order_by('username')) + + # Conversió de les tuples en llistes, per poder modificar els valors. + usuaris_olddb_id_username_firstname_lastname_list = [] + usuaris_olddb_id_username_firstname_lastname_list = [list(usuari) for usuari in usuaris_olddb_id_username_firstname_lastname_llista_de_tuples] + del usuaris_olddb_id_username_firstname_lastname_llista_de_tuples + + # Dades de les actuacions + actuacions_olddb_list = list(Actuacio.objects. + using(nom_dbold). + values(). + order_by('id')) + + actuacions_id_data_alumneid_list = list(Actuacio.objects. + values_list('id', 'moment_actuacio', 'alumne_id'). + order_by('id')) + + + ############################## + # 4t PAS # 1r CANVI # OLD BD # + ############################## + + # 4.1 Substitució dels usernames antics dels professionals pels actuals usernames. + for professional in usuaris_olddb_id_username_firstname_lastname_list: + username_oldb_professional = professional[1] + if usernames_oldb_to_usernames_curs_actual_dict.get(username_oldb_professional): + username_professional = usernames_oldb_to_usernames_curs_actual_dict.get(username_oldb_professional) + professional[1] = username_professional + + # Substitucions a les actuacions + for actuacio in actuacions_olddb_list: + + # 4.2 Substitució de l'identificador de l'alumne pel RALC, que és universal. + # El camps alumne_id té foreign_key amb el camp id de la taula alumnes_alumne. + # No obstant es deixa la marca (None) si no es trobés l'alumne al llistat general d'alumnes. + identificador_alumne = actuacio.get('alumne_id') + for alumne in alumnes_olddb_id_ralc_nom_cognoms_list: + if identificador_alumne == alumne[0]: + ralc_alumne = alumne[1] + nom_alumne = alumne[2] + cognoms_alumne = alumne[3] + actuacio.update({'alumne_id':ralc_alumne}) + actuacio.update({'nom_alumne':nom_alumne}) + actuacio.update({'cognoms_alumne':cognoms_alumne}) + + + # 4.3 Substituint l'identificador del professional per l'username, + # El camp professional_id té foreign_key amb algun lloc que no he sabut trobar + # No obstant es deixa la marca (None) si no es trobés el professional al llistat general d'usuaris. + identificador_professional = actuacio.get('professional_id') + for professional in usuaris_olddb_id_username_firstname_lastname_list: + if identificador_professional == professional[0]: + username_professional = professional[1] + nom_professional = professional[2] + cognoms_professional = professional[3] + #Valorar si no fer-ho i afegir-ho per codi al template emprant professionals_foracentre + actuacio.update({'professional_id':username_professional}) + actuacio.update({'nom_professional':nom_professional}) + actuacio.update({'cognoms_professional':cognoms_professional}) + + + ################################# + # 5é PAS # 2n CANVI # BD ACTUAL # + ################################# + + for actuacio in actuacions_olddb_list: + + # Substituint el ralc de l'actuació per l'identificador de l'alumne a la nova BD. + # Si no troba l'alumne és que no s'ha maticulat, se'n guarden algunes dades + # i es deixa la marca (None) per excloure-la més endavant amb facilitat. + + ralc_alumne = actuacio.get('alumne_id') # Després del 1r canvi, el camp alumne_id conté el ralc, no l'alumne_id + identificador_alumne = False + for alumne in alumnes_id_ralc_nom_cognoms_list: + if ralc_alumne == alumne[1]: + identificador_alumne = alumne[0] + + if ralc_alumne and identificador_alumne: + actuacio.update({'alumne_id':identificador_alumne}) + elif ralc_alumne and not identificador_alumne: # Si l'alumne ja no hi és, és un alumne desmatriculat. + + # Guardem les actuacions associades a alumnes desmatriculats en una llista específica. + actuacions_sense_alumne_curs_actual.append(deepcopy(actuacio)) + + # Guardem els ralcs, noms i cognoms dels alumnes ara desmatriculats que tenen actuacions a la BD antiga + for alumne in alumnes_olddb_id_ralc_nom_cognoms_list: + if ralc_alumne == alumne[1]: + nom_alumne = alumne[2] + cognoms_alumne = alumne[3] + dades_alumne_desmatriculat = {'ralc':ralc_alumne,'nom':nom_alumne,'cognoms':cognoms_alumne} + if not alumnes_desmatriculats or dades_alumne_desmatriculat not in alumnes_desmatriculats: + alumnes_desmatriculats.append(dades_alumne_desmatriculat) + + actuacio.update({'alumne_id':None}) # Marcada per a no importar-la a la BD nova + + # Substituint l'username del professional pel seu identificador a la nova BD, + username_professional = actuacio.get('professional_id') # Després del 1r canvi, el camp professional_id conté l'username, no l'identificador del professional + identificador_professional = usuaris_username_id.get(username_professional) + if username_professional and identificador_professional: + actuacio.update({'professional_id':identificador_professional}) + elif username_professional and not identificador_professional: # Si el professional ja no és al centre... + + # Guardem les actuacions sense profesional a la BD nova en una llista específica. + actuacions_sense_professional.append(deepcopy(actuacio)) + + # Guardem els usernames, noms i cognoms, dels professionals que ja no hi son al centre. + for professional in usuaris_olddb_id_username_firstname_lastname_list: + if username_professional == professional[1]: + nom_professional = professional[2] + cognoms_professional = professional[3] + dades_professional_foracentre = {'username':username_professional,'nom':nom_professional,'cognoms':cognoms_professional} + if not professionals_foracentre or dades_professional_foracentre not in professionals_foracentre: + professionals_foracentre.append(dades_professional_foracentre) + + # S'afegeix una frase a l'inici del text de l'actuació per deixar constància de qui i quan es va fer l'actuació. + text_actuacio = u'El o la professional '+nom_professional+' '+cognoms_professional + text_actuacio += ' ('+username_professional+')' + text_actuacio += ' va redactar aquesta actuació però ja no es troba al centre educatiu.' + text_actuacio += ' No obstant, a continuació se\'n mostra el text original: \n\n' + text_actuacio += actuacio.get('actuacio') + + actuacio.update({'actuacio':text_actuacio}) + + + # S'elimina l'username del camp professional_id. Aquest camp pot ser NULL a la BD. + actuacio.update({'professional_id':None}) + + ################################## + # 6é PAS # PREPARANT LA INSERCIÓ # + ################################## + + actuacions_ja_importades = [] + global actuacions_a_importar + actuacions_a_importar = [] + + for actuacio_olddb in actuacions_olddb_list: + if actuacio_olddb.get('alumne_id')!=None: # Només s'hi afegiran totes les actuacions associades a un alumne matriculat en el curs actual. + + # Comprovació para no importar una actuació que ja va ser importada per algú + # la data exacta és gairebé impossible que es pugui repetir perquè haurien d'haver-hi dues actuacions creades en el mateix segon. + data_actuacio_a_importar = actuacio_olddb.get('moment_actuacio') + coincidencia = False + for actuacio in actuacions_id_data_alumneid_list: + data_actuacio_curs_actual = actuacio[1] + if data_actuacio_a_importar == data_actuacio_curs_actual: + coincidencia = True + + if not coincidencia: + actuacions_a_importar.append(actuacio_olddb) + else: + actuacions_ja_importades.append(actuacio_olddb) + + return render( + request, + '../templates/importacio.html', + { + 'nom_dbold':nom_dbold, + 'head':head, + 'alumnes_desmatriculats':alumnes_desmatriculats, + 'actuacions_sense_alumne_curs_actual':actuacions_sense_alumne_curs_actual, + 'professionals_foracentre':professionals_foracentre, + 'actuacions_sense_professional':actuacions_sense_professional, + 'actuacions_olddb_list':actuacions_olddb_list, + 'actuacions_ja_importades': actuacions_ja_importades, + 'actuacions_a_importar': actuacions_a_importar, + },) + + +##################### +# 7é PAS # INSERCIÓ # +##################### + +@login_required +@group_required(['direcció','administradors']) +def importacio(request): + + global actuacions_a_importar + global actuacions_pel_bulkcreate + + head = u"Resultats de la importació de les actuacions d'un curs anterior" + + # Redirecció si hi ha un accès indegut i conseqüent error en la connexió a la BD antiga + connexio = check_database_connection(request) + if connexio is not None: + return connexio + if not actuacions_a_importar: + return render(request,'404.html',{},) + + if request.method == 'POST': + actuacions_pel_bulkcreate.clear() + + # Es decideix afegir-hi l'id per facilitar esborrar les actuacions afegides si quelcom ha anat malament. + # PERFER: Una taula amb checkbox per esborrar les actuacions afegides, habilitant el checkbox només d'aquestes actuacions. + ultim_id_abans_actualitzacio = (Actuacio.objects.last()).id + identificador_nova_actuacio = ultim_id_abans_actualitzacio + 1 + + # Preparació de les dades a inserir + for actuacio in actuacions_a_importar: + act = Actuacio( + id = identificador_nova_actuacio, + moment_actuacio = actuacio.get('moment_actuacio'), + qui_fa_actuacio = actuacio.get('qui_fa_actuacio'), + amb_qui_es_actuacio = actuacio.get('amb_qui_es_actuacio'), + assumpte = actuacio.get('assumpte'), + actuacio = actuacio.get('actuacio'), + alumne_id = actuacio.get('alumne_id'), + professional_id = actuacio.get('professional_id'), + ) + actuacions_pel_bulkcreate.append(act) + identificador_nova_actuacio += 1 + + # Inserció de les actuacions de la BD antiga a la BD actual (per fi, badum txas!) + Actuacio.objects.bulk_create(actuacions_pel_bulkcreate) + + # PER ARREGLAR: Renderitzar dues taules paginades amb table2 al mateix template provoca que quan es pagina una taula, l'altra es pagina igual. + + # Per mostrar, un últim cop, les actuacions que s'han importat. + table_actuacions_importades = Table2_llista_actuacions(actuacions_pel_bulkcreate) + table_actuacions_importades.order_by = '-id_actuacio' + RequestConfig(request, paginate={"paginator_class":DiggPaginator , "per_page": 20}).configure(table_actuacions_importades) + + # Per mostrar cóm ha queat finalment la taula de les actuacions + actuacions = Actuacio.objects.all() + table = Table2_llista_actuacions(actuacions) + table.order_by = '-id_actuacio' + RequestConfig(request, paginate={"paginator_class":DiggPaginator , "per_page": 20}).configure(table) + + return render( + request, + '../templates/resultatImportacio.html', + { + 'head': head, + 'table': table, + 'table_actuacions_importades': table_actuacions_importades, + } + ) diff --git a/aula/apps/tutoria/templates/lesMevesActuacions.html b/aula/apps/tutoria/templates/lesMevesActuacions.html index d3dab70c..c3e4d90d 100644 --- a/aula/apps/tutoria/templates/lesMevesActuacions.html +++ b/aula/apps/tutoria/templates/lesMevesActuacions.html @@ -7,13 +7,34 @@ {% block posttaula %} + {% if not veure_dades_actuacions_antigues %} +Les actuacions dutes a terme en cursos anteriors es poden consultar en aquest enllaç. +