From c023fdc182df8d4e05cd4bb2696ad06f1230a1a5 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Thu, 25 Apr 2019 18:21:06 +0200 Subject: [PATCH] =?UTF-8?q?nanterre:=20am=C3=A9liore=20le=20passage=20?= =?UTF-8?q?=C3=A0=20la=20majorit=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Les trames sont envoyés de manière différée pour ne pas ralentir le processus. - Le cas des enfants sans adresses ou avec deux adresses est pris en compte. - Un message particulier est envoyé dans le journal pour le processus de base et pour chaque trame, le message de base a été modifié pour comporter deux parties une fixe en fonction de l'action et un deuxième variable en fonction du statut. --- tests/test_nanterre.py | 30 ++++--- zoo/zoo_nanterre/fragments.py | 33 +++++--- .../management/commands/rsu-cron.py | 6 +- zoo/zoo_nanterre/utils.py | 83 +++++++++++++++---- 4 files changed, 106 insertions(+), 46 deletions(-) diff --git a/tests/test_nanterre.py b/tests/test_nanterre.py index 8fdbfa2..d217ea5 100644 --- a/tests/test_nanterre.py +++ b/tests/test_nanterre.py @@ -1216,7 +1216,7 @@ def test_rsu_cron(db, settings, nanterre_classic_family): assert Log.objects.count() == 20 call_command('rsu-cron', verbosity=0) - assert Log.objects.count() == 10 + assert Log.objects.count() == 11 def test_passage_a_la_majorite(db, settings, nanterre_classic_family, freezer): @@ -1241,20 +1241,10 @@ def test_passage_a_la_majorite(db, settings, nanterre_classic_family, freezer): # passage à la majorité de lilou requests = [] - @httmock.urlmatch() - def technocarte_ok(url, request): - requests.append(request) - return httmock.response( - 200, 'null', - { - 'Content-Type': 'application/json', - }) - with httmock.HTTMock(technocarte_ok): - result = passage_a_la_majorite() + result = passage_a_la_majorite() assert result['updated_entities'] == 1 assert result['deleted_relations'] == 2 - assert not result['errors'] assert Entity.objects.filter(schema__slug='individu').count() == 4 assert Entity.objects.filter(schema__slug='adresse').count() == 2 assert Relation.objects.filter(schema__slug='habite').count() == 4 @@ -1262,7 +1252,22 @@ def test_passage_a_la_majorite(db, settings, nanterre_classic_family, freezer): assert Entity.objects.filter(content__statut_legal='majeur').count() == 3 assert Entity.objects.filter(content__prenoms='LILOU', content__statut_legal='majeur').count() == 1 + assert Job.objects.count() == 1 + assert Job.objects.todo().count() == 1 + assert len(requests) == 0 + + @httmock.urlmatch() + def technocarte_ok(url, request): + requests.append(request) + return httmock.response( + 200, 'null', + { + 'Content-Type': 'application/json', + }) + with httmock.HTTMock(technocarte_ok): + Job.redo(timestamp=now() + datetime.timedelta(seconds=20)) assert len(requests) == 1 + req_content = json.loads(requests[0].body) assert req_content['metadonnees']['service'] == 'passage-majorite' assert len(req_content['fragments']) == 3 @@ -1282,7 +1287,6 @@ def test_passage_a_la_majorite(db, settings, nanterre_classic_family, freezer): result = passage_a_la_majorite() assert result['updated_entities'] == 0 assert result['deleted_relations'] == 0 - assert not result['errors'] assert Entity.objects.filter(content__statut_legal='majeur').count() == 3 assert Entity.objects.filter(content__prenoms='LILOU', content__statut_legal='majeur').count() == 1 diff --git a/zoo/zoo_nanterre/fragments.py b/zoo/zoo_nanterre/fragments.py index 28b9a89..b1ccfb2 100644 --- a/zoo/zoo_nanterre/fragments.py +++ b/zoo/zoo_nanterre/fragments.py @@ -210,15 +210,16 @@ class FragmentBuilder(object): state = self.handle_response(response, job=job) app_name = self.application['name'] kwargs = {} + message = self.journal_message if state == job.STATE_SUCCESS: - message = u'Synchronisation réussie avec %s' % app_name # reset errors self.error = {} + message += u': ok' elif state == Job.STATE_ERROR: - message = u'Erreur temporaire de synchronisation avec %s' % app_name + message += u': erreur temporaire' kwargs['error'] = self.error elif state == Job.STATE_UNRECOVERABLE_ERROR: - message = u'Erreur irrécupérable de synchronisation avec %s' % app_name + message += u': erreur irrécupérable' kwargs['error'] = self.error else: raise NotImplementedError @@ -247,6 +248,11 @@ class FragmentBuilder(object): **kwargs) return state + @property + def journal_message(self): + app_name = self.application['name'] + return u'Synchronisation avec %s' % app_name + def to_json(self): s = { 'application_id': self.application_id, @@ -817,6 +823,7 @@ class SuppressionResponsabiliteEnfant(RelationSynchro): class PassageALaMajorite(RelationSynchro): + # PassageALaMajorite does not send fragments immediatelly, it's special service = 'passage-majorite' @classmethod @@ -842,12 +849,8 @@ class PassageALaMajorite(RelationSynchro): def par_application(cls, application, individu, relations, meta=None, transaction=None): relations = [relation for relation in relations if cls.condition(application, relation)] action = cls.create(application, individu, relations, meta=meta) - job = Job.create(action, transaction=transaction) - if job.state != Job.STATE_SUCCESS: - if action.human_result: - yield action.human_result - else: - yield 'Erreur interne' + # PassageALaMajorite does not send fragments immediatelly, it's special + Job.create(action, do_later=True, transaction=transaction) @classmethod def pour_chaque_application(cls, individu, relations, meta=None, transaction=None): @@ -855,7 +858,11 @@ class PassageALaMajorite(RelationSynchro): for application in utils.get_applications(rsu_ws_url=True): if application not in individu.content['cles_de_federation']: continue - for message in cls.par_application(application, individu, relations, meta=meta, - transaction=transaction): - yield message - return list(helper()) + cls.par_application(application, individu, relations, + meta=meta, transaction=transaction) + helper() + + @property + def journal_message(self): + app_name = self.application['name'] + return u'Passage à la majorité sur %s' % app_name diff --git a/zoo/zoo_nanterre/management/commands/rsu-cron.py b/zoo/zoo_nanterre/management/commands/rsu-cron.py index 34d5ee7..df096e7 100644 --- a/zoo/zoo_nanterre/management/commands/rsu-cron.py +++ b/zoo/zoo_nanterre/management/commands/rsu-cron.py @@ -45,11 +45,11 @@ class Command(BaseCommand): print('Suppression de %d entrées du journal.' % count) def passage_a_la_majorite(self): - with transaction.atomic(): - result = passage_a_la_majorite() + result = passage_a_la_majorite() if result['errors'] and self.options['verbosity'] > 0: print('Mise à jour de %d enfants.' % result['updated_entities']) for individu in result['errors']: - print('Erreur:', individu, result['errors'][individu]) + for error in result['errors'][individu]: + print('Erreur:', 'individu %s' % individu.pk, error) elif result['updated_entities'] and self.options['verbosity'] > 1: print('Mise à jour de %d enfants.' % result['updated_entities']) diff --git a/zoo/zoo_nanterre/utils.py b/zoo/zoo_nanterre/utils.py index f88ca3c..65c0977 100644 --- a/zoo/zoo_nanterre/utils.py +++ b/zoo/zoo_nanterre/utils.py @@ -1284,14 +1284,21 @@ def csv_export_response(rows, filename): return r +@transaction.atomic def passage_a_la_majorite(): from . import fragments + transaction = Transaction.get_transaction() + transaction.content = { + 'action': 'passage-a-la-majorite', + } + entity_schema = EntitySchema.objects.get(slug=INDIVIDU_ENT) responsabilite_legale_schema = RelationSchema.objects.get(slug=RESPONSABILITE_LEGALE_REL) non_majeurs = Entity.objects.filter(schema=entity_schema).exclude(content__statut_legal='majeur') birthdate_threshold = now().date() - relativedelta(years=18) + transaction.content['birthdate_threshold'] = str(birthdate_threshold) non_majeurs_to_update = non_majeurs.filter(content__date_de_naissance__timestamp__lte=birthdate_threshold) updated_entities = non_majeurs_to_update.count() @@ -1300,6 +1307,8 @@ def passage_a_la_majorite(): schema=responsabilite_legale_schema, right__in=non_majeurs_to_update)) deleted_relations = len(relations_to_delete) + schema_adresse = EntitySchema.objects.get(slug=ADRESSE_ENT) + habite_schema = RelationSchema.objects.get(slug=HABITE_REL) errors = {} # updating @@ -1307,24 +1316,60 @@ def passage_a_la_majorite(): individu.content['statut_legal'] = 'majeur' individu.save() # computing new adress, reusing first adresse - new_adresse, new_adresse_rel = adresses(individu)[0] - # delete link to old address - new_adresse_rel.delete() - # create new address - new_adresse.pk = None - new_adresse.save() - assert new_adresse.pk - # link new address to old mineur - new_adresse_rel.pk = None - new_adresse_rel.content['principale'] = False - new_adresse_rel.right = new_adresse - new_adresse_rel.save() + adrs = adresses(individu) + _parents = parents(individu) + relations_parentales = [rel for parent, rel in _parents] + journalize( + individu, + old_adresses=[adr[0].pk for adr in adrs], + old_parents=[parent.pk for parent, rel in _parents], + transaction=transaction, + text=u'Passage à la majorité') + if adrs: + new_adresse, new_adresse_rel = adrs[0] + # delete link to old addresses + for _0, rel in adrs: + rel.delete() + # create new address + new_adresse.pk = None + new_adresse.created = transaction + new_adresse.save() + assert new_adresse.pk + # link new address to old mineur + new_adresse_rel.pk = None + new_adresse_rel.created = transaction + new_adresse_rel.content['principale'] = False + new_adresse_rel.right = new_adresse + new_adresse_rel.save() + else: + # set unknown address + new_adresse = Entity.objects.create( + schema=schema_adresse, + created=transaction, + content={ + "at": "", + "city": "NANTERRE", + "ext1": "", + "ext2": "", + "country": "FR", + "zipcode": "92000", + "inseecode": "92050", + "streetname": "VOIE INCONNUE", + "streetnumber": "0", + "streetnumberext": "", + "streetmatriculation": "" + }) + new_adresse_rel = Relation( + created=transaction, + left=individu, + right=new_adresse, + schema=habite_schema, + content={ + 'principale': False, + }) assert len(adresses(individu)) == 1 - relations_parentales = [rel for parent, rel in parents(individu)] # launch messages to applications - messages = fragments.PassageALaMajorite.pour_chaque_application(individu, relations_parentales) - if messages: - errors[individu] = messages + fragments.PassageALaMajorite.pour_chaque_application(individu, relations_parentales) # delete relations for relation in relations_to_delete: @@ -1333,8 +1378,12 @@ def passage_a_la_majorite(): # we cannot delete relation if no entity is updated assert updated_entities or (not deleted_relations) - return { + result = transaction.content['result'] = { 'updated_entities': updated_entities, 'deleted_relations': deleted_relations, 'errors': errors, } + + transaction.save() + + return result -- 2.20.1