Skip to content

Commit cb58914

Browse files
authored
Merge pull request #4327 from hove-io/fix_disruptions_on_all_pois_in_journey
jormungandr: Update poi objects in journeys if active by configuration
2 parents e3587c7 + 2f48ae3 commit cb58914

File tree

13 files changed

+172
-29
lines changed

13 files changed

+172
-29
lines changed

source/jormungandr/jormungandr/instance.py

+6
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,12 @@ def car_park_provider(self):
614614
instance_db = self.get_models()
615615
return get_value_or_default('car_park_provider', instance_db, self.name)
616616

617+
@property
618+
def disruptions_on_poi(self):
619+
# type: () -> bool
620+
instance_db = self.get_models()
621+
return get_value_or_default('disruptions_on_poi', instance_db, self.name)
622+
617623
@property
618624
def max_additional_connections(self):
619625
# type: () -> int

source/jormungandr/jormungandr/interfaces/v1/Journeys.py

+21-12
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,14 @@ def get_disruption_uris(object):
377377

378378
return uris
379379

380+
def impact_on_poi():
381+
for d in objects[0].get('disruptions', []):
382+
for io in d.get('impacted_objects', []):
383+
if io.get('pt_object', {}).get('embedded_type') == "poi":
384+
return True
385+
386+
return False
387+
380388
def update_for_poi(object):
381389
# Add links in poi object
382390
object_copy = deepcopy(object)
@@ -388,22 +396,20 @@ def update_for_poi(object):
388396
create_internal_link(_type="disruption", rel="disruptions", id=disruption_uri)
389397
)
390398

391-
# We should only update 'from' object of the first section as well as 'to' object of the last one
392-
# since object poi can only be present in those two cases
393-
# If object is absent in first_section['from'] as well as last_section['to'] for the first journey
394-
# then no need to verify for the remaining journeys
399+
# If no disruption on poi exist, no action to do
400+
if not impact_on_poi():
401+
return objects
402+
403+
# We should update 'from' and 'to' object of all the sections if object is POI
395404
for j in objects[0].get('journeys', []):
396405
if "sections" not in j:
397406
continue
398407

399-
first_sec = j['sections'][0]
400-
last_sec = j['sections'][-1]
401-
if first_sec['from']['embedded_type'] != "poi" and last_sec['to']['embedded_type'] != "poi":
402-
break
403-
if first_sec['from']['embedded_type'] == "poi":
404-
update_for_poi(first_sec['from']['poi'])
405-
if last_sec['to']['embedded_type'] == "poi":
406-
update_for_poi(last_sec['to']['poi'])
408+
for s in j.get('sections', []):
409+
if s.get('from', {}).get('embedded_type') == "poi":
410+
update_for_poi(s['from']['poi'])
411+
if s.get('to', {}).get('embedded_type') == "poi":
412+
update_for_poi(s['to']['poi'])
407413

408414
return objects
409415

@@ -906,6 +912,9 @@ def _set_specific_params(mod):
906912
if args.get('_use_predicted_traffic') is None:
907913
args['_use_predicted_traffic'] = mod.use_predicted_traffic
908914

915+
if args.get('_disruptions_on_poi') is None:
916+
args['_disruptions_on_poi'] = mod.disruptions_on_poi
917+
909918
# When computing 'same_journey_schedules'(is_journey_schedules=True), some parameters need to be overridden
910919
# because they are contradictory to the request
911920
if args.get("is_journey_schedules"):

source/jormungandr/jormungandr/interfaces/v1/journey_common.py

+6
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,12 @@ def __init__(self, output_type_serializer):
395395
'and thus avoid disrupted public transport.\n'
396396
'Nota: `disruption_active=true` <=> `data_freshness=realtime`',
397397
)
398+
parser_get.add_argument(
399+
"_disruptions_on_poi",
400+
type=BooleanType(),
401+
hidden=True,
402+
help="Fetch and display disruptions on poi in the journey response",
403+
)
398404
# no default value for data_freshness because we need to maintain retrocomp with disruption_active
399405
parser_get.add_argument(
400406
"data_freshness",

source/jormungandr/jormungandr/interfaces/v1/test/journey_tests.py

+18-5
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ def handle_poi_disruptions_test():
245245
resp = get_response_with_poi_and_disruptions()
246246
assert len(resp[0].get("journeys", 0)) == 2
247247

248-
# Journey 1: a disruption exist for poi_uri_a: the poi in journey should have links and
248+
# Journey 1: a disruption exist for poi_uri_a (origin): the poi in journey should have links and
249249
# impacted_object should have object poi
250250
origin = resp[0].get("journeys", 0)[0]['sections'][0]['from']['poi']
251251
assert origin['id'] == "poi_uri_a"
@@ -254,23 +254,36 @@ def handle_poi_disruptions_test():
254254
assert impacted_object['id'] == "poi_uri_a"
255255
assert "links" not in impacted_object
256256

257-
# No disruption exist for poi_uri_b: the poi in journey doesn't have links and object poi is absent
257+
# No disruption exist for poi_uri_b (destination): the poi in journey doesn't have links and object poi is absent
258258
# in impacted_object
259259
destination = resp[0].get("journeys", 0)[0]['sections'][2]['to']['poi']
260260
assert destination['id'] == "poi_uri_b"
261261
assert len(destination["links"]) == 0
262262

263-
# Journey 2: a disruption exist for poi_uri_a: the poi in journey should have links and
264-
# impacted_object should have object poi
263+
# Journey 2: a disruption exist for poi_uri_a (origin) and another exist for poi_uri_from:
264+
# both pois in journey should have links and impacted_object should have object poi
265265
origin = resp[0].get("journeys", 0)[1]['sections'][0]['from']['poi']
266266
assert origin['id'] == "poi_uri_a"
267267
assert len(origin['links']) == 1
268268
impacted_object = resp[0]['disruptions'][0]['impacted_objects'][0]['pt_object']['poi']
269269
assert impacted_object['id'] == "poi_uri_a"
270270
assert "links" not in impacted_object
271271

272+
sections = resp[0].get("journeys", 0)[1]['sections']
273+
assert len(sections) == 3
274+
poi = sections[0]['to']['poi']
275+
assert poi['id'] == "poi_uri_from"
276+
assert len(poi['links']) == 1
277+
impacted_object = resp[0]['disruptions'][1]['impacted_objects'][0]['pt_object']['poi']
278+
assert impacted_object['id'] == "poi_uri_from"
279+
assert "links" not in impacted_object
280+
281+
poi = sections[1]['to']['poi']
282+
assert poi['id'] == "poi_uri_to"
283+
assert len(poi['links']) == 0
284+
272285
# No disruption exist for poi_uri_b: the poi in journey doesn't have links and object poi is absent
273286
# in impacted_object
274-
destination = resp[0].get("journeys", 0)[1]['sections'][0]['to']['poi']
287+
destination = sections[2]['to']['poi']
275288
assert destination['id'] == "poi_uri_b"
276289
assert len(destination["links"]) == 0

source/jormungandr/jormungandr/scenarios/new_default.py

+34-4
Original file line numberDiff line numberDiff line change
@@ -503,16 +503,21 @@ def update_total_co2_emission(pb_resp):
503503
j.co2_emission.unit = 'gEC'
504504

505505

506-
def update_disruptions_on_pois(instance, pb_resp):
506+
def update_disruptions_on_pois(instance, api_request, pb_resp):
507507
"""
508-
Maintain a set of uri from g.origin_detail and g.destination_detail of type Poi,
509-
call loki with api api_disruptions&pois[]...
508+
Maintain a set of uri from g.origin_detail and g.destination_detail of type Poi
509+
Add uri from all journey.section.origin and journey.section.destination of type Poi
510+
Call loki with api api_disruptions&pois[]...
510511
For each disruption on poi, add disruption id in the attribute links and add disruptions in the response
511512
"""
513+
required_mode_list = {'bss', 'car'}
514+
if not api_request.get('_disruptions_on_poi'):
515+
return
512516
if not pb_resp.journeys:
513517
return
514518
# Add uri of all the pois in a set
515519
poi_uris = set()
520+
poi_objets = []
516521
since_datetime = date_to_timestamp(datetime.utcnow())
517522
until_datetime = date_to_timestamp(datetime.utcnow())
518523

@@ -523,6 +528,23 @@ def update_disruptions_on_pois(instance, pb_resp):
523528
if g.destination_detail and g.destination_detail.get('embedded_type') == "poi":
524529
poi_uris.add(g.destination_detail.get('id'))
525530

531+
# Add pois present in all journeys if any of modes={'bss', 'car'} is present in
532+
# origin_mode or destination_mode or direct_path_mode
533+
mode_list = api_request.get('origin_mode', [])
534+
mode_list.extend(api_request.get('destination_mode', []))
535+
if set(mode_list).intersection(required_mode_list):
536+
for j in pb_resp.journeys:
537+
for s in j.sections:
538+
if s.origin.embedded_type == type_pb2.POI:
539+
poi_uris.add(s.origin.uri)
540+
poi_objets.append(s.origin.poi)
541+
since_datetime = min(since_datetime, s.begin_date_time)
542+
543+
if s.destination.embedded_type == type_pb2.POI:
544+
poi_uris.add(s.destination.uri)
545+
poi_objets.append(s.destination.poi)
546+
until_datetime = max(until_datetime, s.end_date_time)
547+
526548
if since_datetime >= until_datetime:
527549
since_datetime = until_datetime - 1
528550

@@ -531,6 +553,14 @@ def update_disruptions_on_pois(instance, pb_resp):
531553
if poi_disruptions is None:
532554
return
533555

556+
# For each poi in pt_objects:
557+
# add impact_uris from resp_poi and
558+
# copy object poi in impact.impacted_objects
559+
for pt_object in poi_objets:
560+
impact_uris = get_impact_uris_for_poi(poi_disruptions, pt_object)
561+
for impact_uri in impact_uris:
562+
pt_object.impact_uris.append(impact_uri)
563+
534564
# Add all impacts from resp_poi to the response
535565
add_disruptions(pb_resp, poi_disruptions)
536566

@@ -1507,7 +1537,7 @@ def fill_journeys(self, request_type, api_request, instance):
15071537
journey_filter.remove_excess_terminus(pb_resp)
15081538

15091539
# Update disruptions on pois
1510-
update_disruptions_on_pois(instance, pb_resp)
1540+
update_disruptions_on_pois(instance, api_request, pb_resp)
15111541

15121542
# Update booking_url in booking_rule for all sections of type ON_DEMAND_TRANSPORT
15131543
update_booking_rule_url_in_response(pb_resp)

source/jormungandr/jormungandr/scenarios/tests/helpers_tests.py

+29-4
Original file line numberDiff line numberDiff line change
@@ -529,8 +529,6 @@ def get_response_with_a_disruption_on_poi(uri="poi_uri", name="poi_name_from_lok
529529
impact.disruption_uri = "test_disruption_uri"
530530
impacted_object = impact.impacted_objects.add()
531531

532-
# poi = make_pt_object(type_pb2.POI, lon=1, lat=2, uri='poi:test_uri')
533-
# impacted_object.pt_object.CopyFrom(poi)
534532
impacted_object.pt_object.name = name
535533
impacted_object.pt_object.uri = uri
536534
impacted_object.pt_object.embedded_type = type_pb2.POI
@@ -667,19 +665,46 @@ def get_pb_response_with_journeys_and_disruptions():
667665
section.destination.uri = 'address_b'
668666
section.destination.embedded_type = type_pb2.ADDRESS
669667

670-
# Add a journey : walking address to address
668+
# Add a journey : walking address to poi + poi to poi + poi to address
671669
journey = response.journeys.add()
672670
section = journey.sections.add()
673671
section.type = response_pb2.STREET_NETWORK
674672
section.street_network.mode = response_pb2.Walking
675673
section.origin.uri = 'address_a'
676674
section.origin.embedded_type = type_pb2.ADDRESS
675+
section.destination.uri = 'poi_uri_from'
676+
section.destination.embedded_type = type_pb2.POI
677+
section.destination.poi.uri = 'poi_uri_from'
678+
section.destination.poi.name = 'poi_name_from'
679+
680+
section = journey.sections.add()
681+
section.type = response_pb2.STREET_NETWORK
682+
section.origin.uri = 'poi_uri_from'
683+
section.origin.embedded_type = type_pb2.POI
684+
section.origin.poi.uri = 'poi_uri_from'
685+
section.origin.poi.name = 'poi_name_from'
686+
section.street_network.mode = response_pb2.Bss
687+
section.destination.uri = 'poi_uri_to'
688+
section.destination.embedded_type = type_pb2.POI
689+
section.destination.poi.uri = 'poi_uri_to'
690+
section.destination.poi.name = 'poi_name_to'
691+
692+
section = journey.sections.add()
693+
section.type = response_pb2.STREET_NETWORK
694+
section.origin.uri = 'poi_uri_to'
695+
section.origin.embedded_type = type_pb2.POI
696+
section.origin.poi.uri = 'poi_uri_to'
697+
section.origin.poi.name = 'poi_name_to'
698+
section.street_network.mode = response_pb2.Walking
677699
section.destination.uri = 'address_b'
678700
section.destination.embedded_type = type_pb2.ADDRESS
679701

680-
# Add disruption on poi 'poi_uri_a':
702+
# Add disruption on poi 'poi_uri_a' (poi of origin):
681703
pb_disruptions = get_response_with_a_disruption_on_poi(uri="poi_uri_a", name="poi_name_a")
682704
response.impacts.extend(pb_disruptions.impacts)
705+
# Add disruption on poi 'poi_uri_from':
706+
pb_disruptions = get_response_with_a_disruption_on_poi(uri="poi_uri_from", name="poi_name_from")
707+
response.impacts.extend(pb_disruptions.impacts)
683708
response.status_code = 200
684709
return response
685710

source/jormungandr/jormungandr/scenarios/tests/new_default_tests.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import pytest
5151
from pytest_mock import mocker
5252
from collections import defaultdict
53+
import copy
5354

5455
"""
5556
sections 0 1 2 3 4 5 6 7 8 9 10
@@ -816,6 +817,8 @@ def journey_with_disruptions_on_poi_test(mocker):
816817
journey = response_journey_with_pois.journeys[0]
817818
assert len(journey.sections) == 3
818819

820+
original_response = copy.deepcopy(response_journey_with_pois)
821+
819822
# Prepare disruptions on poi as response of end point poi_disruptions of loki
820823
# pt_object poi as impacted object is absent in the response of poi_disruptions
821824
disruptions_with_poi = helpers_tests.get_response_with_a_disruption_on_poi()
@@ -828,7 +831,8 @@ def journey_with_disruptions_on_poi_test(mocker):
828831
mock = mocker.patch(
829832
'jormungandr.scenarios.new_default.get_disruptions_on_poi', return_value=disruptions_with_poi
830833
)
831-
update_disruptions_on_pois(instance, response_journey_with_pois)
834+
mocked_request = {'origin_mode': [], 'destination_mode': [], '_disruptions_on_poi': True}
835+
update_disruptions_on_pois(instance, mocked_request, response_journey_with_pois)
832836

833837
assert len(response_journey_with_pois.impacts) == 1
834838
impact = response_journey_with_pois.impacts[0]
@@ -837,8 +841,11 @@ def journey_with_disruptions_on_poi_test(mocker):
837841

838842
# In this state we haven't yet managed the final response so poi object is empty
839843
helpers_tests.verify_poi_in_impacted_objects(object=object, poi_empty=True)
844+
mocked_request = {'origin_mode': [], 'destination_mode': [], '_disruptions_on_poi': True}
845+
update_disruptions_on_pois(instance, mocked_request, original_response)
846+
assert len(original_response.impacts) == 1
840847

841-
mock.assert_called_once()
848+
mock.assert_called()
842849
return
843850

844851

source/navitiacommon/navitiacommon/default_values.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,15 @@
100100
# will be chosen.
101101
priority = 0
102102

103-
# activate / desactivate call to bss provider
103+
# activate / deactivate call to bss provider
104104
bss_provider = True
105105

106-
# activate / desactivate call to car parking provider
106+
# activate / deactivate call to car parking provider
107107
car_park_provider = True
108108

109+
# activate / deactivate adding disruptions on poi in journeys
110+
disruptions_on_poi = False
111+
109112
# Maximum number of connections allowed in journeys is calculated as
110113
# max_additional_connections + minimum connections among the journeys
111114
max_additional_connections = 2

source/navitiacommon/navitiacommon/models/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,10 @@ class Instance(db.Model): # type: ignore
464464
db.Boolean, default=default_values.car_park_provider, nullable=False, server_default=true()
465465
)
466466

467+
disruptions_on_poi = db.Column(
468+
db.Boolean, default=default_values.disruptions_on_poi, nullable=False, server_default=false()
469+
)
470+
467471
max_additional_connections = db.Column(
468472
db.Integer, default=default_values.max_additional_connections, nullable=False, server_default='2'
469473
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""
2+
Add attribute disruptions_on_poi in the table instance with default value False
3+
4+
Revision ID: ca5a0a70a9ba
5+
Revises: c3ba234a3b9c
6+
Create Date: 2024-12-04 11:47:52.807680
7+
8+
"""
9+
10+
# revision identifiers, used by Alembic.
11+
revision = 'ca5a0a70a9ba'
12+
down_revision = 'c3ba234a3b9c'
13+
14+
from alembic import op
15+
import sqlalchemy as sa
16+
from sqlalchemy.dialects import postgresql
17+
18+
19+
def upgrade():
20+
op.add_column(
21+
'instance', sa.Column('disruptions_on_poi', sa.Boolean(), server_default='false', nullable=False)
22+
)
23+
24+
25+
def downgrade():
26+
op.drop_column('instance', 'disruptions_on_poi')

source/tyr/tests/integration/instance_test.py

+4
Original file line numberDiff line numberDiff line change
@@ -553,27 +553,31 @@ def test_update_forgotten_attributs_in_backend(create_instance):
553553
assert resp[0]['car_park_provider'] is True
554554
assert resp[0]['filter_odt_journeys'] is False
555555
assert resp[0]['additional_parameters'] is False
556+
assert resp[0]['disruptions_on_poi'] is False
556557

557558
params = {
558559
'max_additional_connections': 3,
559560
'successive_physical_mode_to_limit_id': 'physical_mode:Train',
560561
'car_park_provider': False,
561562
'filter_odt_journeys': True,
562563
'additional_parameters': True,
564+
'disruptions_on_poi': True,
563565
}
564566
resp = api_put('/v0/instances/fr', data=json.dumps(params), content_type='application/json')
565567
assert resp['max_additional_connections'] == 3
566568
assert resp['successive_physical_mode_to_limit_id'] == 'physical_mode:Train'
567569
assert resp['car_park_provider'] is False
568570
assert resp['filter_odt_journeys'] is True
569571
assert resp['additional_parameters'] is True
572+
assert resp['disruptions_on_poi'] is True
570573

571574
resp = api_get('/v0/instances/fr')
572575
assert resp[0]['max_additional_connections'] == 3
573576
assert resp[0]['successive_physical_mode_to_limit_id'] == 'physical_mode:Train'
574577
assert resp[0]['car_park_provider'] is False
575578
assert resp[0]['filter_odt_journeys'] is True
576579
assert resp[0]['additional_parameters'] is True
580+
assert resp[0]['disruptions_on_poi'] is True
577581

578582

579583
def test_update_taxi_speed(create_instance):

0 commit comments

Comments
 (0)