Skip to content

Commit 91934ea

Browse files
authored
Merge pull request #4296 from hove-io/manage_odt_information
[jormun]: Update deeplink placeholders in odt_information
2 parents 2239687 + 7f15152 commit 91934ea

File tree

8 files changed

+236
-2
lines changed

8 files changed

+236
-2
lines changed

source/jormungandr/jormungandr/interfaces/v1/serializer/journey.py

+11
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
SectionType,
6969
CyclePathType,
7070
BoardingPosition,
71+
OdtInformation,
7172
)
7273
import navitiacommon.response_pb2
7374
from navitiacommon.type_pb2 import RTLevel
@@ -331,6 +332,15 @@ class RidesharingInformationSerializer(PbNestedSerializer):
331332
seats = SeatsDescriptionSerializer(display_none=False)
332333

333334

335+
class OdtInformationSerializer(PbNestedSerializer):
336+
name = jsonschema.Field(schema_type=str, display_none=True)
337+
url = jsonschema.Field(schema_type=str, display_none=True)
338+
conditions = jsonschema.Field(schema_type=str, display_none=True)
339+
phone = jsonschema.Field(schema_type=str, display_none=True)
340+
deeplink = jsonschema.Field(schema_type=str, display_none=True)
341+
applies_on = EnumListField(attr='applies_on', pb_type=OdtInformation.AppliesOn)
342+
343+
334344
class SectionSerializer(PbNestedSerializer):
335345
id = jsonschema.Field(schema_type=str, display_none=True)
336346
duration = jsonschema.Field(
@@ -421,6 +431,7 @@ def get_ridesharing_journeys(self, obj):
421431
street_informations = StreetInformationSerializer(
422432
attr="street_network.street_information", many=True, display_none=False
423433
)
434+
odt_informations = OdtInformationSerializer(display_none=False)
424435

425436

426437
class JourneySerializer(PbNestedSerializer):

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

+32
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@
3131
from __future__ import absolute_import, print_function, unicode_literals, division
3232

3333
from jormungandr.interfaces.v1.serializer.base import SortedGenericSerializer
34+
from jormungandr.interfaces.v1.decorators import get_serializer
35+
from jormungandr.interfaces.v1.serializer import api
36+
from jormungandr import app
37+
import pytz
38+
from flask import g
39+
import jormungandr.scenarios.tests.helpers_tests as helpers_tests
3440
import serpy
3541

3642

@@ -47,3 +53,29 @@ def sort_key(self, obj):
4753
assert data[1]['v'] == 2
4854
assert data[2]['v'] == 3
4955
assert data[3]['v'] == 4
56+
57+
58+
@get_serializer(serpy=api.JourneysSerializer)
59+
def abcd():
60+
deeplink = "https://toto.com?from=from_value&to=to_value"
61+
return helpers_tests.get_odt_journey(deeplink=deeplink)
62+
63+
64+
def odt_information_serialization_test():
65+
with app.app_context():
66+
with app.test_request_context():
67+
g.timezone = pytz.utc
68+
# get journey response in json
69+
resp = abcd()
70+
assert len(resp.get("journeys", 0)) == 1
71+
journey = resp["journeys"][0]
72+
assert len(journey.get("sections", 0)) == 3
73+
section = journey["sections"][1]
74+
odt_information = section.get("odt_informations", None)
75+
assert odt_information is not None
76+
assert odt_information["url"] == "odt_url_value"
77+
assert odt_information["name"] == "odt_name_value"
78+
assert odt_information["phone"] == "odt_phone_value"
79+
assert odt_information["conditions"] == "odt_conditions_value"
80+
assert odt_information["deeplink"] == "https://toto.com?from=from_value&to=to_value"
81+
assert odt_information["applies_on"] == ["from"]

source/jormungandr/jormungandr/scenarios/new_default.py

+18
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
get_disruptions_on_poi,
5151
add_disruptions,
5252
get_impact_uris_for_poi,
53+
update_odt_information_deeplink_in_section,
5354
)
5455
from navitiacommon import type_pb2, response_pb2, request_pb2
5556
from jormungandr.scenarios.qualifier import (
@@ -539,6 +540,20 @@ def update_disruptions_on_pois(instance, pb_resp):
539540
add_disruptions(pb_resp, poi_disruptions)
540541

541542

543+
def update_odt_information_deeplink(pb_resp):
544+
"""
545+
Update placeholders present in sections[i].odt_information.deeplink with their values for each journey
546+
for each section of type ON_DEMAND_TRANSPORT
547+
"""
548+
if not pb_resp.journeys:
549+
return
550+
551+
for j in pb_resp.journeys:
552+
for s in j.sections:
553+
if s.type == response_pb2.ON_DEMAND_TRANSPORT:
554+
update_odt_information_deeplink_in_section(s)
555+
556+
542557
def update_total_air_pollutants(pb_resp):
543558
"""
544559
update journey.air_pollutants
@@ -1485,6 +1500,9 @@ def fill_journeys(self, request_type, api_request, instance):
14851500
# Update disruptions on pois
14861501
update_disruptions_on_pois(instance, pb_resp)
14871502

1503+
# Update deeplink in odt_information for all sections of type ON_DEMAND_TRANSPORT
1504+
update_odt_information_deeplink(pb_resp)
1505+
14881506
self._compute_pagination_links(pb_resp, instance, api_request['clockwise'])
14891507
return pb_resp
14901508

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

+39
Original file line numberDiff line numberDiff line change
@@ -635,3 +635,42 @@ def verify_poi_in_impacted_objects(object, poi_empty=True):
635635
assert object.poi.name == 'poi_name_from_kraken'
636636
assert object.poi.coord.lon == 1.0
637637
assert object.poi.coord.lat == 2.0
638+
639+
640+
def get_odt_journey(deeplink):
641+
response = response_pb2.Response()
642+
journey = response.journeys.add()
643+
644+
section = journey.sections.add()
645+
section.type = response_pb2.STREET_NETWORK
646+
section.street_network.mode = response_pb2.Walking
647+
section.duration = 20
648+
section = journey.sections.add()
649+
section.type = response_pb2.ON_DEMAND_TRANSPORT
650+
section.duration = 70
651+
section.begin_date_time = utils.str_to_time_stamp("20240806T060500")
652+
section.origin.uri = 'stop_a'
653+
section.origin.embedded_type = type_pb2.STOP_POINT
654+
section.origin.stop_point.uri = 'stop_a'
655+
section.origin.stop_point.name = 'stop_a_name'
656+
section.origin.stop_point.coord.lon = 1.0
657+
section.origin.stop_point.coord.lat = 2.0
658+
section.destination.uri = 'stop_b'
659+
section.destination.embedded_type = type_pb2.STOP_POINT
660+
section.destination.stop_point.uri = 'stop_b'
661+
section.destination.stop_point.name = 'stop_b_name'
662+
section.destination.stop_point.coord.lon = 3.0
663+
section.destination.stop_point.coord.lat = 4.0
664+
odt_information = section.odt_informations
665+
odt_information.name = "odt_name_value"
666+
odt_information.deeplink = deeplink
667+
odt_information.url = "odt_url_value"
668+
odt_information.conditions = "odt_conditions_value"
669+
odt_information.phone = "odt_phone_value"
670+
odt_information.applies_on.append(response_pb2.OdtInformation.AppliesOn.FROM)
671+
section = journey.sections.add()
672+
section.type = response_pb2.STREET_NETWORK
673+
section.street_network.mode = response_pb2.Walking
674+
section.duration = 10
675+
676+
return response

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

+26
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
get_kraken_calls,
3939
update_best_boarding_positions,
4040
update_disruptions_on_pois,
41+
update_odt_information_deeplink,
4142
)
4243
from jormungandr.instance import Instance
4344
from jormungandr.scenarios.utils import switch_back_to_ridesharing
@@ -831,3 +832,28 @@ def journey_with_disruptions_on_poi_test(mocker):
831832

832833
mock.assert_called_once()
833834
return
835+
836+
837+
def journey_with_odt_information_test():
838+
deeplink = (
839+
"https://domaine/search?departure-address={from_name}&destination-address={to_name}"
840+
"&requested-departure-time={departure_datetime}&from_coord_lat={from_coord_lat}"
841+
"&from_coord_lon={from_coord_lon}&not_managed={not_managed}"
842+
)
843+
response_journey_with_odt = helpers_tests.get_odt_journey(deeplink=deeplink)
844+
assert len(response_journey_with_odt.journeys) == 1
845+
journey = response_journey_with_odt.journeys[0]
846+
assert len(journey.sections) == 3
847+
odt_section = journey.sections[1]
848+
assert odt_section.type == response_pb2.ON_DEMAND_TRANSPORT
849+
assert (
850+
odt_section.odt_informations.deeplink
851+
== "https://domaine/search?departure-address={from_name}&destination-address={to_name}&requested-departure-time={departure_datetime}&from_coord_lat={from_coord_lat}&from_coord_lon={from_coord_lon}&not_managed={not_managed}"
852+
)
853+
854+
update_odt_information_deeplink(response_journey_with_odt)
855+
odt_section = response_journey_with_odt.journeys[0].sections[1]
856+
assert (
857+
odt_section.odt_informations.deeplink
858+
== "https://domaine/search?departure-address=stop_a_name&destination-address=stop_b_name&requested-departure-time=1722924300&from_coord_lat=2.0&from_coord_lon=1.0&not_managed=N/A"
859+
)

source/jormungandr/jormungandr/scenarios/tests/utils_tests.py

+64-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,12 @@
2929

3030
from navitiacommon import type_pb2, response_pb2
3131
import jormungandr.scenarios.tests.helpers_tests as helpers_tests
32-
from jormungandr.scenarios.utils import fill_disruptions_on_pois, fill_disruptions_on_places_nearby
32+
from jormungandr.scenarios.utils import (
33+
fill_disruptions_on_pois,
34+
fill_disruptions_on_places_nearby,
35+
update_odt_information_deeplink_in_section,
36+
)
37+
3338
import pytest
3439
from pytest_mock import mocker
3540

@@ -94,3 +99,61 @@ def update_disruptions_on_pois_for_places_nearby_test(mocker):
9499

95100
mock.assert_called_once()
96101
return
102+
103+
104+
def journey_with_deeplink_in_odt_information_test():
105+
instance = lambda: None
106+
# Get a response with a section of ODT having odt_information.
107+
deeplink = (
108+
"https://domaine/search?departure-address={from_name}&destination-address={to_name}"
109+
"&requested-departure-time={departure_datetime}&from_coord_lat={from_coord_lat}"
110+
"&from_coord_lon={from_coord_lon}&to_coord_lat={to_coord_lat}&to_coord_lon={to_coord_lon}"
111+
)
112+
response_journey_with_odt = helpers_tests.get_odt_journey(deeplink=deeplink)
113+
assert len(response_journey_with_odt.journeys) == 1
114+
journey = response_journey_with_odt.journeys[0]
115+
assert len(journey.sections) == 3
116+
odt_section = journey.sections[1]
117+
assert odt_section.type == response_pb2.ON_DEMAND_TRANSPORT
118+
odt_information = odt_section.odt_informations
119+
assert odt_information.name == "odt_name_value"
120+
assert (
121+
odt_information.deeplink
122+
== "https://domaine/search?departure-address={from_name}&destination-address={to_name}&requested-departure-time={departure_datetime}&from_coord_lat={from_coord_lat}&from_coord_lon={from_coord_lon}&to_coord_lat={to_coord_lat}&to_coord_lon={to_coord_lon}"
123+
)
124+
assert odt_information.url == "odt_url_value"
125+
assert odt_information.conditions == "odt_conditions_value"
126+
assert odt_information.phone == "odt_phone_value"
127+
update_odt_information_deeplink_in_section(odt_section)
128+
assert (
129+
odt_information.deeplink
130+
== "https://domaine/search?departure-address=stop_a_name&destination-address=stop_b_name&requested-departure-time=1722924300&from_coord_lat=2.0&from_coord_lon=1.0&to_coord_lat=4.0&to_coord_lon=3.0"
131+
)
132+
133+
# Use a deeplink with fewer placeholders
134+
deeplink = (
135+
"https://domaine/search?departure-address={from_name}&destination-address={to_name}"
136+
"&requested-departure-time={departure_datetime}&from_coord_lat={from_coord_lat}&from_coord_lon={from_coord_lon}"
137+
)
138+
response_journey_with_odt = helpers_tests.get_odt_journey(deeplink=deeplink)
139+
odt_section = response_journey_with_odt.journeys[0].sections[1]
140+
update_odt_information_deeplink_in_section(odt_section)
141+
assert (
142+
odt_section.odt_informations.deeplink
143+
== "https://domaine/search?departure-address=stop_a_name&destination-address=stop_b_name&requested-departure-time=1722924300&from_coord_lat=2.0&from_coord_lon=1.0"
144+
)
145+
146+
# Add a placeholder which is not predefined in the function to update deeplink
147+
# This placeholder will not be replaced(updated)
148+
deeplink = (
149+
"https://domaine/search?departure-address={from_name}&destination-address={to_name}"
150+
"&requested-departure-time={departure_datetime}&from_coord_lat={from_coord_lat}"
151+
"&from_coord_lon={from_coord_lon}&toto={toto}"
152+
)
153+
response_journey_with_odt = helpers_tests.get_odt_journey(deeplink=deeplink)
154+
odt_section = response_journey_with_odt.journeys[0].sections[1]
155+
update_odt_information_deeplink_in_section(odt_section)
156+
assert (
157+
odt_section.odt_informations.deeplink
158+
== "https://domaine/search?departure-address=stop_a_name&destination-address=stop_b_name&requested-departure-time=1722924300&from_coord_lat=2.0&from_coord_lon=1.0&toto=N/A"
159+
)

source/jormungandr/jormungandr/scenarios/utils.py

+45
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
import navitiacommon.request_pb2 as request_pb2
3434
from future.moves.itertools import zip_longest
3535
from jormungandr.fallback_modes import FallbackModes
36+
import re
37+
from collections import defaultdict
38+
from string import Formatter
3639
from copy import deepcopy
3740
import six
3841

@@ -551,3 +554,45 @@ def add_disruptions(pb_resp, pb_disruptions):
551554
if pb_disruptions is None:
552555
return
553556
pb_resp.impacts.extend(pb_disruptions.impacts)
557+
558+
559+
def update_odt_information_deeplink_in_section(section):
560+
if section.type != response_pb2.ON_DEMAND_TRANSPORT:
561+
return
562+
563+
deeplink = section.odt_informations.deeplink
564+
if not deeplink:
565+
return
566+
567+
departure_datetime = section.begin_date_time
568+
from_name = section.origin.stop_point.name
569+
from_coord_lat = section.origin.stop_point.coord.lat
570+
from_coord_lon = section.origin.stop_point.coord.lon
571+
to_name = section.destination.stop_point.name
572+
to_coord_lat = section.destination.stop_point.coord.lat
573+
to_coord_lon = section.destination.stop_point.coord.lon
574+
575+
# Get all placeholders present in deeplink and match with predefined placeholder variables. value of those
576+
# present in deeplink but absent in predefined placeholder variables will be replaced by N/A
577+
placeholders = re.findall(r"{(\w+)}", deeplink)
578+
579+
placeholder_dict = defaultdict(lambda: 'N/A')
580+
fmtr = Formatter()
581+
582+
for p in placeholders:
583+
if p == "departure_datetime":
584+
placeholder_dict[p] = departure_datetime
585+
elif p == "from_name":
586+
placeholder_dict[p] = from_name
587+
elif p == "from_coord_lat":
588+
placeholder_dict[p] = from_coord_lat
589+
elif p == "from_coord_lon":
590+
placeholder_dict[p] = from_coord_lon
591+
elif p == "to_name":
592+
placeholder_dict[p] = to_name
593+
elif p == "to_coord_lat":
594+
placeholder_dict[p] = to_coord_lat
595+
elif p == "to_coord_lon":
596+
placeholder_dict[p] = to_coord_lon
597+
598+
section.odt_informations.deeplink = fmtr.vformat(deeplink, (), placeholder_dict)

source/navitia-proto

0 commit comments

Comments
 (0)