diff --git a/seminar/utils.py b/seminar/utils.py index 1c9668ec..c8705a55 100644 --- a/seminar/utils.py +++ b/seminar/utils.py @@ -8,6 +8,8 @@ from django.contrib.auth.decorators import permission_required, \ from html.parser import HTMLParser from django import views as DjangoViews +from django.db import transaction + from django.contrib.auth.models import AnonymousUser from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist @@ -376,3 +378,134 @@ def sync_skoly(base_url): for skola in serializers.deserialize('json', json): skola.save() +@transaction.atomic +def merge_resitele(cilovy, zdrojovy): + """Spojí dva řešitelské objekty do cílového. + + Pojmenování "zdrojový" je silně nepřiléhající, ale co už…""" + + # Postup: + # Sjednotit / upravit informace cílového řešitele + print('Upravuji data modelu') + fieldy_shoda = ['skola', 'poznamka', 'rok_maturity', 'zasilat', 'zasilat_cislo_emailem'] + + for f in fieldy_shoda: + zf = getattr(zdrojovy, f) + cf = getattr(cilovy, f) + if cf == zf: + print(f' Údaj {f} je shodný ({zf})') + else: + if zf is None: + print(f' Údaj {f} je pouze v cílovém, používám') + continue + if cf is None: + setattr(cilovy, f, zf) + cilovy.poznamka += f'\nDEBUG: Merge: doplnéný údaj {f} ze zdrojového: {zf}' + print(f" Přiřazuji {f} ze zdrojového: {zf}") + continue + # Jsou fakt různé… + # FIXME: chybí možnost na vlastní úpravu… + verdikt = input(f"\n\n Údaj {f} se u řešitele {cilovy} ({cilovy.id}) liší:\n Zdrojový: {zf}\n Cílový: {cf}\n Který použít, [z]drojový, [c]ílový? ") + verdikt = verdikt[0].casefold() + if verdikt == 'z': + setattr(cilovy, f, zf) + cilovy.poznamka += f'\nDEBUG: Merge: pro {f} použit údaj {zf} (zdrojový), nepoužit {cf} (cílový)' + elif verdikt == 'c': + cilovy.poznamka += f'\nDEBUG: Merge: pro {f} použit údaj {cf} (cílový), nepoužit {cf} (zdrojový)' + else: raise ValueError('Špatná odpověď, řešitel pravděpodobně neuložen') + # poznámku chceme nezahodit… + cilovy.poznamka += f'\nDEBUG: Merge: Původní poznámka: {zdrojovy.poznamka}' + print(f' Výsledný řešitel: {cilovy.__dict__}, ukládám') + cilovy.save() + + + # Přepojit všechny vazby ze zdrojového na cílového + print('Přepojuji vazby') + # Vazby: Škola (hotovo), Řešení_Řešitelé, Konfery_Účastníci, Soustředění_Účastníci, Osoba (vyřeší se později, nejde přepojit) + ct = m.Reseni_Resitele.objects.filter(resitele=zdrojovy).update(resitele=cilovy) + print(f' Přepojeno {ct} řešení') + ct = m.Konfery_Ucastnici.objects.filter(resitel=zdrojovy).update(resitel=cilovy) + print(f' Přepojeno {ct} konfer') + ct = m.Soustredeni_Ucastnici.objects.filter(resitel=zdrojovy).update(resitel=cilovy) + print(f' Přepojeno {ct} sousů') + + # Teď by na zdrojovém řešiteli nemělo nic viset, smazat ho, pamatujíce si jeho Osobu + zdrosoba = zdrojovy.osoba + print(f'Mažu zdrojového řešitele {zdrojovy.__dict__}') + zdrojovy.delete() + # Spojit osoby (separátní funkce). + merge_osoby(cilovy.osoba, zdrosoba) + + input("Potvrdit transakci řešitelů (^C pro zrušení) ") + +@transaction.atomic +def merge_osoby(cilova, zdrojova): + """ Spojí dvě osoby do cílové + + Nehlídá omezení typu "max 1 řešitel na osobu", to by měla hlídat databáze (OneToOneField).""" + # Sjednocení dat + print('Sjednocuji data osob') + # ID, User neřešíme, poznámku vyřešíme separátně. + fieldy = ['datum_narozeni', 'datum_registrace', 'datum_souhlasu_udaje', + 'datum_souhlasu_zasilani', 'email', 'foto', 'jmeno', 'mesto', + 'pohlavi_muz', 'prezdivka', 'prijmeni', 'psc', 'stat', 'telefon', 'ulice'] + for f in fieldy: + zf = getattr(zdrojova, f) + cf = getattr(cilova, f) + if cf == zf: + print(f' Údaj {f} je shodný ({zf})') + else: + if zf is None: + print(f' Údaj {f} je pouze v cílové, používám') + continue + if cf is None: + setattr(cilova, f, zf) + cilova.poznamka += f'\nDEBUG: Merge: doplnéný údaj {f} ze zdrojové: {zf}' + print(f" Přiřazuji {f} ze zdrojové: {zf}") + continue + # Jsou fakt různé… + # FIXME: chybí možnost na vlastní úpravu… + verdikt = input(f"\n\n Údaj {f} se u osoby {cilova} ({cilova.id}) liší:\n Zdrojový: {zf}\n Cílový: {cf}\n Který použít, [z]drojový, [c]ílový? ") + verdikt = verdikt[0].casefold() + if verdikt == 'z': + setattr(cilova, f, zf) + cilova.poznamka += f'\nDEBUG: Merge: pro {f} použit údaj {zf} (zdrojová), nepoužit {cf} (cílová)' + elif verdikt == 'c': + cilova.poznamka += f'\nDEBUG: Merge: pro {f} použit údaj {cf} (cílová), nepoužit {cf} (zdrojová)' + else: raise ValueError('Špatná odpověď, řešitel pravděpodobně neuložen') + # poznámku chceme nezahodit… + cilova.poznamka += f'\nDEBUG: Merge: Původní poznámka: {zdrojova.poznamka}' + print(f' Výsledná osoba: {cilova.__dict__}, ukládám') + cilova.save() + + # Vazby: Řešitel, User, Příjemce, Organizátor, Škola.kontaktní_osoba + print('Přepojuji vazby') + ct = m.Skola.objects.filter(kontaktni_osoba=zdrojova).update(kontaktni_osoba=cilova) + print(f' Přepojeno {ct} kontaktních osob') + # Ostatní vazby vyřeší OneToOneFieldy, ale někdy nemusí existovat… + ct = m.Resitel.objects.filter(osoba=zdrojova).update(osoba=cilova) + print(f' Přepojeno {ct} řešitelů') + ct = m.Prijemce.objects.filter(osoba=zdrojova).update(osoba=cilova) + print(f' Přepojeno {ct} příjemců') + ct = m.Organizator.objects.filter(osoba=zdrojova).update(osoba=cilova) + print(f' Přepojeno {ct} organizátorů') + # Uživatelé vedou opačným směrem, radši chceme zkontrolovat, že jsou různí ručně: + if zdrojova.user != cilova.user: + # Jeden z nich může být nenastavený… + if zdrojova.user is None: + print('Uživatel je již v cílové osobě') + elif cilova.user is None: + print('Používám uživatele zdrojové osoby') + cilova.user = zdrojova.user + # Teď nemůžeme uložit, protože kolize uživatelů. Ukládat cílovou budeme až po smazání zdrojové. + else: raise ValueError('Osoby mají obě uživatele, radši padám') + + # Uložení a mazání + print(f'Mažu zdrojovou osobu {zdrojova.__dict__}') + zdrojova.delete() + print(f'Ukládám cílovou osobu {cilova.__dict__}') + cilova.save() + + input("Potvrdit transakci osob (^C pro zrušení) ") + +