diff --git a/autotests/bcbpdata/easyjet.json b/autotests/bcbpdata/easyjet.json index 7e9f099..5200801 100644 --- a/autotests/bcbpdata/easyjet.json +++ b/autotests/bcbpdata/easyjet.json @@ -1,34 +1,35 @@ [ { "@context": "http://schema.org", "@type": "FlightReservation", "airplaneSeat": "3C", + "passengerSequenceNumber": "506", "reservationFor": { "@type": "Flight", "airline": { "@type": "Airline", "iataCode": "EZY" }, "arrivalAirport": { "@type": "Airport", "iataCode": "LGW" }, "departureAirport": { "@type": "Airport", "iataCode": "MRS" }, "departureDay": "2018-04-09", "flightNumber": "8724" }, "reservationNumber": "ABCDEFG", "reservedTicket": { "@type": "Ticket", "ticketToken": "aztecCode:M1DOE/JOHN EABCDEFGMRSLGWEZY8724 99 3C 506 10Axxxxxxxxxx" }, "underName": { "@type": "Person", "familyName": "DOE", "givenName": "JOHN" } } ] diff --git a/autotests/bcbpdata/iata-resolution792-example1.json b/autotests/bcbpdata/iata-resolution792-example1.json index a596a6f..d4f05ba 100644 --- a/autotests/bcbpdata/iata-resolution792-example1.json +++ b/autotests/bcbpdata/iata-resolution792-example1.json @@ -1,34 +1,35 @@ [ { "@context": "http://schema.org", "@type": "FlightReservation", "airplaneSeat": "1A", + "passengerSequenceNumber": "25", "reservationFor": { "@type": "Flight", "airline": { "@type": "Airline", "iataCode": "AC" }, "arrivalAirport": { "@type": "Airport", "iataCode": "FRA" }, "departureAirport": { "@type": "Airport", "iataCode": "YUL" }, "departureDay": "2018-11-22", "flightNumber": "834" }, "reservationNumber": "ABC123", "reservedTicket": { "@type": "Ticket", "ticketToken": "aztecCode:M1DESMARAIS/LUC EABC123 YULFRAAC 0834 326J001A0025 100" }, "underName": { "@type": "Person", "familyName": "DESMARAIS", "givenName": "LUC" } } ] diff --git a/autotests/bcbpdata/iata-resolution792-example2.json b/autotests/bcbpdata/iata-resolution792-example2.json index b9fb244..6980684 100644 --- a/autotests/bcbpdata/iata-resolution792-example2.json +++ b/autotests/bcbpdata/iata-resolution792-example2.json @@ -1,34 +1,35 @@ [ { "@context": "http://schema.org", "@type": "FlightReservation", "airplaneSeat": "3A", + "passengerSequenceNumber": "27", "reservationFor": { "@type": "Flight", "airline": { "@type": "Airline", "iataCode": "AC" }, "arrivalAirport": { "@type": "Airport", "iataCode": "FRA" }, "departureAirport": { "@type": "Airport", "iataCode": "YUL" }, "departureDay": "2011-11-22", "flightNumber": "834" }, "reservationNumber": "AB12C3", "reservedTicket": { "@type": "Ticket", "ticketToken": "aztecCode:M1DESMARAIS/LUC EAB12C3 YULFRAAC 0834 326J003A0027 167>5321WW1325BAC 0014123456002001412346700100141234789012A0141234567890 1AC AC 1234567890123 4PCYLX58Z^108ABCDEFGH" }, "underName": { "@type": "Person", "familyName": "DESMARAIS", "givenName": "LUC" } } ] diff --git a/autotests/bcbpdata/iata-resolution792-example3.json b/autotests/bcbpdata/iata-resolution792-example3.json index 97f91fa..ab8efff 100644 --- a/autotests/bcbpdata/iata-resolution792-example3.json +++ b/autotests/bcbpdata/iata-resolution792-example3.json @@ -1,34 +1,35 @@ [ { "@context": "http://schema.org", "@type": "FlightReservation", "airplaneSeat": "2F", + "passengerSequenceNumber": "25", "reservationFor": { "@type": "Flight", "airline": { "@type": "Airline", "iataCode": "AF" }, "arrivalAirport": { "@type": "Airport", "iataCode": "CDG" }, "departureAirport": { "@type": "Airport", "iataCode": "GVA" }, "departureDay": "2018-12-05", "flightNumber": "123" }, "reservationNumber": "ABC123", "reservedTicket": { "@type": "Ticket", "ticketToken": "aztecCode:M1GRANDMAIRE/MELANIE EABC123 GVACDGAF 0123 339C002F0025 130>5002A0571234567890 AF AF 1234567890123456 Y^18ABCDEFGH" }, "underName": { "@type": "Person", "familyName": "GRANDMAIRE", "givenName": "MELANIE" } } ] diff --git a/autotests/bcbpdata/iata-resolution792-example4.json b/autotests/bcbpdata/iata-resolution792-example4.json index 93e64be..a6ec514 100644 --- a/autotests/bcbpdata/iata-resolution792-example4.json +++ b/autotests/bcbpdata/iata-resolution792-example4.json @@ -1,66 +1,68 @@ [ { "@context": "http://schema.org", "@type": "FlightReservation", "airplaneSeat": "3A", + "passengerSequenceNumber": "27", "reservationFor": { "@type": "Flight", "airline": { "@type": "Airline", "iataCode": "AC" }, "arrivalAirport": { "@type": "Airport", "iataCode": "FRA" }, "departureAirport": { "@type": "Airport", "iataCode": "YUL" }, "departureDay": "2011-11-22", "flightNumber": "834" }, "reservationNumber": "AB12C3", "reservedTicket": { "@type": "Ticket", "ticketToken": "aztecCode:M2DESMARAIS/LUC EAB12C3 YULFRAAC 0834 326J003A0027 167>5321WW1325BAC 0014123456002001412346700100141234789012A0141234567890 1AC AC 1234567890123 4PCYLX58ZDEF456 FRAGVALH 3664 327C012C0002 12E2A0140987654321 1AC AC 1234567890123 3PCNWQ^108ABCDEFGH" }, "underName": { "@type": "Person", "familyName": "DESMARAIS", "givenName": "LUC" } }, { "@context": "http://schema.org", "@type": "FlightReservation", + "passengerSequenceNumber": "2", "airplaneSeat": "12C", "reservationFor": { "@type": "Flight", "airline": { "@type": "Airline", "iataCode": "LH" }, "arrivalAirport": { "@type": "Airport", "iataCode": "GVA" }, "departureAirport": { "@type": "Airport", "iataCode": "FRA" }, "departureDay": "2011-11-23", "flightNumber": "3664" }, "reservationNumber": "DEF456", "reservedTicket": { "@type": "Ticket", "ticketToken": "aztecCode:M2DESMARAIS/LUC EAB12C3 YULFRAAC 0834 326J003A0027 167>5321WW1325BAC 0014123456002001412346700100141234789012A0141234567890 1AC AC 1234567890123 4PCYLX58ZDEF456 FRAGVALH 3664 327C012C0002 12E2A0140987654321 1AC AC 1234567890123 3PCNWQ^108ABCDEFGH" }, "underName": { "@type": "Person", "familyName": "DESMARAIS", "givenName": "LUC" } } ] diff --git a/autotests/bcbpdata/iata-resolution792-example5.json b/autotests/bcbpdata/iata-resolution792-example5.json index 2c7f9b9..2293e4a 100644 --- a/autotests/bcbpdata/iata-resolution792-example5.json +++ b/autotests/bcbpdata/iata-resolution792-example5.json @@ -1,66 +1,68 @@ [ { "@context": "http://schema.org", "@type": "FlightReservation", "airplaneSeat": "2F", + "passengerSequenceNumber": "25", "reservationFor": { "@type": "Flight", "airline": { "@type": "Airline", "iataCode": "AF" }, "arrivalAirport": { "@type": "Airport", "iataCode": "CDG" }, "departureAirport": { "@type": "Airport", "iataCode": "GVA" }, "departureDay": "2018-12-05", "flightNumber": "123" }, "reservationNumber": "ABC123", "reservedTicket": { "@type": "Ticket", "ticketToken": "aztecCode:M2GRANDMAIRE/MELANIE EABC123 GVACDGAF 0123 339C002F0025 130>5002A0571234567890 AF AF 1234567890123456 YDEF456 CDGDTWNW 0049 339F001A0002 12C2A012098765432101 2PC ^18ABCDEFGH" }, "underName": { "@type": "Person", "familyName": "GRANDMAIRE", "givenName": "MELANIE" } }, { "@context": "http://schema.org", "@type": "FlightReservation", "airplaneSeat": "1A", + "passengerSequenceNumber": "2", "reservationFor": { "@type": "Flight", "airline": { "@type": "Airline", "iataCode": "NW" }, "arrivalAirport": { "@type": "Airport", "iataCode": "DTW" }, "departureAirport": { "@type": "Airport", "iataCode": "CDG" }, "departureDay": "2018-12-05", "flightNumber": "49" }, "reservationNumber": "DEF456", "reservedTicket": { "@type": "Ticket", "ticketToken": "aztecCode:M2GRANDMAIRE/MELANIE EABC123 GVACDGAF 0123 339C002F0025 130>5002A0571234567890 AF AF 1234567890123456 YDEF456 CDGDTWNW 0049 339F001A0002 12C2A012098765432101 2PC ^18ABCDEFGH" }, "underName": { "@type": "Person", "familyName": "GRANDMAIRE", "givenName": "MELANIE" } } ] diff --git a/autotests/bcbpdata/issue-date.json b/autotests/bcbpdata/issue-date.json index e3ed630..bdbae5f 100644 --- a/autotests/bcbpdata/issue-date.json +++ b/autotests/bcbpdata/issue-date.json @@ -1,34 +1,35 @@ [ { "@context": "http://schema.org", "@type": "FlightReservation", "airplaneSeat": "23D", + "passengerSequenceNumber": "999", "reservationFor": { "@type": "Flight", "airline": { "@type": "Airline", "iataCode": "SN" }, "arrivalAirport": { "@type": "Airport", "iataCode": "BRU" }, "departureAirport": { "@type": "Airport", "iataCode": "TXL" }, "departureDay": "2017-02-03", "flightNumber": "2588" }, "reservationNumber": "XXX007", "reservedTicket": { "@type": "Ticket", "ticketToken": "aztecCode:M1DOE/JOHN EXXX007 TXLBRUSN 2588 034Y023D0999 35D>5181WM7034BSN 2A08200000000000 SN LH 123456789012345 *30600000K0902 " }, "underName": { "@type": "Person", "familyName": "DOE", "givenName": "JOHN" } } ] diff --git a/autotests/bcbpdata/missing-eticket-indicator.json b/autotests/bcbpdata/missing-eticket-indicator.json index d21b39e..b2fa341 100644 --- a/autotests/bcbpdata/missing-eticket-indicator.json +++ b/autotests/bcbpdata/missing-eticket-indicator.json @@ -1,34 +1,35 @@ [ { "@context": "http://schema.org", "@type": "FlightReservation", "airplaneSeat": "12C", + "passengerSequenceNumber": "30", "reservationFor": { "@type": "Flight", "airline": { "@type": "Airline", "iataCode": "EW" }, "arrivalAirport": { "@type": "Airport", "iataCode": "TXL" }, "departureAirport": { "@type": "Airport", "iataCode": "BRU" }, "departureDay": "2018-02-04", "flightNumber": "8103" }, "reservationNumber": "XXX007", "reservedTicket": { "@type": "Ticket", "ticketToken": "aztecCode:M1DOE/JOHN XXX007 BRUTXLEW 8103 035Y012C0030 147>1181W 8033BEW 0000000000000291040000000000 0 LH 123456789012345 " }, "underName": { "@type": "Person", "familyName": "DOE", "givenName": "JOHN" } } ] diff --git a/autotests/bcbpdata/tap-missing-issue-date.json b/autotests/bcbpdata/tap-missing-issue-date.json index a7c7443..29c3506 100644 --- a/autotests/bcbpdata/tap-missing-issue-date.json +++ b/autotests/bcbpdata/tap-missing-issue-date.json @@ -1,34 +1,35 @@ [ { "@context": "http://schema.org", "@type": "FlightReservation", "airplaneSeat": "2D", + "passengerSequenceNumber": "3", "reservationFor": { "@type": "Flight", "airline": { "@type": "Airline", "iataCode": "TP" }, "arrivalAirport": { "@type": "Airport", "iataCode": "LCG" }, "departureAirport": { "@type": "Airport", "iataCode": "LIS" }, "departureDay": "2018-07-23", "flightNumber": "1080" }, "reservationNumber": "XXX007", "reservedTicket": { "@type": "Ticket", "ticketToken": "aztecCode:M1DOE/JOHN EXXX007 LISLCGTP 1080 204Y002D0003 35C>2180 B1A 2904712345678900 *306 09 BRND" }, "underName": { "@type": "Person", "familyName": "DOE", "givenName": "JOHN" } } ] diff --git a/autotests/pkpassdata/airbaltic.json b/autotests/pkpassdata/airbaltic.json index a0a01b6..225ae74 100644 --- a/autotests/pkpassdata/airbaltic.json +++ b/autotests/pkpassdata/airbaltic.json @@ -1,58 +1,59 @@ [ { "@context": "http://schema.org", "@type": "FlightReservation", "airplaneSeat": "14E", + "passengerSequenceNumber": "63", "reservationFor": { "@type": "Flight", "airline": { "@type": "Airline", "iataCode": "BT" }, "arrivalAirport": { "@type": "Airport", "address": { "@type": "PostalAddress", "addressCountry": "LV" }, "geo": { "@type": "GeoCoordinates", "latitude": 56.92359924316406, "longitude": 23.971099853515625 }, "iataCode": "RIX" }, "boardingTime": { "@type": "QDateTime", "@value": "2017-11-05T08:25:00+01:00", "timezone": "Europe/Berlin" }, "departureAirport": { "@type": "Airport", "address": { "@type": "PostalAddress", "addressCountry": "DE" }, "geo": { "@type": "GeoCoordinates", "latitude": 52.55970001220703, "longitude": 13.287799835205078 }, "iataCode": "TXL" }, "departureDay": "2017-11-05", "flightNumber": "212" }, "reservationNumber": "XXX007", "reservedTicket": { "@type": "Ticket", "ticketToken": "aztecCode:M1KRAUSE/VOLKER EXXX007 TXLRIXBT 0212 309Y014E0063 100" }, "underName": { "@type": "Person", "familyName": "KRAUSE", "givenName": "VOLKER", "name": "VOLKER KRAUSE" } } ] diff --git a/autotests/pkpassdata/airberlin.json b/autotests/pkpassdata/airberlin.json index 6b00724..72ca51b 100644 --- a/autotests/pkpassdata/airberlin.json +++ b/autotests/pkpassdata/airberlin.json @@ -1,58 +1,59 @@ [ { "@context": "http://schema.org", "@type": "FlightReservation", "airplaneSeat": "19F", + "passengerSequenceNumber": "60", "reservationFor": { "@type": "Flight", "airline": { "@type": "Airline", "iataCode": "AB" }, "arrivalAirport": { "@type": "Airport", "address": { "@type": "PostalAddress", "addressCountry": "DE" }, "geo": { "@type": "GeoCoordinates", "latitude": 48.35390090942383, "longitude": 11.786100387573242 }, "iataCode": "MUC" }, "boardingTime": { "@type": "QDateTime", "@value": "2017-10-24T15:55:00+02:00", "timezone": "Europe/Berlin" }, "departureAirport": { "@type": "Airport", "address": { "@type": "PostalAddress", "addressCountry": "DE" }, "geo": { "@type": "GeoCoordinates", "latitude": 52.559688568115234, "longitude": 13.287711143493652 }, "iataCode": "TXL" }, "departureDay": "2017-10-24", "flightNumber": "6203" }, "reservationNumber": "XXX007", "reservedTicket": { "@type": "Ticket", "ticketToken": "aztecCode:M1KRAUSE/VOLKER EXXX007 TXLMUCAB 6203 297Y019F0060 33C>5080 B2A N00 " }, "underName": { "@type": "Person", "familyName": "KRAUSE", "givenName": "VOLKER", "name": "VOLKER KRAUSE" } } ] diff --git a/autotests/pkpassdata/eurowings.json b/autotests/pkpassdata/eurowings.json index f66ce67..e23be85 100644 --- a/autotests/pkpassdata/eurowings.json +++ b/autotests/pkpassdata/eurowings.json @@ -1,62 +1,63 @@ [ { "@context": "http://schema.org", "@type": "FlightReservation", "airplaneSeat": "17C", + "passengerSequenceNumber": "40", "reservationFor": { "@type": "Flight", "airline": { "@type": "Airline", "iataCode": "4U", "name": "Germanwings" }, "arrivalAirport": { "@type": "Airport", "address": { "@type": "PostalAddress", "addressCountry": "DE" }, "geo": { "@type": "GeoCoordinates", "latitude": 52.55970001220703, "longitude": 13.287799835205078 }, "iataCode": "TXL", "name": "Berlin-Tegel" }, "boardingTime": { "@type": "QDateTime", "@value": "2017-06-18T18:40:00+01:00", "timezone": "Europe/London" }, "departureAirport": { "@type": "Airport", "address": { "@type": "PostalAddress", "addressCountry": "GB" }, "geo": { "@type": "GeoCoordinates", "latitude": 51.477500915527344, "longitude": -0.4613890051841736 }, "iataCode": "LHR", "name": "London Heathrow" }, "departureDay": "2017-06-18", "departureGate": " - ", "flightNumber": "8465" }, "reservationNumber": "XXX007", "reservedTicket": { "@type": "Ticket", "ticketToken": "aztecCode:M1KRAUSE/VOLKER EXXX007 LHRTXL4U 8465 169Y017C0040 147>1181 7168B4U 0000000000000291040PASSPORTID2 LH 123412341234012 " }, "underName": { "@type": "Person", "familyName": "KRAUSE", "givenName": "VOLKER", "name": "VOLKER KRAUSE" } } ] diff --git a/autotests/pkpassdata/lufthansa.json b/autotests/pkpassdata/lufthansa.json index 5855133..f0c07dc 100644 --- a/autotests/pkpassdata/lufthansa.json +++ b/autotests/pkpassdata/lufthansa.json @@ -1,61 +1,62 @@ [ { "@context": "http://schema.org", "@type": "FlightReservation", "airplaneSeat": "5A", + "passengerSequenceNumber": "17", "reservationFor": { "@type": "Flight", "airline": { "@type": "Airline", "iataCode": "LH" }, "arrivalAirport": { "@type": "Airport", "address": { "@type": "PostalAddress", "addressCountry": "DE" }, "geo": { "@type": "GeoCoordinates", "latitude": 52.55970001220703, "longitude": 13.287799835205078 }, "iataCode": "TXL", "name": "BERLIN" }, "boardingTime": { "@type": "QDateTime", "@value": "2018-03-06T17:05:00+01:00", "timezone": "Europe/Berlin" }, "departureAirport": { "@type": "Airport", "address": { "@type": "PostalAddress", "addressCountry": "DE" }, "geo": { "@type": "GeoCoordinates", "latitude": 48.35390090942383, "longitude": 11.786100387573242 }, "iataCode": "MUC", "name": "MUNICH" }, "departureDay": "2018-03-06", "departureGate": "G20", "flightNumber": "2724" }, "reservationNumber": "XXX007", "reservedTicket": { "@type": "Ticket", "ticketToken": "aztecCode:M1DOE/JOHN EXXX007 MUCTXLLH 2724 065M005A0017 35D>6180WW8064BLH 2A22012345678900 LH N*30600000K09 " }, "underName": { "@type": "Person", "familyName": "DOE", "givenName": "JOHN", "name": "JOHN DOE" } } ] diff --git a/autotests/pkpassdata/swiss.json b/autotests/pkpassdata/swiss.json index a791821..cfb01cc 100644 --- a/autotests/pkpassdata/swiss.json +++ b/autotests/pkpassdata/swiss.json @@ -1,61 +1,62 @@ [ { "@context": "http://schema.org", "@type": "FlightReservation", "airplaneSeat": "10E", + "passengerSequenceNumber": "143", "pkpassPassTypeIdentifier": "pass.booking.swiss.com", "pkpassSerialNumber": "123456789", "reservationFor": { "@type": "Flight", "airline": { "@type": "Airline", "iataCode": "LX" }, "arrivalAirport": { "@type": "Airport", "address": { "@type": "PostalAddress", "addressCountry": "DE" }, "geo": { "@type": "GeoCoordinates", "latitude": 52.55970001220703, "longitude": 13.287799835205078 }, "iataCode": "TXL" }, "boardingTime": { "@type": "QDateTime", "@value": "2017-09-15T20:25:00+02:00", "timezone": "Europe/Zurich" }, "departureAirport": { "@type": "Airport", "address": { "@type": "PostalAddress", "addressCountry": "CH" }, "geo": { "@type": "GeoCoordinates", "latitude": 47.452301025390625, "longitude": 8.560830116271973 }, "iataCode": "ZRH" }, "departureDay": "2017-09-15", "departureGate": "AB", "flightNumber": "962" }, "reservationNumber": "XXX007", "reservedTicket": { "@type": "Ticket", "ticketToken": "aztecCode:M1KRAUSE/VOLKER EXXX007 ZRHTXLLX 0962 258Y010E0143 15D>5180 M7258BLX 2A724xxxxxxxxxx0 LX LH 123456789012345 N*30600000K09 " }, "underName": { "@type": "Person", "familyName": "KRAUSE", "givenName": "VOLKER", "name": "VOLKER KRAUSE" } } ] diff --git a/autotests/postprocessordata/bcbp-expansion.post.json b/autotests/postprocessordata/bcbp-expansion.post.json index aeca939..977d168 100644 --- a/autotests/postprocessordata/bcbp-expansion.post.json +++ b/autotests/postprocessordata/bcbp-expansion.post.json @@ -1,58 +1,59 @@ [ { "@context": "http://schema.org", "@type": "FlightReservation", "airplaneSeat": "1A", + "passengerSequenceNumber": "25", "reservationFor": { "@type": "Flight", "airline": { "@type": "Airline", "iataCode": "AC" }, "arrivalAirport": { "@type": "Airport", "address": { "@type": "PostalAddress", "addressCountry": "DE" }, "geo": { "@type": "GeoCoordinates", "latitude": 50.03329849243164, "longitude": 8.570560455322266 }, "iataCode": "FRA" }, "boardingTime": { "@type": "QDateTime", "@value": "2027-03-05T06:30:00-05:00", "timezone": "America/Toronto" }, "departureAirport": { "@type": "Airport", "address": { "@type": "PostalAddress", "addressCountry": "CA" }, "geo": { "@type": "GeoCoordinates", "latitude": 45.47060012817383, "longitude": -73.74079895019531 }, "iataCode": "YUL" }, "departureDay": "2027-03-05", "flightNumber": "834" }, "reservationNumber": "ABC123", "reservedTicket": { "@type": "Ticket", "ticketToken": "aztecCode:M1DESMARAIS/LUC EABC123 YULFRAAC 0834 326J001A0025 100" }, "underName": { "@type": "Person", "name": "LUC DESMARAIS", "familyName": "DESMARAIS", "givenName": "LUC" } } ] diff --git a/autotests/postprocessordata/bcbp-two-leg-expansion.post.json b/autotests/postprocessordata/bcbp-two-leg-expansion.post.json index 3e91d77..99b7e05 100644 --- a/autotests/postprocessordata/bcbp-two-leg-expansion.post.json +++ b/autotests/postprocessordata/bcbp-two-leg-expansion.post.json @@ -1,53 +1,54 @@ [ { "@context": "http://schema.org", "@type": "FlightReservation", "airplaneSeat": "2F", + "passengerSequenceNumber": "25", "reservationFor": { "@type": "Flight", "airline": { "@type": "Airline", "iataCode": "AF" }, "arrivalAirport": { "@type": "Airport", "address": { "@type": "PostalAddress", "addressCountry": "FR" }, "geo": { "@type": "GeoCoordinates", "latitude": 49.009700775146484, "longitude": 2.5477800369262695 }, "iataCode": "CDG" }, "departureAirport": { "@type": "Airport", "address": { "@type": "PostalAddress", "addressCountry": "CH" }, "geo": { "@type": "GeoCoordinates", "latitude": 46.23830032348633, "longitude": 6.109439849853516 }, "iataCode": "GVA" }, "departureDay": "2018-12-05", "flightNumber": "123" }, "reservationNumber": "ABC123", "reservedTicket": { "@type": "Ticket", "ticketToken": "aztecCode:M2GRANDMAIRE/MELANIE EABC123 GVACDGAF 0123 339C002F0025 130>5002A0571234567890 AF AF 1234567890123456 YDEF456 CDGDTWNW 0049 339F001A0002 12C2A012098765432101 2PC ^18ABCDEFGH" }, "underName": { "@type": "Person", "familyName": "GRANDMAIRE", "givenName": "MELANIE", "name": "MELANIE GRANDMAIRE" } } ] diff --git a/autotests/postprocessordata/flight-merge.post.json b/autotests/postprocessordata/flight-merge.post.json index c2e51b7..f97ea0c 100644 --- a/autotests/postprocessordata/flight-merge.post.json +++ b/autotests/postprocessordata/flight-merge.post.json @@ -1,73 +1,74 @@ [ { "@context": "http://schema.org", "@type": "FlightReservation", "airplaneSeat": "14D", + "passengerSequenceNumber": "14", "pkpassPassTypeIdentifier": "pass.ncr.brussels.boarding-pass", "pkpassSerialNumber": "123456789", "reservationFor": { "@type": "Flight", "airline": { "@type": "Airline", "iataCode": "SN", "name": "Brussels Airlines" }, "arrivalAirport": { "@type": "Airport", "address": { "@type": "PostalAddress", "addressCountry": "FR" }, "geo": { "@type": "GeoCoordinates", "latitude": 43.6349983215332, "longitude": 1.3677799701690674 }, "iataCode": "TLS", "name": "Toulouse, Blagnac Airport, FR" }, "arrivalTime": { "@type": "QDateTime", "@value": "2018-04-20T11:20:00+02:00", "timezone": "Europe/Paris" }, "boardingTime": { "@type": "QDateTime", "@value": "2018-04-20T09:10:00+02:00", "timezone": "Europe/Brussels" }, "departureAirport": { "@type": "Airport", "address": { "@type": "PostalAddress", "addressCountry": "BE" }, "geo": { "@type": "GeoCoordinates", "latitude": 50.88970184326172, "longitude": 4.478000164031982 }, "iataCode": "BRU", "name": "Brussels Airport, BE" }, "departureDay": "2018-04-20", "departureTime": { "@type": "QDateTime", "@value": "2018-04-20T09:40:00+02:00", "timezone": "Europe/Brussels" }, "flightNumber": "3667" }, "reservationNumber": "XXX007", "reservedTicket": { "@type": "Ticket", "ticketToken": "aztecCode:M1DOE/JOHNMR EXXX007 BRUTLSSN 3667 110Y014D0014 35D>5181WM8109BSN 2A08221234567890 SN LH 123456789012345 *30600000K0902 " }, "underName": { "@type": "Person", "name": "JOHNMR DOE", "familyName": "DOE", "givenName": "JOHNMR" } } ] diff --git a/autotests/postprocessordata/lh-incomplete-departure-time.post.json b/autotests/postprocessordata/lh-incomplete-departure-time.post.json index 949c31a..bb22101 100644 --- a/autotests/postprocessordata/lh-incomplete-departure-time.post.json +++ b/autotests/postprocessordata/lh-incomplete-departure-time.post.json @@ -1,51 +1,52 @@ [ { "@context": "http://schema.org", "@type": "FlightReservation", "airplaneSeat": "5A", + "passengerSequenceNumber": "42", "reservationFor": { "@type": "Flight", "airline": { "@type": "Airline", "iataCode": "LH", "name": "Lufthansa" }, "arrivalAirport": { "@type": "Airport", "address": { "@type": "PostalAddress", "addressCountry": "DE" }, "geo": { "@type": "GeoCoordinates", "latitude": 52.55970001220703, "longitude": 13.287799835205078 }, "iataCode": "TXL", "name": "Berlin" }, "boardingTime": { "@type": "QDateTime", "@value": "2018-03-06T17:05:00+01:00", "timezone": "Europe/Berlin" }, "departureAirport": { "@type": "Airport", "address": { "@type": "PostalAddress", "addressCountry": "DE" }, "geo": { "@type": "GeoCoordinates", "latitude": 48.35390090942383, "longitude": 11.786100387573242 }, "iataCode": "MUC", "name": "Munich" }, "departureDay": "2018-03-06", "flightNumber": "2724" }, "reservationNumber": "XXX007" } ] diff --git a/src/datatypes/reservation.cpp b/src/datatypes/reservation.cpp index 4027bcd..7eed53c 100644 --- a/src/datatypes/reservation.cpp +++ b/src/datatypes/reservation.cpp @@ -1,128 +1,130 @@ /* Copyright (C) 2018 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "reservation.h" #include "organization.h" #include "datatypes_p.h" #include #include using namespace KItinerary; namespace KItinerary { class ReservationPrivate : public QSharedData { KITINERARY_PRIVATE_BASE_GADGET(Reservation) public: QString reservationNumber; QVariant reservationFor; QVariant reservedTicket; QVariant underName; QUrl url; QUrl cancelReservationUrl; QUrl modifyReservationUrl; QString pkpassPassTypeIdentifier; QString pkpassSerialNumber; Organization provider; }; KITINERARY_MAKE_BASE_CLASS(Reservation) KITINERARY_MAKE_PROPERTY(Reservation, QString, reservationNumber, setReservationNumber) KITINERARY_MAKE_PROPERTY(Reservation, QVariant, reservationFor, setReservationFor) KITINERARY_MAKE_PROPERTY(Reservation, QVariant, reservedTicket, setReservedTicket) KITINERARY_MAKE_PROPERTY(Reservation, QVariant, underName, setUnderName) KITINERARY_MAKE_PROPERTY(Reservation, QUrl, cancelReservationUrl, setCancelReservationUrl) KITINERARY_MAKE_PROPERTY(Reservation, QUrl, modifyReservationUrl, setModifyReservationUrl) KITINERARY_MAKE_PROPERTY(Reservation, QUrl, url, setUrl) KITINERARY_MAKE_PROPERTY(Reservation, QString, pkpassPassTypeIdentifier, setPkpassPassTypeIdentifier) KITINERARY_MAKE_PROPERTY(Reservation, QString, pkpassSerialNumber, setPkpassSerialNumber) KITINERARY_MAKE_PROPERTY(Reservation, Organization, provider, setProvider) class LodgingReservationPrivate : public ReservationPrivate { KITINERARY_PRIVATE_GADGET(LodgingReservation) public: QDateTime checkinTime; QDateTime checkoutTime; }; KITINERARY_MAKE_SUB_CLASS(LodgingReservation, Reservation) KITINERARY_MAKE_PROPERTY(LodgingReservation, QDateTime, checkinTime, setCheckinTime) KITINERARY_MAKE_PROPERTY(LodgingReservation, QDateTime, checkoutTime, setCheckoutTime) QString LodgingReservation::checkinDateLocalized() const { K_D(const LodgingReservation); return QLocale().toString(d->checkinTime.date(), QLocale::ShortFormat); } QString LodgingReservation::checkoutDateLocalized() const { K_D(const LodgingReservation); return QLocale().toString(d->checkoutTime.date(), QLocale::ShortFormat); } class FlightReservationPrivate : public ReservationPrivate { KITINERARY_PRIVATE_GADGET(FlightReservation) public: + QString passengerSequenceNumber; QString airplaneSeat; QString boardingGroup; QUrl ticketDownloadUrl; }; KITINERARY_MAKE_SUB_CLASS(FlightReservation, Reservation) +KITINERARY_MAKE_PROPERTY(FlightReservation, QString, passengerSequenceNumber, setPassengerSequenceNumber) KITINERARY_MAKE_PROPERTY(FlightReservation, QString, airplaneSeat, setAirplaneSeat) KITINERARY_MAKE_PROPERTY(FlightReservation, QString, boardingGroup, setBoardingGroup) KITINERARY_MAKE_PROPERTY(FlightReservation, QUrl, ticketDownloadUrl, setTicketDownloadUrl) class TrainReservationPrivate : public ReservationPrivate { KITINERARY_PRIVATE_GADGET(TrainReservation) }; KITINERARY_MAKE_SUB_CLASS(TrainReservation, Reservation) class BusReservationPrivate : public ReservationPrivate { KITINERARY_PRIVATE_GADGET(BusReservation) }; KITINERARY_MAKE_SUB_CLASS(BusReservation, Reservation) class FoodEstablishmentReservationPrivate : public ReservationPrivate { KITINERARY_PRIVATE_GADGET(FoodEstablishmentReservation) public: QDateTime endTime; QDateTime startTime; int partySize = 0; }; KITINERARY_MAKE_SUB_CLASS(FoodEstablishmentReservation, Reservation) KITINERARY_MAKE_PROPERTY(FoodEstablishmentReservation, QDateTime, endTime, setEndTime) KITINERARY_MAKE_PROPERTY(FoodEstablishmentReservation, int, partySize, setPartySize) KITINERARY_MAKE_PROPERTY(FoodEstablishmentReservation, QDateTime, startTime, setStartTime) } template <> KItinerary::ReservationPrivate *QExplicitlySharedDataPointer::clone() { return d->clone(); } #include "moc_reservation.cpp" diff --git a/src/datatypes/reservation.h b/src/datatypes/reservation.h index fe681f7..f4e763d 100644 --- a/src/datatypes/reservation.h +++ b/src/datatypes/reservation.h @@ -1,133 +1,139 @@ /* Copyright (C) 2018 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef KITINERARY_RESERVATION_H #define KITINERARY_RESERVATION_H #include "kitinerary_export.h" #include "datatypes.h" class QUrl; namespace KItinerary { class ReservationPrivate; class Organization; /** Abstract base class for reservations. * @see https://schema.org/Reservation */ class KITINERARY_EXPORT Reservation { KITINERARY_BASE_GADGET(Reservation) KITINERARY_PROPERTY(QString, reservationNumber, setReservationNumber) KITINERARY_PROPERTY(QVariant, reservationFor, setReservationFor) KITINERARY_PROPERTY(QVariant, reservedTicket, setReservedTicket) KITINERARY_PROPERTY(QVariant, underName, setUnderName) KITINERARY_PROPERTY(KItinerary::Organization, provider, setProvider) KITINERARY_PROPERTY(QUrl, url, setUrl) // Google extension KITINERARY_PROPERTY(QUrl, cancelReservationUrl, setCancelReservationUrl) KITINERARY_PROPERTY(QUrl, modifyReservationUrl, setModifyReservationUrl) // KDE extensions /** Pass type identifier of an associated Apple Wallet boarding pass. * @see KPkPass::Pass::passTypeIdentifier */ KITINERARY_PROPERTY(QString, pkpassPassTypeIdentifier, setPkpassPassTypeIdentifier) /** Serial number of an associated Apple Wallet boarding pass. * @see KPkPass::Pass::serialNumber */ KITINERARY_PROPERTY(QString, pkpassSerialNumber, setPkpassSerialNumber) protected: ///@cond internal QExplicitlySharedDataPointer d; ///@endcond }; /** A hotel reservation. * @see https://schema.org/LodgingReservation * @see https://developers.google.com/gmail/markup/reference/hotel-reservation */ class KITINERARY_EXPORT LodgingReservation : public Reservation { KITINERARY_GADGET(LodgingReservation) KITINERARY_PROPERTY(QDateTime, checkinTime, setCheckinTime) KITINERARY_PROPERTY(QDateTime, checkoutTime, setCheckoutTime) Q_PROPERTY(QString checkinDateLocalized READ checkinDateLocalized STORED false CONSTANT) Q_PROPERTY(QString checkoutDateLocalized READ checkoutDateLocalized STORED false CONSTANT) private: QString checkinDateLocalized() const; QString checkoutDateLocalized() const; }; /** A flight reservation. * @see https://schema.org/FlightReservation * @see https://developers.google.com/gmail/markup/reference/flight-reservation */ class KITINERARY_EXPORT FlightReservation : public Reservation { KITINERARY_GADGET(FlightReservation) + /** Passenger sequnce number + * Despite the name, do not expect this to be a number, infants without + * their own seat get vendor-defined codes here for example. + * @see https://schema.org/passengerSequenceNumber + */ + KITINERARY_PROPERTY(QString, passengerSequenceNumber, setPassengerSequenceNumber) // Google extensions KITINERARY_PROPERTY(QString, airplaneSeat, setAirplaneSeat) KITINERARY_PROPERTY(QString, boardingGroup, setBoardingGroup) KITINERARY_PROPERTY(QUrl, ticketDownloadUrl, setTicketDownloadUrl) }; /** A train reservation. * @see https://schema.org/TrainReservation */ class KITINERARY_EXPORT TrainReservation : public Reservation { KITINERARY_GADGET(TrainReservation) }; /** A bus reservation. * @see https://schema.org/BusReservation */ class KITINERARY_EXPORT BusReservation : public Reservation { KITINERARY_GADGET(BusReservation) }; /** A restaurant reservation. * @see https://schema.org/FoodEstablishmentReservation * @see https://developers.google.com/gmail/markup/reference/restaurant-reservation */ class KITINERARY_EXPORT FoodEstablishmentReservation : public Reservation { KITINERARY_GADGET(FoodEstablishmentReservation) KITINERARY_PROPERTY(QDateTime, endTime, setEndTime) KITINERARY_PROPERTY(int, partySize, setPartySize) KITINERARY_PROPERTY(QDateTime, startTime, setStartTime) }; } Q_DECLARE_METATYPE(KItinerary::FlightReservation) Q_DECLARE_METATYPE(KItinerary::LodgingReservation) Q_DECLARE_METATYPE(KItinerary::TrainReservation) Q_DECLARE_METATYPE(KItinerary::BusReservation) Q_DECLARE_METATYPE(KItinerary::FoodEstablishmentReservation) #endif // KITINERARY_RESERVATION_H diff --git a/src/iatabcbpparser.cpp b/src/iatabcbpparser.cpp index d521746..5106d65 100644 --- a/src/iatabcbpparser.cpp +++ b/src/iatabcbpparser.cpp @@ -1,239 +1,239 @@ /* Copyright (C) 2018 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "iatabcbpparser.h" #include "logging.h" #include #include #include #include #include #include #include #include using namespace KItinerary; namespace KItinerary { enum Constants { UniqueMandatorySize = 23, RepeatedMandatorySize = 37, FormatCode = 'M', BeginOfVersionNumber = '>' }; static QStringRef stripLeadingZeros(const QStringRef &s) { const auto it = std::find_if(s.begin(), s.end(), [](const QChar &c) { return c != QLatin1Char('0'); }); const auto d = std::distance(s.begin(), it); return s.mid(d); } static int readHexValue(const QStringRef &s, int width) { return s.mid(0, width).toInt(nullptr, 16); } static int parseRepeatedMandatorySection(const QStringRef& msg, FlightReservation& res) { if (msg.size() < 24) { // pre-checking data, technically incomplete, but we can make use of this nevertheless qCWarning(Log) << "IATA BCBP repeated mandatory section too short"; return -1; // error } res.setReservationNumber(msg.mid(0, 7).trimmed().toString()); Flight flight; Airport airport; airport.setIataCode(msg.mid(7, 3).toString()); flight.setDepartureAirport(airport); airport.setIataCode(msg.mid(10, 3).toString()); flight.setArrivalAirport(airport); Airline airline; airline.setIataCode(msg.mid(13, 3).trimmed().toString()); flight.setAirline(airline); flight.setFlightNumber(stripLeadingZeros(msg.mid(16, 5).trimmed()).toString()); // 3x Date of flight, as days since Jan 1st // we don't know the year here, so use 1970, will be filled up or discarded by the caller const auto days = msg.mid(21, 3).toInt() - 1; flight.setDepartureDay(QDate(1970, 1, 1).addDays(days)); res.setReservationFor(flight); if (msg.size() < RepeatedMandatorySize) { return 0; } // 1x Compartment code res.setAirplaneSeat(stripLeadingZeros(msg.mid(25, 4)).trimmed().toString()); + res.setPassengerSequenceNumber(stripLeadingZeros(msg.mid(29, 5)).trimmed().toString()); - // 5x Checkin sequence number // 1x Passenger status // field size of conditional section + airline use section return readHexValue(msg.mid(35), 2); } } QVector IataBcbpParser::parse(const QString& message, const QDate &externalIssueDate) { if (message.size() < UniqueMandatorySize) { qCWarning(Log) << "IATA BCBP code too short for unique mandatory section"; return {}; } if (message.at(0) != QLatin1Char(FormatCode) || !message.at(1).isDigit()) { qCWarning(Log) << "IATA BCBP code invalid unique mandatory section format"; return {}; } // parse unique mandatory section const auto legCount = message.at(1).toLatin1() - '0'; QVector result; result.reserve(legCount); FlightReservation res1; { Person person; const auto fullName = message.midRef(2, 20).trimmed(); const auto idx = fullName.indexOf(QLatin1Char('/')); if (idx > 0 && idx < fullName.size() - 1) { person.setFamilyName(fullName.left(idx).toString()); person.setGivenName(fullName.mid(idx + 1).toString()); } else { person.setName(fullName.toString()); } res1.setUnderName(person); } { Ticket ticket; ticket.setTicketToken(QStringLiteral("aztecCode:") + message); res1.setReservedTicket(ticket); } const auto varSize = parseRepeatedMandatorySection(message.midRef(UniqueMandatorySize), res1); if (varSize < 0) { // parser error return {}; } int index = UniqueMandatorySize + RepeatedMandatorySize; auto issueDate = externalIssueDate; if (varSize > 0) { if (message.size() < (index + varSize)) { qCWarning(Log) << "IATA BCBP code too short for conditional section in first leg" << varSize << message.size(); return {}; } // parse unique conditional section, if there is one, otherwise we skip all of this assuming "for airline use" if (message.at(index) == QLatin1Char(BeginOfVersionNumber)) { // 1x version number // 2x field size of unique conditional section const auto uniqCondSize = readHexValue(message.midRef(index + 2), 2); if (uniqCondSize + 4 > varSize) { qCWarning(Log) << "IATA BCBP unique conditional section has invalid size" << varSize << uniqCondSize; return {}; } // 1x passenger description // 1x source of checking // 1x source of boarding pass issuance // 4x date of issue of boarding pass // this only contains the last digit of the year (sic), but we assume it to be in the past // so this still gives us a 10 year range of correctly determined times if (uniqCondSize >= 11 && externalIssueDate.isValid() && message.at(index + 7).isDigit() && message.at(index + 10).isDigit()) { const auto year = message.at(index + 7).toLatin1() - '0'; const auto days = message.midRef(index + 8, 3).toInt() - 1; if (year < 0 || year > 9 || days < 0 || days > 365) { qCWarning(Log) << "IATA BCBP invalid boarding pass issue date format" << message.midRef(index + 7, 4); return {}; } auto currentYear = externalIssueDate.year() - externalIssueDate.year() % 10 + year; if (currentYear > externalIssueDate.year()) { currentYear -= 10; } issueDate = QDate(currentYear, 1, 1).addDays(days); } // 1x document type // 3x airline code of boarding pass issuer // 3x 13x baggage tag numbers // skip repeated conditional section, containing mainly bonus program data } // skip for airline use section index += varSize; } result.push_back(res1); // all following legs only contain repeated sections, copy content from the unique ones from the first leg for (int i = 1; i < legCount; ++i) { if (message.size() < (index + RepeatedMandatorySize)) { qCWarning(Log) << "IATA BCBP repeated mandatory section too short" << i; return {}; } FlightReservation res = res1; const auto varSize = parseRepeatedMandatorySection(message.midRef(index), res); if (varSize < 0) { // parser error return {}; } index += RepeatedMandatorySize; if (message.size() < (index + varSize)) { qCWarning(Log) << "IATA BCBP repeated conditional section too short" << i; return {}; } // skip repeated conditional section // skip for airline use section index += varSize; result.push_back(res); } // optional security section at the end, not interesting for us // complete departure dates with the now (hopefully known issue date) for (auto it = result.begin(); it != result.end(); ++it) { auto res = (*it).value(); auto flight = res.reservationFor().value(); if (issueDate.isValid()) { const auto days = flight.departureDay().dayOfYear() - 1; QDate date(issueDate.year(), 1, 1); date = date.addDays(days); if (date >= issueDate) { flight.setDepartureDay(date); } else { flight.setDepartureDay(QDate(issueDate.year() + 1, 1, 1).addDays(days)); } } else { flight.setDepartureDay(QDate()); } res.setReservationFor(flight); *it = res; } return result; }