6#include "fcbextractor_p.h"
8#include "variantvisitor_p.h"
10#include <KItinerary/ExtractorValidator>
11#include <KItinerary/Organization>
12#include <KItinerary/Person>
13#include <KItinerary/ProgramMembership>
14#include <KItinerary/Reservation>
15#include <KItinerary/Ticket>
16#include <KItinerary/TrainTrip>
25 return VariantVisitor([](
auto &&doc) {
26 auto n = doc.tariffs.isEmpty() ?
QString() : doc.tariffs.at(0).tariffDesc;
31 if (!doc.passDescription.isEmpty()) {
32 return doc.passDescription;
37 }).visit<FCB_VERSIONED(ReservationData), FCB_VERSIONED(OpenTicketData), FCB_VERSIONED(PassData)>(doc);
40QString FcbExtractor::ticketName(
const Fcb::UicRailTicketData &fcb)
42 return std::visit([](
auto &&fcb) {
43 for (
const auto &doc : fcb.transportDocument) {
44 if (
auto n = ticketNameForDocument(doc.ticket); !n.isEmpty()) {
53[[nodiscard]]
static QString fcbReference(
const T &data)
55 if (!data.referenceIA5.isEmpty()) {
58 if (data.referenceNumIsSet()) {
64QString FcbExtractor::pnr(
const Fcb::UicRailTicketData &fcb)
66 return std::visit([](
auto &&fcb) {
67 if (!fcb.issuingDetail.issuerPNR.isEmpty()) {
71 for (
const auto &doc : fcb.transportDocument) {
72 auto pnr = VariantVisitor([](
auto &&doc) {
73 return fcbReference(doc);
74 }).
template visit<FCB_VERSIONED(ReservationData), FCB_VERSIONED(OpenTicketData), FCB_VERSIONED(PassData)>(doc.ticket);
84QString FcbExtractor::seatingType(
const Fcb::UicRailTicketData &fcb)
86 return std::visit([](
auto &&fcb) {
87 for (
const auto &doc : fcb.transportDocument) {
88 auto s = VariantVisitor([](
auto &&doc) {
90 }).
template visit<FCB_VERSIONED(ReservationData), FCB_VERSIONED(OpenTicketData), FCB_VERSIONED(PassData)>(doc.ticket);
99[[nodiscard]]
static QString formatIssuerId(
int num)
103 id.insert(0,
QString(4 -
id.size(),
'0'_L1));
108QString FcbExtractor::issuerId(
const Fcb::UicRailTicketData &fcb)
110 return std::visit([](
auto &&fcb) {
111 if (fcb.issuingDetail.issuerNumIsSet()) {
112 return formatIssuerId(fcb.issuingDetail.issuerNum);
114 if (fcb.issuingDetail.issuerIA5IsSet()) {
117 if (fcb.issuingDetail.securityProviderNumIsSet()) {
118 return formatIssuerId(fcb.issuingDetail.securityProviderNum);
120 if (fcb.issuingDetail.securityProviderIA5IsSet()) {
127Organization FcbExtractor::issuer(
const Fcb::UicRailTicketData &fcb)
130 if (
auto id = issuerId(fcb); !
id.isEmpty()) {
131 issuer.setIdentifier(
"uic:"_L1 +
id);
133 std::visit([&issuer](
auto &&fcb) {
134 if (fcb.issuingDetail.issuerNameIsSet()) {
135 issuer.setName(fcb.issuingDetail.issuerName);
141Person FcbExtractor::person(
const Fcb::UicRailTicketData &fcb)
143 return std::visit([](
auto &&fcb) {
145 if (!fcb.travelerDetailIsSet() || fcb.travelerDetail.traveler.size() != 1) {
148 const auto traveler = fcb.travelerDetail.traveler.at(0);
149 if (traveler.firstNameIsSet() || traveler.secondNameIsSet()) {
150 p.setGivenName(
QString(traveler.firstName +
' '_L1 + traveler.secondName).
trimmed());
152 p.setFamilyName(traveler.lastName);
157QDateTime FcbExtractor::issuingDateTime(
const Fcb::UicRailTicketData &fcb)
159 return std::visit([](
auto &&data) {
return data.issuingDetail.issueingDateTime(); }, fcb);
162QDateTime FcbExtractor::validFrom(
const Fcb::UicRailTicketData &fcb)
164 return std::visit([](
auto &&fcb) {
165 for (
const auto &doc : fcb.transportDocument) {
166 auto dt = VariantVisitor([&fcb](
auto &&doc) {
167 return doc.departureDateTime(fcb.issuingDetail.issueingDateTime());
168 }).
template visit<FCB_VERSIONED(ReservationData)>(doc.ticket);
172 dt = VariantVisitor([&fcb](
auto &&doc) {
173 return doc.validFrom(fcb.issuingDetail.issueingDateTime());
174 }).
template visit<FCB_VERSIONED(OpenTicketData), FCB_VERSIONED(PassData)>(doc.ticket);
183QDateTime FcbExtractor::validUntil(
const Fcb::UicRailTicketData &fcb)
185 return std::visit([](
auto &&fcb) {
186 for (
const auto &doc : fcb.transportDocument) {
187 auto dt = VariantVisitor([&fcb](
auto &&doc) {
188 return doc.arrivalDateTime(fcb.issuingDetail.issueingDateTime());
189 }).
template visit<FCB_VERSIONED(ReservationData)>(doc.ticket);
193 dt = VariantVisitor([&fcb](
auto &&doc) {
194 return doc.validUntil(fcb.issuingDetail.issueingDateTime());
195 }).
template visit<FCB_VERSIONED(OpenTicketData), FCB_VERSIONED(PassData)>(doc.ticket);
204FcbExtractor::PriceData FcbExtractor::price(
const Fcb::UicRailTicketData &fcb)
206 return std::visit([](
auto &&fcb) {
209 const auto fract = std::pow(10, fcb.issuingDetail.currencyFract);
210 for (
const auto &doc : fcb.transportDocument) {
211 p.price = VariantVisitor([fract](
auto &&doc) {
212 return doc.priceIsSet() ? doc.price / fract : NAN;
213 }).
template visit<FCB_VERSIONED(ReservationData), FCB_VERSIONED(OpenTicketData), FCB_VERSIONED(PassData)>(doc.ticket);
214 if (!std::isnan(p.price)) {
222template <
typename CardReferenceTypeT>
226 p.setProgramName(card.cardName);
227 if (card.cardIdNumIsSet()) {
229 }
else if (card.cardIdIA5IsSet()) {
235template <
typename TariffTypeT>
239 for (
const auto &tariff : tariffs) {
240 for (
const auto &card : tariff.reductionCard) {
241 return extractCustomerCard(card);
250 const auto issuingDateTime = FcbExtractor::issuingDateTime(fcb);
251 VariantVisitor([&fcb, &result, ticket, issuingDateTime](
auto &&irt) {
255 trip.setProvider(FcbExtractor::issuer(fcb));
256 if (trip.provider().identifier().
isEmpty() && trip.provider().name().
isEmpty()) {
257 trip.setProvider(ticket.issuedBy());
262 FcbExtractor::readDepartureStation(irt, dep);
263 trip.setDepartureStation(dep);
266 FcbExtractor::readArrivalStation(irt, arr);
267 trip.setArrivalStation(arr);
269 trip.setDepartureTime(irt.departureDateTime(issuingDateTime));
270 trip.setArrivalTime(irt.arrivalDateTime(issuingDateTime));
272 if (irt.trainNumIsSet()) {
273 trip.setTrainNumber(irt.serviceBrandAbrUTF8 +
' '_L1 +
QString::number(irt.trainNum));
275 trip.setTrainNumber(irt.serviceBrandAbrUTF8 +
' '_L1 +
QString::fromUtf8(irt.trainIA5));
280 if (irt.placesIsSet()) {
283 for (
const auto &b : irt.places.placeIA5) {
286 for (
auto i : irt.places.placeNum) {
289 s.setSeatNumber(l.
join(
", "_L1));
292 t.setTicketedSeat(s);
295 res.setReservationNumber(FcbExtractor::pnr(fcb));
296 if (res.reservationNumber().
isEmpty()) {
297 res.setReservationNumber(ticket.ticketNumber());
299 t.setTicketNumber(fcbReference(irt));
300 res.setUnderName(FcbExtractor::person(fcb));
301 res.setProgramMembershipUsed(::extractCustomerCard(irt.tariffs));
303 if (irt.priceIsSet()) {
304 res.setTotalPrice(irt.price / std::pow(10, std::visit([](
auto &&fcb) { return fcb.issuingDetail.currencyFract; }, fcb)));
306 res.setPriceCurrency(
QString::fromUtf8(std::visit([](
auto &&fcb) {
return fcb.issuingDetail.currency; }, fcb)));
311 res.setReservationFor(trip);
312 res.setReservedTicket(t);
315 }).visit<FCB_VERSIONED(ReservationData)>(res);
320 return VariantVisitor([&baseTrip, issuingDateTime, &baseRes, &result](
auto &&trainLink) {
324 if (trainLink.fromStationNameUTF8IsSet()) {
326 dep.setName(trainLink.fromStationNameUTF8);
327 FcbExtractor::fixStationCode(dep);
328 trip.setDepartureStation(dep);
331 if (trainLink.toStationNameUTF8IsSet()) {
333 arr.setName(trainLink.toStationNameUTF8);
334 FcbExtractor::fixStationCode(arr);
335 trip.setArrivalStation(arr);
338 trip.setDepartureDay({});
339 trip.setDepartureTime(trainLink.departureDateTime(issuingDateTime));
341 if (trainLink.trainNumIsSet()) {
351 res.setReservationFor(trip);
357 }).visit<FCB_VERSIONED(TrainLinkType)>(regionalValidity);
362 const auto issuingDateTime = FcbExtractor::issuingDateTime(fcb);
363 VariantVisitor([&fcb, ticket, &result, issuingDateTime] (
auto &&nrt) {
367 t.setTicketedSeat(s);
370 res.setReservationNumber(FcbExtractor::pnr(fcb));
371 if (res.reservationNumber().
isEmpty()) {
372 res.setReservationNumber(ticket.ticketNumber());
374 t.setTicketNumber(fcbReference(nrt));
376 res.setReservedTicket(t);
378 res.setUnderName(FcbExtractor::person(fcb));
379 res.setProgramMembershipUsed(::extractCustomerCard(nrt.tariffs));
381 if (nrt.priceIsSet()) {
382 res.setTotalPrice(nrt.price / std::pow(10, std::visit([](
auto &&fcb) { return fcb.issuingDetail.currencyFract; }, fcb)));
384 res.setPriceCurrency(
QString::fromUtf8(std::visit([](
auto &&fcb) {
return fcb.issuingDetail.currency; }, fcb)));
387 baseTrip.setProvider(FcbExtractor::issuer(fcb));
388 if (baseTrip.provider().name().
isEmpty() && baseTrip.provider().identifier().
isEmpty()) {
389 baseTrip.setProvider(ticket.issuedBy());
392 FcbExtractor::readDepartureStation(nrt, dep);
393 baseTrip.setDepartureStation(dep);
395 FcbExtractor::readArrivalStation(nrt, arr);
396 baseTrip.setArrivalStation(arr);
397 baseTrip.setDepartureDay(nrt.validFrom(issuingDateTime).date());
403 bool trainLinkTypeFound =
false;
404 for (
const auto ®ionalValidity : nrt.validRegion) {
405 trainLinkTypeFound |= extractValidRegion(regionalValidity.
value, issuingDateTime, res, baseTrip, result);
408 if (!trainLinkTypeFound) {
410 res.setReservationFor(baseTrip);
416 if (nrt.returnIncluded) {
418 FcbExtractor::readDepartureStation(nrt.returnDescription, nrt.stationCodeTable, retDep);
420 FcbExtractor::readArrivalStation(nrt.returnDescription, nrt.stationCodeTable, retArr);
423 retBaseTrip.setProvider(baseTrip.provider());
424 retBaseTrip.setDepartureStation(retDep);
425 retBaseTrip.setArrivalStation(retArr);
427 bool retTrainLinkTypeFound =
false;
428 for (
const auto ®ionalValidity : nrt.returnDescription.validReturnRegion) {
429 retTrainLinkTypeFound |= extractValidRegion(regionalValidity.
value, issuingDateTime, res, retBaseTrip, result);
432 if (!retTrainLinkTypeFound && validator.
isValidElement(retBaseTrip)) {
433 res.setReservationFor(retBaseTrip);
437 }).visit<FCB_VERSIONED(OpenTicketData)>(res);
442 VariantVisitor([&fcb, &result, ticket](
auto &&ccd) {
444 if (ccd.cardIdNumIsSet()) {
449 pm.setProgramName(ccd.cardTypeDescr);
450 pm.setMember(FcbExtractor::person(fcb));
451 pm.setValidFrom(ccd.validFrom().startOfDay());
452 pm.setValidUntil(ccd.validUntil().startOfDay());
455 }).visit<FCB_VERSIONED(CustomerCardData)>(ccd);
460 VariantVisitor([&station](
auto &&data) {
461 FcbExtractor::readDepartureStation(data, station);
462 }).visit<FCB_VERSIONED(ReservationData), FCB_VERSIONED(OpenTicketData)>(doc);
467 VariantVisitor([&station](
auto &&data) {
468 FcbExtractor::readArrivalStation(data, station);
469 }).visit<FCB_VERSIONED(ReservationData), FCB_VERSIONED(OpenTicketData)>(doc);
479 addr.setAddressCountry(u
"DE"_s);
480 station.setAddress(addr);
481 station.setIdentifier(
QString());
static QString classCodeToString(Fcb::v13::TravelClassType classCode)
Convert a class code enum value to a string for human representation.
Rail pass document (RPT).
Rail pass document (RPT).
Rail pass document (RPT).
QString identifier
Identifier.
A frequent traveler, bonus points or discount scheme program membership.
QString ticketToken
The raw ticket token string.
Classes for reservation/travel data models, data extraction and data augmentation.
void push_back(parameter_type value)
QString fromLatin1(QByteArrayView str)
QString fromUtf8(QByteArrayView str)
bool isEmpty() const const
QString number(double n, char format, int precision)
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QString trimmed() const const
QString join(QChar separator) const const