Skip to content
Merged
Show file tree
Hide file tree
Changes from 60 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
ebe2c42
Add experimental schema for Fares V2
leonardehrenfried Feb 28, 2023
e290053
Flesh out schema
leonardehrenfried Feb 28, 2023
1b8c7c2
Generate code for FareProduct
leonardehrenfried Mar 1, 2023
c73be93
Flesh out implementation
leonardehrenfried Mar 1, 2023
df09496
Add documentation
leonardehrenfried Mar 1, 2023
028aab3
Fix serialization issues
leonardehrenfried Mar 1, 2023
e1636d4
Add documentation
leonardehrenfried Mar 1, 2023
d6f70b9
Add test for indexed leg products, documentation
leonardehrenfried Mar 1, 2023
9b98207
Keep insertion order of fares
leonardehrenfried Mar 1, 2023
0e54e23
Rework leg products
leonardehrenfried Mar 3, 2023
cadfbfa
Implement leg based API
leonardehrenfried Mar 3, 2023
d671d26
Use FeedScopedId for container and category
leonardehrenfried Mar 4, 2023
7eae96f
Add documentation
leonardehrenfried Mar 6, 2023
f131ff8
Update test
leonardehrenfried Mar 6, 2023
59ba6f0
Rename type
leonardehrenfried Mar 6, 2023
ba2d1ac
Make code compile
leonardehrenfried Mar 21, 2023
6d36a92
Add name to fare product
leonardehrenfried Mar 21, 2023
93b8dd0
Rename container to medium
leonardehrenfried Mar 21, 2023
7f60652
Rename fare container to fare medium
leonardehrenfried Mar 22, 2023
fc0cfa0
Make instanceId more unique
leonardehrenfried Mar 22, 2023
4dd9e23
Use more FareProductInstances
leonardehrenfried Mar 24, 2023
7d01cdf
Update snapshot tests
leonardehrenfried Mar 24, 2023
5636019
Add tests for fare instance id calculation
leonardehrenfried Mar 27, 2023
292bc8b
Improve documentation of ItineraryFares
leonardehrenfried Mar 27, 2023
4e0c6bc
Re-add backwards compatibility with the fare component
leonardehrenfried Mar 27, 2023
7392cc5
Add Javadoc
leonardehrenfried Mar 27, 2023
256229b
Separate fare product from its instance
leonardehrenfried Mar 28, 2023
ea707fd
Update documentation
leonardehrenfried Mar 28, 2023
d048f96
Remove superflouos operation
leonardehrenfried Mar 29, 2023
94b8c7e
Merge remote-tracking branch 'upstream/dev-2.x' into fares-v2-graphql
leonardehrenfried Apr 12, 2023
f8e0a93
Don't assume that fares are covering an entire itinerary
leonardehrenfried Apr 13, 2023
07ca4e3
Fix tests
leonardehrenfried Apr 13, 2023
7d5929d
Set a default list for the scheduled transit leg
leonardehrenfried Apr 13, 2023
da2396b
Add documentation
leonardehrenfried Apr 13, 2023
44a8094
Move mapping code into separate class
leonardehrenfried Apr 13, 2023
cd71e57
Move mapping code into separate class
leonardehrenfried Apr 13, 2023
3c89f1c
Make calculation of instanceId more robust
leonardehrenfried Apr 13, 2023
21dd2be
Remove name from FareComponent
leonardehrenfried Apr 13, 2023
9278bcc
Add itinerary prices in Atlanta
leonardehrenfried Apr 13, 2023
878b9c8
Deprecate the old fares
leonardehrenfried Apr 13, 2023
2cc4b46
Also add itinerary fare for Houston]
leonardehrenfried Apr 14, 2023
a23355d
Remove duplicate currency type
leonardehrenfried Apr 14, 2023
8a9151e
Combine Uber and Fares V2 features
leonardehrenfried Apr 14, 2023
dda9049
Merge remote-tracking branch 'upstream/dev-2.x' into fares-v2-graphql
leonardehrenfried Apr 17, 2023
6d3e8f7
Add test for default fares value
leonardehrenfried Apr 17, 2023
c1cd32f
Improve test
leonardehrenfried Apr 17, 2023
b8309b7
Deprecated more fields
leonardehrenfried Apr 17, 2023
5f276fe
Rename method
leonardehrenfried Apr 18, 2023
6f095af
Use fractional amounts for money representation
leonardehrenfried Apr 20, 2023
4ace231
Merge remote-tracking branch 'upstream/dev-2.x' into fares-v2-graphql
leonardehrenfried Apr 20, 2023
8f92d2c
Use new method
leonardehrenfried Apr 20, 2023
65517cf
Improve fractional digits
leonardehrenfried Apr 24, 2023
4fe7553
Rename Instance to Use
leonardehrenfried Apr 25, 2023
2852252
Merge remote-tracking branch 'upstream/dev-2.x' into fares-v2-graphql
leonardehrenfried Apr 25, 2023
db6c760
Move fare classes to core model, add @Sandbox annotation
leonardehrenfried Apr 27, 2023
899882f
Add UnsupportedOperationException
leonardehrenfried Apr 27, 2023
26d34f0
Fix fare mapping
leonardehrenfried Apr 27, 2023
a4660cc
Apply suggestions from code review
leonardehrenfried Apr 28, 2023
27a4894
Address review feedback
leonardehrenfried Apr 28, 2023
249df16
Document deprecation
leonardehrenfried Apr 28, 2023
bab7a1e
Merge remote-tracking branch 'upstream/dev-2.x' into fares-v2-graphql
leonardehrenfried May 3, 2023
f6bcbef
Fix formatting
leonardehrenfried May 3, 2023
6811254
Rename amount to price in internal model
leonardehrenfried May 3, 2023
74b7d38
Rename duration to validityDuration
leonardehrenfried May 3, 2023
b19f553
Rename 'duration' to 'validity'
leonardehrenfried May 4, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.opentripplanner.model.plan.TestItineraryBuilder.newItinerary;
import static org.opentripplanner.transit.model._data.TransitModelForTest.id;

import java.util.List;
import org.junit.jupiter.api.Test;
import org.opentripplanner.model.fare.FareProduct;
import org.opentripplanner.model.fare.FareProductUse;
import org.opentripplanner.model.fare.ItineraryFares;
import org.opentripplanner.model.plan.Itinerary;
import org.opentripplanner.model.plan.Place;
import org.opentripplanner.model.plan.PlanTestConstants;
import org.opentripplanner.routing.core.FareType;
import org.opentripplanner.routing.core.ItineraryFares;
import org.opentripplanner.routing.fares.FareService;
import org.opentripplanner.transit.model._data.TransitModelForTest;
import org.opentripplanner.transit.model.basic.Money;
Expand All @@ -30,14 +33,23 @@ public void shouldAddFare() {

input.forEach(i -> assertEquals(ItineraryFares.empty(), i.getFares()));

var twoEighty = new ItineraryFares();
twoEighty.addFare(FareType.regular, Money.euros(280));
var fares = new ItineraryFares();
fares.addFare(FareType.regular, Money.euros(280));

var filter = new FaresFilter((FareService) itinerary -> twoEighty);
var leg = i1.getLegs().get(1);
var fp = new FareProduct(id("fp"), "fare product", Money.euros(1000), null, null, null);
fares.addFareProduct(leg, fp);

var filter = new FaresFilter((FareService) itinerary -> fares);
var filtered = filter.filter(input);

filtered.forEach(i -> {
assertEquals(twoEighty, i.getFares());
});
filtered.forEach(i -> assertEquals(fares, i.getFares()));

var busLeg = filtered.get(0).getTransitLeg(1);

assertEquals(
List.of(new FareProductUse("c1a04702-1fb6-32d4-ba02-483bf68111ed", fp)),
busLeg.fareProducts()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import static org.opentripplanner.model.plan.TestItineraryBuilder.newItinerary;

import java.util.Collection;
import java.util.Currency;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -17,11 +18,12 @@
import org.opentripplanner.ext.fares.model.FareRuleSet;
import org.opentripplanner.framework.geometry.WgsCoordinate;
import org.opentripplanner.framework.i18n.NonLocalizedString;
import org.opentripplanner.model.fare.ItineraryFares;
import org.opentripplanner.model.plan.Leg;
import org.opentripplanner.model.plan.Place;
import org.opentripplanner.model.plan.PlanTestConstants;
import org.opentripplanner.routing.core.FareType;
import org.opentripplanner.routing.core.ItineraryFares;
import org.opentripplanner.transit.model.basic.Money;
import org.opentripplanner.transit.model.basic.TransitMode;
import org.opentripplanner.transit.model.framework.FeedScopedId;
import org.opentripplanner.transit.model.network.Route;
Expand All @@ -32,6 +34,7 @@ public class AtlantaFareServiceTest implements PlanTestConstants {

public static final float DEFAULT_TEST_RIDE_PRICE = 3.49f;
public static final float DEFAULT_RIDE_PRICE_IN_CENTS = DEFAULT_TEST_RIDE_PRICE * 100;
public static final Currency USD = Currency.getInstance("USD");
private static AtlantaFareService atlFareService;

@BeforeAll
Expand Down Expand Up @@ -205,8 +208,18 @@ public void useStreetcar() {
*/
private static void calculateFare(List<Leg> rides, float expectedFareInCents) {
ItineraryFares fare = new ItineraryFares();
atlFareService.populateFare(fare, null, FareType.electronicRegular, rides, null);
atlFareService.populateFare(fare, USD, FareType.electronicRegular, rides, null);
assertEquals(expectedFareInCents, fare.getFare(FareType.electronicRegular).amount());

var fareProducts = fare
.getItineraryProducts()
.stream()
.filter(fp -> fp.id().getId().equals(FareType.electronicRegular.name()))
.toList();

assertEquals(1, fareProducts.size());
var fp = fareProducts.get(0);
assertEquals(Money.usDollars((int) expectedFareInCents), fp.amount());
}

private static Leg getLeg(String agencyId, long startTimeMins) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
import org.opentripplanner.TestServerContext;
import org.opentripplanner._support.time.ZoneIds;
import org.opentripplanner.model.GenericLocation;
import org.opentripplanner.model.fare.ItineraryFares;
import org.opentripplanner.model.plan.Itinerary;
import org.opentripplanner.routing.api.request.RouteRequest;
import org.opentripplanner.routing.api.request.request.filter.AllowAllTransitFilter;
import org.opentripplanner.routing.core.FareType;
import org.opentripplanner.routing.core.ItineraryFares;
import org.opentripplanner.routing.graph.Graph;
import org.opentripplanner.standalone.api.OtpServerRequestContext;
import org.opentripplanner.transit.model.basic.Money;
Expand Down Expand Up @@ -130,7 +130,7 @@ public void testFareComponent() {

var fare = getFare(from, to, dateTime, serverContext);

var fareComponents = fare.getDetails(FareType.regular);
var fareComponents = fare.getComponents(FareType.regular);
assertEquals(fareComponents.size(), 1);
assertEquals(fareComponents.get(0).price(), tenUSD);
assertEquals(fareComponents.get(0).fareId(), new FeedScopedId(feedId, "AB"));
Expand All @@ -149,7 +149,7 @@ public void testFareComponent() {
to = GenericLocation.fromStopId("Destination", feedId, "C");
fare = getFare(from, to, dateTime, serverContext);

fareComponents = fare.getDetails(FareType.regular);
fareComponents = fare.getComponents(FareType.regular);
assertEquals(fareComponents.size(), 2);
assertEquals(fareComponents.get(0).price(), tenUSD);
assertEquals(fareComponents.get(0).fareId(), new FeedScopedId(feedId, "AB"));
Expand All @@ -163,7 +163,7 @@ public void testFareComponent() {
to = GenericLocation.fromStopId("Destination", feedId, "D");
fare = getFare(from, to, dateTime, serverContext);

fareComponents = fare.getDetails(FareType.regular);
fareComponents = fare.getComponents(FareType.regular);
assertEquals(fareComponents.size(), 1);
assertEquals(fareComponents.get(0).price(), tenUSD);
assertEquals(fareComponents.get(0).fareId(), new FeedScopedId(feedId, "BD"));
Expand All @@ -175,7 +175,7 @@ public void testFareComponent() {
to = GenericLocation.fromStopId("Destination", feedId, "G");
fare = getFare(from, to, dateTime, serverContext);

fareComponents = fare.getDetails(FareType.regular);
fareComponents = fare.getComponents(FareType.regular);
assertEquals(fareComponents.size(), 1);
assertEquals(fareComponents.get(0).price(), tenUSD);
assertEquals(fareComponents.get(0).fareId(), new FeedScopedId(feedId, "EG"));
Expand All @@ -187,7 +187,7 @@ public void testFareComponent() {
to = GenericLocation.fromStopId("Destination", feedId, "E");
fare = getFare(from, to, dateTime, serverContext);

fareComponents = fare.getDetails(FareType.regular);
fareComponents = fare.getComponents(FareType.regular);
assertEquals(fareComponents.size(), 1);
assertEquals(fareComponents.get(0).price(), tenUSD);
assertEquals(fareComponents.get(0).fareId(), new FeedScopedId(feedId, "CD"));
Expand All @@ -198,7 +198,7 @@ public void testFareComponent() {
to = GenericLocation.fromStopId("Destination", feedId, "G");
fare = getFare(from, to, dateTime, serverContext);

fareComponents = fare.getDetails(FareType.regular);
fareComponents = fare.getComponents(FareType.regular);
assertEquals(fareComponents.size(), 1);
assertEquals(fareComponents.get(0).price(), tenUSD);
assertEquals(fareComponents.get(0).fareId(), new FeedScopedId(feedId, "EG"));
Expand All @@ -210,7 +210,7 @@ public void testFareComponent() {
to = GenericLocation.fromStopId("Destination", feedId, "D");
fare = getFare(from, to, dateTime, serverContext);

fareComponents = fare.getDetails(FareType.regular);
fareComponents = fare.getComponents(FareType.regular);
assertEquals(fareComponents.size(), 2);
assertEquals(fareComponents.get(0).price(), tenUSD);
assertEquals(fareComponents.get(0).fareId(), new FeedScopedId(feedId, "AB"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
import java.util.Set;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.opentripplanner.ext.fares.model.Distance;
import org.opentripplanner.ext.fares.model.FareDistance;
import org.opentripplanner.ext.fares.model.FareLegRule;
import org.opentripplanner.ext.fares.model.FareProduct;
import org.opentripplanner.ext.fares.model.FareTransferRule;
import org.opentripplanner.framework.geometry.SphericalDistanceLibrary;
import org.opentripplanner.model.fare.Distance;
import org.opentripplanner.model.fare.FareDistance;
import org.opentripplanner.model.fare.FareLegRule;
import org.opentripplanner.model.fare.FareProduct;
import org.opentripplanner.model.fare.FareTransferRule;
import org.opentripplanner.model.plan.Itinerary;
import org.opentripplanner.model.plan.Place;
import org.opentripplanner.model.plan.PlanTestConstants;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.opentripplanner.model.plan.Itinerary;
import org.opentripplanner.model.plan.Place;
import org.opentripplanner.model.plan.PlanTestConstants;
import org.opentripplanner.routing.core.FareComponent;
import org.opentripplanner.routing.core.FareType;
import org.opentripplanner.routing.fares.FareService;
import org.opentripplanner.transit.model.basic.TransitMode;
Expand All @@ -35,7 +36,12 @@ public void canCalculateHSLFares(
) {
Assertions.assertArrayEquals(
expectedFareIds.toArray(),
fareService.getCost(i).getDetails(FareType.regular).stream().map(f -> f.fareId()).toArray()
fareService
.getCost(i)
.getComponents(FareType.regular)
.stream()
.map(FareComponent::fareId)
.toArray()
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.opentripplanner.ext.fares.impl;

import static graphql.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.opentripplanner.model.plan.TestItineraryBuilder.newItinerary;
import static org.opentripplanner.transit.model._data.TransitModelForTest.FEED_ID;
Expand All @@ -14,6 +15,7 @@
import org.opentripplanner.ext.fares.model.FareAttribute;
import org.opentripplanner.ext.fares.model.FareRuleSet;
import org.opentripplanner.framework.i18n.NonLocalizedString;
import org.opentripplanner.model.fare.FareProduct;
import org.opentripplanner.model.plan.Itinerary;
import org.opentripplanner.model.plan.PlanTestConstants;
import org.opentripplanner.routing.core.FareType;
Expand Down Expand Up @@ -41,9 +43,20 @@ public void canCalculateFare(
float expectedFare
) {
var fares = fareService.getCost(i);
assertEquals(Money.usDollars(Math.round(expectedFare * 100)), fares.getFare(FareType.regular));

fares.getTypes().forEach(t -> assertEquals(List.of(), fares.getDetails(t)));
final Money expected = Money.usDollars(Math.round(expectedFare * 100));
assertEquals(expected, fares.getFare(FareType.regular));

for (var type : fares.getFareTypes()) {
assertTrue(fares.getComponents(type).isEmpty());

var prices = fares
.getItineraryProducts()
.stream()
.filter(fp -> fp.name().equals(type.name()))
.map(FareProduct::amount)
.toList();
assertEquals(List.of(expected), prices);
}
}

private static List<Arguments> createTestCases() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,18 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.opentripplanner.model.fare.ItineraryFares;
import org.opentripplanner.model.plan.Itinerary;
import org.opentripplanner.routing.core.FareType;
import org.opentripplanner.routing.core.ItineraryFares;
import org.opentripplanner.routing.fares.FareService;
import org.opentripplanner.transit.model.basic.Money;

/**
* @author laurent
*/
@Disabled
public class MultipleFareServiceTest {

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import java.util.Arrays;
import java.util.Collection;
import java.util.Currency;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -30,10 +31,11 @@
import org.opentripplanner.ext.fares.model.FareRuleSet;
import org.opentripplanner.framework.geometry.WgsCoordinate;
import org.opentripplanner.framework.i18n.NonLocalizedString;
import org.opentripplanner.model.fare.FareProductUse;
import org.opentripplanner.model.fare.ItineraryFares;
import org.opentripplanner.model.plan.Leg;
import org.opentripplanner.model.plan.Place;
import org.opentripplanner.routing.core.FareType;
import org.opentripplanner.routing.core.ItineraryFares;
import org.opentripplanner.transit.model.basic.TransitMode;
import org.opentripplanner.transit.model.framework.FeedScopedId;
import org.opentripplanner.transit.model.network.Route;
Expand All @@ -42,6 +44,7 @@

public class OrcaFareServiceTest {

public static final Currency USD = Currency.getInstance("USD");
private static TestOrcaFareService orcaFareService;
public static final float DEFAULT_TEST_RIDE_PRICE = 3.49f;
private static final int DEFAULT_RIDE_PRICE_IN_CENTS = (int) (DEFAULT_TEST_RIDE_PRICE * 100);
Expand All @@ -60,7 +63,7 @@ public static void setUpClass() {
*/
private static void calculateFare(List<Leg> legs, FareType fareType, float expectedFareInCents) {
ItineraryFares fare = new ItineraryFares();
orcaFareService.populateFare(fare, null, fareType, legs, null);
orcaFareService.populateFare(fare, USD, fareType, legs, null);
Assertions.assertEquals(expectedFareInCents, fare.getFare(fareType).amount());
}

Expand All @@ -74,8 +77,9 @@ private static void assertLegFareEquals(

var rideCost = legFareProducts
.stream()
.map(FareProductUse::product)
.filter(fp ->
fp.container().name().equals("electronic") &&
fp.medium().name().equals("electronic") &&
fp.category().name().equals("regular") &&
fp.name().equals("rideCost")
)
Expand All @@ -87,8 +91,9 @@ private static void assertLegFareEquals(

var transfer = legFareProducts
.stream()
.map(FareProductUse::product)
.filter(fp ->
fp.container().name().equals("electronic") &&
fp.medium().name().equals("electronic") &&
fp.category().name().equals("regular") &&
fp.name().equals("transfer")
)
Expand Down Expand Up @@ -146,7 +151,7 @@ public void calculateFareWithNoFreeTransfer() {
public void calculateFareByLeg() {
List<Leg> rides = List.of(getLeg(KITSAP_TRANSIT_AGENCY_ID, 0), getLeg(COMM_TRANS_AGENCY_ID, 2));
ItineraryFares fares = new ItineraryFares();
orcaFareService.populateFare(fares, null, FareType.electronicRegular, rides, null);
orcaFareService.populateFare(fares, USD, FareType.electronicRegular, rides, null);

assertLegFareEquals(349, rides.get(0), fares, false);
assertLegFareEquals(0, rides.get(1), fares, true);
Expand Down Expand Up @@ -468,7 +473,7 @@ void nullLongName(FareType type) {
);

var fare = new ItineraryFares();
orcaFareService.populateFare(fare, null, type, legs, null);
orcaFareService.populateFare(fare, USD, type, legs, null);
assertNotNull(fare.getFare(type));
}

Expand All @@ -490,7 +495,7 @@ void nullShortName(FareType type) {
);

var fare = new ItineraryFares();
orcaFareService.populateFare(fare, null, type, legs, null);
orcaFareService.populateFare(fare, USD, type, legs, null);
assertNotNull(fare.getFare(type));
}

Expand Down
Loading