From 86f2302ad4d7cf76627af9eac3cb6343579d5b87 Mon Sep 17 00:00:00 2001 From: Marius Angelmann <70228295+mariusangelmann@users.noreply.github.com> Date: Mon, 14 Jul 2025 19:48:41 +0200 Subject: [PATCH] Add BMIS number support for business customer rates (#30) * Add BMIS number support for business customer rates Introduces a new `bmisNumber` option to journey requests, allowing bahn.business customers to access corporate rates by providing their 7-digit BMIS number. Adds documentation and a `createBusinessClient` helper for convenience. The request payload now includes a `firmenZugehoerigkeit` object when a BMIS number is set. * Update cspell.config.json Update cspell.config.json to fix spell check issues in PR #30 --- cspell.config.json | 5 +++++ docs/journeys.md | 22 ++++++++++++++++++++++ index.js | 28 ++++++++++++++++++++++++++++ p/dbnav/journeys-req.js | 12 +++++++++++- 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/cspell.config.json b/cspell.config.json index 6d6a35ec..fb6e073f 100644 --- a/cspell.config.json +++ b/cspell.config.json @@ -95,6 +95,8 @@ "bitmasks", "Blaschkoallee", "Blissestr", + "bmis", + "BMIS", "BNWNZF", "Böhme", "BONVOYO", @@ -195,6 +197,7 @@ "Fehrbelliner", "Fernbf", "Fernverkehr", + "firmen", "Flexpreis", "Flix", "Fltr", @@ -263,6 +266,7 @@ "Hohenzollerndamm", "Hüngheim", "IBNR", + "identifikationsart", "Ihren", "Ihrer", "Informationen", @@ -610,6 +614,7 @@ "Zoologischer", "Zuege", "zugart", + "Zugehoerigkeit", "zugattrib", "zugattribute", "Zuges", diff --git a/docs/journeys.md b/docs/journeys.md index 8b576890..cdd29d26 100644 --- a/docs/journeys.md +++ b/docs/journeys.md @@ -81,6 +81,7 @@ With `opt`, you can override the default options, which look like this: firstClass: false, // first or second class for tickets loyaltyCard: null, // BahnCards etc., see below language: 'en', // language to get results in + bmisNumber: null, // 7-digit BMIS number for business customer rates } ``` @@ -316,6 +317,27 @@ hafas.journeys(from, to, { }) ``` +## Using the `bmisNumber` option + +bahn.business customers with a BMIS number can get their corporate rates and corporate tariffs by providing their 7-digit BMIS number: + +```js +// Option 1: Using the bmisNumber parameter directly +await client.journeys(from, to, { + bmisNumber: '1234567' // Your 7-digit BMIS number +}) + +// Option 2: Using the createBusinessClient helper function +import {createBusinessClient} from 'db-vendo-client' +import {profile as dbProfile} from 'db-vendo-client/p/db/index.js' + +const businessClient = createBusinessClient(dbProfile, userAgent, '1234567') +// Now all journey searches will automatically include the BMIS number +await businessClient.journeys(from, to) +``` + +When a BMIS number is provided, the request will include a `firmenZugehoerigkeit` object with the BMIS number and identification type, allowing business customers to access their special rates and conditions. + ## The `routingMode` option The `routingMode` option is not supported by db-vendo-client. The behavior will be the same as the [`HYBRID` mode of hafas-client](https://github.com/public-transport/hafas-client/blob/main/p/db/readme.md#using-the-routingmode-option), i.e. cancelled trains/infeasible journeys will also be contained for informational purpose. \ No newline at end of file diff --git a/index.js b/index.js index eaa0a623..b26e9345 100644 --- a/index.js +++ b/index.js @@ -183,6 +183,7 @@ const createClient = (profile, userAgent, opt = {}) => { bestprice: false, // search for lowest prices across the entire day deutschlandTicketDiscount: false, deutschlandTicketConnectionsOnly: false, + bmisNumber: null, // 7-digit BMIS number for business customer rates }, opt); if (opt.when !== undefined) { @@ -243,6 +244,7 @@ const createClient = (profile, userAgent, opt = {}) => { scheduledDays: false, // parse & expose dates the journey is valid on? deutschlandTicketDiscount: false, deutschlandTicketConnectionsOnly: false, + bmisNumber: null, // 7-digit BMIS number for business customer rates }, opt); const req = profile.formatRefreshJourneyReq({profile, opt}, refreshToken); @@ -395,7 +397,33 @@ const createClient = (profile, userAgent, opt = {}) => { return client; }; +const createBusinessClient = (profile, userAgent, bmisNumber, opt = {}) => { + if (!bmisNumber || typeof bmisNumber !== 'string') { + throw new TypeError('bmisNumber must be a non-empty string'); + } + + // Create a client with BMIS number included in all journey requests + const client = createClient(profile, userAgent, opt); + + // Wrap journeys method to always include BMIS number + const originalJourneys = client.journeys; + client.journeys = async (from, to, opt = {}) => { + return originalJourneys(from, to, {...opt, bmisNumber}); + }; + + // Wrap refreshJourney method to always include BMIS number + if (client.refreshJourney) { + const originalRefreshJourney = client.refreshJourney; + client.refreshJourney = async (refreshToken, opt = {}) => { + return originalRefreshJourney(refreshToken, {...opt, bmisNumber}); + }; + } + + return client; +}; + export { createClient, + createBusinessClient, loadEnrichedStationData, }; diff --git a/p/dbnav/journeys-req.js b/p/dbnav/journeys-req.js index ef1354b1..b3baf1d3 100644 --- a/p/dbnav/journeys-req.js +++ b/p/dbnav/journeys-req.js @@ -4,7 +4,7 @@ const formatBaseJourneysReq = (ctx) => { // TODO opt.accessibility // TODO routingMode const travellers = ctx.profile.formatTravellers(ctx); - return { + const baseReq = { autonomeReservierung: false, einstiegsTypList: [ 'STANDARD', @@ -27,6 +27,16 @@ const formatBaseJourneysReq = (ctx) => { }, reservierungsKontingenteVorhanden: false, }; + + // Add business customer affiliation if BMIS number is provided + if (ctx.opt.bmisNumber) { + baseReq.firmenZugehoerigkeit = { + bmisNr: ctx.opt.bmisNumber, + identifikationsart: 'BMIS', + }; + } + + return baseReq; }; const formatJourneysReq = (ctx, from, to, when, outFrwd, journeysRef) => {