import os import shutil import tempfile from datetime import date, timedelta from pathlib import Path from unittest import skip from unittest.mock import patch from freezegun import freeze_time from django.conf.global_settings import PASSWORD_HASHERS from django.contrib.auth.models import Group, Permission from django.core.files import File from django.db.utils import IntegrityError from django.forms import Form from django.forms.models import model_to_dict from django.test import RequestFactory, TestCase, tag from django.test.utils import override_settings from django.urls import reverse from .export import ExportReporting, openxml_contenttype from .forms import ( AgendaForm, FamilleCreateForm, HMDurationField, NiveauForm, PersonneForm, PrestationForm, UtilisateurForm ) from .models import ( Bilan, CercleScolaire, Contact, EtapeFin, Famille, Formation, Intervenant, JournalAcces, LibellePrestation, Niveau, Personne, Prestation, Rapport, Region, Role, Service, Suivi, Utilisateur, ) from .utils import ANTICIPATION_POUR_DEBUT_SUIVI, format_duree, format_d_m_Y from .views_stats import Month, StatistiquesView class InitialDataMixin: @classmethod def setUpTestData(cls): s1, _ = Service.objects.get_or_create(sigle='CRXNE') Service.objects.bulk_create([ Service(sigle='OPEN'), Service(sigle='SSE') ]) CercleScolaire.objects.bulk_create([ CercleScolaire(nom='EOREN-MAIL'), CercleScolaire(nom='EOCF-NUMA-DROZ') ]) grp_aemo = Group.objects.create(name='aemo') grp_aemo.permissions.add(*list( Permission.objects.filter(codename__in=[ 'view_famille', 'add_famille', 'add_prestation' ]) )) Role.objects.bulk_create([ Role(nom='Père', est_famille=True), Role(nom='Mère', est_famille=True), Role(nom='Beau-père', est_famille=True), Role(nom='Enfant suivi', est_famille=True), Role(nom='Enfant non-suivi', est_famille=True), Role(nom='Médecin', est_famille=False), Role(nom='Psy', est_famille=False, est_intervenant=True, est_editeur=True), Role(nom='Educ', est_famille=False, est_intervenant=True, est_editeur=True), Role(nom='Assistant-e social-e', est_famille=False, est_intervenant=True), Role(nom='Référent', est_famille=False), ]) Contact.objects.bulk_create([ Contact(nom='Sybarnez', prenom='Tina', tel_prof='032 886 88 88', service=s1), Contact(nom='Rathfeld', prenom='Christophe', service=Service.objects.get(sigle='OPEN')), Contact(nom='DrSpontz', prenom='Igor'), ]) Contact.objects.get(nom='DrSpontz').roles.add(Role.objects.get(nom='Médecin')) Region.objects.bulk_create([ Region(nom='Littoral Est'), Region(nom='Littoral Ouest'), Region(nom='Montagnes'), Region(nom='Val-de-Ruz'), Region(nom='Val-de-Travers'), ], ignore_conflicts=True) LibellePrestation.objects.bulk_create([ LibellePrestation(code='aemo01', nom='Évaluation'), LibellePrestation(code='aemo02', nom='Accompagnement'), LibellePrestation(code='aemo03', nom='Prestation gén.'), LibellePrestation(code='aemo04', nom='Activités ASE'), ]) grp_admin = Group.objects.create(name='admin') grp_admin.permissions.add(*Permission.objects.filter(codename__in=[ 'add_role', 'change_role', 'delete_role', 'add_service', 'add_utilisateur', 'change_utilisateur', 'delete_utilisateur', 'view_famille', 'change_famille', 'export_stats' ])) cls.aemo_group = Group.objects.get(name='aemo') cls.aemo_group.permissions.add(Permission.objects.get(codename='add_famille')) cls.user_admin = Utilisateur.objects.create_user( 'user_admin', 'user_admin@example.com', nom='Admin', prenom='Prénom', sigle='ADM' ) cls.user_admin.groups.add(grp_admin) cls.user_admin.groups.add(cls.aemo_group) resp = Role.objects.create(nom='Responsable/coordinateur') cls.user_admin.roles.add(resp) cls.user_aemo = Utilisateur.objects.create_user( 'user_aemo', 'user_aemo@example.org', nom='Aemo', prenom='Prénom', sigle='SP', taux_activite=60, ) cls.user_aemo.roles.add(Role.objects.get(nom='Educ')) cls.user_aemo2 = Utilisateur.objects.create_user( 'user_aemo2', 'user_aemo2@example.org', nom='Aemo2', prenom='Prénom', sigle='SP2' ) cls.user_aemo2.roles.add(Role.objects.get(nom='Psy')) cls.user_aemo.groups.add(cls.aemo_group) cls.user_aemo2.groups.add(cls.aemo_group) cls.user_externe = Utilisateur.objects.create_user( 'externe', 'externe@example.org', 'mepassword', prenom='Bruce', nom='Externe', ) cls.create_famille() @classmethod def create_famille(cls, name='Haddock'): famille = Famille.objects.create_famille( nom=name, rue='Château1', npa=2000, localite='Moulinsart', equipe='montagnes', autorite_parentale='conjointe', statut_marital='divorce', monoparentale=False ) pere = Role.objects.get(nom='Père') Personne.objects.create_personne( famille=famille, role=pere, nom=name, prenom='Archibald', genre='M', date_naissance=date(1956, 2, 16), rue='Château1', npa=2000, localite='Moulinsart', ) famille.suivi.ope_referent = Contact.objects.get(nom="Sybarnez") famille.suivi.save() Personne.objects.create_personne( famille=famille, role=Role.objects.get(nom='Enfant suivi'), nom=name, prenom='Toto', genre='M', date_naissance=date(2010, 2, 16), rue='Château1', npa=2000, localite='Moulinsart', ) return famille class TempMediaRootMixin: @classmethod def setUpClass(cls): cls._temp_media = tempfile.mkdtemp() cls._overridden_settings = cls._overridden_settings or {} cls._overridden_settings['MEDIA_ROOT'] = cls._temp_media super().setUpClass() @classmethod def tearDownClass(cls): shutil.rmtree(cls._temp_media) super().tearDownClass() class FamilleTests(InitialDataMixin, TestCase): personne_data = { 'nom': 'Dupont', 'prenom': 'Jean', 'date_naissance': '1950-03-30', 'genre': 'M', } famille_data = { 'nom': 'Dupont', 'rue': 'Rue du Moulins', 'npa': '3000', 'localite': 'Paris', 'autorite_parentale': 'conjointe', 'equipe': 'montagnes', } def setUp(self): self.client.force_login(self.user_aemo) def test_acces(self): """ Sans permission adaptée, un utilisateur ne peut pas accéder à certaines pages (création de famille, etc.). """ user = Utilisateur.objects.create_user( 'qqun', 'qqun@example.org', 'pwd', first_name='Qqun', last_name='Personne', ) self.client.force_login(user) with self.assertLogs('django.request', level='WARNING'): response = self.client.get(reverse('famille-add')) self.assertEqual(response.status_code, 403) def test_personne_creation(self): famille = Famille.objects.get(nom='Haddock') add_url = reverse('personne-add', args=[famille.pk]) response = self.client.get(add_url) self.assertEqual(response.context['form'].initial['nom'], famille.nom) # Données minimales: nom, genre, rôle role = Role.objects.get(nom='Beau-père') response = self.client.post(add_url, data={'nom': 'Smith', 'genre': 'M', 'role': role.pk}) self.assertRedirects(response, reverse('famille-edit', args=[famille.pk])) response = self.client.post( add_url, data={**self.personne_data, 'role': Role.objects.get(nom='Beau-père').pk, 'localite': "bevaix"} ) self.assertEqual(response.status_code, 302) self.assertQuerySetEqual(Personne.objects.all(), [ '', '', '', '', ], transform=repr) p1 = Personne.objects.get(nom='Dupont') self.assertEqual(p1.famille, famille) self.assertEqual(p1.localite, 'Bevaix') with self.assertRaises(Formation.DoesNotExist): p1.formation # Personne < 4 ans pers = Personne.objects.create_personne( famille=famille, prenom='Gaston', nom='Lagaffe', date_naissance=date.today() - timedelta(days=720), role=Role.objects.get(nom='Enfant suivi') ) self.assertEqual(pers.formation.get_statut_display(), 'Pré-scolaire') self.assertTrue(famille.suivi.demande_prioritaire) def test_label_profession_variable(self): famille = Famille.objects.get(nom='Haddock') response = self.client.get( '{}?role={}'.format(reverse('personne-add', args=[famille.pk]), Role.objects.get(nom='Enfant suivi').pk) ) self.assertContains(response, '', html=True) response = self.client.get( '{}?role={}'.format(reverse('personne-add', args=[famille.pk]), Role.objects.get(nom='Père').pk) ) self.assertContains(response, '', html=True) def test_get_membres(self): # Obtention des différents membres avec 2 requêtes: la famille, les membres (prefetch_related) with self.assertNumQueries(2): famille = Famille.objects.get(nom='Haddock') self.assertEqual(famille.membres_suivis()[0].prenom, 'Toto') self.assertEqual(famille.enfants_non_suivis(), []) self.assertEqual([p.nom_prenom for p in famille.parents()], ['Haddock Archibald']) self.assertEqual(famille.autres_parents(), []) def test_personne_age(self): with patch('aemo.models.date') as mock_date: mock_date.today.return_value = date(2019, 1, 16) self.assertEqual(Personne(date_naissance=date(1999, 11, 4)).age, 19.2) self.assertEqual(Personne(date_naissance=date(2000, 1, 1)).age, 19.0) self.assertEqual(Personne(date_naissance=date(2000, 1, 31)).age, 18.9) def test_personne_age_str(self): pers = Personne(prenom='Toto') pers.date_naissance = date.today() - timedelta(days=12) self.assertEqual(pers.age_str(), '12 jours') pers.date_naissance = date.today() - timedelta(days=33) self.assertEqual(pers.age_str(), '4 sem. 5 jours') pers.date_naissance = date.today() - timedelta(days=77) self.assertEqual(pers.age_str(), '2 mois 2 sem.') pers.date_naissance = date.today() - timedelta(days=689) self.assertEqual(pers.age_str(), '22 mois 4 sem.') pers.date_naissance = date.today() - timedelta(days=690) self.assertEqual(pers.age_str(), '1 an 10 mois') pers.date_naissance = date.today() - timedelta(days=691) self.assertEqual(pers.age_str(format_='jour'), '691 jours') def test_personne_edition(self): famille = Famille.objects.create_famille(nom='Dupont', equipe='montagnes') pers_data = dict(self.personne_data, famille=famille.pk, role=Role.objects.get(nom='Père').pk) form = PersonneForm(data=pers_data, famille=famille) self.assertTrue(form.is_valid(), msg=form.errors) pers = form.save() edit_url = reverse('personne-edit', args=[famille.pk, pers.pk]) new_data = dict(pers_data, rue='Rue du Parc 12') response = self.client.post(edit_url, data=new_data) self.assertEqual(response.status_code, 302) pers.refresh_from_db() self.assertEqual(pers.rue, 'Rue du Parc 12') # Edition is refused if user is missing the permission user = Utilisateur.objects.create_user( 'joe', 'joe@example.org', 'pwd', first_name='Joe', last_name='Cook', ) self.client.force_login(user) with self.assertLogs('django.request', level='WARNING'): response = self.client.get(edit_url) self.assertEqual(response.status_code, 403) def test_personne_formation(self): famille = Famille.objects.get(nom='Haddock') pers = Personne.objects.create_personne( famille=famille, prenom='Gaston', nom='Lagaffe', role=Role.objects.get(nom='Enfant suivi') ) self.assertTrue(famille.can_edit(self.user_aemo)) form_url = reverse('formation', args=[pers.pk]) response = self.client.get(form_url) self.assertFalse(response.context['form'].readonly) self.assertContains(response, "Enregistrer") response = self.client.post(form_url, data={ 'statut': 'cycle2', 'cercle_scolaire': CercleScolaire.objects.first().pk, 'college': 'École parfaite', 'classe': '6H', }) self.assertRedirects(response, reverse('famille-edit', args=[famille.pk])) pers.refresh_from_db() self.assertEqual(pers.formation.classe, '6H') def test_delete_personne_formation_impossible(self): pers = Personne.objects.create_personne( famille=Famille.objects.first(), prenom='Gaston', nom='Lagaffe', role=Role.objects.get(nom='Enfant suivi') ) self.assertRaises(IntegrityError, pers.formation.delete) def test_delete_personne(self): famille = Famille.objects.first() pers = Personne.objects.create_personne( famille=famille, prenom='Gaston', nom='Lagaffe', role=Role.objects.get(nom='Père') ) response = self.client.post( reverse('personne-delete', args=[famille.pk, pers.pk]), follow=True ) self.assertRedirects(response, reverse('famille-edit', args=[famille.pk]), status_code=302) def test_famille_creation(self): response = self.client.get(reverse('famille-add')) self.assertContains(response, '', html=True) self.assertContains( response, '', html=True ) self.assertContains(response, "id_motif_detail") response = self.client.post(reverse('famille-add'), data={ **self.famille_data, 'motif_detail': "Un test parmi d'autres" }) famille = Famille.objects.get(nom='Dupont') self.assertRedirects(response, reverse('famille-edit', args=[famille.pk])) famille = Famille.objects.get(nom='Dupont') self.assertEqual(famille.suivi.equipe, 'montagnes') self.assertEqual(famille.suivi.date_demande, date.today()) self.assertEqual(famille.suivi.motif_detail, "Un test parmi d'autres") def test_famille_edition(self): famille = Famille.objects.get(nom='Haddock') edit_url = reverse('famille-edit', args=[famille.pk]) response = self.client.get(edit_url) self.assertContains(response, ''.format(format_d_m_Y(date.today())), html=True ) def test_dates_obligatoires(self): today = date.today() form_data = { field_name: today for field_name in AgendaForm._meta.fields if field_name not in ['date_fin_suivi', 'motif_fin_suivi', 'destination'] } for field, etape in Suivi.WORKFLOW.items(): data2 = dict(form_data) if etape.oblig is True: etape_preced_oblig = Suivi.WORKFLOW[etape.preced_oblig] data2[etape_preced_oblig.date_nom()] = '' if etape.code == 'fin_suivi': data2['date_fin_suivi'] = today data2['motif_fin_suivi'] = 'placement' data2['destination'] = 'fah' form = AgendaForm(data2, request=self.request) self.assertFalse(form.is_valid()) self.assertEqual(form.errors, {'__all__': ['La date «{}» est obligatoire'.format(etape_preced_oblig)]}) else: form = AgendaForm(data2, request=self.request) self.assertTrue(form.is_valid()) def test_fin_suivi(self): famille = Famille.objects.create_famille( nom='Loiseau', rue='Château1', npa=2000, localite='Moulinsart', equipe='montagnes', ) today = date.today() suivi = famille.suivi form_data = {} suivi.date_demande = form_data['date_demande'] = today - timedelta(days=360) suivi.date_debut_evaluation = form_data['date_debut_evaluation'] = today - timedelta(days=290) suivi.date_fin_evaluation = form_data['date_fin_evaluation'] = today - timedelta(days=250) suivi.date_debut_suivi = form_data['date_debut_suivi'] = today - timedelta(days=120) suivi.save() form = AgendaForm( data={**form_data, 'date_fin_suivi': today - timedelta(days=5), 'motif_fin_suivi': 'evol_positive', 'destination': 'fah'}, instance=suivi, request=self.request, ) self.assertTrue(form.is_valid(), msg=form.errors) suivi = form.save() self.assertEqual(suivi.date_fin_suivi, today - timedelta(days=5)) def test_motif_fin_suivi_sans_date(self): data = {'date_demande': date.today(), 'date_debut_evaluation': date.today(), 'date_fin_evaluation': date.today(), 'date_debut_suivi': date.today(), 'motif_fin_suivi': 'evol_positive'} form = AgendaForm(data, request=self.request) self.assertFalse(form.is_valid()) self.assertEqual( form.errors, {'__all__': ["Les champs «Fin de l'accompagnement», «Motif de fin» et «Destination» " "sont obligatoires pour fermer le dossier."]} ) # Test avec date_fin_suivi non valide data['date_fin_suivi'] = '2019-01-32' form = AgendaForm(data, request=self.request) self.assertFalse(form.is_valid()) self.assertEqual( form.errors, {'date_fin_suivi': ['Saisissez une date valide.'], '__all__': ["Les champs «Fin de l'accompagnement», «Motif de fin» et «Destination» " "sont obligatoires pour fermer le dossier."] } ) def test_dates_non_chronologiques(self): data = { field_name: '2019-01-15' for field_name in AgendaForm._meta.fields if field_name not in ['date_fin_suivi', 'motif_fin_suivi', 'destination'] } date_field_preced = None for field_name in AgendaForm._meta.fields: if field_name in ['date_demande', 'motif_fin_suivi', 'destination']: date_field_preced = field_name continue elif field_name == 'date_fin_suivi': data = dict( data, date_fin_suivi='2019-01-15', motif_fin_suivi='placement', destination='famille' ) form = AgendaForm(dict(data, **{date_field_preced: '2019-01-16'}), request=self.request) self.assertFalse(form.is_valid()) self.assertEqual( form.errors, {'__all__': ["La date «{}» ne respecte pas l’ordre chronologique!".format(form.fields[field_name].label)]} ) date_field_preced = field_name # Test avec trou dans les valeurs de dates data = { 'date_demande': '2019-01-15', 'date_fin_evaluation': '2019-01-01', # Ordre chronologique non respecté 'date_debut_suivi': '2019-02-01' } form = AgendaForm(data, request=self.request) self.assertFalse(form.is_valid()) self.assertEqual( form.errors, {'__all__': ["La date «Fin de l’évaluation le» ne respecte pas l’ordre chronologique!"]} ) def test_saisie_date_invalide(self): form = AgendaForm({ 'date_demande': '20.8', }, request=self.request) self.assertFalse(form.is_valid()) self.assertEqual(form.errors, {'date_demande': ['Saisissez une date valide.']}) def test_saisie_par_erreur_OK(self): data = {'motif_fin_suivi': 'erreur'} form = AgendaForm(data, request=self.request) self.assertTrue(form.is_valid()) self.assertEqual(form.cleaned_data['date_fin_suivi'], date.today()) def test_demande_non_aboutie(self): data = {'motif_fin_suivi': 'non_aboutie'} form = AgendaForm(data, request=self.request) self.assertTrue(form.is_valid()) self.assertEqual(form.cleaned_data['date_fin_suivi'], date.today()) def test_abandon_durant_evaluation_1(self): data = {'date_demande': date.today(), 'motif_fin_suivi': 'placement', 'destination': 'famille'} form = AgendaForm(data, request=self.request) self.assertTrue(form.is_valid(), form.errors) def test_abandon_durant_evaluation_2(self): data = {'date_demande': date.today(), 'motif_fin_suivi': 'placement', 'destination': 'famille'} form = AgendaForm(data, request=self.request) self.assertTrue(form.is_valid()) def test_dates_tardives(self): date_passee = date.today() - timedelta(days=31 + Prestation.DELAI_SAISIE_SUPPL) form_data = {} suivi = Suivi() for date_field in AgendaForm._meta.fields: if not date_field.startswith('date'): continue if date_field == 'date_fin_suivi': form_data['motif_fin_suivi'] = 'placement' form_data['destination'] = 'famille' form_data[date_field] = date_passee form = AgendaForm(data=form_data, instance=suivi, request=self.request) self.assertFalse(form.is_valid()) if date_field == 'date_fin_suivi': self.assertEqual( form.errors, {date_field: ["La saisie de dates pour le mois précédent n’est pas permise !"], '__all__': ["Les champs «Fin de l'accompagnement», «Motif de fin» et «Destination» " "sont obligatoires pour fermer le dossier."]} ) else: self.assertEqual( form.errors, {date_field: ["La saisie de dates pour le mois précédent n’est pas permise !"]} ) setattr(suivi, date_field, date.today() - timedelta(days=90)) form_data[date_field] = date.today() - timedelta(days=90) def test_date_demande_anticipee(self): date_demande = date.today() + timedelta(days=1) data = {'date_demande': date_demande} form = AgendaForm(data, request=self.request) self.assertFalse(form.is_valid()) self.assertEqual( form.errors, {'date_demande': ["La saisie anticipée est impossible !"]} ) def test_sans_destination_erreur(self): data = {'date_demande': date.today(), 'date_debut_evaluation': date.today(), 'date_fin_evaluation': date.today(), 'date_debut_suivi': date.today(), 'date_fin_suivi': date.today(), 'motif_fin_suivi': 'evol_positive'} form = AgendaForm(data, request=self.request) self.assertFalse(form.is_valid()) self.assertEqual( form.errors, {'__all__': ["Les champs «Fin de l'accompagnement», «Motif de fin» et «Destination» " "sont obligatoires pour fermer le dossier."]} ) data['destination'] = '' form = AgendaForm(data, request=self.request) self.assertFalse(form.is_valid()) self.assertEqual( form.errors, {'__all__': ["Les champs «Fin de l'accompagnement», «Motif de fin» et «Destination» " "sont obligatoires pour fermer le dossier."]} ) def test_date_debut_suivi_anticipe_ok(self): data = {'date_demande': date.today(), 'date_debut_evaluation': date.today() + timedelta(days=ANTICIPATION_POUR_DEBUT_SUIVI), 'date_fin_evaluation': date.today() + timedelta(days=ANTICIPATION_POUR_DEBUT_SUIVI), 'date_debut_suivi': date.today() + timedelta(days=ANTICIPATION_POUR_DEBUT_SUIVI)} form = AgendaForm(data, request=self.request) self.assertTrue(form.is_valid()) def test_date_debut_suivi_anticipe_error(self): data = {'date_demande': date.today(), 'date_debut_evaluation': date.today() + timedelta(days=ANTICIPATION_POUR_DEBUT_SUIVI + 1), 'date_fin_evaluation': date.today() + timedelta(days=ANTICIPATION_POUR_DEBUT_SUIVI + 1), 'date_debut_suivi': date.today() + timedelta(days=ANTICIPATION_POUR_DEBUT_SUIVI + 1)} form = AgendaForm(data, request=self.request) self.assertFalse(form.is_valid()) def test_date_anticipee_pour_groupe_admin(self): famille = Famille.objects.get(nom='Haddock') self.client.force_login(self.user_admin) response = self.client.post( reverse('famille-agenda', args=[famille.pk]), data={'date_demande': '2022-09-01'}, follow=True ) self.assertContains( response, '
  • Les dates saisies peuvent affecter les statistiques ' 'déjà communiquées !
  • ', html=True ) self.assertContains( response, '
  • Les modifications ont été enregistrées avec succès
  • ', html=True ) def test_affichage_intervention_temporaire(self): famille = Famille.objects.get(nom='Haddock') intervenant = self.user_aemo role = Role.objects.get(nom='Educ') date_debut = date.today() intervention = Intervenant.objects.create( suivi=famille.suivi, intervenant=intervenant, role=role, date_debut=date_debut, date_fin=date.today() ) self.client.force_login(self.user_aemo) suivi_url = reverse('famille-agenda', args=[famille.pk]) response = self.client.get(suivi_url) self.assertContains( response, ( f"
    Aemo Prénom (Educ) ({format_d_m_Y(intervention.date_debut)} - " f"{format_d_m_Y(intervention.date_fin)})
    " ), html=True ) class JournalisationTests(InitialDataMixin, TestCase): def test_acces_famille_journalise(self): famille = Famille.objects.get(nom='Haddock') Intervenant.objects.create( suivi=famille.suivi, intervenant=self.user_aemo, role=Role.objects.get(nom='Educ'), date_debut=date.today(), ) Intervenant.objects.create( suivi=famille.suivi, intervenant=self.user_aemo2, role=Role.objects.get(nom='Educ'), date_debut=date.today() - timedelta(days=3), date_fin=date.today() - timedelta(days=1), ) self.client.force_login(self.user_aemo) suivi_url = reverse('famille-suivi', args=[famille.pk]) response = self.client.get(suivi_url) self.assertTemplateUsed(response, 'aemo/suivi_edit.html') self.client.force_login(self.user_aemo2) response = self.client.get(suivi_url) self.assertTemplateUsed(response, 'aemo/acces_famille.html') response = self.client.get(suivi_url + '?confirm=1') self.assertTemplateUsed(response, 'aemo/suivi_edit.html') line = JournalAcces.objects.get(utilisateur=self.user_aemo) self.assertTrue(line.ordinaire) line = JournalAcces.objects.get(utilisateur=self.user_aemo2) self.assertFalse(line.ordinaire) @tag('pdf') class PdfTests(InitialDataMixin, TestCase): def setUp(self): super().setUp() self.client.force_login(self.user_aemo) def _test_print_pdf(self, url, filename): self.client.force_login(self.user_aemo) response = self.client.get(url) self.assertEqual( response['content-disposition'], 'attachment; filename="{}"'.format(filename) ) self.assertEqual(response['content-type'], 'application/pdf') self.assertGreater(len(response.getvalue()), 200) def test_print_evaluation(self): fam = Famille.objects.get(nom='Haddock') self._test_print_pdf( reverse('print-evaluation', args=(fam.pk,)), 'haddock_aemo_evaluation.pdf' ) # Avec genogramme en PDF with (Path('.').parent / 'aemo' / 'test.pdf').open(mode='rb') as fh: fam.genogramme = File(fh) fam.save() self._test_print_pdf( reverse('print-evaluation', args=(fam.pk,)), 'haddock_aemo_evaluation.pdf' ) def test_print_bilan(self): fam = Famille.objects.get(nom='Haddock') bilan = Bilan.objects.create( date=date(2020, 11, 3), auteur=self.user_aemo, famille=fam, objectifs="

    Para 1

    Para 2

    ", rythme="

    Para 1

    Para 2

    ", ) self._test_print_pdf( reverse('print-bilan', args=(bilan.pk,)), 'haddock_bilan_20201103.pdf' ) def test_print_coord_famille_un_enfant_un_parent(self): fam = Famille.objects.get(nom='Haddock') Personne.objects.create_personne( famille=fam, prenom='Gaston', nom='Lagaffe', role=Role.objects.get(nom='Enfant suivi') ) self._test_print_pdf( reverse('print-coord-famille', args=(fam.pk,)), 'haddock_coordonnees.pdf' ) def test_print_coord_un_enfant_deux_parents(self): fam = Famille.objects.get(nom='Haddock') Personne.objects.create_personne( famille=fam, prenom='Gaston', nom='Lagaffe', role=Role.objects.get(nom='Enfant suivi') ) Personne.objects.create_personne( famille=fam, prenom='Maude', nom='Zarella', role=Role.objects.get(nom='Mère') ) self._test_print_pdf( reverse('print-coord-famille', args=(fam.pk,)), 'haddock_coordonnees.pdf' ) def test_print_coord_pere_mere_beaupere(self): fam = Famille.objects.get(nom='Haddock') Personne.objects.create_personne( famille=fam, prenom='Gaston', nom='Lagaffe', role=Role.objects.get(nom='Enfant suivi') ) Personne.objects.create_personne( famille=fam, prenom='Maude', nom='Zarella', role=Role.objects.get(nom='Mère') ) Personne.objects.create_personne( famille=fam, prenom='Aloïs', nom='Silalune', role=Role.objects.get(nom='Beau-père') ) self._test_print_pdf( reverse('print-coord-famille', args=(fam.pk,)), 'haddock_coordonnees.pdf' ) def test_print_sans_famille(self): famille = Famille.objects.create_famille( nom='Haddock', rue='Château1', npa=2000, localite='Moulinsart', equipe='montagnes', autorite_parentale='conjointe', statut_marital='divorce', monoparentale=False ) Personne.objects.create_personne( famille=famille, prenom='Gaston', nom='Lagaffe', role=Role.objects.get(nom='Enfant suivi') ) self._test_print_pdf( reverse('print-coord-famille', args=(famille.pk,)), 'haddock_coordonnees.pdf' ) class PrestationTests(InitialDataMixin, TestCase): def setUp(self): super().setUp() self.famille = Famille.objects.get(nom='Haddock') Personne.objects.create_personne( famille=self.famille, role=Role.objects.get(nom='Enfant suivi'), nom='Haddock', prenom='Paulet', genre='M', date_naissance=date(1956, 2, 16), rue='Château1', npa=2000, localite='Moulinsart', ) self.famille.suivi.intervenants.add( self.user_aemo, through_defaults={'role': Role.objects.get(nom='Educ')} ) self.prest_fam = LibellePrestation.objects.get(code='aemo01') # Évaluation self.prest_gen = LibellePrestation.objects.get(code='aemo03') def create_prestation_fam(self, texte=""): prest = Prestation.objects.create( auteur=self.user_aemo, date_prestation=date.today(), duree=timedelta(hours=8), famille=self.famille, lib_prestation=self.prest_fam, texte=texte ) prest.intervenants.add(self.user_aemo, self.user_aemo2) return prest def create_prestation_gen(self): data = dict( auteur=self.user_aemo, date_prestation=date.today(), duree=timedelta(hours=8), famille=None, lib_prestation=self.prest_gen ) prest = Prestation.objects.create(**data) prest.intervenants.add(self.user_aemo) return prest def test_prestation_texte_clean(self): """Leading and trailing empty paragraphs are stripped.""" texte = ( '

    \n' '

    Echanges mail fin de suivi, au revoir à la famille

    \n' '

    ' ) data = dict( duree='3:40', date_prestation=date.today(), lib_prestation=self.prest_fam.pk, intervenants=[self.user_aemo.pk], texte=texte ) form = PrestationForm(famille=self.famille, user=self.user_aemo, data=data) self.assertTrue(form.is_valid()) self.assertEqual( form.cleaned_data['texte'], '

    Echanges mail fin de suivi, au revoir à la famille

    ' ) def test_prestation_date_prestation_dans_mois_courant(self): data = dict( duree='3:40', date_prestation=date.today(), lib_prestation=self.prest_fam.pk, intervenants=[self.user_aemo.pk] ) form = PrestationForm(famille=self.famille, user=self.user_aemo, data=data) self.assertTrue(form.is_valid(), msg=form.errors) def test_prestation_saisie_anticipee(self): data = dict( duree='3:40', date_prestation=date.today() + timedelta(days=1), lib_prestation=self.prest_fam.pk, intervenants=[self.user_aemo.pk] ) form = PrestationForm(famille=self.famille, user=self.user_aemo, data=data) self.assertFalse(form.is_valid()) self.assertEqual(form.errors, {'date_prestation': ['La saisie anticipée est impossible !']}) def test_prestation_saisie_tardive(self): data = dict( duree='3:40', date_prestation=date.today() - timedelta(days=31 + Prestation.DELAI_SAISIE_SUPPL), lib_prestation=self.prest_fam.pk, intervenants=[self.user_aemo.pk] ) form = PrestationForm(famille=self.famille, user=self.user_aemo, data=data) self.assertFalse(form.is_valid()) self.assertEqual( form.errors, {'date_prestation': ['La saisie des prestations des mois précédents est close !']} ) def test_prestation_edit_perm_speciale(self): prest = self.create_prestation_fam() prest.date_prestation = date.today() - timedelta(days=31 + Prestation.DELAI_SAISIE_SUPPL) prest.save() self.user_admin.user_permissions.add( Permission.objects.get(codename='edit_prest_prev_month', content_type__app_label='aemo') ) self.client.force_login(self.user_admin) self.client.post(reverse('prestation-edit', args=[self.famille.pk, prest.pk]), data={ 'date_prestation': prest.date_prestation, 'duree': '00:45', 'intervenants': [self.user_aemo.pk], 'texte': 'foo', }) prest.refresh_from_db() self.assertEqual(prest.texte, 'foo') def test_add_prestation_fam(self): add_url = reverse('prestation-famille-add', args=[self.famille.pk]) data = dict( duree='3:40', date_prestation=date.today() - timedelta(days=3), famille=self.famille.pk, intervenants=[self.user_aemo.pk] ) self.client.force_login(self.user_aemo) response = self.client.post(add_url, data) if response.status_code == 200: self.fail(response.context['form'].errors) self.assertRedirects(response, reverse('journal-list', args=[self.famille.pk])) prestation = self.famille.prestations.get(duree="3:40") # Évaluation choisie auto car pas de date de début de suivi self.assertEqual(prestation.lib_prestation.code, 'aemo01') # Le type de prestation dépend de la date exacte de début de suivi. self.famille.suivi.date_debut_suivi = date.today() - timedelta(days=1) self.famille.suivi.save() data.update({'date_prestation': date.today(), 'duree': '1:00'}) response = self.client.post(add_url, data) prestation = self.famille.prestations.get(duree="1:00") self.assertEqual(prestation.lib_prestation.code, 'aemo02') data.update({'date_prestation': date.today() - timedelta(days=2), 'duree': '1:30'}) response = self.client.post(add_url, data) prestation = self.famille.prestations.get(duree="1:30") self.assertEqual(prestation.lib_prestation.code, 'aemo01') def test_affichage_prestation_menu_fam(self): self.create_prestation_fam() menu_url = reverse('prestation-menu') self.client.force_login(self.user_aemo) response = self.client.get(menu_url) self.assertContains( response, '16:00', html=True ) self.assertContains( response, '08:00', html=True ) def test_add_prestation_gen(self): add_url = reverse('prestation-gen-add') data = dict( duree='3:40', famille='', date_prestation=date.today() - timedelta(days=360), # Too old! intervenants=[self.user_aemo.pk] ) self.client.force_login(self.user_aemo) response = self.client.post(add_url, data) self.assertEqual( response.context['form'].errors, {'date_prestation': ['La saisie des prestations des mois précédents est close !']} ) data['date_prestation'] = date.today() response = self.client.post(add_url, data) self.assertRedirects(response, reverse('prestation-gen-list')) self.assertEqual(self.user_aemo.prestations.first().lib_prestation.code, 'aemo03') def test_update_prestation_fam(self): prest = self.create_prestation_fam() url = reverse('prestation-edit', args=[self.famille.pk, prest.pk]) self.client.force_login(self.user_aemo) response = self.client.get(url) self.assertEqual(response.status_code, 200) data = model_to_dict(prest) data['fichier'] = '' data['intervenants'] = [str(interv.pk) for interv in data['intervenants']] data['duree'] = '12:00' response = self.client.post(url, data=data) prest.refresh_from_db() self.assertEqual(prest.duree, timedelta(hours=12)) def test_correction_prestation_debut_suivi_passe(self): """ Quand un début de suivi est saisi dans le passé, les prestations depuis cette date sont passées en accompagnement. """ prest = self.create_prestation_fam() self.assertEqual(prest.lib_prestation.code, 'aemo01') self.assertIsNone(self.famille.suivi.date_debut_suivi) self.famille.suivi.intervenants.add( self.user_aemo, through_defaults={'role': Role.objects.get(nom='Educ')} ) self.client.force_login(self.user_aemo) response = self.client.post( reverse('famille-agenda', args=[self.famille.pk]), data={ 'date_demande': date.today() - timedelta(days=4), 'date_debut_evaluation': date.today() - timedelta(days=4), 'date_fin_evaluation': date.today() - timedelta(days=2), 'date_debut_suivi': date.today() - timedelta(days=2), }, ) self.assertEqual(response.status_code, 302) self.famille.refresh_from_db() self.assertIsNotNone(self.famille.suivi.date_debut_suivi) prest.refresh_from_db() self.assertEqual(prest.lib_prestation.code, 'aemo02') def test_droit_modification_prestation_familiale(self): prest = Prestation.objects.create( famille=self.famille, auteur=self.user_admin, lib_prestation=LibellePrestation.objects.get(code='aemo01'), date_prestation=date.today(), duree='1:10' ) prest.intervenants.set([self.user_aemo]) self.client.force_login(self.user_aemo2) with self.assertLogs('django.request', level='WARNING'): response = self.client.get(reverse('prestation-edit', args=[self.famille.pk, prest.pk])) self.assertEqual(response.status_code, 403) self.assertTrue(prest.can_edit(self.user_aemo)) self.client.force_login(self.user_admin) response = self.client.get(reverse('prestation-edit', args=[self.famille.pk, prest.pk])) self.assertEqual(response.status_code, 200) def test_affichage_prestation_personnelle(self): self.create_prestation_fam() self.create_prestation_gen() self.client.force_login(self.user_aemo) response = self.client.get(reverse('prestation-personnelle')) self.assertContains( response, 'Total prestations aemo0108:00', html=True ) self.assertContains( response, 'Total prestations aemo0308:00', html=True ) self.assertContains( response, 'Total16:00', html=True ) def test_affichage_prestation_generale(self): self.create_prestation_fam() self.create_prestation_gen() self.client.force_login(self.user_aemo) response = self.client.get(reverse('prestation-generale')) self.assertContains( response, '08:00', html=True, count=1 ) def test_suppression_prestation_famille(self): prest_fam = self.create_prestation_fam() self.client.force_login(self.user_aemo) response = self.client.post(reverse('prestation-delete', args=[prest_fam.famille_id, prest_fam.pk])) self.assertRedirects(response, reverse('journal-list', args=[prest_fam.famille_id])) self.assertFalse(Prestation.objects.filter(pk=prest_fam.pk).exists()) def test_recherche_prestations(self): texte1 = "La famille Lucky va bien" texte2 = "En été, Luke tire bien plus vite que son ombre!" prest1 = self.create_prestation_fam(texte1) prest2 = self.create_prestation_fam(texte2) self.client.force_login(self.user_aemo) url = reverse('journal-list', args=[self.famille.pk]) # Note: les chaînes à rechercher sont en majuscule pour s'assurer que # la recherche n'est pas sensible à la casse # mot contenu dans les deux enregistrements response = self.client.get(url, {"recherche": "BIEN"}) self.assertQuerySetEqual(response.context["object_list"], [prest1, prest2]) # mot contenu dans le premier enregistrement response = self.client.get(url, {"recherche": "FAMILLE"}) self.assertQuerySetEqual(response.context["object_list"], [prest1]) # mot contenu dans le deuxième enregistrement response = self.client.get(url, {"recherche": "OMBRE"}) self.assertQuerySetEqual(response.context["object_list"], [prest2]) # mot contenu dans aucun enregistrement response = self.client.get(url, {"recherche": "TINTIN"}) self.assertQuerySetEqual(response.context["object_list"], []) # deux mots contenus chacun dans un enregistrement différent response = self.client.get(url, {"recherche": "FAMILLE OMBRE"}) self.assertQuerySetEqual(response.context["object_list"], []) # deux mots contenus dans le même enregistrement response = self.client.get(url, {"recherche": "BIEN OMBRE"}) self.assertQuerySetEqual(response.context["object_list"], [prest2]) # Recherche d'un mot avec accent (mot clé sans accent) response = self.client.get(url, {"recherche": "ETE"}) self.assertQuerySetEqual(response.context["object_list"], [prest2]) # Recherche d'un mot sans accent (mot clé avec accent) response = self.client.get(url, {"recherche": "FÂMÌLLÉ"}) self.assertQuerySetEqual(response.context["object_list"], [prest1]) def test_message_recherche_prestations_sans_resultat(self): pas_de_prestation = "Aucune prestation saisie" recherche_vide = "Pas de résultat pour votre recherche." self.client.force_login(self.user_aemo) # Message pour contenu vide sans recherche response = self.client.get(reverse('journal-list', args=[self.famille.pk])) self.assertContains(response, pas_de_prestation) self.assertNotContains(response, recherche_vide) # Message pour contenu vide lors d'une recherche response = self.client.get(reverse('journal-list', args=[self.famille.pk]), {"recherche": "VIDE"}) self.assertContains(response, recherche_vide) self.assertNotContains(response, pas_de_prestation) class RapportTests(InitialDataMixin, TestCase): @classmethod def setUpTestData(cls): super().setUpTestData() cls.famille = Famille.objects.create_famille(nom='Doe') cls.educ = Utilisateur.objects.create_user('Educ', 'educ@exemple.org', '123') cls.educ.user_permissions.add(Permission.objects.get(codename='change_famille')) def setUp(self) -> None: self.create_kwargs = { 'famille': self.famille, 'auteur': self.educ, 'date': date.today(), 'situation': 'Situation initiale', 'observations': 'Observation' } def test_create_model(self): rapport = Rapport.objects.create(**self.create_kwargs) self.assertIsInstance(rapport, Rapport) self.assertEqual(str(rapport), f"Résumé du {format_d_m_Y(date.today())} pour la famille Doe - ") def test_create_view_with_observations(self): self.client.force_login(self.educ) response = self.client.get(reverse('famille-rapport-add', args=[self.famille.pk])) self.assertContains( response, '', html=True ) self.assertNotIn('Évaluation / Hypothèses', response) self.assertNotIn('Évolutions et observations', response) def test_display_rapport_with_observations(self): rapport = Rapport.objects.create(**self.create_kwargs) self.client.force_login(self.educ) response = self.client.get(reverse('famille-rapport-view', args=[self.famille.pk, rapport.pk])) self.assertContains(response, '

    Observations, évolution et hypothèses

    ', html=True) class NiveauTests(InitialDataMixin, TestCase): def setUp(self) -> None: self.famille = Famille.objects.get(nom='Haddock') self.client.force_login(self.user_aemo) def test_niveau_model(self): niv = Niveau.objects.create( famille=self.famille, niveau_interv=2, date_debut=date.today() ) self.assertEqual(niv.famille, self.famille) self.assertEqual(niv.niveau_interv, 2) self.assertEqual(niv.date_debut, date.today()) self.assertEqual(niv.date_fin, None) def test_niveau_add_view(self): auj = date.today() demain = auj + timedelta(days=1) response = self.client.post( path=reverse('niveau-add', args=[self.famille.pk]), data={'niveau_interv': 3, 'date_debut': demain}, follow=True ) self.assertContains(response, f"{format_d_m_Y(demain)}---3", html=True) def test_niveau_add_form(self): auj = date.today() demain = auj + timedelta(days=1) form = NiveauForm(famille=self.famille, data={'niveau_interv': 3, 'date_debut': demain}) self.assertTrue(form.is_valid()) def test_niveau_add_second_enregistrement(self): auj = date.today() demain = auj + timedelta(days=1) niv = Niveau.objects.create(famille=self.famille, niveau_interv=2, date_debut=auj, date_fin=None) self.client.post( path=reverse('niveau-add', args=[self.famille.pk]), data={'niveau_interv': 3, 'date_debut': demain}, follow=True ) # Mise à jour dernier enreg. niv.refresh_from_db() self.assertEqual(niv.date_fin, auj) # Test nouvel enreg. self.assertEqual(self.famille.niveaux.count(), 2) der_niv = self.famille.niveaux.last() self.assertEqual(der_niv.famille, self.famille) self.assertEqual(der_niv.niveau_interv, 3) self.assertEqual(der_niv.date_debut, demain) self.assertEqual(der_niv.date_fin, None) def test_niveau_edit_view(self): auj = date.today() demain = auj + timedelta(days=1) niv = Niveau.objects.create(famille=self.famille, niveau_interv=2, date_debut=auj, date_fin=None) self.client.post( path=reverse('niveau-edit', args=[self.famille.pk, niv.pk]), data={'niveau_interv': 3, 'date_debut': demain}, follow=True ) niv.refresh_from_db() self.assertEqual(niv.niveau_interv, 3) def test_niveau_edit_form(self): auj = date.today() demain = auj + timedelta(days=1) niv = Niveau.objects.create(famille=self.famille, niveau_interv=2, date_debut=auj, date_fin=None) form = NiveauForm(famille=self.famille, instance=niv, data={'niveau_interv': 3, 'date_debut': demain}) self.assertTrue(form.is_valid()) form.save() niv.refresh_from_db() self.assertEqual(niv.niveau_interv, 3) def test_niveau_delete(self): auj = date.today() niv = Niveau.objects.create(famille=self.famille, niveau_interv=2, date_debut=auj, date_fin=None) response = self.client.post( path=reverse('niveau-delete', args=[self.famille.pk, niv.pk]), follow=True ) self.assertEqual(len(response.context['niveaux']), 0) def test_niveau_affichage_dans_agenda(self): auj = date.today() Niveau.objects.create( famille=self.famille, niveau_interv=2, date_debut=auj - timedelta(days=10), date_fin=None ) agenda_url = reverse('famille-agenda', args=[self.famille.pk]) response = self.client.get(agenda_url) self.assertContains(response, 'Niv. d’intervention 2', html=True) # Fin niveau affiché au plus tard à fin du suivi. self.famille.suivi.date_fin_suivi = auj self.famille.suivi.save() response = self.client.get(agenda_url) self.assertEqual(response.context['niveaux'][0].date_fin_calc, auj) def test_debut_suivi_selon_niveau(self): """Début du suivi peut varier selon changement de niveau 2/3.""" auj = date.today() self.famille.suivi.date_debut_suivi = auj - timedelta(days=20) self.famille.suivi.save() Niveau.objects.create( famille=self.famille, niveau_interv=2, date_debut=auj - timedelta(days=20), date_fin=auj - timedelta(days=10) ) Niveau.objects.create( famille=self.famille, niveau_interv=3, date_debut=auj - timedelta(days=10), date_fin=None ) self.assertEqual(self.famille.suivi.debut_suivi_selon_niveau, auj - timedelta(days=10)) class UtilisateurTests(InitialDataMixin, TestCase): def test_utilisateur_list(self): self.client.force_login(self.user_admin) response = self.client.get(reverse('utilisateur-list')) self.assertEqual(len(response.context['object_list']), Utilisateur.objects.count()) def test_create_utilisateur(self): self.client.force_login(self.user_admin) response = self.client.post(reverse('utilisateur-add'), data={ 'nom': 'Muller', 'prenom': 'Hans', 'username': 'MullerH', 'sigle': 'HM', 'groups': [Group.objects.create(name='grp1').pk, Group.objects.create(name='grp2').pk], 'taux_activite': 100, 'decharge': 2, }) self.assertEqual(response.status_code, 302) user = Utilisateur.objects.get(nom='Muller') self.assertEqual(user.service.sigle, 'CRNE') self.assertEqual(user.username, 'MullerH') self.assertEqual(user.groups.count(), 2) self.assertEqual(user.charge_max, 30) def test_taux_activite(self): data = { 'nom': 'Muller', 'prenom': 'Hans', 'username': 'MullerH', 'sigle': 'HM', 'taux_activite': 90, } form = UtilisateurForm(data=data) self.assertTrue(form.is_valid()) form = UtilisateurForm(data={**data, 'taux_activite': 110}) self.assertFalse(form.is_valid()) self.assertEqual( form.errors['taux_activite'], ['Assurez-vous que cette valeur est inférieure ou égale à 100.'] ) def test_delete_utilisateur(self): user = Utilisateur.objects.create_user(username='user1', nom='Supprimer') self.client.force_login(self.user_admin) self.client.post(reverse('utilisateur-delete', args=[user.pk])) user.refresh_from_db() self.assertIsNotNone(user.date_desactivation) self.assertFalse(user.is_active) self.assertFalse(user.est_actif) response = self.client.get(reverse('utilisateur-autocomplete') + '?q=Sup') self.assertEqual(response.json()['results'], []) @override_settings(PASSWORD_HASHERS=PASSWORD_HASHERS) def test_reinit_password(self): Utilisateur.objects.create_superuser( 'somebody', 'somebody@example.org', 'somebodypassword', prenom='Jean', nom='Valjean', ) new_user = Utilisateur.objects.create_user(username='user') self.assertTrue(new_user.password.startswith('!')) # Unusable password self.client.login(username='somebody', password='somebodypassword') self.client.post(reverse('utilisateur-password-reinit', args=[new_user.pk])) new_user.refresh_from_db() self.assertTrue(new_user.password.startswith('pbkdf2_sha256$')) # Usable password def test_reinit_mobile(self): from django_otp.plugins.otp_totp.models import TOTPDevice user = Utilisateur.objects.create_user(username='user', nom="Spontz") TOTPDevice.objects.create(user=user, name='default') self.client.force_login(self.user_admin) response = self.client.post(reverse('utilisateur-otp-device-reinit', args=[user.pk]), follow=True) self.assertEqual(str(list(response.context['messages'])[0]), 'Le mobile de «Spontz » a été réinitialisé.') response = self.client.post(reverse('utilisateur-otp-device-reinit', args=[user.pk]), follow=True) self.assertEqual( str(list(response.context['messages'])[0]), 'Aucune configuration mobile trouvée pour «Spontz »' ) def test_liste_utilisateurs_actifs_inactifs(self): user1 = Utilisateur.objects.create_user( 'User1P', 'user1@exemple.org', 'user1_password', prenom='Paul', nom='User1', ) Utilisateur.objects.create_user( 'User2M', 'user2@exemple.org', 'user2_password', prenom='Max', nom='User2', ) self.client.force_login(self.user_admin) response = self.client.get(reverse('utilisateur-list')) self.assertContains(response, 'User1 Paul') self.assertContains(response, 'User2 Max') self.client.post(reverse('utilisateur-delete', args=[user1.pk])) response = self.client.get(reverse('utilisateur-list')) self.assertNotContains(response, 'User1 Paul') response = self.client.get(reverse('utilisateur-desactive-list')) self.assertContains(response, 'User1 Paul') def test_reactivation_utilisateur(self): user1 = Utilisateur.objects.create_user( 'User1P', 'user1@exemple.org', 'user1_password', prenom='Paul', nom='User1', ) Utilisateur.objects.create_user( 'User2M', 'user2@exemple.org', 'user2_password', prenom='Max', nom='User2', ) self.client.force_login(self.user_admin) response = self.client.post(reverse('utilisateur-delete', args=[user1.pk]), follow=True) self.assertNotContains(response, 'User1 Paul') user1.refresh_from_db() self.assertIsNotNone(user1.date_desactivation) response = self.client.post(reverse('utilisateur-reactiver', args=[user1.pk]), follow=True) self.assertContains(response, 'User1 Paul') user1.refresh_from_db() self.assertIsNone(user1.date_desactivation) class OtherTests(InitialDataMixin, TestCase): def setUp(self): self.client.force_login(self.user_aemo) def test_contact_list(self): response = self.client.get(reverse('contact-list')) self.assertEqual(len(response.context['object_list']), 3) response = self.client.get(reverse('contact-list') + '?service=%s' % Service.objects.get(sigle='OPEN').pk) self.assertEqual(len(response.context['object_list']), 1) response = self.client.get(reverse('contact-list') + '?role=%s' % Role.objects.get(nom='Médecin').pk) self.assertEqual(len(response.context['object_list']), 1) response = self.client.get(reverse('contact-list') + '?texte=barn') self.assertEqual(len(response.context['object_list']), 1) def test_contact_autocomplete(self): medecin = Role.objects.get(nom='Médecin') ope_service = Service.objects.create(sigle="OPEC") other_service = Service.objects.get(sigle="SSE") contact_ope = Contact.objects.create( nom="Duplain", prenom="Irma", service=ope_service ) contact_ope.roles.add(medecin) contact_other = Contact.objects.create( nom="Dupont", prenom="Paul", service=other_service ) contact_other.roles.add(medecin) response = self.client.get(reverse('contact-autocomplete') + '?q=Dup') self.assertEqual( [res['text'] for res in response.json()['results']], ['Duplain Irma (OPEC)', 'Dupont Paul (SSE)'] ) # The OPE version response = self.client.get(reverse('contact-ope-autocomplete') + '?q=Dup') self.assertEqual( [res['text'] for res in response.json()['results']], ['Duplain Irma (OPEC)'] ) def test_supression_affichage_du_contact_desactive_dans_contact_autocomplete(self): medecin = Role.objects.get(nom='Médecin') ope_service = Service.objects.create(sigle="OPEC") other_service = Service.objects.get(sigle="SSE") contact_ope = Contact.objects.create( nom="Duplain", prenom="Irma", service=ope_service, est_actif=False ) contact_ope.roles.add(medecin) contact_other = Contact.objects.create( nom="Dupont", prenom="Paul", service=other_service ) contact_other.roles.add(medecin) response = self.client.get(reverse('contact-autocomplete') + '?q=Dup') self.assertEqual( [res['text'] for res in response.json()['results']], ['Dupont Paul (SSE)'] ) def test_suppression_affichage_contact_desactive_dans_list_contact(self): medecin = Role.objects.get(nom='Médecin') ope_service = Service.objects.create(sigle="OPEC") other_service = Service.objects.get(sigle="SSE") contact_ope = Contact.objects.create( nom="Duplain", prenom="Irma", service=ope_service, est_actif=False ) contact_ope.roles.add(medecin) contact_other = Contact.objects.create( nom="Dupont", prenom="Paul", service=other_service ) contact_other.roles.add(medecin) response = self.client.get(reverse('contact-list')) self.assertNotContains(response, 'Duplain') def test_controler_doublon_contact(self): medecin = Role.objects.get(nom='Médecin') contact1 = Contact.objects.create( nom="Duplain", prenom="Irma", est_actif=True ) contact1.roles.add(medecin) doublon_url = reverse('contact-doublon') response = self.client.post(doublon_url, data={'nom': "Duplain", 'prenom': "Irma"}) self.assertEqual(response.json(), [{'nom': "Duplain", 'prenom': "Irma"}]) response = self.client.post(doublon_url, data={'nom': "Nouveau", 'prenom': "Contact"}) # Réponse vide signifie pas de doublon détecté. self.assertEqual(response.json(), '') def test_service_creation(self): s1 = Service.objects.create(sigle='lower') # transform code from lower to uppercase self.assertEqual(s1.sigle, 'LOWER') # By form self.client.force_login(self.user_admin) response = self.client.post( reverse('service-add'), data={'sigle': 'SERVICE', 'nom_complet': 'Super service'} ) self.assertRedirects(response, reverse('service-list')) self.assertEqual(Service.objects.filter(sigle='SERVICE').count(), 1) def test_service_list(self): response = self.client.get(reverse('service-list')) self.assertEqual(len(response.context['object_list']), 3) def test_raise_unique_constraint_school_center_creation(self): sc = CercleScolaire(nom='EOREN-MAIL') self.assertRaises(IntegrityError, sc.save) def test_cerclescolaire_list(self): response = self.client.get(reverse('cercle-list')) self.assertEqual(len(response.context['object_list']), 2) def test_role_create(self): self.client.force_login(self.user_admin) response = self.client.post(reverse('role-add'), data={'nom': 'ROLE1', 'famille': False}) self.assertRedirects(response, reverse('role-list')) self.assertEqual(Role.objects.filter(nom='ROLE1').count(), 1) def test_role_list(self): response = self.client.get(reverse('role-list')) self.assertGreater(len(response.context['object_list']), 10) # Les rôles "protégés" ne sont pas éditables. self.assertContains(response, 'Enfant suivi') def test_delete_used_role(self): """A role with at least one attached Personne cannot be deleted.""" role = Role.objects.get(nom="Père") Personne.objects.create_personne( famille=Famille.objects.create(nom='Schmurz'), role=role, nom='Haddock', prenom='Archibald', genre='M', date_naissance=date(1956, 2, 16), ) self.assertGreater(role.personne_set.count(), 0) self.client.force_login(self.user_admin) response = self.client.post(reverse('role-delete', args=[role.pk]), follow=True) self.assertContains(response, "Cannot delete") def test_truncate_with_more_ttag(self): from aemo.templatetags.my_tags import truncate_html_with_more txt = '

    Ceci est un très long texte HTML.
    Seconde ligne

    ' self.assertHTMLEqual( truncate_html_with_more(txt, 3), '' '

    Ceci est un…

    ' 'Afficher la suite' ) def test_info_ope_ttag(self): from aemo.templatetags.my_tags import info_ope self.assertEqual( info_ope(Contact.objects.get(nom='Sybarnez')), 'Sybarnez Tina' ) def test_check_date_allowed(self): with freeze_time("2021-01-20"): self.assertFalse(Prestation.check_date_allowed(self.user_aemo, date(2020, 1, 20))) with freeze_time("2021-01-04"): self.assertFalse(Prestation.check_date_allowed(self.user_aemo, date(2020, 11, 30))) self.assertTrue(Prestation.check_date_allowed(self.user_aemo, date(2020, 12, 2))) self.assertTrue(Prestation.check_date_allowed(self.user_aemo, date(2021, 1, 2))) with freeze_time("2020-11-02"): self.assertFalse(Prestation.check_date_allowed(self.user_aemo, date(2019, 10, 15))) self.assertTrue(Prestation.check_date_allowed(self.user_aemo, date(2020, 10, 15))) self.assertTrue(Prestation.check_date_allowed(self.user_aemo, date(2020, 11, 12))) def test_duration_field(self): class SomeForm(Form): duration = HMDurationField() form = SomeForm({'duration': timedelta(days=1, hours=2, minutes=21, seconds=4)}) self.assertInHTML( '', form.as_div() ) class TestExporter(ExportReporting): """A fake exporter class that just collect data in lists to be able to assert the contents.""" def __init__(self): super().__init__() self.sheets = {} self._current_sh = None def __call__(self): # This allows to provide an instance to mock return self def setup_sheet(self, title): self.sheets[title] = [] self._current_sh = self.sheets[title] def write_line(self, values, **kwargs): self._current_sh.append(values) class StatTests(TestCase): @classmethod def setUpTestData(cls): group_aemo = Group.objects.create(name='aemo') cls.user = Utilisateur.objects.create( username='me', first_name='Jean', last_name='Valjean', ) cls.user_admin = Utilisateur.objects.create(username='admin') cls.user_admin.user_permissions.add(Permission.objects.get(codename='export_stats')) user_haut = Utilisateur.objects.create(username='ld', prenom='Lise', nom="Duhaut") user_haut.groups.add(group_aemo) user_bas = Utilisateur.objects.create(username='jd', prenom='Jean', nom="Dubas") user_bas.groups.add(group_aemo) role_referent = Role.objects.create(nom='Référent', est_famille=False) cls.enf_suivi = Role.objects.create(nom='Enfant suivi', est_famille=True) cls.role_pere = Role.objects.create(nom='Père', est_famille=True) cls.role_mere = Role.objects.create(nom='Mère', est_famille=True) cls.famille_litt = Famille.objects.create_famille( equipe='littoral', nom='Haddock', rue='Château1', npa=2000, localite='Moulinsart', ) Personne.objects.create_personne( famille=cls.famille_litt, role=cls.enf_suivi, nom='Haddock', prenom='Archibald', genre='M', date_naissance=date(1996, 2, 16) ) Personne.objects.create_personne( famille=cls.famille_litt, role=cls.enf_suivi, nom='Haddock', prenom='Honorine', genre='F', date_naissance=date(1999, 11, 2) ) cls.famille_litt.suivi.date_demande = '2019-01-01' cls.famille_litt.suivi.intervenants.add(user_bas, through_defaults={'role': role_referent}) cls.famille_litt.suivi.save() cls.famille_mont = Famille.objects.create_famille( equipe='montagnes', nom='Tournesol', rue='Château1', npa=2000, localite='Moulinsart', ) Personne.objects.create_personne( famille=cls.famille_mont, role=cls.enf_suivi, nom='Tournesol', prenom='Tryphon', genre='M', date_naissance=date(1991, 1, 3) ) cls.famille_mont.suivi.date_demande = '2019-01-01' cls.famille_mont.suivi.intervenants.add(user_haut, through_defaults={'role': role_referent}) cls.famille_mont.suivi.save() LibellePrestation.objects.bulk_create([ LibellePrestation(code='aemo01', nom='Évaluation AEMO'), LibellePrestation( code='aemo04', nom='Activités ASE'), ]) def test_accueil_statistiques(self): self.client.force_login(self.user_admin) response = self.client.get(reverse('stats')) self.assertContains(response, 'Statistiques du 1er') @freeze_time("2020-12-04") def test_accueil_statistiques_decembre(self): self.client.force_login(self.user_admin) response = self.client.get(reverse('stats')) self.assertEqual(response.context['date_form'].data['end_month'], 1) self.assertEqual(response.context['date_form'].data['end_year'], 2021) def test_temps_total_prestations(self): """ Test Famille.temps_total_prestations()/temps_total_prestations_reparti(), Test Utilisateur.temps_total_prestations() """ self.assertEqual(self.famille_litt.temps_total_prestations(), timedelta(0)) auj = date.today() mois_sui1 = date(auj.year, auj.month, 3) mois_sui2 = date(auj.year, auj.month, 4) user2 = Utilisateur.objects.create( username='you', first_name='Hans', last_name='Zwei', ) user2.groups.add(Group.objects.get(name='aemo')) p1 = Prestation.objects.create( auteur=self.user, famille=self.famille_litt, date_prestation=auj, duree='0:45' ) p1.intervenants.set([self.user]) p2 = Prestation.objects.create( auteur=self.user, famille=self.famille_litt, date_prestation=mois_sui1, duree='1:0' ) # Chaque intervenant saisit ses propres prestations p2.intervenants.set([self.user]) p3 = Prestation.objects.create( auteur=self.user, famille=self.famille_litt, date_prestation=mois_sui2, duree='1:05' ) p3.intervenants.set([user2]) # Avec ce processus, la même prestation peut avoir des durées différentes!!! # p1 (00:45) + 2 interv. x p2 (1:00) >> p1(00:45) + p2(1:00) + p3(1:05) = 2:50 self.assertEqual(self.famille_litt.temps_total_prestations(), timedelta(hours=2, minutes=50)) self.assertEqual(self.famille_litt.temps_total_prestations_reparti(), timedelta(hours=1, minutes=25)) # self.user = p1 (00:45) + p2 (1:00) = 1:45 # user2 = p3(1:05) self.assertEqual(format_duree(self.user.temps_total_prestations('aemo')), '01:45') self.assertEqual(format_duree(user2.temps_total_prestations('aemo')), '01:05') def test_stats(self): auj = date.today() mois_sui1 = date(auj.year, auj.month, 3) user_bas = Utilisateur.objects.get(nom='Dubas') p = Prestation.objects.create( auteur=self.user, famille=self.famille_litt, date_prestation=auj, duree='0:45' ) p.intervenants.set([user_bas]) p = Prestation.objects.create( auteur=self.user, famille=self.famille_litt, date_prestation=mois_sui1, duree='1:00' ) p.intervenants.set([user_bas]) p = Prestation.objects.create( auteur=self.user, famille=self.famille_litt, date_prestation=auj, duree='0:00', manque=True, ) # Cette famille est du littoral, mais n'a pas Lise Dubas comme référente Famille.objects.create_famille( equipe='littoral', nom='Tintin', rue='Château1', npa=2000, localite='Moulinsart', ) months = [Month(date.today().year, date.today().month)] stats = StatistiquesView( date_start=date.today().replace(day=1), date_end=(date.today().replace(day=1) + timedelta(days=35)).replace(day=1), ).get_stats(months) self.assertEqual(stats['familles']['familles_evaluees']['total'], 3) self.assertEqual(stats['familles']['enfants_evalues']['total'], 3) self.assertEqual(stats['familles']['rdv_manques']['total'], 1) def test_total_mensuel(self): """Test Famille.total_mensuel() method.""" famille = Famille.objects.get(nom='Haddock') auj = date.today() mois_suiv = auj + timedelta(days=31) self.assertEqual(famille.total_mensuel(auj), timedelta(0)) Prestation.objects.bulk_create([ Prestation( auteur=self.user, famille=famille, date_prestation=date(auj.year, auj.month, 1), duree='1:30' ), Prestation( auteur=self.user, famille=famille, date_prestation=date(auj.year, auj.month, 25), duree='0:15' ), # Not included in this month Prestation( auteur=self.user, famille=famille, date_prestation=date(mois_suiv.year, mois_suiv.month, 1), duree='0:15' ), ]) self.assertEqual(famille.total_mensuel(auj), timedelta(minutes=105)) def test_total_prestations(self): famille = Famille.objects.get(nom='Haddock') user = Utilisateur.objects.get(nom='Duhaut') my_group = Group.objects.get(name='aemo') my_group.user_set.add(user) prestation_data = { 'auteur': self.user, 'famille': famille, 'date_prestation': date(2019, 3, 1), 'lib_prestation': LibellePrestation.objects.get(code='aemo01'), } Prestation.objects.bulk_create([ Prestation(**{**prestation_data, 'duree': '3:40'}), Prestation(**{**prestation_data, 'duree': '6:40'}), # Not included in this month Prestation(**{**prestation_data, 'date_prestation': date(2019, 4, 1), 'duree': '2:00'}), ]) for p in Prestation.objects.filter(famille=famille): p.intervenants.set([user]) self.assertEqual(format_duree(user.total_mensuel('aemo', 3, 2019)), '10:20') self.assertEqual(format_duree(user.totaux_mensuels('aemo', 2019)[3]), '02:00') self.assertEqual(format_duree(user.total_annuel('aemo', 2019)), '12:20') totaux_2019 = Prestation.temps_totaux_mensuels(2019) self.assertEqual(totaux_2019[0], timedelta()) self.assertEqual(format_duree(totaux_2019[2]), '10:20') self.assertEqual(format_duree(totaux_2019[3]), '02:00') self.assertEqual(format_duree(Prestation.temps_total_general(2019)), '12:20') user.user_permissions.add(Permission.objects.get(codename='export_stats')) self.client.force_login(user) exp = TestExporter() with patch('aemo.views.ExportReporting', new=exp): self.client.post(reverse('export-prestation'), {'mois': '3', 'annee': '2019'}) self.assertEqual(format_duree(exp._total_spe['eval']), '10:20') def test_export_prestations_decembre(self): self.client.force_login(self.user_admin) response = self.client.post(reverse('export-prestation'), {'mois': '12', 'annee': '2019'}) self.assertEqual(response.status_code, 200) @freeze_time("2020-12-14") def test_affichage_prestation(self): famille = Famille.objects.get(nom='Tournesol') auj = date.today() self.assertEqual(famille.total_mensuel(auj), timedelta(0)) user_haut = Utilisateur.objects.get(nom='Duhaut') user_haut.taux_activite = 100.0 user_haut.save() Prestation.objects.bulk_create([ Prestation(auteur=user_haut, famille=famille, date_prestation=date(auj.year, 3, 1), duree='1:45'), Prestation(auteur=user_haut, famille=famille, date_prestation=date(auj.year, 5, 25), duree='0:15'), # Not included in this month Prestation(auteur=user_haut, famille=famille, date_prestation=date(auj.year, 7, 1), duree='0:15'), ]) for p in Prestation.objects.filter(famille=famille): p.intervenants.set([user_haut]) self.user.user_permissions.add(Permission.objects.get(codename='export_stats')) self.client.force_login(self.user) response = self.client.get(reverse('stats-prestations')) data = response.context['intervenants'][user_haut] self.assertEqual(format_duree(data['heures_prestees'][2]), '01:45') self.assertEqual(format_duree(data['heures_prestees'][4]), '00:15') self.assertEqual(format_duree(data['heures_prestees'][6]), '00:15') self.assertEqual(format_duree(data['tot_prestees']), '02:15') self.assertEqual(format_duree(response.context['totaux_prest_mensuels'][Month(auj.year, 3)]['total']), '01:45') self.assertEqual(format_duree(response.context['total_gen']), '02:15') @skip("This statistic is currently deactivated") def test_stats_interv(self): last_year = date.today().year - 1 famille = Famille.objects.get(nom='Haddock') famille.suivi.date_debut_suivi = date(last_year, 2, 1) famille.suivi.save() user_bas = Utilisateur.objects.get(nom='Dubas') self.client.force_login(self.user_admin) params = '&'.join( f'{key}={val}' for key, val in { 'start_year': last_year, 'start_month': '3', 'end_year': last_year, 'end_month': '5' }.items() ) response = self.client.get(reverse('stats-interv') + '?' + params) self.assertEqual(response.context['interv_spe'][user_bas]['num_familles']['total'], 1) def test_stats_par_niveau(self): auj = date.today() Niveau.objects.create( famille=self.famille_litt, niveau_interv=2, date_debut=auj - timedelta(days=1) ) # Niveau obsolète Niveau.objects.create( famille=self.famille_litt, niveau_interv=1, date_debut=auj - timedelta(days=360), date_fin=auj - timedelta(days=100) ) Prestation.objects.create( famille=self.famille_litt, auteur=self.user, date_prestation=auj, lib_prestation=LibellePrestation.objects.get(code='aemo04'), duree=timedelta(minutes=90) ) ilya2mois = auj - timedelta(days=60) params = '&'.join( f'{key}={val}' for key, val in { 'start_year': ilya2mois.year, 'start_month': ilya2mois.month, 'end_year': auj.year, 'end_month': auj.month, }.items() ) self.client.force_login(self.user_admin) response = self.client.get(reverse('stats-niveaux') + '?' + params) self.assertEqual(response.status_code, 200) self.assertEqual( response.context['stats'][2]['aemo04'][Month.from_date(auj)], timedelta(minutes=90) ) self.assertEqual( response.context['stats'][2]['aemo04']['total'], timedelta(minutes=90) ) class ExportTests(InitialDataMixin, TestCase): def setUp(self): self.client.force_login(self.user_admin) self.cfg_date = date(2019, 10, 3) self.cfg_sheet = 'En_cours_{}.{}'.format(self.cfg_date.month, self.cfg_date.year) self.cfg_export_month = {'mois': self.cfg_date.month, 'annee': self.cfg_date.year} self.entetes_communs = [ 'Institution', 'Prestation', 'Nom', 'Prenom', 'Genre', 'Date de naissance', 'Adresse', 'NPA', 'Localité', 'Canton', 'OPE', 'Nom mère', 'Prénom mère', 'Nom père', 'Prénom père', 'Autorité parentale', 'Statut marital', 'Statut financier', 'Fam. monopar.', 'Nbre enfants', 'Date demande', 'Provenance', 'Motif demande', 'Début suivi' ] self.entetes_nouveaux = self.entetes_communs self.entetes_en_cours = self.entetes_communs + ['H. Évaluation', 'H. Suivi', 'H. Prest. gén.'] self.entetes_termines = (self.entetes_communs + ['Date fin suivi', 'Motif fin suivi', 'Destination', 'Total heures']) self.enf_suivi = Role.objects.get(nom='Enfant suivi', est_famille=True) self.role_pere = Role.objects.get(nom='Père', est_famille=True) self.role_mere = Role.objects.get(nom='Mère', est_famille=True) def test_entete_nouveux_suivis(self): exp = TestExporter() with patch('aemo.views.ExportReporting', new=exp): self.client.post(reverse('export-prestation'), {'mois': '10', 'annee': '2019'}) sheet_name = 'Nouveaux_10.2019' self.assertEqual(len(exp.sheets[sheet_name]), 1) self.assertEqual(exp.sheets[sheet_name][0], self.entetes_nouveaux) def test_entete_suivis_en_cours(self): exp = TestExporter() with patch('aemo.views.ExportReporting', new=exp): self.client.post(reverse('export-prestation'), {'mois': '10', 'annee': '2019'}) sheet_name = 'En_cours_10.2019' self.assertEqual(len(exp.sheets[sheet_name]), 1) self.assertEqual(exp.sheets[sheet_name][0], self.entetes_en_cours) def test_entete_suivis_termines(self): exp = TestExporter() with patch('aemo.views.ExportReporting', new=exp): self.client.post(reverse('export-prestation'), {'mois': '10', 'annee': '2019'}) sheet_name = 'Terminés_10.2019' self.assertEqual(len(exp.sheets[sheet_name]), 1) self.assertEqual(exp.sheets[sheet_name][0], self.entetes_termines) def test_export_prestations_decembre(self): self.client.force_login(self.user_admin) response = self.client.post(reverse('export-prestation'), {'mois': '12', 'annee': '2019'}) self.assertEqual(response.status_code, 200) def test_date_nouveau_suivi(self): fam1 = self.create_famille(name='Haddock') fam1.suivi.date_demande = '2019-09-20' fam1.suivi.save() fam2 = self.create_famille(name='Tournesol') fam2.suivi.date_demande = '2019-10-20' fam2.suivi.save() fam3 = self.create_famille(name='Castafiore') fam3.suivi.date_demande = '2019-11-20' fam3.suivi.save() exp = TestExporter() with patch('aemo.views.ExportReporting', new=exp): self.client.post(reverse('export-prestation'), {'mois': '10', 'annee': '2019'}) sheet_name = 'Nouveaux_10.2019' self.assertEqual(len(exp.sheets[sheet_name]), 2) self.assertEqual([line[2] for line in exp.sheets[sheet_name]], ['Nom', 'Tournesol']) def test_date_suivi_en_cours(self): fam1 = self.create_famille(name='Haddock') fam1.suivi.date_demande = '2019-09-20' fam1.suivi.save() fam2 = self.create_famille(name='Tournesol') fam2.suivi.date_demande = '2019-10-20' fam2.suivi.save() fam3 = self.create_famille(name='Castafiore') fam3.suivi.date_demande = '2019-11-20' fam3.suivi.save() self.benef1 = dict(nom='Haddock', date_admission='2019-10-02') self.benef2 = dict(nom='Tournesol', date_admission='2019-09-30') def test_date_suivi_termine(self): fam1 = self.create_famille(name='Haddock') fam1.suivi.date_demande = '2019-09-20' fam1.suivi.date_fin_suivi = '2019-10-31' fam1.suivi.save() fam2 = self.create_famille(name='Tournesol') fam2.suivi.date_demande = '2019-10-20' fam2.suivi.save() fam3 = self.create_famille(name='Castafiore') fam3.suivi.date_demande = '2019-11-20' fam3.suivi.date_fin_suivi = '2019-12-31' fam3.suivi.save() exp = TestExporter() with patch('aemo.views.ExportReporting', new=exp): self.client.post(reverse('export-prestation'), {'mois': '10', 'annee': '2019'}) sheet_name = 'Terminés_10.2019' self.assertEqual(len(exp.sheets[sheet_name]), 2) self.assertEqual([line[2] for line in exp.sheets[sheet_name]], ['Nom', 'Haddock']) def test_un_enfant_par_ligne(self): fam = self.create_famille() fam.suivi.date_demande = '2019-10-20' fam.suivi.save() Personne.objects.create_personne( famille=fam, role=Role.objects.get(nom='Enfant suivi'), nom='Haddock', prenom='Ursule', genre='M', date_naissance=date(2008, 11, 6), ) exp = TestExporter() with patch('aemo.views.ExportReporting', new=exp): self.client.post(reverse('export-prestation'), {'mois': '10', 'annee': '2019'}) sheet_name = 'Nouveaux_10.2019' self.assertEqual(len(exp.sheets[sheet_name]), 3) self.assertEqual( [(line[2], line[3]) for line in exp.sheets['Nouveaux_10.2019']], [('Nom', 'Prenom'), ('Haddock', 'Ursule'), ('Haddock', 'Toto')] ) def test_repartition_temps_total_prestation_mensuel_entre_enfants(self): fam = self.create_famille() fam.suivi.date_demande = '2019-10-20' fam.suivi.save() Personne.objects.create_personne( famille=fam, role=Role.objects.get(nom='Enfant suivi'), nom='Haddock', prenom='Ursule', genre='M', date_naissance=date(2008, 11, 6), ) aemo01 = LibellePrestation.objects.get(code='aemo01') Prestation.objects.bulk_create([ Prestation( auteur=self.user_aemo, famille=fam, date_prestation=date(2019, 10, 21), lib_prestation=aemo01, duree='3:40' ), Prestation( auteur=self.user_aemo, famille=fam, date_prestation=date(2019, 10, 22), lib_prestation=aemo01, duree='6:40' ), Prestation( auteur=self.user_aemo, famille=fam, date_prestation=date(2019, 10, 30), lib_prestation=aemo01, duree='2:00' ), ]) for prest in Prestation.objects.all(): prest.intervenants.add(self.user_aemo) exp = TestExporter() with patch('aemo.views.ExportReporting', new=exp): self.client.post(reverse('export-prestation'), {'mois': '10', 'annee': '2019'}) sheet_name = 'En_cours_10.2019' self.assertEqual(len(exp.sheets[sheet_name]), 3) self.assertEqual( [(line[2], line[3], line[24]) for line in exp.sheets[sheet_name]], [('Nom', 'Prenom', 'H. Évaluation'), ('Haddock', 'Ursule', timedelta(hours=6, minutes=10)), ('Haddock', 'Toto', timedelta(hours=6, minutes=10)), ] ) def test_export_nouvelle_famille(self): fam = self.create_famille() fam.suivi.date_demande = '2019-10-20' fam.suivi.date_debut_suivi = '2019-10-21' fam.suivi.motif_demande = ['integration'] fam.suivi.save() Prestation.objects.bulk_create([ Prestation(auteur=self.user_aemo, famille=fam, date_prestation=date(2019, 10, 21), duree='3:40'), Prestation(auteur=self.user_aemo, famille=fam, date_prestation=date(2019, 10, 22), duree='6:40'), # Not included in this month Prestation(auteur=self.user_aemo, famille=fam, date_prestation=date(2019, 11, 1), duree='2:00'), ]) self.assertEqual(Prestation.objects.filter(famille=fam).count(), 3) for p in Prestation.objects.filter(famille=fam): p.intervenants.set([self.user_aemo]) exp = TestExporter() with patch('aemo.views.ExportReporting', new=exp): self.client.post(reverse('export-prestation'), {'mois': '10', 'annee': '2019'}) sheet_name = 'Nouveaux_10.2019' self.assertEqual(len(exp.sheets[sheet_name]), 2) self.assertEqual( exp.sheets[sheet_name][1], ['Fondation Transit', 'AEMO', 'Haddock', 'Toto', 'M', '16.02.2010', 'Château1', '2000', 'Moulinsart', 'NE', 'Sybarnez Tina', '', '', 'Haddock', 'Archibald', 'Conjointe', 'Divorcé', '', 'NON', 1, '20.10.2019', '', 'Aide à l’intégration', '21.10.2019'] ) def test_export_total_prestation_mois_courant(self): fam = self.create_famille() fam.suivi.date_demande = '2019-10-20' fam.suivi.save() aemo01 = LibellePrestation.objects.get(code='aemo01') Prestation.objects.bulk_create([ Prestation( auteur=self.user_aemo, famille=fam, date_prestation=date(2019, 10, 21), lib_prestation=aemo01, duree='3:40' ), Prestation( auteur=self.user_aemo, famille=fam, date_prestation=date(2019, 10, 22), lib_prestation=aemo01, duree='6:40' ), # Not included in this month Prestation( auteur=self.user_aemo, famille=fam, date_prestation=date(2019, 11, 1), lib_prestation=aemo01, duree='2:00' ), ]) for p in Prestation.objects.filter(famille=fam): p.intervenants.set([self.user_aemo]) exp = TestExporter() with patch('aemo.views.ExportReporting', new=exp): self.client.post(reverse('export-prestation'), {'mois': '10', 'annee': '2019'}) self.assertEqual(len(exp.sheets['En_cours_10.2019']), 2) self.assertEqual(exp.sheets['En_cours_10.2019'][1][24], timedelta(hours=10, minutes=20)) def test_export_prest_gen(self): familles = [self.create_famille('Fam_{}'.format(i)) for i in range(5)] for famille in familles: famille.suivi.date_demande = date(2019, 10, 1) famille.suivi.save() prestation_data = { 'auteur': self.user_aemo, 'famille': None, 'date_prestation': date(2019, 10, 21), 'lib_prestation': LibellePrestation.objects.get(code='aemo03') } Prestation.objects.create(**{**prestation_data, 'duree': '6:50'}) Prestation.objects.create(**{**prestation_data, 'duree': '3:50'}) for prest in Prestation.objects.all(): prest.intervenants.add(self.user_aemo) exp = TestExporter() with patch('aemo.views.ExportReporting', new=exp): self.client.post(reverse('export-prestation'), self.cfg_export_month) self.assertEqual(len(exp.sheets[self.cfg_sheet]), 6) self.assertEqual(format_duree(exp._total_spe['gen']), '10:40') # Les 10h40 sont divisées par le nombre d'enfants suivis (= 5 * 2h08): self.assertEqual(exp.sheets[self.cfg_sheet][1][26], timedelta(hours=2, minutes=8)) self.assertEqual(exp.sheets[self.cfg_sheet][2][26], timedelta(hours=2, minutes=8)) self.assertEqual(exp.sheets[self.cfg_sheet][3][26], timedelta(hours=2, minutes=8)) self.assertEqual(exp.sheets[self.cfg_sheet][4][26], timedelta(hours=2, minutes=8)) self.assertEqual(exp.sheets[self.cfg_sheet][5][26], timedelta(hours=2, minutes=8)) def test_export_evaluation(self): familles = [self.create_famille('Fam_{}'.format(i)) for i in range(3)] for famille in familles: famille.suivi.date_demande = date(2019, 10, 1) famille.suivi.save() prestation_data = { 'auteur': self.user_aemo, 'date_prestation': date(2019, 10, 21), 'lib_prestation': LibellePrestation.objects.get(code='aemo01'), } Prestation.objects.bulk_create([ Prestation(**{**prestation_data, 'famille': familles[0], 'duree': '6:50'}), Prestation(**{**prestation_data, 'famille': familles[0], 'duree': '1:00'}), Prestation(**{**prestation_data, 'famille': familles[1], 'duree': '1:25'}), Prestation(**{**prestation_data, 'famille': familles[2], 'duree': '4:40'}), ]) for prest in Prestation.objects.all(): prest.intervenants.add(self.user_aemo) exp = TestExporter() with patch('aemo.views.ExportReporting', new=exp): self.client.post(reverse('export-prestation'), self.cfg_export_month) sheet_name = exp.sheets[self.cfg_sheet] self.assertEqual(len(sheet_name), 4) self.assertEqual(sheet_name[1][24], timedelta(hours=7, minutes=50)) self.assertEqual(sheet_name[2][24], timedelta(hours=1, minutes=25)) self.assertEqual(sheet_name[3][24], timedelta(hours=4, minutes=40)) self.assertEqual(format_duree(exp._total_spe['eval']), '13:55') def test_export_suivi(self): familles = [self.create_famille('Fam_{}'.format(i)) for i in range(3)] for famille in familles: famille.suivi.date_demande = date(2019, 10, 1) famille.suivi.save() prestation_data = dict( {'auteur': self.user_aemo, 'date_prestation': date(2019, 10, 21), 'lib_prestation': LibellePrestation.objects.get(code='aemo02')} ) Prestation.objects.bulk_create([ Prestation(**{**prestation_data, 'famille': familles[0], 'duree': '1:10'}), Prestation(**{**prestation_data, 'famille': familles[0], 'duree': '2:20'}), Prestation(**{**prestation_data, 'famille': familles[1], 'duree': '3:30'}), Prestation(**{**prestation_data, 'famille': familles[2], 'duree': '4:45'}), ]) for prest in Prestation.objects.all(): prest.intervenants.add(self.user_aemo) exp = TestExporter() with patch('aemo.views.ExportReporting', new=exp): self.client.post(reverse('export-prestation'), self.cfg_export_month) sheet_name = exp.sheets[self.cfg_sheet] self.assertEqual(len(sheet_name), 4) self.assertEqual(sheet_name[1][25], timedelta(hours=3, minutes=30)) self.assertEqual(sheet_name[2][25], timedelta(hours=3, minutes=30)) self.assertEqual(sheet_name[3][25], timedelta(hours=4, minutes=45)) self.assertEqual(format_duree(exp._total_spe['suivi']), '11:45') def test_export_authorization(self): self.client.force_login(self.user_externe) # Test denied access without export_stats permission with self.assertLogs('django.request', level='WARNING'): response = self.client.get(reverse('export-prestation')) self.assertEqual(response.status_code, 403) self.user_externe.user_permissions.add(Permission.objects.get(codename='export_stats')) # Test default selected options in export form with patch('aemo.views.date') as mock_date: mock_date.today.return_value = date(2019, 7, 3) response = self.client.get(reverse('export-prestation')) self.assertContains( response, '' ) self.assertContains( response, '' ) mock_date.today.return_value = date(2020, 1, 30) response = self.client.get(reverse('export-prestation')) self.assertContains( response, '' ) self.assertContains( response, '' ) response = self.client.post(reverse('export-prestation'), data={'mois': '2', 'annee': '2019'}) self.assertEqual(response['Content-Type'], openxml_contenttype) self.assertEqual( response['Content-Disposition'], 'attachment; filename="aemo_reporting_02_2019.xlsx"' ) def test_openxml_export_sheets(self): # "Nouvelle" famille famille = Famille.objects.create_famille( equipe='littoral', nom='NouvelleFamille', rue='Château 4', npa=2000, localite='Moulinsart', ) famille.suivi.date_demande = '2019-02-10' # famille.suivi.date_fin_suivi = '2019-05-30' famille.suivi.save() Personne.objects.create_personne( famille=famille, role=Role.objects.get(nom='Enfant suivi'), nom='NouvelleFamille', prenom='Hégésipe', genre='M', date_naissance=date(1996, 2, 16) ) # Famille "en cours" famille = Famille.objects.create_famille( equipe='littoral', nom='FamilleEnCours', rue='Château 5', npa=2000, localite='Moulinsart', autorite_parentale='conjointe', statut_marital='divorce', monoparentale=False, ) famille.suivi.date_demande = '2019-01-01' famille.suivi.date_debut_suivi = '2019-01-28' ope_service = Service.objects.create(sigle="OPEC") famille.suivi.ope_referent = Contact.objects.create( nom="Duplain", prenom="Irma", service=ope_service ) famille.suivi.save() Personne.objects.create_personne( famille=famille, role=Role.objects.get(nom='Enfant suivi'), nom='FamilleEnCours', prenom='Alain', genre='M', date_naissance=date(2003, 4, 23), localite='Moulinsart', ) Personne.objects.create_personne( famille=famille, role=self.role_mere, nom='FamilleEnCours', prenom='Judith', genre='F', date_naissance=date(1974, 11, 2) ) Personne.objects.create_personne( famille=famille, role=self.role_pere, nom='NomDuPere', prenom='Hans', genre='M', date_naissance=date(1968, 3, 13) ) # Famille "terminée" famille = Famille.objects.create_famille( nom='FamilleTerminée', rue='Château 6', npa=2000, localite='Moulinsart', ) famille.suivi.date_demande = '2018-10-02' famille.suivi.date_debut_suivi = '2018-11-11' famille.suivi.date_fin_suivi = '2019-02-20' famille.suivi.motif_fin_suivi = 'relai' famille.suivi.save() Personne.objects.create_personne( famille=famille, role=self.enf_suivi, nom='FamilleTerminée', prenom='Jeanne', genre='F', date_naissance=date(1998, 12, 14) ) self.client.force_login(self.user_admin) exp = TestExporter() with patch('aemo.views.ExportReporting', new=exp): self.client.post(reverse('export-prestation'), {'mois': '2', 'annee': '2019'}) self.assertEqual(len(exp.sheets['En_cours_02.2019']), 4) self.assertEqual(exp.sheets['En_cours_02.2019'][0], self.entetes_en_cours) self.assertEqual( exp.sheets['En_cours_02.2019'][1], ['Fondation Transit', 'AEMO', 'FamilleEnCours', 'Alain', 'M', '23.04.2003', '', '', 'Moulinsart', 'NE', 'Duplain Irma', 'FamilleEnCours', 'Judith', 'NomDuPere', 'Hans', 'Conjointe', 'Divorcé', '', 'NON', 1, '01.01.2019', '', '', '28.01.2019', timedelta(0), timedelta(0), timedelta(0)] ) self.assertEqual( [(line[2], line[3]) for line in exp.sheets['En_cours_02.2019'][1:]], [('FamilleEnCours', 'Alain'), ('FamilleTerminée', 'Jeanne'), ('NouvelleFamille', 'Hégésipe')] ) self.assertEqual(len(exp.sheets['Nouveaux_02.2019']), 2) self.assertEqual(exp.sheets['Nouveaux_02.2019'][0], self.entetes_nouveaux) self.assertEqual( exp.sheets['Nouveaux_02.2019'][1], ['Fondation Transit', 'AEMO', 'NouvelleFamille', 'Hégésipe', 'M', '16.02.1996', '', '', '', 'NE', '', '', '', '', '', '', '', '', '', 1, '10.02.2019', '', '', '' ] ) self.assertEqual(len(exp.sheets['Terminés_02.2019']), 2) self.assertEqual(exp.sheets['Terminés_02.2019'][0], self.entetes_termines) self.assertEqual( exp.sheets['Terminés_02.2019'][1], ['Fondation Transit', 'AEMO', 'FamilleTerminée', 'Jeanne', 'F', '14.12.1998', '', '', '', 'NE', '', '', '', '', '', '', '', '', '', 1, '02.10.2018', '', '', '11.11.2018', '20.02.2019', 'Relai vers autre service', '', timedelta(0) ] ) famille = Famille.objects.get(nom='NouvelleFamille') famille.suivi.motif_fin_suivi = 'erreur' famille.suivi.date_fin_suivi = date(2019, 2, 17) famille.suivi.save() famille = Famille.objects.get(nom='FamilleTerminée') famille.suivi.motif_fin_suivi = 'erreur' famille.suivi.date_fin_suivi = date(2019, 2, 17) famille.suivi.save() exp = TestExporter() with patch('aemo.views.ExportReporting', new=exp): self.client.post(reverse('export-prestation'), {'mois': '2', 'annee': '2019'}) # Plus de famille, puisque les motifs de fin de suivi "erreur" ne sont pas pris en compte self.assertEqual(len(exp.sheets['Nouveaux_02.2019']), 1) self.assertEqual(len(exp.sheets['Terminés_02.2019']), 1) # 'NouvelleFamille' plus exportée self.assertEqual(len(exp.sheets['En_cours_02.2019']), 2)