    CREATE OR REPLACE VIEW v_public_vehiclepositions_future_stop_times
    AS WITH RECURSIVE stop_times AS (
            SELECT rst.trip_id,
                vt.id AS trips_id,
                vt.provider_source_type,
                vp.delay,
                COALESCE(vp.last_stop_sequence, 1) AS initial_stop_sequence,
                vp.state_position,
                rst.stop_id,
                rst.stop_sequence,
                rst.computed_dwell_time_seconds,
                    CASE
                        WHEN vp.last_stop_sequence IS NULL THEN vp.delay
                        ELSE vp.delay_stop_arrival
                    END AS arrival_delay_seconds,
                    CASE
                        WHEN vp.last_stop_sequence IS NULL THEN predict_delay_seconds(vp.delay, rst.computed_dwell_time_seconds, vt.provider_source_type)
                        WHEN vp.state_position::text = 'at_stop'::text THEN
                        CASE
                            WHEN vt.provider_source_type::text = '1'::text THEN GREATEST(0, vp.delay)
                            ELSE vp.delay
                        END
                        ELSE vp.delay_stop_departure
                    END AS departure_delay_seconds
            FROM ropidgtfs_stop_times rst
                JOIN vehiclepositions_trips vt ON vt.gtfs_trip_id::text = rst.trip_id::text
                JOIN vehiclepositions_positions vp ON vp.id = vt.last_position_id AND (vp.valid_to IS NULL OR vp.valid_to >= now()) AND (vp.state_position::text = ANY (ARRAY['on_track'::character varying, 'at_stop'::character varying, 'before_track'::character varying, 'before_track_delayed'::character varying]::text[]))
            WHERE vt.gtfs_trip_id IS NOT NULL AND rst.stop_sequence = COALESCE(vp.last_stop_sequence, 1)
            UNION ALL
            SELECT rst.trip_id,
                previous_row.trips_id,
                previous_row.provider_source_type,
                previous_row.delay,
                previous_row.initial_stop_sequence,
                previous_row.state_position,
                rst.stop_id,
                rst.stop_sequence,
                rst.computed_dwell_time_seconds,
                    CASE
                        WHEN (rst.stop_sequence - previous_row.initial_stop_sequence) = 1 AND previous_row.state_position::text <> 'at_stop'::text THEN previous_row.delay
                        ELSE previous_row.departure_delay_seconds
                    END AS arrival_delay_seconds,
                predict_delay_seconds(
                    CASE
                        WHEN (rst.stop_sequence - previous_row.initial_stop_sequence) = 1 AND previous_row.state_position::text <> 'at_stop'::text THEN previous_row.delay
                        ELSE previous_row.departure_delay_seconds
                    END, rst.computed_dwell_time_seconds, previous_row.provider_source_type) AS departure_delay_seconds
            FROM stop_times previous_row
                JOIN ropidgtfs_stop_times rst ON rst.trip_id::text = previous_row.trip_id::text AND rst.stop_sequence = (previous_row.stop_sequence + 1)
            )
    SELECT stop_times.trips_id AS rt_trip_id,
        stop_times.stop_sequence,
        COALESCE(stop_times.arrival_delay_seconds, 0) AS stop_arr_delay,
        COALESCE(stop_times.departure_delay_seconds, 0) AS stop_dep_delay,
        stop_times.stop_id
    FROM stop_times    
    ORDER BY stop_times.trip_id, stop_times.stop_sequence;