Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lib/dotcom/trip_plan/fares.ex
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,16 @@ defmodule Dotcom.TripPlan.Fares do

defp add_fares({leg, 0}, 0, _), do: cents_for_leg(leg)

# credo:disable-for-next-line
defp add_fares({leg, leg_index}, total, transit_legs) do
# Look at this transit leg and previous transit leg(s)
two_legs = transit_legs |> Enum.slice(leg_index - 1, 2)
three_legs = transit_legs |> Enum.slice(leg_index - 2, 3)
# If this is part of a free transfer, don't add fare
cond do
Transfer.subway_transfer?(three_legs) ->
total

Transfer.bus_to_subway_transfer?(three_legs) ->
if total == cents_for_leg(List.first(three_legs)),
do: total + 70,
Expand All @@ -46,6 +50,9 @@ defmodule Dotcom.TripPlan.Fares do
Transfer.maybe_transfer?(three_legs) ->
total

Transfer.subway_transfer?(two_legs) ->
total

Transfer.subway_after_sl1_from_airport?(two_legs) ->
total

Expand Down
12 changes: 10 additions & 2 deletions lib/dotcom/trip_plan/transfer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ defmodule Dotcom.TripPlan.Transfer do
# (can't be certain, as it depends on media used)!
@single_ride_transfers %{
:bus => [:subway, :bus],
:subway => [:subway, :bus],
:subway => [:bus],
:express_bus => [:subway, :bus, :express_bus]
}

Expand All @@ -34,12 +34,20 @@ defmodule Dotcom.TripPlan.Transfer do

@doc "Searches a list of legs for evidence of an in-station subway transfer."
@spec subway_transfer?([Leg.t()]) :: boolean
def subway_transfer?([first_leg, next_leg | _])
def subway_transfer?([first_leg, next_leg])
when agency_name?(first_leg, "MBTA") and agency_name?(next_leg, "MBTA") do
same_station?(first_leg.to, next_leg.from) and subway?(first_leg.route) and
subway?(next_leg.route)
end

def subway_transfer?([first_leg, next_leg, last_leg])
when agency_name?(first_leg, "MBTA") and agency_name?(next_leg, "MBTA") and
agency_name?(last_leg, "MBTA") do
same_station?(first_leg.to, next_leg.from) and subway?(first_leg.route) and
subway?(next_leg.route) and same_station?(next_leg.to, last_leg.from) and
subway?(last_leg.route)
end

def subway_transfer?([_ | legs]), do: subway_transfer?(legs)

def subway_transfer?(_), do: false
Expand Down
182 changes: 182 additions & 0 deletions test/dotcom/trip_plan/fares_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,188 @@ defmodule Dotcom.TripPlan.FaresTest do
end
end

test "valid two leg subway transfers" do
start_leg =
build(:transit_leg,
from: build(:place, stop: build(:stop, parent_station: %{gtfs_id: "mock-start"})),
to: build(:place, stop: build(:stop, parent_station: %{gtfs_id: "mock-midA"})),
route:
build(:route,
agency: build(:agency, name: "MBTA"),
type: 0
)
)

end_leg =
build(:transit_leg,
from: build(:place, stop: build(:stop, parent_station: %{gtfs_id: "mock-midA"})),
to: build(:place, stop: build(:stop, parent_station: %{gtfs_id: "mock-end"})),
route:
build(:route,
agency: build(:agency, name: "MBTA"),
type: 0
)
)

one_subway_fare =
build(:itinerary,
legs:
build_list(1, :transit_leg,
route:
build(:route,
agency: build(:agency, name: "MBTA"),
type: 0
)
)
)
|> fare()

fare = build(:itinerary, legs: [start_leg, end_leg]) |> fare()
assert fare <= one_subway_fare
end

test "valid three leg subway transfers" do
start_leg =
build(:transit_leg,
from: build(:place, stop: build(:stop, parent_station: %{gtfs_id: "mock-start"})),
to: build(:place, stop: build(:stop, parent_station: %{gtfs_id: "mock-midA"})),
route:
build(:route,
agency: build(:agency, name: "MBTA"),
type: 0
)
)

mid_leg =
build(:transit_leg,
from: build(:place, stop: build(:stop, parent_station: %{gtfs_id: "mock-midA"})),
to: build(:place, stop: build(:stop, parent_station: %{gtfs_id: "mock-midB"})),
route:
build(:route,
agency: build(:agency, name: "MBTA"),
type: 0
)
)

end_leg =
build(:transit_leg,
from: build(:place, stop: build(:stop, parent_station: %{gtfs_id: "mock-midB"})),
to: build(:place, stop: build(:stop, parent_station: %{gtfs_id: "mock-end"})),
route:
build(:route,
agency: build(:agency, name: "MBTA"),
type: 0
)
)

one_subway_fare =
build(:itinerary,
legs:
build_list(1, :transit_leg,
route:
build(:route,
agency: build(:agency, name: "MBTA"),
type: 0
)
)
)
|> fare()

fare = build(:itinerary, legs: [start_leg, mid_leg, end_leg]) |> fare()
assert fare <= one_subway_fare
end

test "invalid two leg subway transfers (eg red <-> blue)" do
start_leg =
build(:transit_leg,
from: build(:place, stop: build(:stop, parent_station: %{gtfs_id: "mock-start"})),
to: build(:place, stop: build(:stop, parent_station: %{gtfs_id: "mock-midA"})),
route:
build(:route,
agency: build(:agency, name: "MBTA"),
type: 0
)
)

end_leg =
build(:transit_leg,
from: build(:place, stop: build(:stop, parent_station: %{gtfs_id: "mock-midB"})),
to: build(:place, stop: build(:stop, parent_station: %{gtfs_id: "mock-end"})),
route:
build(:route,
agency: build(:agency, name: "MBTA"),
type: 0
)
)

one_subway_fare =
build(:itinerary,
legs:
build_list(1, :transit_leg,
route:
build(:route,
agency: build(:agency, name: "MBTA"),
type: 0
)
)
)
|> fare()

fare = build(:itinerary, legs: [start_leg, end_leg]) |> fare()
assert fare > one_subway_fare
end

test "invalid three leg subway transfers (eg red <-> blue)" do
start_leg =
build(:transit_leg,
from: build(:place, stop: build(:stop, parent_station: %{gtfs_id: "mock-start"})),
to: build(:place, stop: build(:stop, parent_station: %{gtfs_id: "mock-midA"})),
route:
build(:route,
agency: build(:agency, name: "MBTA"),
type: 0
)
)

mid_leg =
build(:transit_leg,
from: build(:place, stop: build(:stop, parent_station: %{gtfs_id: "mock-midA"})),
to: build(:place, stop: build(:stop, parent_station: %{gtfs_id: "mock-midB"})),
route:
build(:route,
agency: build(:agency, name: "MBTA"),
type: 0
)
)

end_leg =
build(:transit_leg,
from: build(:place, stop: build(:stop, parent_station: %{gtfs_id: "mock-other"})),
to: build(:place, stop: build(:stop, parent_station: %{gtfs_id: "mock-end"})),
route:
build(:route,
agency: build(:agency, name: "MBTA"),
type: 0
)
)

one_subway_fare =
build(:itinerary,
legs:
build_list(1, :transit_leg,
route:
build(:route,
agency: build(:agency, name: "MBTA"),
type: 0
)
)
)
|> fare()

fare = build(:itinerary, legs: [start_leg, mid_leg, end_leg]) |> fare()
assert fare > one_subway_fare
end

describe "cents_for_leg/1" do
test "walking leg" do
leg = build(:walking_leg)
Expand Down
4 changes: 0 additions & 4 deletions test/dotcom/trip_plan/transfer_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,6 @@ defmodule Dotcom.TripPlan.TransferTest do
refute [nil, bus_leg()] |> maybe_transfer?
end

test "subway -> subway" do
assert [subway_leg(), subway_leg()] |> maybe_transfer?
end

test "subway -> local bus" do
assert [subway_leg(), bus_leg()] |> maybe_transfer?
end
Expand Down
Loading