Link to Eurostar search page with pricing; add Bristol departures RTT link
Replace the Eurostar timetable link with the search URL (eurostar.com/search/uk-en?adult=1&origin=…&destination=…&outbound=…) so the footer links directly to the page that shows prices for the specific date and destination. Add a Bristol Temple Meads → Paddington departures link on RTT alongside the existing Paddington arrivals link. Also update "morning service unavailable" badge and tests to reflect the removal of the morning-only cutoff filter from find_unreachable_morning_eurostars. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
4e4202e220
commit
06afd57957
5 changed files with 27 additions and 8 deletions
10
app.py
10
app.py
|
|
@ -16,6 +16,12 @@ RTT_PADDINGTON_URL = (
|
|||
"?stp=WVS&show=pax-calls&order=wtt"
|
||||
)
|
||||
|
||||
RTT_BRISTOL_URL = (
|
||||
"https://www.realtimetrains.co.uk/search/detailed/"
|
||||
"gb-nr:BRI/to/gb-nr:PAD/{date}/0000-2359"
|
||||
"?stp=WVS&show=pax-calls&order=wtt"
|
||||
)
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
DESTINATIONS = {
|
||||
|
|
@ -154,8 +160,9 @@ def results(slug, travel_date):
|
|||
next_date = (dt + timedelta(days=1)).isoformat()
|
||||
travel_date_display = dt.strftime('%A %-d %B %Y')
|
||||
|
||||
eurostar_url = eurostar_scraper.timetable_url(destination) + f"?date={travel_date}"
|
||||
eurostar_url = eurostar_scraper.search_url(destination, travel_date)
|
||||
rtt_url = RTT_PADDINGTON_URL.format(date=travel_date)
|
||||
rtt_bristol_url = RTT_BRISTOL_URL.format(date=travel_date)
|
||||
|
||||
return render_template(
|
||||
'results.html',
|
||||
|
|
@ -175,6 +182,7 @@ def results(slug, travel_date):
|
|||
error=error,
|
||||
eurostar_url=eurostar_url,
|
||||
rtt_url=rtt_url,
|
||||
rtt_bristol_url=rtt_bristol_url,
|
||||
min_connection=min_connection,
|
||||
max_connection=max_connection,
|
||||
valid_min_connections=sorted(VALID_MIN_CONNECTIONS),
|
||||
|
|
|
|||
|
|
@ -48,6 +48,14 @@ def _slugify_station_name(name: str) -> str:
|
|||
return re.sub(r'[^a-z0-9]+', '-', name.lower()).strip('-')
|
||||
|
||||
|
||||
def search_url(destination: str, travel_date: str) -> str:
|
||||
dest_id = DESTINATION_STATION_IDS[destination]
|
||||
return (
|
||||
f'https://www.eurostar.com/search/uk-en'
|
||||
f'?adult=1&origin={ORIGIN_STATION_ID}&destination={dest_id}&outbound={travel_date}'
|
||||
)
|
||||
|
||||
|
||||
def timetable_url(destination: str) -> str:
|
||||
dest_id = DESTINATION_STATION_IDS[destination]
|
||||
dest_slug = _slugify_station_name(destination)
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@
|
|||
{% if unreachable_morning_services %}
|
||||
·
|
||||
<span style="color:#718096">
|
||||
{{ unreachable_morning_services | length }} morning service{{ 's' if unreachable_morning_services | length != 1 }} unavailable from Bristol
|
||||
{{ unreachable_morning_services | length }} Eurostar service{{ 's' if unreachable_morning_services | length != 1 }} unavailable from Bristol
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if from_cache %}
|
||||
|
|
@ -209,6 +209,8 @@
|
|||
Eurostar Standard prices are for 1 adult in GBP; always check
|
||||
<a href="{{ eurostar_url }}" target="_blank" rel="noopener">eurostar.com</a> to book.
|
||||
·
|
||||
<a href="{{ rtt_bristol_url }}" target="_blank" rel="noopener">Bristol departures on RTT</a>
|
||||
·
|
||||
<a href="{{ rtt_url }}" target="_blank" rel="noopener">Paddington arrivals on RTT</a>
|
||||
</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -211,11 +211,10 @@ def test_results_shows_unreachable_morning_eurostar_services(monkeypatch):
|
|||
html = resp.get_data(as_text=True)
|
||||
|
||||
assert resp.status_code == 200
|
||||
assert '1 morning service unavailable from Bristol' in html
|
||||
assert '2 Eurostar services unavailable from Bristol' in html
|
||||
assert '09:30' in html
|
||||
assert 'ES 9001' in html
|
||||
assert 'Unavailable from Bristol' in html
|
||||
assert 'Morning means Eurostar departures before 12:00 from St Pancras.' in html
|
||||
assert html.index('09:30') < html.index('10:15')
|
||||
|
||||
|
||||
|
|
@ -267,6 +266,6 @@ def test_results_can_show_only_unreachable_morning_services(monkeypatch):
|
|||
|
||||
assert resp.status_code == 200
|
||||
assert 'No valid journeys found.' not in html
|
||||
assert '1 morning service unavailable from Bristol' in html
|
||||
assert '1 Eurostar service unavailable from Bristol' in html
|
||||
assert '09:30' in html
|
||||
assert 'Unavailable from Bristol' in html
|
||||
|
|
|
|||
|
|
@ -131,7 +131,9 @@ def test_connection_duration_in_trip():
|
|||
assert trips[0]['connection_duration'] == '1h 16m'
|
||||
|
||||
|
||||
def test_unreachable_morning_eurostars_lists_only_unreachable_morning_services():
|
||||
def test_find_unreachable_eurostars_excludes_connectable_services():
|
||||
# GWR arrives 08:45; default min=50/max=110 → viable window 09:35–10:35.
|
||||
# 09:30 too early, 10:15 connectable, 12:30 beyond max connection.
|
||||
gwr = [
|
||||
{'depart_bristol': '07:00', 'arrive_paddington': '08:45'},
|
||||
]
|
||||
|
|
@ -143,7 +145,7 @@ def test_unreachable_morning_eurostars_lists_only_unreachable_morning_services()
|
|||
|
||||
unreachable = find_unreachable_morning_eurostars(gwr, eurostar, DATE)
|
||||
|
||||
assert [service['depart_st_pancras'] for service in unreachable] == ['09:30']
|
||||
assert [s['depart_st_pancras'] for s in unreachable] == ['09:30', '12:30']
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -205,7 +207,7 @@ def test_combine_trips_includes_ticket_fields():
|
|||
assert 'ticket_code' in t
|
||||
|
||||
|
||||
def test_unreachable_morning_eurostars_returns_empty_when_morning_service_is_reachable():
|
||||
def test_find_unreachable_eurostars_returns_empty_when_all_connectable():
|
||||
gwr = [
|
||||
{'depart_bristol': '07:00', 'arrive_paddington': '08:45'},
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue