Skip to content

Commit 3c44baa

Browse files
Merge pull request opentripplanner#7290 from ibi-group/hop-fare-caluclator-no-timeframes
Custom HOP fare calculator for Portand & Vancouver
2 parents 31dad82 + f3990db commit 3c44baa

6 files changed

Lines changed: 729 additions & 4 deletions

File tree

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package org.opentripplanner.ext.fares.service.gtfs.v2.custom;
2+
3+
import static com.google.common.truth.Truth.assertThat;
4+
import static org.opentripplanner.ext.fares.service.gtfs.v2.custom.OregonHopFareFactory.ADULT_REGIONAL_SINGLE_RIDE;
5+
import static org.opentripplanner.ext.fares.service.gtfs.v2.custom.OregonHopFareFactory.CATEGORY_ADULT;
6+
import static org.opentripplanner.ext.fares.service.gtfs.v2.custom.OregonHopFareFactory.HOP_FASTPASS;
7+
import static org.opentripplanner.ext.fares.service.gtfs.v2.custom.OregonHopFareFactory.LG_CTRAN_REGIONAL;
8+
import static org.opentripplanner.ext.fares.service.gtfs.v2.custom.OregonHopFareFactory.LG_TRIMET_TRIMET;
9+
import static org.opentripplanner.ext.fares.service.gtfs.v2.custom.OregonHopFareFactory.TRIMET_ADULT_SINGLE_RIDE;
10+
import static org.opentripplanner.transit.model._data.FeedScopedIdForTestFactory.id;
11+
12+
import java.util.List;
13+
import java.util.Set;
14+
import org.junit.jupiter.api.Test;
15+
import org.opentripplanner.core.model.id.FeedScopedId;
16+
import org.opentripplanner.ext.fares.model.FareLegRule;
17+
import org.opentripplanner.ext.fares.model.FareRulesData;
18+
import org.opentripplanner.ext.fares.model.FareTestConstants;
19+
import org.opentripplanner.model.fare.FareOffer;
20+
import org.opentripplanner.model.fare.FareProduct;
21+
import org.opentripplanner.model.plan.TestItinerary;
22+
import org.opentripplanner.model.plan.TestTransitLeg;
23+
import org.opentripplanner.routing.fares.FareService;
24+
import org.opentripplanner.transit.model.basic.Money;
25+
26+
class OregonHopFareFactoryTest implements FareTestConstants {
27+
28+
private static final FeedScopedId NETWORK_TRIMET = id("network-trimet");
29+
private static final FeedScopedId NETWORK_CTRAN = id("network-ctran");
30+
31+
private static final FareProduct FP_TRIMET_REGULAR = FareProduct.of(
32+
TRIMET_ADULT_SINGLE_RIDE,
33+
"regular",
34+
Money.usDollars(10)
35+
).build();
36+
37+
private static final FareProduct FP_CTRAN_REGIONAL = FareProduct.of(
38+
ADULT_REGIONAL_SINGLE_RIDE,
39+
"regular",
40+
Money.usDollars(5)
41+
).build();
42+
43+
private static final FareProduct FP_TRIMET_TO_CTRAN_TRANSFER = FareProduct.of(
44+
OregonHopFareFactory.TRIMET_TO_CTRAN_ADULT_TRANSFER,
45+
"TriMet to C-TRAN",
46+
FP_CTRAN_REGIONAL.price()
47+
)
48+
.withCategory(CATEGORY_ADULT)
49+
.withMedium(HOP_FASTPASS)
50+
.build();
51+
52+
@Test
53+
void trimetToCtranTransfer() {
54+
var service = hopService();
55+
56+
var trimetLeg = TestTransitLeg.of().withNetwork(NETWORK_TRIMET).build();
57+
var ctranLeg = TestTransitLeg.of().withNetwork(NETWORK_CTRAN).build();
58+
59+
var results = service.calculateFares(TestItinerary.of(trimetLeg, ctranLeg).build());
60+
61+
assertThat(results.getItineraryProducts()).containsExactly(FP_TRIMET_REGULAR);
62+
}
63+
64+
@Test
65+
void ctranToTrimetTransfer() {
66+
var service = hopService();
67+
68+
var ctranLeg = TestTransitLeg.of().withStartTime("10:00").withNetwork(NETWORK_CTRAN).build();
69+
var trimetLeg = TestTransitLeg.of().withStartTime("11:00").withNetwork(NETWORK_TRIMET).build();
70+
71+
var results = service.calculateFares(TestItinerary.of(ctranLeg, trimetLeg).build());
72+
73+
assertThat(results.getItineraryProducts()).isEmpty();
74+
75+
assertThat(results.getLegProducts().get(ctranLeg)).containsExactly(
76+
FareOffer.of(ctranLeg.startTime(), FP_CTRAN_REGIONAL)
77+
);
78+
assertThat(results.getLegProducts().get(trimetLeg)).contains(
79+
FareOffer.of(ctranLeg.startTime(), FP_TRIMET_TO_CTRAN_TRANSFER, Set.of(FP_CTRAN_REGIONAL))
80+
);
81+
}
82+
83+
private static FareService hopService() {
84+
var factory = new OregonHopFareFactory();
85+
86+
var data = new FareRulesData();
87+
data
88+
.fareLegRules()
89+
.addAll(
90+
List.of(
91+
FareLegRule.of(id("trimet-local"), FP_TRIMET_REGULAR)
92+
.withLegGroupId(LG_TRIMET_TRIMET)
93+
.withNetworkId(NETWORK_TRIMET)
94+
.build(),
95+
FareLegRule.of(id("ctran-regional"), FP_CTRAN_REGIONAL)
96+
.withLegGroupId(LG_CTRAN_REGIONAL)
97+
.withNetworkId(NETWORK_CTRAN)
98+
.build()
99+
)
100+
);
101+
102+
factory.processGtfs(data);
103+
return factory.makeFareService();
104+
}
105+
}

application/src/ext/java/org/opentripplanner/ext/fares/FaresConfiguration.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import org.opentripplanner.ext.fares.service.gtfs.v1.custom.HSLFareServiceFactory;
99
import org.opentripplanner.ext.fares.service.gtfs.v1.custom.HighestFareInFreeTransferWindowFareServiceFactory;
1010
import org.opentripplanner.ext.fares.service.gtfs.v1.custom.OrcaFareFactory;
11+
import org.opentripplanner.ext.fares.service.gtfs.v2.custom.OregonHopFareFactory;
1112
import org.opentripplanner.routing.fares.FareServiceFactory;
1213
import org.opentripplanner.standalone.config.framework.json.NodeAdapter;
1314
import org.opentripplanner.standalone.config.framework.json.OtpVersion;
@@ -75,6 +76,7 @@ private static FareServiceFactory createFactory(String type) {
7576
case "hsl" -> new HSLFareServiceFactory();
7677
case "atlanta" -> new AtlantaFareServiceFactory();
7778
case "orca" -> new OrcaFareFactory();
79+
case "hop" -> new OregonHopFareFactory();
7880
case "combine-interlined-legs" -> new CombineInterlinedLegsFactory();
7981
default -> throw new IllegalArgumentException(String.format("Unknown fare type: '%s'", type));
8082
};

application/src/ext/java/org/opentripplanner/ext/fares/service/gtfs/v1/DefaultFareServiceFactory.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@ public class DefaultFareServiceFactory implements FareServiceFactory {
3636

3737
protected Map<FeedScopedId, FareRuleSet> regularFareRules = new HashMap<>();
3838

39-
private final List<FareLegRule> fareLegRules = new ArrayList<>();
40-
private final List<FareTransferRule> fareTransferRules = new ArrayList<>();
39+
protected final List<FareLegRule> fareLegRules = new ArrayList<>();
40+
protected final List<FareTransferRule> fareTransferRules = new ArrayList<>();
4141

4242
// mapping the stop ids to area ids. one stop can be in several areas.
43-
private final Multimap<FeedScopedId, FeedScopedId> stopAreas = ArrayListMultimap.create();
44-
private final Multimap<FeedScopedId, LocalDate> serviceDates = ArrayListMultimap.create();
43+
protected final Multimap<FeedScopedId, FeedScopedId> stopAreas = ArrayListMultimap.create();
44+
protected final Multimap<FeedScopedId, LocalDate> serviceDates = ArrayListMultimap.create();
4545

4646
@Override
4747
public FareService makeFareService() {

0 commit comments

Comments
 (0)