Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fare media #355

Merged
merged 39 commits into from
Mar 14, 2023
Merged

Conversation

isabelle-dr
Copy link
Collaborator

@isabelle-dr isabelle-dr commented Nov 1, 2022

Hi everyone!

I am opening this Pull Request as part of the second implementation of Fares v2. I am opening it in the exact same state PR #342 was when closed, and I will update the proposal based on feedback already received so we can resume where we left off. For more information on the plan, please refer to issue #341.
This pull request covers Fare Containers, which is a section of the entire GTFS-Fares v2 proposal.
EDIT: this proposal has been slightly modified to represent a broader "fare media", that contains fare media and passes and can be used to travel. See the latest proposal here: https://share.mobilitydata.org/fare-container-updated-proposal

Scope of this PR:

  • To define the fare containers media that an agency accepts
  • To describe the fares if riders pay using their fare containers media (vs. tickets not loaded on a fare container)

Not doing as part of this PR:

  • The scope does not include any functionalities that pertain to tracking when riders recharge or use up their fare containers.

[Original message posted by @omar-kabbani in PR #342]

The changes in this pull request are:

  • Add new file; fare_containers.txt, to define new fare containers.
  • Extend fare_products.txt with fare_container_id to assign fare products to fare containers and to define the price of a fare if a fare container is used to pay.

The behaviour of fare_leg_rules.txt and fare_transfer_rules.txt is unchanged as the cost of a fare leg or a transfer is tied to a fare product. The modelling of the cost of a one-way ticket purchased as a ticket vs. loaded on a fare container factors in fare_products.txt.

Here's a quick example:

  • A fare container costs 5 CAD.
  • A fare is 3 CAD, however, if riders load the fare on their fare container and pay with it, a fare is 2.95 CAD.
  • Riders can transfer once - in a period of one hour - if they do not have a fare container, they will pay 0.05 CAD to transfer, however, if they transfer using their fare container, the transfer is free.

Define a fare container in fare_containers.txt

fare_container_id amount currency
container 5 CAD

Define the fare structure (paying for a fare with and without the fare container) in fare_products.txt

fare_product_id fare_container_id amount currency
single_leg 3 CAD
single_leg container 2.95 CAD
transfer_cost 0.05 CAD
transfer_cost container 0 CAD

Define fare legs using fare_leg_rules.txt

leg_group_id from_area_id to_area_id network_id fare_product_id
leg1 zoneA zoneB bus single_leg

Define transfer rules using fare_transfer_rules.txt

from_leg_group_id to_leg_group_id transfer_count duration_limit duration_limit_type fare_transfer_type fare_product_id
leg1 leg1 1 3600 0 0 transfer_cost

Data consumer: Apple
Data producer:

 Interline

Please go through the changes and share your thoughts here!
Looking forward to feedback and contribution on this proposal.

For other questions/concerns, don’t hesitate to reach out to specifications@mobilitydata.org.

Clearly indicate that fare_containers.txt falls under GTFS-Fares v2 and not v1
Add fare_containers to the dataset files table
@google-cla
Copy link

google-cla bot commented Nov 1, 2022

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@isabelle-dr isabelle-dr linked an issue Nov 1, 2022 that may be closed by this pull request
@isabelle-dr isabelle-dr added the GTFS Schedule Issues and Pull Requests that focus on GTFS Schedule label Nov 1, 2022
@isabelle-dr isabelle-dr mentioned this pull request Nov 1, 2022
@isabelle-dr
Copy link
Collaborator Author

Based on the discussions that already happened, as of today the open items are:

  • Adding a fare container type, which would be done by extending fare_containers.txt with a field called fare_container_type that defines whether the container is a physical card, a mobile app, or both.
  • review the field name amount in fare_containers.txt to better represent the cost to purchase the fare container.
  • discuss if we want travel_rules.payment_method (part of the broader GTFS-Travel-Rules proposal) moved to fare_products.txt, to provide information on how can riders can pay for the fare products.

@e-lo
Copy link

e-lo commented Nov 3, 2022

We at Cal-ITP just want to be able to efficiently provide information (e.g. adding this handy icon to the travel plan in a trip planner app) that a rider can tap to pay w/a normal EMV card. I do not believe the current proposal does this - we will support one that does.

image

@irees
Copy link

irees commented Nov 5, 2022

I think this works well with Interline's current data and implementation. 👍

@isabelle-dr
Copy link
Collaborator Author

isabelle-dr commented Nov 11, 2022

Thank you for the feedback!
Here are the latest updates to this proposal:

  1. updated the description of amount and minimal_initial_purchase to clarify their intended use. I kept the amount field name to stay consistent with fare_products.txt. Let me know if you still think the field name should be changed, or if this new description solves the confusion. See the change here.
  2. added an optional fare_container_type field to define whether the container is a physical card, a mobile app, or both.
  3. Updated the primary key of fare_products.txt as flagged by @npaun

For payment methods: I see the temptation to use the container to discriminate fares that depend on the payment method. Before modifying the proposal, I'd like to know if we have a general agreement on the following design. I used Interline's MTC dataset as an example:

  • fare_container.txt
fare_container_id fare_container_name amount minimum_initial_purchase currency
clipper Clipper 3   USD
  • fare_products.txt (current)
fare_product_id fare_product_name amount currency fare_container_id
AC:local:single AC Transit local fare 2.5 USD cash
AC:local:single AC Transit local fare 2.25 USD clipper
AC:transfer:transbay-upgrade AC Transit Transbay upgrade 3.5 USD cash
AC:transfer:transbay-upgrade AC Transit Transbay upgrade 3.75 USD clipper
  • fare_products.txt with added payment_method
fare_product_id fare_product_name amount currency fare_container_id payment_method
AC:local:single AC Transit local fare 2.5 USD   [3, 4, 5]
AC:local:single AC Transit local fare 2.25 USD clipper [3, 4, 5, 6]
AC:transfer:transbay-upgrade AC Transit Transbay upgrade 3.5 USD   [3, 4, 5]
AC:transfer:transbay-upgrade AC Transit Transbay upgrade 3.75 USD clipper [3, 4, 5, 6]

Assuming payment_method would be a list of payments accepted. What we currently have in GTFS-TravelRules is:
0: any
1: coins
2: exact cash (includes 1)
3: cash with change (includes 1 and 2)
4: bank card
5: contactless bank card (physical or virtual card in Apple Pay &co)
6: mobile wallet (ex: Clipper)

Note that this field was initially designed as an Enum (pick only one) and not a List (pick all that apply).

  • fare_leg_rules.txt
leg_group_id from_area_id to_area_id network_id fare_product_id
AC AC:local AC:local AC AC:local:single
AC AC:transbay AC:transbay AC AC:local:single
  • fare_transfer_rules.txt
from_leg_group_id to_leg_group_id transfer_count duration_limit duration_limit_type fare_transfer_type fare_product_id
AC AC:transbay   7200 1 0 AC:transfer:transbay-upgrade

Looking forward to hear your thoughts on this.
Tagging @irees @e-lo @davidlewis-ito @flocsy who were involved in the previous PR.

@bdferris-v2
Copy link
Collaborator

The combination of payment_method and fare_container_id seem a bit duplicative of each other, especially when treating payment_method as a list. In AC:local:single with fare_container_id=clipper, what does it mean that cash is accepted as a payment method but the Clipper card is the fare container? I'd be interested to hear more from the original authors about the interactions of these fields.

@flocsy
Copy link
Contributor

flocsy commented Nov 13, 2022

I agree with @bdferris-v2 regarding the issue with "clipper + cash", though I thought it's mainly a typo. The payment method in the clipper lines should be [6]

However even after fixing that he's right, that it's repeating itself (fare_container_id: clipper and [6])

I don't understand some of the payment_methods:

  • I guess 1:coins means no paper, because it needs to be entered to a machine that only accepts coins?

  • 6:mobile_wallet is a little bit confusing, because Google wallet, Google Pay, Apple pay, Garmin pay are all considered a wallet by many (and Google wallet even called as such). Maybe mobile_app is better? But not sure, 'cause all the above are also apps :) Maybe a way to clarify the difference is to include also "NFC" in 5:contactless_bank_card. I'd even change their names to 5:contactless_nfc and 6:mobile_app This still has some overlap because of the app, but maybe because of the NFC being part of the name it's clearer that 5 means anything that uses the NFC technology (at 1st I thought it's not a good idea to include one particular technology as the name, but then I thought about it: if there will ever be another contactless technology then we'll anyway need to add a new enum value to be differentiate, because when I go abroad with my NFC compatible phone I'll need to know if I can or can't use it) and this leaves the 6:mobile_app a little bit clearer (though it'll also need a description that tells that it's an app that doesn't use NFC but rather some other way (QA code / numeric code / bar code / camera / push notification / etc...) to validate/pay.

I'll also drop in another thought/question: Let's say there's a container called "C". It can be loaded with $5 | $25 | $50. How would we indicate this information? We could add these as 3 lines in fare_products.txt but how do we indicate in fare_container.txt that it can be only loaded using these 3 amounts and not any amount I choose?

Also maybe it's better to keep all the filenames either single or plural (currently we have fare_productS vs fare_container)

@davidlewis-ito
Copy link

Great to see this discussion moving forward.

Payment Types
I would suggest that this column should appear both on the fare_product table AND the fare_container table.

  • Within the fare_product table the field should be empty where there is a fare_container_id. this implies that option 6 of the payment_type enum is not required
  • Within the fare_container table the payment_type refers to the means by which the container stored value may be increased.

Transfers
In many cases a (free) transfer only applies if the same fare_container or payment type is used on both legs. Examples include the London Bus, New York MTA.

So given we are now proposing to introduce these discriminating factors into the product table it seems we need to revisit how fare_transfer_rules interact with fare_leg_rules and/or fare_products. We haven't thought this through in great detail but perhaps introducing a fare_group_id into fare_products would allow one to filter the available transfers appropriately. We note also that there is more work to be done with respect to fare_transfer_rules to make them fit for the real world.

@isabelle-dr
Copy link
Collaborator Author

Hello everyone,

MobilityData will host a roundtable discussion this week on Thursday 1 December 11:00 AM ET to discuss the open items in this PR.
We are also hosting a discussion around higher-level GTFS Fares-v2 discriminating factors and design principles, which will happen the day before on Wednesday 30 November 11:00 AM ET and it is intended to inform the decisions for this PR.

You can access both events via this calendar, and you can reach out to specifications@mobilitydata.org to get an invite on your e-mail.

@npaun
Copy link
Contributor

npaun commented Nov 30, 2022

We'd love to see fare containers move forward as a simple, straightforward proposal.

Minimum requirements

If you strip the proposal down to the bare minimum, you have this:

fare_products.txt

fare_product_id fare_product_name amount currency fare_container_id (new)
single-ride Single ride 2.50 USD clipper

fare_containers.txt

fare_container_id fare_container_name
clipper Clipper card

With just this functionality, we can already tell riders whether they need to use a fare container for their trip, and what it's called. This proposal documents the existing data produced by Interline, consumed by Transit and Apple. It gives us room to expand as needs are identified concretely later.

Payment types

I'd propose going one step further in this PR. We should add a fare_container_type enum including:

  • Fare card
  • Mobile app
  • Contactless payment
  • Cash

This has a number of advantages:

  • As @e-lo mentioned, just being able to show riders a contactless symbol where this is available is a massive value-add to user experience.
  • We would have just one consistent abstraction covering all of the different 'ways to pay', rather than treating fare cards as as a special case.

We're already using a similar approach internally (for example, we detect Interline's cash and clipper fare containers), but it would be nice to have a standardized approach.

If necessary, I'd suggest proceding with a vote on just the 'bare minimum' proposal for now, with payment types being a 'nice to have' extension.

@bdferris-v2
Copy link
Collaborator

As mentioned in today's meeting, I have thoughts and in the interest of not holding up the process (though my thoughts will inevitably hold up the process), let me be up-front about them:

In general, I'm tentatively on-board with a pivot from "fare containers" to "fare payment". But if we make that pivot, then I think we need to be serious about it. The file and field names we choose here are going to be with us for years (if we do it right) and I don't want to spend the next decade explaining why we used confusing name for something.

To that end, I think file and field naming should reflect "fare payment types", not "fare containers" (unless someone wants to convince me that cash is a fare container somehow?). To be specific:

  • fare_containers.txt => fare_payment_types.txt
  • fare_container_id => fare_payment_type_id
  • fare_container_type => fare_payment_type and make this field required (and possibly non-repeatable? Should cash be usable twice, for example?) - making this required because there is a ton of value for feed consumers being able to distinguish different types of payment in a consistent way without having to parse the name field.
  • fare_container_name => fare_payment_type_name
  • amount + minimum_initial_purchase + currency: these field names are even more confusing when used in the context of a fare payment type like cash. I'd propose naming + textual descriptions that indicate that these are specific to fare cards/containers, like fare_container_purchase_price and fare_care_initial_purchase_balance or something.

Ok, maybe you just read that and groaned "omg we are never going to get this passed". Fair enough.

Potentially-less-impactful alternatives considered:

  • I suspect that for most providers, the fare_payment_type enum is going to be the only field used. To split the difference between @isabelle-dr 's proposal in Add fare media #355 (comment) and @npaun 's proposal in Add fare media #355 (comment), I'd propose adding fare_payment_type as a field in fare_products.txt, but keep it as a single-valued column (it was a collection of values in the first proposal, or at least as I read it). For simple, cash-based systems, it'd be straight-forward to specify the single type column there without having to specify an additional file. The remainder of the fare container proposal would be kept as originally proposed, such that for container payment types, you could link out to additional information in fare_containers.txt. Similarly, specifying a fare container for a non-container type (e.g. cash) would probably be forbidden. Really, this fixes my original concern with the proposal from @isabelle-dr in Add fare media #355 (comment), where multiple payment types + containers were all bundled together. It still may result in a lot of duplicated rows in fare_products.txt where the price is the same for N different fare payment types, but the proposal from @npaun in Add fare media #355 (comment) has the same properties.

Thoughts?

@npaun
Copy link
Contributor

npaun commented Dec 1, 2022

  • We would prefer to proceed with option A (fare_containers renamed to fare_payment_types).
  • We would drop the fields amount and mimimum_initial_purchase from this PR because they created a lot of debate over interpretation, and I don't think there is any consumer that currently plans to show this data in their UI. They could easily be brought back in a later proposal once a UX case is developed by a consumer.
  • Option B spreads payment type info over two files: fare_products.txt and fare_containers.txt. At some point during the discussion, fare_containers.txt also had a different payment type enum (for mobile app vs physical card), leading to redundancy. It also raises questions about whether or not fare_products.payment_type is redundant with fare_products.fare_container_id.

- replaced container with payment type
- made fare_payment_type required
- changed the id to fare_payment_type_group as a non-unique ID field
@isabelle-dr
Copy link
Collaborator Author

isabelle-dr commented Dec 8, 2022

Hello,

We have worked on a modification for this proposal. We believe this would address the in-scope issues raised on this PR & during the roundtable discussions, and it could be extended to address the other needs expressed.

Please note that Mobilitydata would like to open a vote on this proposal if there are no major concerns and if organizations already working with fare containers can confirm this proposal works in practice: Interline, Apple, TransitApp, Cal-ITP, Maryland Transit Administration, San Diego MTS.

Here are the changes:

  • renamed fare_containers to fare_payment_types to include cash and bank cards, as proposed by @bdferris-v2 and as a result of discussions in the original PR. We acknowledge that this concept contains payment methods (cash and bank card) and "supports" used to validate a fare product that has already been purchased (transit card, mobile app). We see payment types as "what a traveler can bring with them to pay for the ride". We explored keeping these concepts separate and it led to considerably more complexity for questionable value.
  • the "types" enum values were chosen based on what stakeholders are interested in showing to riders. There is a mention that the name field should be added if the type is transit card or mobile app, so that it can be displayed to riders.
  • dropped amount and mimimum_initial_purchase as @npaun suggested.
  • instead of having unique ids in fare_payment_types.txt, each id would form a group, a bit like how fare_products.txt work: in the same way one fare_product_id is a group of fare products that have the same behaviour in leg and transfer rules, fare_payment_method_group_id is a group composed of payment methods that have similar behaviour. This would avoid duplicating lines in fare_products.txt when we have the same price for N payment methods as @bdferris-v2 flagged.

Functionalities this allows

  • model price differences based on the payment type
  • show a rider the “tap-to-pay” icon, meaning that a contactless bank card can be used, as flagged by @e-lo
  • show riders transit cards and mobile apps that can be used for the ride

Further possible iterations

  • allowing a simple design for cash-only fare systems: consider that empty fare_products.fare_payment_type_group_id means cash or add fare_payment_type in fare_products.txt with a mention that only one of fare_payment_type and fare_payment_type_group_id can be specified for a record in fare_products.txt
  • modeling transfers discounts (where a transfer is free only if a certain payment method is used): we could imagine using a method similar to the idea behind the filter_fare_product field: fare_payment_method_type in fare_transfer_rules.txt, for example.
  • expanding fare_payment_types.txt to add how much a transit card costs, how much has to be (or can be) loaded on it, more enums, etc.

This proposal is available in a google doc format with a data example at https://share.mobilitydata.org/fare-containers-to-fare-payment-types-proposal.

Looking forward to hearing your thoughts!

@isabelle-dr
Copy link
Collaborator Author

Hello everyone,
The proposal has been updated to reflect the last details (using media instead of medium for the singular, updating the description of fare_media_type = 0, and resolving small typos).
Apple has updated the changes to their end-to-end test environment, and they confirm that the dataset posted by Interline works and can replace the current production dataset (with fare_containers.txt).
Please note that fare_media_type=1 is reserved for physical paper tickets and will be adopted when we have a producer for it.

We are opening a vote for adding Fare Media, which is part of the GTFS-fares v2 proposal.

There are at least two producers:

And at least one consumer:

Voting ends on 2023-03-13 at 23:59:59 UTC.

@isabelle-dr isabelle-dr added the Status: Voting Pull Requests where the advocate has called for a vote as described in the changes.md label Mar 6, 2023
@bdferris-v2
Copy link
Collaborator

I guess someone needs to go first:

+1 from Google

Though I'll note most of the test feeds still reference fare_medium_* field names, not fare_media_*. I don't think that's a blocker, but wanted to call it out.

gtfs/spec/en/reference.md Outdated Show resolved Hide resolved
@flocsy
Copy link
Contributor

flocsy commented Mar 7, 2023

Added a comment about what I think is a small typo. I'll let the native English speakers decide and fix that if it's necessary. Other than that I am voting for it:
+1 Moovit

@davidlewis-ito
Copy link

+1 Ito

@saraemarcus
Copy link

+1 Apple

@matikin9
Copy link

matikin9 commented Mar 7, 2023

+1 LA Metro! 💃

@drewda
Copy link

drewda commented Mar 7, 2023

+1 from Interline (as producer of the SF Bay Area Regional Feed)

@e-lo
Copy link

e-lo commented Mar 8, 2023

+1 🥳 👩‍🎤 🎸 Cal-ITP and Friends. 🙇‍♀️ to all who helped make this happen.

We are really looking forward to getting this information to customers!

@westontrillium
Copy link
Contributor

+1 from Trillium!

@brodyFlannigan
Copy link

+1 Transcollines!

@isabelle-dr
Copy link
Collaborator Author

isabelle-dr commented Mar 14, 2023

The voting period ended on 2023-03-13 at 23:59:59 UTC.

With 9 votes in favour and no votes against, the vote to extend GTFS with Fare Media passes! The votes came from:
Google (@bdferris-v2)
Moovit (@flocsy)
ITO World (@davidlewis-ito)
Apple Maps (@saraemarcus)
LA Metro (@matikin9)
Interline (@drewda)
Cal-ITP (@e-lo)
Trillium (@westontrillium)
Transcollines (@brodyFlannigan)

The GTFS Fares-v2 Google Doc (share.mobilitydata.org/gtfs-fares-v2) has been updated to reflect this change and also contains additional Fare Media fields that were not part of this Pull Request, mainly:

  • the paper_ticket value for fare_media_type
  • the fare_media_groups.txt file, which provides a mechanism to model groups of fare media that can each be associated with the same fare product
  • a fare_validation_method field

Many thanks to everyone who participated in this Pull Request and in the working group meetings! Your time and dedication have truly made this possible. Thank you all so much for your outstanding contributions!

For those of you who want to stick around, the work continues in PR#357 to add time-variable fares!

@drewda
Copy link

drewda commented Mar 14, 2023

Thank you, @isabelle-dr and all.

For those interested in how this will affect the SF Bay Area Regional Feed, our team will be taking the following steps to migrate:

  1. add fare_media.txt (and continue to include fare_containers.txt)
  2. wait a few weeks while data consumers switch to processing the new fare_media.txt file)
  3. remove the fare_containers.txt file

We'll also be updating our tables at https://www.interline.io/blog/mtc-regional-gtfs-feed-fares-updates/#gtfs-fares-v2-base-implementation-and-future-additions-to-the-specification to reflect the adoption of fare_media.txt

(Any questions about this and other topics related to the SF Bay Area Regional Feed are welcome at https://groups.google.com/g/511sfbaydeveloperresources/ )

@emmambd emmambd removed the Status: Voting Pull Requests where the advocate has called for a vote as described in the changes.md label May 5, 2023
@isabelle-dr isabelle-dr added Change: Addition New function proposed to the specification. Extension: GTFS-Fares Issues and Pull Requests that focus on GTFS-Fares Extension labels Jul 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Change: Addition New function proposed to the specification. Extension: GTFS-Fares Issues and Pull Requests that focus on GTFS-Fares Extension GTFS Schedule Issues and Pull Requests that focus on GTFS Schedule
Projects
None yet
Development

Successfully merging this pull request may close these issues.

GTFS-Fares v2 Fare containers