Skip to content

[CHANGE REQUEST] Per-tariff service fees in /operator/pricing-plans for out-of-station/area returns #585

@stephan233

Description

@stephan233

API Version

TOMP-API 1.6 (baseline for the proposed extension)

Summary

Introduce an optional per-tariff service fee descriptor in /operator/pricing-plans to allow to expose static fees that apply when a vehicle (e.g., bike) is returned outside a station or outside the operator’s business area. This removes the need for MaaS platforms to hardcode such fees and ensures fees are machine-readable and consistent across implementations.

We implemented the proposed functionality like in the example given in the end for the TOMP API of Call a Bike, the bikesharing system of Deutsche Bahn.

Expected Behavior

  • GET /operator/pricing-plans returns pricing plans whose tariffs may include an optional list of service fees.
  • Fees are static (non-dynamic) and defined per tariff, not globally.
  • Typical fees include charges for “return outside station” and “return outside operation area.”
  • Each fee includes amount, type (e.g., FIXED), VAT rate, and currency, aligned with existing tariff components.
  • MaaS platforms consume these fields to display and calculate total costs accordingly, without hardcoding.

Current Behavior

  • No standardized, per-tariff representation of these service fees in /operator/pricing-plans.
  • MaaS platforms often hardcode or infer such fees, leading to inconsistency and potential mismatches.

Possible Solution

Steps to Reproduce

This is no bug.

Context (Environment)

  • Use case: Free-floating or station-based micromobility where returns outside a station or outside the operator’s business area incur a fixed fee.
  • Stakeholders: MaaS Providers (defining fees per tariff), MaaS platforms (consuming and presenting fees, ensuring price transparency).
  • The extension is optional and per-tariff to allow fine-grained control, even if it introduces some redundancy across tariffs.

Detailed Description

  • Scope: Operator Information module, specifically GET /operator/pricing-plans.
  • Data model change: Introduce an optional field fees within each tariff.
  • Semantics:
    • Fees are static and applied when a vehicle is returned outside a station or outside the operation area.
    • Per-tariff configuration allows different fees by tariff/product.
  • Field definitions (aligned with existing tariff components):
    • amount: decimal >= 0
    • type: enum, FIXED (initial scope)
    • kind: categorization (e.g., SURGE; consistent usage across tariffs)
    • name: stable technical code (e.g., feeReturnOutsideStation, feeReturnOutsideOperationArea)
    • vatRate: percentage 0–100
    • currencyCode: ISO 4217 code (e.g., EUR)
    • description: optional, localization handled by MaaS platform
  • Backward compatibility: Fully backward compatible; absent field or empty array indicates no service fees. No deprecation phase required.
  • Validation: Same as existing tariff parts (amount >= 0, vatRate within 0–100, valid currencyCode, recognized type/kind).

Possible Implementation

Illustrative schema snippet for GET /operator/pricing-plans (showing a tariff with time-based components and per-tariff fee components embedded in the existing array):

[
  {
    "planId": "1532788324",
    "name": "RMVplus Starter",
    "fare": {
      "estimated": false,
      "parts": [
        {
          "amount": 0,
          "kind": "DISCOUNT",
          "unitType": "MINUTE",
          "scaleFrom": 0,
          "scaleTo": 0,
          "scaleType": "MINUTE",
          "units": 1,
          "meta": {
            "applicableAssetSubClass": "BIKE"
          },
          "type": "FLEX",
          "vatRate": 19.0,
          "currencyCode": "EUR"
        },
        {
          "amount": 1.00,
          "kind": "DEFAULT",
          "unitType": "MINUTE",
          "maximumAmount": 12.00,
          "scaleFrom": 0,
          "scaleTo": 1440,
          "scaleType": "MINUTE",
          "units": 15,
          "meta": {
            "applicableAssetSubClass": "BIKE"
          },
          "type": "FLEX",
          "vatRate": 19.0,
          "currencyCode": "EUR"
        },
        {
          "amount": 12.00,
          "kind": "DEFAULT",
          "unitType": "MINUTE",
          "maximumAmount": 12.00,
          "scaleFrom": 1440,
          "scaleType": "MINUTE",
          "units": 1440,
          "meta": {
            "applicableAssetSubClass": "BIKE"
          },
          "type": "FLEX",
          "vatRate": 19.0,
          "currencyCode": "EUR"
        },
        {
          "amount": 0.00,
          "kind": "DEFAULT",
          "type": "FIXED",
          "vatRate": 19.0,
          "currencyCode": "EUR"
        },
        {
          "amount": 0.00,
          "kind": "DISCOUNT",
          "type": "FIXED",
          "vatRate": 19.0,
          "currencyCode": "EUR"
        },
        {
          "amount": 10.00,
          "kind": "SURGE",
          "name": "feeReturnOutsideStation",
          "type": "FIXED",
          "vatRate": 19.0,
          "currencyCode": "EUR"
        },
        {
          "amount": 25.00,
          "kind": "SURGE",
          "name": "feeReturnOutsideOperationArea",
          "type": "FIXED",
          "vatRate": 19.0,
          "currencyCode": "EUR"
        }
      ]
    },
    "isTaxable": true
  }
]

Metadata

Metadata

Labels

WT1To be discussed at the next meeting

Projects

Status

In progress

Relationships

None yet

Development

No branches or pull requests

Issue actions