diff --git a/example.js b/example.js index 57d13694..ed52a3fa 100644 --- a/example.js +++ b/example.js @@ -6,7 +6,7 @@ const dbProfile = require('./p/db') const client = createClient(dbProfile) // Berlin Jungfernheide to München Hbf -client.journeys('8011167', '8000261', {results: 1}) +client.journeys('8011167', '8000261', {results: 1, tickets: true}) // client.departures('8011167', {duration: 1}) // client.locations('Berlin Jungfernheide') // client.locations('ATZE Musiktheater', {poi: true, addressses: false, fuzzy: false}) diff --git a/index.js b/index.js index 21ac30bb..69ff8c21 100644 --- a/index.js +++ b/index.js @@ -57,6 +57,7 @@ const createClient = (profile) => { // todo: does this work with every endpoint? accessibility: 'none', // 'none', 'partial' or 'complete' bike: false, // only bike-friendly journeys + tickets: false, // return tickets? }, opt) if (opt.via) opt.via = profile.formatLocation(profile, opt.via) opt.when = opt.when || new Date() @@ -78,7 +79,7 @@ const createClient = (profile) => { // todo: what are all these for? getPT: true, outFrwd: true, - getTariff: false, + getTariff: !!opt.tickets, getIV: false, // walk & bike as alternatives? getPolyline: false // shape for displaying on a map? }, opt) diff --git a/p/vbb/index.js b/p/vbb/index.js index 3b750d81..ea9753fa 100644 --- a/p/vbb/index.js +++ b/p/vbb/index.js @@ -3,10 +3,12 @@ const shorten = require('vbb-short-station-name') const {to12Digit, to9Digit} = require('vbb-translate-ids') const parseLineName = require('vbb-parse-line') +const parseTicket = require('vbb-parse-ticket') -const _formatStation = require('../../format/station') const _parseLine = require('../../parse/line') const _parseLocation = require('../../parse/location') +const _createParseJourney = require('../../parse/journey') +const _formatStation = require('../../format/station') const createParseBitmask = require('../../parse/products-bitmask') const createFormatBitmask = require('../../format/products-bitmask') @@ -15,8 +17,8 @@ const modes = require('./modes') const formatBitmask = createFormatBitmask(modes) const transformReqBody = (body) => { - body.client = {type: 'IPA', id: 'BVG'} - body.ext = 'VBB.2' + body.client = {type: 'IPA', id: 'VBB', name: 'vbbPROD', v: '4010300'} + body.ext = 'VBB.1' body.ver = '1.11' body.auth = {type: 'AID', aid: 'hafas-vbb-apps'} @@ -58,6 +60,36 @@ const parseLocation = (profile, l) => { return res } +const createParseJourney = (profile, stations, lines, remarks) => { + const parseJourney = _createParseJourney(profile, stations, lines, remarks) + + const parseJourneyWithTickets = (j) => { + const res = parseJourney(j) + + if ( + j.trfRes && + Array.isArray(j.trfRes.fareSetL) && + j.trfRes.fareSetL[0] && + Array.isArray(j.trfRes.fareSetL[0].fareL) + ) { + res.tickets = [] + const sets = j.trfRes.fareSetL[0].fareL + for (let s of sets) { + if (!Array.isArray(s.ticketL) || s.ticketL.length === 0) continue + for (let t of s.ticketL) { + const ticket = parseTicket(t) + ticket.name = s.name + ' – ' + ticket.name + res.tickets.push(ticket) + } + } + } + + return res + } + + return parseJourneyWithTickets +} + const isIBNR = /^\d{9,}$/ const formatStation = (id) => { if (!isIBNR.test(id)) throw new Error('station ID must be an IBNR.') @@ -92,6 +124,7 @@ const vbbProfile = { parseLocation, parseLine, parseProducts: createParseBitmask(modes.bitmasks), + parseJourney: createParseJourney, formatStation, formatProducts, diff --git a/package.json b/package.json index 6f570e43..fdb0a12b 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "pinkie-promise": "^2.0.1", "query-string": "^5.0.0", "slugg": "^1.2.0", + "vbb-parse-ticket": "^0.2.1", "vbb-short-station-name": "^0.4.0", "vbb-translate-ids": "^3.1.0" }, diff --git a/test/util.js b/test/util.js index 323a185e..a8cda88e 100644 --- a/test/util.js +++ b/test/util.js @@ -97,6 +97,37 @@ const assertValidWhen = (t, w) => { t.ok(isValidWhen(w), 'invalid when') } +const assertValidTicket = (t, ti) => { + t.strictEqual(typeof ti.name, 'string') + t.ok(ti.name.length > 0) + if (ti.price !== null) { + t.strictEqual(typeof ti.price, 'number') + t.ok(ti.price > 0) + } + if (ti.amount !== null) { + t.strictEqual(typeof ti.amount, 'number') + t.ok(ti.amount > 0) + } + + if ('bike' in ti) t.strictEqual(typeof ti.bike, 'boolean') + if ('shortTrip' in ti) t.strictEqual(typeof ti.shortTrip, 'boolean') + if ('group' in ti) t.strictEqual(typeof ti.group, 'boolean') + if ('fullDay' in ti) t.strictEqual(typeof ti.fullDay, 'boolean') + + if (ti.tariff !== null) { + t.strictEqual(typeof ti.tariff, 'string') + t.ok(ti.tariff.length > 0) + } + if (ti.coverage !== null) { + t.strictEqual(typeof ti.coverage, 'string') + t.ok(ti.coverage.length > 0) + } + if (ti.variant !== null) { + t.strictEqual(typeof ti.variant, 'string') + t.ok(ti.variant.length > 0) + } +} + module.exports = { assertValidStation, assertValidPoi, @@ -106,5 +137,6 @@ module.exports = { assertValidLine, isValidDateTime, assertValidStopover, - hour, when, isValidWhen, assertValidWhen + hour, when, isValidWhen, assertValidWhen, + assertValidTicket } diff --git a/test/vbb.js b/test/vbb.js index 4c5fbb00..546f0633 100644 --- a/test/vbb.js +++ b/test/vbb.js @@ -19,7 +19,8 @@ const { assertValidLine: _assertValidLine, assertValidStopover, hour, when, - assertValidWhen // todo: timezone + assertValidWhen, // todo: timezone + assertValidTicket } = require('./util') const assertValidStation = (t, s, coordsOptional = false) => { @@ -100,6 +101,9 @@ test('journeys – station to station', co.wrap(function* (t) { t.ok(Array.isArray(part.passed)) for (let passed of part.passed) assertValidStopover(t, passed) + + t.ok(Array.isArray(journey.tickets)) + for (let ticket of journey.tickets) assertValidTicket(t, ticket) } t.end() }))