0001-nanterre-am-liore-le-passage-la-majorit.patch
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 |
- |