Show cheapest GWR fare per journey and flag unreachable morning Eurostars

Add cheapest_gwr_ticket() to trip_planner.py encoding the SSS/SVS/SDS
walk-on single restrictions for Bristol Temple Meads → Paddington: on
weekdays, Super Off-Peak (£45) is valid before 05:05 or from 09:58,
Off-Peak (£63.60) from 08:26, and Anytime (£138.70) covers the gap.
Weekends have no restrictions. The fare is included in each trip dict
and displayed in a new GWR Fare column on the results page.

Also wire up find_unreachable_morning_eurostars() into the results view
so early Eurostar services unreachable from Bristol appear in the table,
with tests covering both features.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Edward Betts 2026-04-04 10:22:47 +01:00
parent b88d23a270
commit 804fcedfad
5 changed files with 428 additions and 44 deletions

16
app.py
View file

@ -7,7 +7,7 @@ from datetime import date, timedelta
from cache import get_cached, set_cached
import scraper.eurostar as eurostar_scraper
import scraper.realtime_trains as rtt_scraper
from trip_planner import combine_trips
from trip_planner import combine_trips, find_unreachable_morning_eurostars
RTT_PADDINGTON_URL = (
"https://www.realtimetrains.co.uk/search/detailed/"
@ -109,6 +109,18 @@ def results(slug, travel_date):
error = f"{error}; {msg}" if error else msg
trips = combine_trips(gwr_trains, eurostar_trains, travel_date, min_connection, max_connection)
unreachable_morning_services = find_unreachable_morning_eurostars(
gwr_trains,
eurostar_trains,
travel_date,
min_connection,
max_connection,
)
result_rows = sorted(
[{'row_type': 'trip', **trip} for trip in trips]
+ [{'row_type': 'unreachable', **service} for service in unreachable_morning_services],
key=lambda row: row['depart_st_pancras'],
)
dt = date.fromisoformat(travel_date)
prev_date = (dt - timedelta(days=1)).isoformat()
@ -121,6 +133,8 @@ def results(slug, travel_date):
return render_template(
'results.html',
trips=trips,
result_rows=result_rows,
unreachable_morning_services=unreachable_morning_services,
destinations=DESTINATIONS,
destination=destination,
travel_date=travel_date,