From 1415c6a13a42003e860a516b36cb11d13414cc48 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 9 Dec 2024 20:41:00 -0800 Subject: [PATCH 1/5] automatically calculate WSF fares --- .../ext/fares/impl/OrcaFareServiceTest.java | 19 ++++---- .../ext/fares/impl/OrcaFareService.java | 27 ++--------- .../ext/fares/impl/OrcaFaresData.java | 48 ------------------- .../transit/model/basic/Money.java | 5 ++ 4 files changed, 19 insertions(+), 80 deletions(-) delete mode 100644 application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFaresData.java diff --git a/application/src/ext-test/java/org/opentripplanner/ext/fares/impl/OrcaFareServiceTest.java b/application/src/ext-test/java/org/opentripplanner/ext/fares/impl/OrcaFareServiceTest.java index d1e3bd4837c..c819d4abc2e 100644 --- a/application/src/ext-test/java/org/opentripplanner/ext/fares/impl/OrcaFareServiceTest.java +++ b/application/src/ext-test/java/org/opentripplanner/ext/fares/impl/OrcaFareServiceTest.java @@ -54,8 +54,7 @@ public class OrcaFareServiceTest { private static final Money ONE_DOLLAR = usDollars(1f); private static final Money TWO_DOLLARS = usDollars(2); - private static final Money FERRY_FARE = usDollars(6.50f); - private static final Money HALF_FERRY_FARE = usDollars(3.25f); + private static final Money HALF_FERRY_FARE = usDollars(1.75f); private static final Money ORCA_SPECIAL_FARE = usDollars(1.00f); public static final Money VASHON_WATER_TAXI_CASH_FARE = usDollars(6.75f); public static final Money WEST_SEATTLE_WATER_TAXI_CASH_FARE = usDollars(5.75f); @@ -219,24 +218,24 @@ void calculateFareThatIncludesNoFreeTransfers() { getLeg(KITSAP_TRANSIT_AGENCY_ID, 121), getLeg(WASHINGTON_STATE_FERRIES_AGENCY_ID, 150, "Fauntleroy-VashonIsland") ); - calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(3).plus(FERRY_FARE)); + calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(5)); calculateFare( rides, FareType.senior, - ONE_DOLLAR.plus(ONE_DOLLAR).plus(HALF_FERRY_FARE).plus(usDollars(0.5f)) + ONE_DOLLAR.plus(ONE_DOLLAR).plus(HALF_FERRY_FARE.times(2)).plus(usDollars(0.5f)) ); calculateFare(rides, FareType.youth, Money.ZERO_USD); // We don't get any fares for the skagit transit leg below here because they don't accept ORCA (electronic) - calculateFare(rides, FareType.electronicSpecial, ONE_DOLLAR.plus(ONE_DOLLAR).plus(FERRY_FARE)); + calculateFare(rides, FareType.electronicSpecial, ONE_DOLLAR.plus(ONE_DOLLAR).plus(DEFAULT_TEST_RIDE_PRICE.times(2))); calculateFare( rides, FareType.electronicRegular, - DEFAULT_TEST_RIDE_PRICE.times(2).plus(FERRY_FARE) + DEFAULT_TEST_RIDE_PRICE.times(4) ); calculateFare( rides, FareType.electronicSenior, - ONE_DOLLAR.plus(ONE_DOLLAR).plus(HALF_FERRY_FARE) + ONE_DOLLAR.plus(ONE_DOLLAR).plus(HALF_FERRY_FARE.times(2)) ); calculateFare(rides, FareType.electronicYouth, ZERO_USD); } @@ -326,11 +325,11 @@ void calculateFareForWSFPtToTahlequah() { List rides = List.of( getLeg(WASHINGTON_STATE_FERRIES_AGENCY_ID, 0, "Point Defiance - Tahlequah") ); - calculateFare(rides, regular, FERRY_FARE); + calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE); calculateFare(rides, FareType.senior, HALF_FERRY_FARE); calculateFare(rides, FareType.youth, Money.ZERO_USD); - calculateFare(rides, FareType.electronicSpecial, FERRY_FARE); - calculateFare(rides, FareType.electronicRegular, FERRY_FARE); + calculateFare(rides, FareType.electronicSpecial, DEFAULT_TEST_RIDE_PRICE); + calculateFare(rides, FareType.electronicRegular, DEFAULT_TEST_RIDE_PRICE); calculateFare(rides, FareType.electronicSenior, HALF_FERRY_FARE); calculateFare(rides, FareType.electronicYouth, Money.ZERO_USD); } diff --git a/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java b/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java index c3c1873ad6d..1087ee6afbc 100644 --- a/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java +++ b/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java @@ -398,28 +398,11 @@ private Money getWashingtonStateFerriesFare( return defaultFare; } - var longName = routeLongName.toString().replaceAll(" ", ""); - - Map fares = OrcaFaresData.washingtonStateFerriesFares.get(longName); - // WSF doesn't support transfers so we only care about cash fares. - FareType wsfFareType; - if (fareType == FareType.electronicRegular) { - wsfFareType = FareType.regular; - } else if (fareType == FareType.electronicSenior) { - wsfFareType = FareType.senior; - } else if (fareType == FareType.electronicYouth) { - wsfFareType = FareType.youth; - } else if (fareType == FareType.electronicSpecial) { - wsfFareType = FareType.regular; - } else { - wsfFareType = fareType; - } - // WSF is free in one direction on each route - // If a fare is not found in the map, we can assume it's free. - // Route long name is reversed for the reverse direction on a single WSF route - return (fares != null && fares.get(wsfFareType) != null) - ? fares.get(wsfFareType) - : Money.ZERO_USD; + return switch (fareType) { + case youth, electronicYouth -> Money.ZERO_USD; + case regular, electronicRegular, electronicSpecial -> defaultFare; + case senior, electronicSenior -> defaultFare.half().roundDownToNearestFiveCents(); + }; } /** diff --git a/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFaresData.java b/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFaresData.java deleted file mode 100644 index acef59a7c03..00000000000 --- a/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFaresData.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.opentripplanner.ext.fares.impl; - -import java.util.Map; -import org.opentripplanner.routing.core.FareType; -import org.opentripplanner.transit.model.basic.Money; - -/** - * Class used to store all the fares for Sounder commuter rail. - * Data comes from a Python script that parses SoundTransit's website. - * A matrix or CSV parser would be a better approach to storing this data, - * but a refactor is unneeded given the proximity of GTFS Fares V2 which will render this redundant. - */ -class OrcaFaresData { - - // Spaces have been removed from the route name because of inconsistencies in the WSF GTFS route dataset. - public static Map> washingtonStateFerriesFares = Map.ofEntries( - sEntry("Seattle-BainbridgeIsland", 9.85f, 4.90f), - sEntry("Seattle-Bremerton", 9.85f, 4.90f), - sEntry("Mukilteo-Clinton", 6f, 3f), - sEntry("Fauntleroy-VashonIsland", 6.50f, 3.25f), - sEntry("Fauntleroy-Southworth", 7.70f, 3.85f), - sEntry("Edmonds-Kingston", 9.85f, 4.90f), - sEntry("PointDefiance-Tahlequah", 6.50f, 3.25f), - sEntry("Anacortes-FridayHarbor", 15.85f, 7.90f), - sEntry("Anacortes-LopezIsland", 15.85f, 7.90f), - sEntry("Anacortes-OrcasIsland", 15.85f, 7.90f), - sEntry("Anacortes-ShawIsland", 15.85f, 7.90f), - sEntry("Coupeville-PortTownsend", 4.10f, 2.05f), - sEntry("PortTownsend-Coupeville", 4.10f, 2.05f), - sEntry("Southworth-VashonIsland", 6.50f, 3.25f) - ); - - private static Map.Entry> sEntry( - String name, - float regularFare, - float seniorFare - ) { - return Map.entry( - name, - Map.of( - FareType.regular, - Money.usDollars(regularFare), - FareType.senior, - Money.usDollars(seniorFare) - ) - ); - } -} diff --git a/application/src/main/java/org/opentripplanner/transit/model/basic/Money.java b/application/src/main/java/org/opentripplanner/transit/model/basic/Money.java index 97d6f91be5a..ea0aac85cc8 100644 --- a/application/src/main/java/org/opentripplanner/transit/model/basic/Money.java +++ b/application/src/main/java/org/opentripplanner/transit/model/basic/Money.java @@ -147,6 +147,11 @@ public Money half() { return new Money(currency, IntUtils.round(amount / 2f)); } + public Money roundDownToNearestFiveCents() { + int rounded = (this.minorUnitAmount() / 5) * 5; + return new Money(Money.USD, rounded); + } + /** * Multiplies the amount with the multiplicator. */ From 3138dccf88d9f79506eb283f0820d811784b5fe7 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 9 Dec 2024 21:09:32 -0800 Subject: [PATCH 2/5] update WSF agency ID --- .../org/opentripplanner/ext/fares/impl/OrcaFareService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java b/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java index 1087ee6afbc..6ff38ad243e 100644 --- a/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java +++ b/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java @@ -39,7 +39,7 @@ public class OrcaFareService extends DefaultFareService { public static final String PIERCE_COUNTY_TRANSIT_AGENCY_ID = "3"; public static final String SKAGIT_TRANSIT_AGENCY_ID = "e0e4541a-2714-487b-b30c-f5c6cb4a310f"; public static final String SEATTLE_STREET_CAR_AGENCY_ID = "23"; - public static final String WASHINGTON_STATE_FERRIES_AGENCY_ID = "WSF"; + public static final String WASHINGTON_STATE_FERRIES_AGENCY_ID = "95"; public static final String KITSAP_TRANSIT_AGENCY_ID = "kt"; public static final String WHATCOM_AGENCY_ID = "14"; public static final int ROUTE_TYPE_FERRY = 4; From c43e2b9c858d30d9b49f89991dca02ba92870a01 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 9 Dec 2024 20:41:00 -0800 Subject: [PATCH 3/5] add javadoc, tests --- .../org/opentripplanner/ext/fares/impl/OrcaFareService.java | 3 +-- .../java/org/opentripplanner/transit/model/basic/Money.java | 6 +++++- .../java/org/opentripplanner/routing/core/MoneyTest.java | 6 ++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java b/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java index 6ff38ad243e..2b732c8dbc4 100644 --- a/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java +++ b/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java @@ -25,7 +25,6 @@ import org.opentripplanner.transit.model.basic.Money; import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.network.Route; -import org.opentripplanner.transit.model.organization.Agency; public class OrcaFareService extends DefaultFareService { @@ -401,7 +400,7 @@ private Money getWashingtonStateFerriesFare( return switch (fareType) { case youth, electronicYouth -> Money.ZERO_USD; case regular, electronicRegular, electronicSpecial -> defaultFare; - case senior, electronicSenior -> defaultFare.half().roundDownToNearestFiveCents(); + case senior, electronicSenior -> defaultFare.half().roundDownToNearestFiveMinorUnits(); }; } diff --git a/application/src/main/java/org/opentripplanner/transit/model/basic/Money.java b/application/src/main/java/org/opentripplanner/transit/model/basic/Money.java index ea0aac85cc8..5cfcf185af8 100644 --- a/application/src/main/java/org/opentripplanner/transit/model/basic/Money.java +++ b/application/src/main/java/org/opentripplanner/transit/model/basic/Money.java @@ -147,7 +147,11 @@ public Money half() { return new Money(currency, IntUtils.round(amount / 2f)); } - public Money roundDownToNearestFiveCents() { + /** + * Returns the instance rounded down to the nearest multiple of 5 cents + * So $0.25 becomes $0.10 + */ + public Money roundDownToNearestFiveMinorUnits() { int rounded = (this.minorUnitAmount() / 5) * 5; return new Money(Money.USD, rounded); } diff --git a/application/src/test/java/org/opentripplanner/routing/core/MoneyTest.java b/application/src/test/java/org/opentripplanner/routing/core/MoneyTest.java index 01392e64493..4fdb74d5340 100644 --- a/application/src/test/java/org/opentripplanner/routing/core/MoneyTest.java +++ b/application/src/test/java/org/opentripplanner/routing/core/MoneyTest.java @@ -91,6 +91,12 @@ void half() { assertEquals(Money.usDollars(0.38f), Money.usDollars(0.75f).half()); } + @Test + void roundDownToNearestFiveMinorUnits() { + assertEquals(Money.usDollars(0.1f), Money.usDollars(0.11f).roundDownToNearestFiveMinorUnits()); + assertEquals(Money.usDollars(0.5f), Money.usDollars(0.54f).roundDownToNearestFiveMinorUnits()); + } + @Test void greaterThan() { assertTrue(twoDollars.greaterThan(oneDollar)); From ce2bf50e33091d75b56d52af18bd209f10c7606e Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Wed, 11 Dec 2024 11:55:11 -0800 Subject: [PATCH 4/5] fix silly math error in comment --- .../java/org/opentripplanner/transit/model/basic/Money.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/opentripplanner/transit/model/basic/Money.java b/application/src/main/java/org/opentripplanner/transit/model/basic/Money.java index 5cfcf185af8..64238ad7afd 100644 --- a/application/src/main/java/org/opentripplanner/transit/model/basic/Money.java +++ b/application/src/main/java/org/opentripplanner/transit/model/basic/Money.java @@ -149,7 +149,7 @@ public Money half() { /** * Returns the instance rounded down to the nearest multiple of 5 cents - * So $0.25 becomes $0.10 + * So $0.14 becomes $0.10 */ public Money roundDownToNearestFiveMinorUnits() { int rounded = (this.minorUnitAmount() / 5) * 5; From 4141ce9e49205747aa34ec795fa547ab760c19c1 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Wed, 11 Dec 2024 13:37:02 -0800 Subject: [PATCH 5/5] use currency from instance --- .../java/org/opentripplanner/transit/model/basic/Money.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/opentripplanner/transit/model/basic/Money.java b/application/src/main/java/org/opentripplanner/transit/model/basic/Money.java index 64238ad7afd..8f28614069c 100644 --- a/application/src/main/java/org/opentripplanner/transit/model/basic/Money.java +++ b/application/src/main/java/org/opentripplanner/transit/model/basic/Money.java @@ -153,7 +153,7 @@ public Money half() { */ public Money roundDownToNearestFiveMinorUnits() { int rounded = (this.minorUnitAmount() / 5) * 5; - return new Money(Money.USD, rounded); + return new Money(currency, rounded); } /**