Projet

Général

Profil

0001-nanterre-am-liore-le-passage-la-majorit.patch

Benjamin Dauvergne, 02 mai 2019 12:57

Télécharger (12,9 ko)

Voir les différences:

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(-)
tests/test_nanterre.py
1216 1216

  
1217 1217
    assert Log.objects.count() == 20
1218 1218
    call_command('rsu-cron', verbosity=0)
1219
    assert Log.objects.count() == 10
1219
    assert Log.objects.count() == 11
1220 1220

  
1221 1221

  
1222 1222
def test_passage_a_la_majorite(db, settings, nanterre_classic_family, freezer):
......
1241 1241
    # passage à la majorité de lilou
1242 1242
    requests = []
1243 1243

  
1244
    @httmock.urlmatch()
1245
    def technocarte_ok(url, request):
1246
        requests.append(request)
1247
        return httmock.response(
1248
            200, 'null',
1249
            {
1250
                'Content-Type': 'application/json',
1251
            })
1252
    with httmock.HTTMock(technocarte_ok):
1253
        result = passage_a_la_majorite()
1244
    result = passage_a_la_majorite()
1254 1245

  
1255 1246
    assert result['updated_entities'] == 1
1256 1247
    assert result['deleted_relations'] == 2
1257
    assert not result['errors']
1258 1248
    assert Entity.objects.filter(schema__slug='individu').count() == 4
1259 1249
    assert Entity.objects.filter(schema__slug='adresse').count() == 2
1260 1250
    assert Relation.objects.filter(schema__slug='habite').count() == 4
......
1262 1252
    assert Entity.objects.filter(content__statut_legal='majeur').count() == 3
1263 1253
    assert Entity.objects.filter(content__prenoms='LILOU', content__statut_legal='majeur').count() == 1
1264 1254

  
1255
    assert Job.objects.count() == 1
1256
    assert Job.objects.todo().count() == 1
1257
    assert len(requests) == 0
1258

  
1259
    @httmock.urlmatch()
1260
    def technocarte_ok(url, request):
1261
        requests.append(request)
1262
        return httmock.response(
1263
            200, 'null',
1264
            {
1265
                'Content-Type': 'application/json',
1266
            })
1267
    with httmock.HTTMock(technocarte_ok):
1268
        Job.redo(timestamp=now() + datetime.timedelta(seconds=20))
1265 1269
    assert len(requests) == 1
1270

  
1266 1271
    req_content = json.loads(requests[0].body)
1267 1272
    assert req_content['metadonnees']['service'] == 'passage-majorite'
1268 1273
    assert len(req_content['fragments']) == 3
......
1282 1287
    result = passage_a_la_majorite()
1283 1288
    assert result['updated_entities'] == 0
1284 1289
    assert result['deleted_relations'] == 0
1285
    assert not result['errors']
1286 1290
    assert Entity.objects.filter(content__statut_legal='majeur').count() == 3
1287 1291
    assert Entity.objects.filter(content__prenoms='LILOU', content__statut_legal='majeur').count() == 1
1288 1292

  
zoo/zoo_nanterre/fragments.py
210 210
            state = self.handle_response(response, job=job)
211 211
        app_name = self.application['name']
212 212
        kwargs = {}
213
        message = self.journal_message
213 214
        if state == job.STATE_SUCCESS:
214
            message = u'Synchronisation réussie avec %s' % app_name
215 215
            # reset errors
216 216
            self.error = {}
217
            message += u': ok'
217 218
        elif state == Job.STATE_ERROR:
218
            message = u'Erreur temporaire de synchronisation avec %s' % app_name
219
            message += u': erreur temporaire'
219 220
            kwargs['error'] = self.error
220 221
        elif state == Job.STATE_UNRECOVERABLE_ERROR:
221
            message = u'Erreur irrécupérable de synchronisation avec %s' % app_name
222
            message += u': erreur irrécupérable'
222 223
            kwargs['error'] = self.error
223 224
        else:
224 225
            raise NotImplementedError
......
247 248
                        **kwargs)
248 249
        return state
249 250

  
251
    @property
252
    def journal_message(self):
253
        app_name = self.application['name']
254
        return u'Synchronisation avec %s' % app_name
255

  
250 256
    def to_json(self):
251 257
        s = {
252 258
            'application_id': self.application_id,
......
817 823

  
818 824

  
819 825
class PassageALaMajorite(RelationSynchro):
826
    # PassageALaMajorite does not send fragments immediatelly, it's special
820 827
    service = 'passage-majorite'
821 828

  
822 829
    @classmethod
......
842 849
    def par_application(cls, application, individu, relations, meta=None, transaction=None):
843 850
        relations = [relation for relation in relations if cls.condition(application, relation)]
844 851
        action = cls.create(application, individu, relations, meta=meta)
845
        job = Job.create(action, transaction=transaction)
846
        if job.state != Job.STATE_SUCCESS:
847
            if action.human_result:
848
                yield action.human_result
849
            else:
850
                yield 'Erreur interne'
852
        # PassageALaMajorite does not send fragments immediatelly, it's special
853
        Job.create(action, do_later=True, transaction=transaction)
851 854

  
852 855
    @classmethod
853 856
    def pour_chaque_application(cls, individu, relations, meta=None, transaction=None):
......
855 858
            for application in utils.get_applications(rsu_ws_url=True):
856 859
                if application not in individu.content['cles_de_federation']:
857 860
                    continue
858
                for message in cls.par_application(application, individu, relations, meta=meta,
859
                                                   transaction=transaction):
860
                    yield message
861
        return list(helper())
861
                cls.par_application(application, individu, relations,
862
                                    meta=meta, transaction=transaction)
863
        helper()
864

  
865
    @property
866
    def journal_message(self):
867
        app_name = self.application['name']
868
        return u'Passage à la majorité sur %s' % app_name
zoo/zoo_nanterre/management/commands/rsu-cron.py
45 45
            print('Suppression de %d entrées du journal.' % count)
46 46

  
47 47
    def passage_a_la_majorite(self):
48
        with transaction.atomic():
49
            result = passage_a_la_majorite()
48
        result = passage_a_la_majorite()
50 49
        if result['errors'] and self.options['verbosity'] > 0:
51 50
            print('Mise à jour de %d enfants.' % result['updated_entities'])
52 51
            for individu in result['errors']:
53
                print('Erreur:', individu, result['errors'][individu])
52
                for error in result['errors'][individu]:
53
                    print('Erreur:', 'individu %s' % individu.pk, error)
54 54
        elif result['updated_entities'] and self.options['verbosity'] > 1:
55 55
            print('Mise à jour de %d enfants.' % result['updated_entities'])
zoo/zoo_nanterre/utils.py
1284 1284
    return r
1285 1285

  
1286 1286

  
1287
@transaction.atomic
1287 1288
def passage_a_la_majorite():
1288 1289
    from . import fragments
1289 1290

  
1291
    transaction = Transaction.get_transaction()
1292
    transaction.content = {
1293
        'action': 'passage-a-la-majorite',
1294
    }
1295

  
1290 1296
    entity_schema = EntitySchema.objects.get(slug=INDIVIDU_ENT)
1291 1297
    responsabilite_legale_schema = RelationSchema.objects.get(slug=RESPONSABILITE_LEGALE_REL)
1292 1298

  
1293 1299
    non_majeurs = Entity.objects.filter(schema=entity_schema).exclude(content__statut_legal='majeur')
1294 1300
    birthdate_threshold = now().date() - relativedelta(years=18)
1301
    transaction.content['birthdate_threshold'] = str(birthdate_threshold)
1295 1302
    non_majeurs_to_update = non_majeurs.filter(content__date_de_naissance__timestamp__lte=birthdate_threshold)
1296 1303
    updated_entities = non_majeurs_to_update.count()
1297 1304

  
......
1300 1307
        schema=responsabilite_legale_schema,
1301 1308
        right__in=non_majeurs_to_update))
1302 1309
    deleted_relations = len(relations_to_delete)
1310
    schema_adresse = EntitySchema.objects.get(slug=ADRESSE_ENT)
1311
    habite_schema = RelationSchema.objects.get(slug=HABITE_REL)
1303 1312

  
1304 1313
    errors = {}
1305 1314
    # updating
......
1307 1316
        individu.content['statut_legal'] = 'majeur'
1308 1317
        individu.save()
1309 1318
        # computing new adress, reusing first adresse
1310
        new_adresse, new_adresse_rel = adresses(individu)[0]
1311
        # delete link to old address
1312
        new_adresse_rel.delete()
1313
        # create new address
1314
        new_adresse.pk = None
1315
        new_adresse.save()
1316
        assert new_adresse.pk
1317
        # link new address to old mineur
1318
        new_adresse_rel.pk = None
1319
        new_adresse_rel.content['principale'] = False
1320
        new_adresse_rel.right = new_adresse
1321
        new_adresse_rel.save()
1319
        adrs = adresses(individu)
1320
        _parents = parents(individu)
1321
        relations_parentales = [rel for parent, rel in _parents]
1322
        journalize(
1323
            individu,
1324
            old_adresses=[adr[0].pk for adr in adrs],
1325
            old_parents=[parent.pk for parent, rel in _parents],
1326
            transaction=transaction,
1327
            text=u'Passage à la majorité')
1328
        if adrs:
1329
            new_adresse, new_adresse_rel = adrs[0]
1330
            # delete link to old addresses
1331
            for _0, rel in adrs:
1332
                rel.delete()
1333
            # create new address
1334
            new_adresse.pk = None
1335
            new_adresse.created = transaction
1336
            new_adresse.save()
1337
            assert new_adresse.pk
1338
            # link new address to old mineur
1339
            new_adresse_rel.pk = None
1340
            new_adresse_rel.created = transaction
1341
            new_adresse_rel.content['principale'] = False
1342
            new_adresse_rel.right = new_adresse
1343
            new_adresse_rel.save()
1344
        else:
1345
            # set unknown address
1346
            new_adresse = Entity.objects.create(
1347
                schema=schema_adresse,
1348
                created=transaction,
1349
                content={
1350
                    "at": "",
1351
                    "city": "NANTERRE",
1352
                    "ext1": "",
1353
                    "ext2": "",
1354
                    "country": "FR",
1355
                    "zipcode": "92000",
1356
                    "inseecode": "92050",
1357
                    "streetname": "VOIE INCONNUE",
1358
                    "streetnumber": "0",
1359
                    "streetnumberext": "",
1360
                    "streetmatriculation": ""
1361
                })
1362
            new_adresse_rel = Relation(
1363
                created=transaction,
1364
                left=individu,
1365
                right=new_adresse,
1366
                schema=habite_schema,
1367
                content={
1368
                    'principale': False,
1369
                })
1322 1370
        assert len(adresses(individu)) == 1
1323
        relations_parentales = [rel for parent, rel in parents(individu)]
1324 1371
        # launch messages to applications
1325
        messages = fragments.PassageALaMajorite.pour_chaque_application(individu, relations_parentales)
1326
        if messages:
1327
            errors[individu] = messages
1372
        fragments.PassageALaMajorite.pour_chaque_application(individu, relations_parentales)
1328 1373

  
1329 1374
    # delete relations
1330 1375
    for relation in relations_to_delete:
......
1333 1378
    # we cannot delete relation if no entity is updated
1334 1379
    assert updated_entities or (not deleted_relations)
1335 1380

  
1336
    return {
1381
    result = transaction.content['result'] = {
1337 1382
        'updated_entities': updated_entities,
1338 1383
        'deleted_relations': deleted_relations,
1339 1384
        'errors': errors,
1340 1385
    }
1386

  
1387
    transaction.save()
1388

  
1389
    return result
1341
-