KItinerary

eradocumentprocessor.cpp
1/*
2 SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "eradocumentprocessor.h"
8#include "logging.h"
9
10#include "era/elbticket.h"
11#include "era/ssbticketreader.h"
12#include "era/ssbv1ticket.h"
13#include "era/ssbv2ticket.h"
14#include "era/ssbv3ticket.h"
15
16#include "text/pricefinder_p.h"
17
18#include <KItinerary/ExtractorResult>
19
20#include <KItinerary/Reservation>
21#include <KItinerary/Ticket>
22#include <KItinerary/TrainTrip>
23
24using namespace KItinerary;
25
26bool ElbDocumentProcessor::canHandleData(const QByteArray &encodedData, [[maybe_unused]] QStringView fileName) const
27{
28 return ELBTicket::maybeELBTicket(encodedData);
29}
30
32{
34 if (const auto ticket = ELBTicket::parse(encodedData)) {
35 node.setContent(*ticket);
36 }
37 return node;
38}
39
40bool SsbDocumentProcessor::canHandleData(const QByteArray &encodedData, [[maybe_unused]] QStringView fileName) const
41{
42 return SSBTicketReader::maybeSSB(encodedData);
43}
44
46{
48 node.setContent(SSBTicketReader::read(encodedData));
49 return node;
50}
51
52TrainStation makeStation(int idType, const QString &alphaId, int numericId)
53{
54 TrainStation station;
55 if (idType == 0 && numericId > 10'00000 && numericId < 99'99999) {
56 station.setIdentifier(QLatin1StringView("uic:") +
57 QString::number(numericId));
58 station.setName(QString::number(numericId));
59 } else if (idType == 1 && alphaId.size() == 5 && std::all_of(alphaId.begin(), alphaId.end(), [](QChar c) { return c.isUpper(); })) {
60 // TODO is the identifier type defined in that case??
61 station.setName(alphaId);
62 }
63 return station;
64}
65
66void SsbDocumentProcessor::preExtract(ExtractorDocumentNode &node, [[maybe_unused]] const ExtractorEngine *engine) const
67{
68 if (node.isA<SSBv3Ticket>()) {
69 const auto ssb = node.content<SSBv3Ticket>();
70
71 Seat seat;
72 seat.setSeatingType(QString::number(ssb.classOfTravel()));
73 Ticket ticket;
74 ticket.setTicketToken(QLatin1StringView("aztecbin:") +
75 QString::fromLatin1(ssb.rawData().toBase64()));
76
77 Organization issuer;
78 issuer.setIdentifier(
79 QLatin1StringView("uic:") +
80 QString::number(ssb.issuerCode())); // left pad with 0 to 4 digets?
81 TrainTrip trip;
82 trip.setProvider(issuer);
83
85 res.setReservationNumber(ssb.tcn());
86 ticket.setTicketNumber(ssb.tcn());
87
88 switch (ssb.ticketTypeCode()) {
89 case SSBv3Ticket::IRT_RES_BOA:
90 trip.setDepartureDay(ssb.type1DepartureDay(node.contextDateTime()));
91 trip.setTrainNumber(ssb.type1TrainNumber());
92 seat.setSeatSection(QString::number(ssb.type1CoachNumber()));
93 seat.setSeatNumber(ssb.type1SeatNumber());
94 trip.setDepartureStation(makeStation(ssb.type1StationCodeNumericOrAlpha(), ssb.type1DepartureStationAlpha(), ssb.type1DepartureStationNum()));
95 trip.setDepartureStation(makeStation(ssb.type1StationCodeNumericOrAlpha(), ssb.type1ArrivalStationAlpha(), ssb.type1ArrivalStationNum()));
96 break;
97 case SSBv3Ticket::NRT:
98 trip.setDepartureStation(makeStation(ssb.type2StationCodeNumericOrAlpha(), ssb.type2DepartureStationAlpha(), ssb.type2DepartureStationNum()));
99 trip.setArrivalStation(makeStation(ssb.type2StationCodeNumericOrAlpha(), ssb.type2ArrivalStationAlpha(), ssb.type2ArrivalStationNum()));
100 ticket.setValidFrom(ssb.type2ValidFrom(node.contextDateTime()).startOfDay());
101 ticket.setValidUntil({ssb.type2ValidUntil(node.contextDateTime()), {23, 59, 59}});
102 if (const auto &t = ssb.type2OpenText().trimmed(); !t.isEmpty()) {
103 ticket.setName(t);
104 }
105 trip.setDepartureDay(ssb.type2ValidFrom(node.contextDateTime()));
106 break;
107 case SSBv3Ticket::GRT:
108 {
109 trip.setDepartureStation(makeStation(ssb.type3StationCodeNumericOrAlpha(), ssb.type3DepartureStationAlpha(), ssb.type3DepartureStationNum()));
110 trip.setArrivalStation(makeStation(ssb.type3StationCodeNumericOrAlpha(), ssb.type3ArrivalStationAlpha(), ssb.type3ArrivalStationNum()));
111 ticket.setValidFrom(ssb.type3ValidFrom(node.contextDateTime()).startOfDay());
112 ticket.setValidUntil({ssb.type3ValidUntil(node.contextDateTime()), {23, 59, 59}});
113 trip.setDepartureDay(ssb.type3ValidFrom(node.contextDateTime()));
114 Person p;
115 p.setName(ssb.type3NameOfGroupLeader());
116 res.setUnderName(p);
117 break;
118 }
119 case SSBv3Ticket::RPT:
120 qCWarning(Log) << "Unsupported SSB v3 ticket type:" << ssb.ticketTypeCode();
121 return;
122 }
123
124 // e.g. MAV has the price in openText
125 PriceFinder finder;
126 if (const auto &price = finder.findHighest(ticket.name()); price.hasResult()) {
127 ticket.setName(QString());
128 res.setPriceCurrency(price.currency);
129 res.setTotalPrice(price.value);
130 }
131
132 // turn incomplete things into generic tickets (e.g. platform keybards)
133 if (trip.departureStation().name().isEmpty() || trip.arrivalStation().name().isEmpty()) {
134 ticket.setIssuedBy(issuer);
136 return;
137 }
138
139 res.setReservationFor(trip);
140 ticket.setTicketedSeat(seat);
141 res.setReservedTicket(ticket);
143 }
144}
ExtractorDocumentNode createNodeFromData(const QByteArray &encodedData) const override
Create a document node from raw data.
bool canHandleData(const QByteArray &encodedData, QStringView fileName) const override
Fast check whether the given encoded data can possibly be processed by this instance.
A node in the extracted document object tree.
bool isA() const
Checks if the content of this node is of type T.
QJSValue content
The decoded content of this node.
void addResult(ExtractorResult &&result)
Add additional results from an extraction step.
QDateTime contextDateTime
The best known context date/time at this point in the document tree.
void setContent(const QVariant &content)
Set decoded content.
Semantic data extraction engine.
A person.
Definition person.h:20
ERA SSB ticket barcode (version 3).
Definition ssbv3ticket.h:20
A reserved seat.
Definition ticket.h:23
void preExtract(ExtractorDocumentNode &node, const ExtractorEngine *engine) const override
Called before extractors are applied to node.
ExtractorDocumentNode createNodeFromData(const QByteArray &encodedData) const override
Create a document node from raw data.
bool canHandleData(const QByteArray &encodedData, QStringView fileName) const override
Fast check whether the given encoded data can possibly be processed by this instance.
A booked ticket.
Definition ticket.h:41
A train reservation.
Train station.
Definition place.h:126
A train trip.
Definition traintrip.h:24
QVariant read(const QByteArray &data, int versionOverride=0)
Attempt to read an SSB ticket.
bool maybeSSB(const QByteArray &data)
Returns whether data could be an ERA SSB ticket.
Classes for reservation/travel data models, data extraction and data augmentation.
Definition berelement.h:17
iterator begin()
iterator end()
QString fromLatin1(QByteArrayView str)
bool isEmpty() const const
QString number(double n, char format, int precision)
qsizetype size() const const
QVariant fromValue(T &&value)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Feb 28 2025 11:55:14 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.