Commit graph

5 commits

Author SHA1 Message Date
89a536dfd3 Add Eurostar Plus prices and NR advance fare support
- Eurostar scraper now fetches both Standard and Plus (PLUS class code)
  prices/seats in a single API call; each service dict gains plus_price
  and plus_seats fields
- GWR fares scraper gains fetch_advance() which makes two sets of
  paginated calls (standard advance + first-class advance) and returns
  cheapest per departure; shared _run_pages() generator reduces
  duplication in fetch()
- New /api/advance_fares/<station_crs>/<travel_date> endpoint returns
  advance fares as JSON, cached for 24 hours
- Results page gains NR ticket selector (Walk-on / Std Advance / 1st
  Advance) and Eurostar selector (Standard / Plus); total column is
  JS-computed from the selected combination with cheapest/priciest
  highlighting
- Load advance prices button fetches the API lazily; if advance fares
  are already cached they are embedded in the page and applied on load
  so the button is hidden automatically

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 16:22:24 +01:00
c22a3ea0fc Consolidate to single GraphQL call; show indirect trains; fix price formatting
Replace two-step Eurostar fetch (HTML timetable + GraphQL prices) with a
single GraphQL call that returns timing, train numbers, prices, and seats.
Support indirect services (e.g. Amsterdam) by joining multi-leg train numbers
with ' + ' and keeping the earliest arrival per departure time.
Fix half-pound prices by casting displayPrice to float instead of int.
Wrap each train number segment in white-space:nowrap so 'ES 9132 + ER 9363'
never breaks mid-segment.
Format Eurostar prices with two decimal places.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 14:46:22 +01:00
4de4c1d556 Add app route tests and fix stale assertions 2026-04-01 14:33:10 +01:00
945d028c13 Generate Eurostar timetable URLs from station IDs 2026-04-01 12:17:50 +01:00
a8e0bd39e5 Initial commit. 2026-03-30 19:34:46 +01:00