diff --git a/lib/dotcom/trip_plan/fares.ex b/lib/dotcom/trip_plan/fares.ex index 1ca35715c4..5750806bdf 100644 --- a/lib/dotcom/trip_plan/fares.ex +++ b/lib/dotcom/trip_plan/fares.ex @@ -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, @@ -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 diff --git a/lib/dotcom/trip_plan/transfer.ex b/lib/dotcom/trip_plan/transfer.ex index 27eef59609..ce85decb78 100644 --- a/lib/dotcom/trip_plan/transfer.ex +++ b/lib/dotcom/trip_plan/transfer.ex @@ -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] } @@ -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 diff --git a/test/dotcom/trip_plan/fares_test.exs b/test/dotcom/trip_plan/fares_test.exs index 944ff8fba8..4dd8079ca6 100644 --- a/test/dotcom/trip_plan/fares_test.exs +++ b/test/dotcom/trip_plan/fares_test.exs @@ -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) diff --git a/test/dotcom/trip_plan/transfer_test.exs b/test/dotcom/trip_plan/transfer_test.exs index ae589b57f2..32ac64adb1 100644 --- a/test/dotcom/trip_plan/transfer_test.exs +++ b/test/dotcom/trip_plan/transfer_test.exs @@ -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