mirror of
https://github.com/public-transport/db-vendo-client.git
synced 2025-09-17 19:49:23 +03:00
Fixing issues in 5a0bfd954e
This commit is contained in:
parent
45991eb45c
commit
3e666c0b1b
9 changed files with 57 additions and 58 deletions
18
index.js
18
index.js
|
@ -110,7 +110,7 @@ const createClient = (profile, userAgent, opt = {}) => {
|
||||||
|
|
||||||
const {res} = await profile.request({profile, opt}, userAgent, req);
|
const {res} = await profile.request({profile, opt}, userAgent, req);
|
||||||
|
|
||||||
const ctx = {profile, opt, common, res};
|
const ctx = {profile, opt, common, res, userAgent};
|
||||||
let results = (res[resultsField] || res.items || res.bahnhofstafelAbfahrtPositionen || res.bahnhofstafelAnkunftPositionen || res.entries.flat())
|
let results = (res[resultsField] || res.items || res.bahnhofstafelAbfahrtPositionen || res.bahnhofstafelAnkunftPositionen || res.entries.flat())
|
||||||
.map(res => parse(ctx, res)); // TODO sort?, slice
|
.map(res => parse(ctx, res)); // TODO sort?, slice
|
||||||
|
|
||||||
|
@ -209,13 +209,13 @@ const createClient = (profile, userAgent, opt = {}) => {
|
||||||
|
|
||||||
const req = profile.formatJourneysReq({profile, opt}, from, to, when, outFrwd, journeysRef);
|
const req = profile.formatJourneysReq({profile, opt}, from, to, when, outFrwd, journeysRef);
|
||||||
const {res} = await profile.request({profile, opt}, userAgent, req);
|
const {res} = await profile.request({profile, opt}, userAgent, req);
|
||||||
const ctx = {profile, opt, common, res};
|
const ctx = {profile, opt, common, res, userAgent};
|
||||||
if (opt.bestprice) {
|
if (opt.bestprice) {
|
||||||
res.verbindungen = (res.intervalle || res.tagesbestPreisIntervalle).flatMap(i => i.verbindungen.map(v => ({...v, ...v.verbindung})));
|
res.verbindungen = (res.intervalle || res.tagesbestPreisIntervalle).flatMap(i => i.verbindungen.map(v => ({...v, ...v.verbindung})));
|
||||||
}
|
}
|
||||||
const verbindungen = Number.isInteger(opt.results) && opt.results != 3 ? res.verbindungen.slice(0, opt.results) : res.verbindungen; // TODO remove default from hafas-rest-api
|
const verbindungen = Number.isInteger(opt.results) && opt.results != 3 ? res.verbindungen.slice(0, opt.results) : res.verbindungen; // TODO remove default from hafas-rest-api
|
||||||
const journeys = verbindungen
|
const journeys = await Promise.all(verbindungen
|
||||||
.map(j => profile.parseJourney(ctx, j));
|
.map(j => profile.parseJourney(ctx, j)));
|
||||||
if (opt.bestprice) {
|
if (opt.bestprice) {
|
||||||
journeys.sort((a, b) => a.price?.amount - b.price?.amount);
|
journeys.sort((a, b) => a.price?.amount - b.price?.amount);
|
||||||
}
|
}
|
||||||
|
@ -252,10 +252,10 @@ const createClient = (profile, userAgent, opt = {}) => {
|
||||||
const req = profile.formatRefreshJourneyReq({profile, opt}, refreshToken);
|
const req = profile.formatRefreshJourneyReq({profile, opt}, refreshToken);
|
||||||
|
|
||||||
const {res} = await profile.request({profile, opt}, userAgent, req);
|
const {res} = await profile.request({profile, opt}, userAgent, req);
|
||||||
const ctx = {profile, opt, common, res};
|
const ctx = {profile, opt, common, res, userAgent};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
journey: profile.parseJourney(ctx, res.verbindungen && res.verbindungen[0] || res),
|
journey: await profile.parseJourney(ctx, res.verbindungen && res.verbindungen[0] || res),
|
||||||
realtimeDataUpdatedAt: null, // TODO
|
realtimeDataUpdatedAt: null, // TODO
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -280,7 +280,7 @@ const createClient = (profile, userAgent, opt = {}) => {
|
||||||
|
|
||||||
const {res} = await profile.request({profile, opt}, userAgent, req);
|
const {res} = await profile.request({profile, opt}, userAgent, req);
|
||||||
|
|
||||||
const ctx = {profile, opt, common, res};
|
const ctx = {profile, opt, common, res, userAgent};
|
||||||
const results = res.map(loc => profile.parseLocation(ctx, loc));
|
const results = res.map(loc => profile.parseLocation(ctx, loc));
|
||||||
|
|
||||||
return Number.isInteger(opt.results)
|
return Number.isInteger(opt.results)
|
||||||
|
@ -329,7 +329,7 @@ const createClient = (profile, userAgent, opt = {}) => {
|
||||||
const req = profile.formatNearbyReq({profile, opt}, location);
|
const req = profile.formatNearbyReq({profile, opt}, location);
|
||||||
const {res} = await profile.request({profile, opt}, userAgent, req);
|
const {res} = await profile.request({profile, opt}, userAgent, req);
|
||||||
|
|
||||||
const ctx = {profile, opt, common, res};
|
const ctx = {profile, opt, common, res, userAgent};
|
||||||
const results = res.map(loc => {
|
const results = res.map(loc => {
|
||||||
const res = profile.parseLocation(ctx, loc);
|
const res = profile.parseLocation(ctx, loc);
|
||||||
if (res.latitude || res.location?.latitude) {
|
if (res.latitude || res.location?.latitude) {
|
||||||
|
@ -361,7 +361,7 @@ const createClient = (profile, userAgent, opt = {}) => {
|
||||||
const req = profile.formatTripReq({profile, opt}, id);
|
const req = profile.formatTripReq({profile, opt}, id);
|
||||||
|
|
||||||
const {res} = await profile.request({profile, opt}, userAgent, req);
|
const {res} = await profile.request({profile, opt}, userAgent, req);
|
||||||
const ctx = {profile, opt, common, res};
|
const ctx = {profile, opt, common, res, userAgent};
|
||||||
|
|
||||||
const trip = profile.parseTrip(ctx, res, id);
|
const trip = profile.parseTrip(ctx, res, id);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import {formatBaseJourneysReq} from '../p/dbnav/journeys-req.js';
|
|
||||||
import {getHeaders} from '../p/dbnav/header.js';
|
import {getHeaders} from '../p/dbnav/header.js';
|
||||||
|
|
||||||
// Helper to fetch Verbundticket prices via recon API
|
// Helper to fetch Verbundticket prices via recon API
|
||||||
|
@ -26,7 +25,7 @@ const fetchVerbundticketPrices = async (ctx, userAgent, journey) => {
|
||||||
body: {
|
body: {
|
||||||
fahrverguenstigungen: {
|
fahrverguenstigungen: {
|
||||||
nurDeutschlandTicketVerbindungen: ctx.opt.deutschlandTicketConnectionsOnly || false,
|
nurDeutschlandTicketVerbindungen: ctx.opt.deutschlandTicketConnectionsOnly || false,
|
||||||
deutschlandTicketVorhanden: ctx.opt.deutschlandTicketDiscount || false
|
deutschlandTicketVorhanden: ctx.opt.deutschlandTicketDiscount || false,
|
||||||
},
|
},
|
||||||
reservierungsKontingenteVorhanden: false,
|
reservierungsKontingenteVorhanden: false,
|
||||||
suchParameter: {
|
suchParameter: {
|
||||||
|
@ -37,31 +36,32 @@ const fetchVerbundticketPrices = async (ctx, userAgent, journey) => {
|
||||||
fahrradmitnahme: false,
|
fahrradmitnahme: false,
|
||||||
zielLocationId: ankunftsOrt?.locationId || extractLocationFromKontext(kontext, 'to'),
|
zielLocationId: ankunftsOrt?.locationId || extractLocationFromKontext(kontext, 'to'),
|
||||||
zeitWunsch: {
|
zeitWunsch: {
|
||||||
reiseDatum: abgangsDatum || new Date().toISOString(),
|
reiseDatum: abgangsDatum || new Date()
|
||||||
zeitPunktArt: 'ABFAHRT'
|
.toISOString(),
|
||||||
|
zeitPunktArt: 'ABFAHRT',
|
||||||
|
},
|
||||||
|
verkehrsmittel: ['ALL'],
|
||||||
},
|
},
|
||||||
verkehrsmittel: ['ALL']
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
einstiegsTypList: ['STANDARD'],
|
einstiegsTypList: ['STANDARD'],
|
||||||
klasse: 'KLASSE_2',
|
klasse: 'KLASSE_2',
|
||||||
verbindungHin: {
|
verbindungHin: {
|
||||||
kontext: kontext
|
kontext: kontext,
|
||||||
},
|
},
|
||||||
reisendenProfil: {
|
reisendenProfil: {
|
||||||
reisende: [{
|
reisende: [{
|
||||||
reisendenTyp: 'ERWACHSENER',
|
reisendenTyp: 'ERWACHSENER',
|
||||||
ermaessigungen: ['KEINE_ERMAESSIGUNG KLASSENLOS']
|
ermaessigungen: ['KEINE_ERMAESSIGUNG KLASSENLOS'],
|
||||||
}]
|
}],
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add business customer affiliation if BMIS number is provided
|
// Add business customer affiliation if BMIS number is provided
|
||||||
if (ctx.opt.bmisNumber) {
|
if (ctx.opt.bmisNumber) {
|
||||||
reconRequest.body.firmenZugehoerigkeit = {
|
reconRequest.body.firmenZugehoerigkeit = {
|
||||||
bmisNr: ctx.opt.bmisNumber,
|
bmisNr: ctx.opt.bmisNumber,
|
||||||
identifikationsart: 'BMIS'
|
identifikationsart: 'BMIS',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {parseJourney as parseJourneyDefault} from '../../parse/journey.js';
|
import {parseJourney as parseJourneyDefault} from '../../parse/journey.js';
|
||||||
|
|
||||||
const parseJourney = (ctx, jj) => {
|
const parseJourney = async (ctx, jj) => {
|
||||||
const legs = (jj.verbindung || jj).verbindungsAbschnitte;
|
const legs = (jj.verbindung || jj).verbindungsAbschnitte;
|
||||||
if (legs.length > 0) {
|
if (legs.length > 0) {
|
||||||
legs[0] = preprocessJourneyLeg(legs[0]);
|
legs[0] = preprocessJourneyLeg(legs[0]);
|
||||||
|
|
|
@ -41,7 +41,7 @@ const trimJourneyId = (journeyId) => {
|
||||||
return journeyId;
|
return journeyId;
|
||||||
};
|
};
|
||||||
|
|
||||||
const parseJourney = (ctx, jj) => { // j = raw journey
|
const parseJourney = async (ctx, jj) => { // j = raw journey
|
||||||
const {profile, opt} = ctx;
|
const {profile, opt} = ctx;
|
||||||
const j = jj.verbindung || jj;
|
const j = jj.verbindung || jj;
|
||||||
const fallbackLocations = parseLocationsFromCtxRecon(ctx, j);
|
const fallbackLocations = parseLocationsFromCtxRecon(ctx, j);
|
||||||
|
@ -89,15 +89,14 @@ const parseJourney = (ctx, jj) => { // j = raw journey
|
||||||
const hasKontext = j.kontext || j.ctxRecon;
|
const hasKontext = j.kontext || j.ctxRecon;
|
||||||
|
|
||||||
// Also check for the warning message that prices need to be fetched
|
// Also check for the warning message that prices need to be fetched
|
||||||
const hasVerbundWarning = angebote?.angebotsMeldungen?.some(msg =>
|
const hasVerbundWarning = angebote?.angebotsMeldungen?.some(msg => msg.includes('Verbindung liegt in der Vergangenheit')
|
||||||
msg.includes('Verbindung liegt in der Vergangenheit') ||
|
|| msg.includes('Preis')
|
||||||
msg.includes('Preis') ||
|
|| msg.includes('Verbund'),
|
||||||
msg.includes('Verbund')
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if ((hasVerbundCode && hasEmptyAngebotsCluster || hasVerbundWarning) && hasKontext && userAgent && opt.tickets && opt.autoFetchVerbundtickets) {
|
if ((hasVerbundCode && hasEmptyAngebotsCluster || hasVerbundWarning) && hasKontext && ctx.userAgent && opt.tickets && opt.autoFetchVerbundtickets) {
|
||||||
// Fetch Verbundticket prices via recon API
|
// Fetch Verbundticket prices via recon API
|
||||||
const reconResult = await fetchVerbundticketPrices(ctx, userAgent, j);
|
const reconResult = await fetchVerbundticketPrices(ctx, ctx.userAgent, j);
|
||||||
if (reconResult) {
|
if (reconResult) {
|
||||||
// Use the recon result for price and ticket parsing
|
// Use the recon result for price and ticket parsing
|
||||||
if (reconResult.angebote) {
|
if (reconResult.angebote) {
|
||||||
|
|
|
@ -73,14 +73,14 @@ const parseTickets = (ctx, j) => {
|
||||||
|
|
||||||
// Handle regular einfacheFahrt
|
// Handle regular einfacheFahrt
|
||||||
if (p.einfacheFahrt?.standard?.reisePosition) {
|
if (p.einfacheFahrt?.standard?.reisePosition) {
|
||||||
const rp = p.einfacheFahrt.standard.reisePosition;
|
const rp = p.einfacheFahrt.standard.reisePosition.reisePosition || p.einfacheFahrt.standard.reisePosition;
|
||||||
rp.teilpreis = Boolean(p.einfacheFahrt.standard.teilpreisInformationen?.length);
|
rp.teilpreis = Boolean(p.einfacheFahrt.standard.teilpreisInformationen?.length);
|
||||||
positions.push(rp);
|
positions.push(rp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle upsell
|
// Handle upsell
|
||||||
if (p.einfacheFahrt?.upsellEntgelt?.einfacheFahrt?.reisePosition) {
|
if (p.einfacheFahrt?.upsellEntgelt?.einfacheFahrt?.reisePosition) {
|
||||||
const rp = p.einfacheFahrt.upsellEntgelt.einfacheFahrt.reisePosition;
|
const rp = p.einfacheFahrt.upsellEntgelt.einfacheFahrt.reisePosition.reisePosition || p.einfacheFahrt.upsellEntgelt.einfacheFahrt.reisePosition;
|
||||||
rp.teilpreis = Boolean(p.einfacheFahrt.upsellEntgelt.einfacheFahrt.teilpreisInformationen?.length);
|
rp.teilpreis = Boolean(p.einfacheFahrt.upsellEntgelt.einfacheFahrt.teilpreisInformationen?.length);
|
||||||
positions.push(rp);
|
positions.push(rp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,9 +26,9 @@ const opt = {
|
||||||
products: {},
|
products: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
tap.test('parses a refresh journey correctly (DB)', (t) => {
|
tap.test('parses a refresh journey correctly (DB)', async (t) => {
|
||||||
const ctx = {profile, opt, common: null, res};
|
const ctx = {profile, opt, common: null, res, userAgent: 'test'};
|
||||||
const journey = profile.parseJourney(ctx, res);
|
const journey = await profile.parseJourney(ctx, res);
|
||||||
|
|
||||||
t.same(journey, expected.journey);
|
t.same(journey, expected.journey);
|
||||||
t.end();
|
t.end();
|
||||||
|
|
|
@ -26,9 +26,9 @@ const opt = {
|
||||||
products: {},
|
products: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
tap.test('parses a dbweb journey correctly', (t) => { // TODO DEVI leg
|
tap.test('parses a dbweb journey correctly', async (t) => { // TODO DEVI leg
|
||||||
const ctx = {profile, opt, common: null, res};
|
const ctx = {profile, opt, common: null, res};
|
||||||
const journey = profile.parseJourney(ctx, res.verbindungen[0]);
|
const journey = await profile.parseJourney(ctx, res.verbindungen[0]);
|
||||||
|
|
||||||
t.same(journey, expected);
|
t.same(journey, expected);
|
||||||
t.end();
|
t.end();
|
||||||
|
|
|
@ -26,9 +26,9 @@ const opt = {
|
||||||
products: {},
|
products: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
tap.test('parses a refresh journey correctly (dbweb)', (t) => {
|
tap.test('parses a refresh journey correctly (dbweb)', async (t) => {
|
||||||
const ctx = {profile, opt, common: null, res};
|
const ctx = {profile, opt, common: null, res};
|
||||||
const journey = profile.parseJourney(ctx, res.verbindungen[0]);
|
const journey = await profile.parseJourney(ctx, res.verbindungen[0]);
|
||||||
|
|
||||||
t.same(journey, expected.journey);
|
t.same(journey, expected.journey);
|
||||||
t.end();
|
t.end();
|
||||||
|
|
|
@ -469,8 +469,8 @@ const input = {
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
tap.test('dbnav profile fixes time zone bug', (t) => { // see https://github.com/public-transport/db-vendo-client/issues/24
|
tap.test('dbnav profile fixes time zone bug', async (t) => { // see https://github.com/public-transport/db-vendo-client/issues/24
|
||||||
const parsedJourney = parseJourneyDbnav(ctx, structuredClone(input));
|
const parsedJourney = await parseJourneyDbnav(ctx, structuredClone(input));
|
||||||
const expectedDeparture = '2025-03-06T14:52:00+01:00';
|
const expectedDeparture = '2025-03-06T14:52:00+01:00';
|
||||||
t.equal(parsedJourney.legs[0].departure, expectedDeparture)
|
t.equal(parsedJourney.legs[0].departure, expectedDeparture)
|
||||||
|
|
||||||
|
@ -484,14 +484,14 @@ tap.test('dbnav profile fixes time zone bug', (t) => { // see https://github.com
|
||||||
t.end();
|
t.end();
|
||||||
})
|
})
|
||||||
|
|
||||||
tap.test('dbnav profile parses journey without time zone bug like other profiles', (t) => {
|
tap.test('dbnav profile parses journey without time zone bug like other profiles', async (t) => {
|
||||||
const _input = structuredClone(input);
|
const _input = structuredClone(input);
|
||||||
// fix bug by hand
|
// fix bug by hand
|
||||||
_input.verbindungsAbschnitte[0].ezAbgangsDatum = '2025-03-06T14:52:00+01:00';
|
_input.verbindungsAbschnitte[0].ezAbgangsDatum = '2025-03-06T14:52:00+01:00';
|
||||||
_input.verbindungsAbschnitte[0].ezAnkunftsDatum = '2025-03-06T14:54:00+01:00';
|
_input.verbindungsAbschnitte[0].ezAnkunftsDatum = '2025-03-06T14:54:00+01:00';
|
||||||
const expected = parseJourneyDefault(ctx, _input)
|
const expected = await parseJourneyDefault(ctx, _input)
|
||||||
|
|
||||||
t.same(parseJourneyDbnav(ctx, _input), expected);
|
t.same(await parseJourneyDbnav(ctx, _input), expected);
|
||||||
|
|
||||||
t.end();
|
t.end();
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Reference in a new issue