summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBirte Kristina Friesel <derf@finalrewind.org>2025-02-02 18:25:47 +0100
committerBirte Kristina Friesel <derf@finalrewind.org>2025-02-02 18:25:47 +0100
commit7cb9cb9836af5db19568886f9804b7032d27312f (patch)
tree5327fea154cda3a6fbad33241f1d1c61f08273f1
parent43f9af3c356a0607e3fcc121311f11bf57746e2b (diff)
add ticket offer API client and --with-offers option
-rwxr-xr-xbin/dbris27
-rw-r--r--lib/Travel/Routing/DE/DBRIS.pm118
-rw-r--r--lib/Travel/Routing/DE/DBRIS/Connection.pm3
-rw-r--r--lib/Travel/Routing/DE/DBRIS/Offer.pm39
4 files changed, 151 insertions, 36 deletions
diff --git a/bin/dbris b/bin/dbris
index 7d06b64..9c0eb54 100755
--- a/bin/dbris
+++ b/bin/dbris
@@ -16,9 +16,9 @@ use Travel::Routing::DE::DBRIS;
my ( $date, $time, $arrival, $from, $to, $language );
my $mots;
+my ( $show_jid, $show_full_route, $show_offers );
my ( $first_class, $passengers );
my ( $developer_mode, $verbose );
-my ( $show_jid, $show_full_route );
my ( $json_output, $raw_json_output );
my $use_cache = 1;
my $cache;
@@ -55,6 +55,7 @@ GetOptions(
'j|with-jid' => \$show_jid,
'm|modes-of-transit=s' => \$mots,
'l|language=s' => \$language,
+ 'o|with-offers' => \$show_offers,
'p|passengers=s' => \$passengers,
't|time=s' => \$time,
'v|verbose' => \$verbose,
@@ -369,6 +370,30 @@ for my $connection ( $ris->connections ) {
$header,
);
+ if ($show_offers) {
+ my $offers_req = Travel::Routing::DE::DBRIS->new(
+ developer_mode => $developer_mode,
+ offers => {
+ recon => $connection->recon,
+ },
+ passengers => $opt{passengers},
+ first_class => $opt{first_class},
+ );
+ if ( my $err = $offers_req->errstr ) {
+ say STDERR "Request error while looking up offers: ${err}";
+ }
+ for my $offer ($offers_req->offers) {
+ printf('- %5.2f %s %s', $offer->price, $offer->price_unit =~ s{EUR}{€}r, $offer->name);
+ if ($first_class and $offer->class == 2 or not $first_class and $offer->class == 1) {
+ printf(" %d. Klasse", $offer->class);
+ }
+ if (scalar $offer->conditions) {
+ printf(' (%s)', join(q{ · }, map { $_->{textKurz} } $offer->conditions));
+ }
+ say q{};
+ }
+ }
+
if ($verbose) {
for my $note ( $connection->notes ) {
printf( "| %s (%s)\n", $note->{value}, $note->{key} );
diff --git a/lib/Travel/Routing/DE/DBRIS.pm b/lib/Travel/Routing/DE/DBRIS.pm
index f596bfd..07399a3 100644
--- a/lib/Travel/Routing/DE/DBRIS.pm
+++ b/lib/Travel/Routing/DE/DBRIS.pm
@@ -16,6 +16,7 @@ use JSON;
use LWP::UserAgent;
use Travel::Status::DE::DBRIS;
use Travel::Routing::DE::DBRIS::Connection;
+use Travel::Routing::DE::DBRIS::Offer;
our $VERSION = '0.03';
@@ -60,37 +61,67 @@ sub new {
@mots = @{ $conf{modes_of_transit} // [] };
}
- my $req_url
- = $self->{language} eq 'de'
- ? 'https://www.bahn.de/web/api/angebote/fahrplan'
- : 'https://int.bahn.de/web/api/angebote/fahrplan';
- my $req = {
- abfahrtsHalt => $conf{from}->id,
- ankunftsHalt => $conf{to}->id,
- anfrageZeitpunkt => $dt->strftime('%Y-%m-%dT%H:%M:00'),
- ankunftSuche => $conf{arrival} ? 'ANKUNFT' : 'ABFAHRT',
- klasse => $conf{first_class} ? 'KLASSE_1' : 'KLASSE_2',
- produktgattungen => \@mots,
- reisende => [
- {
- typ => 'ERWACHSENER',
- ermaessigungen => [
- {
- art => 'KEINE_ERMAESSIGUNG',
- klasse => 'KLASSENLOS'
- },
- ],
- alter => [],
- anzahl => 1,
- }
- ],
- schnelleVerbindungen => \1,
- sitzplatzOnly => \0,
- bikeCarriage => \0,
- reservierungsKontingenteVorhanden => \0,
- nurDeutschlandTicketVerbindungen => \0,
- deutschlandTicketVorhanden => \0
- };
+ my ($req_url, $req);
+
+ if ($conf{from} and $conf{to}) {
+ $req_url
+ = $self->{language} eq 'de'
+ ? 'https://www.bahn.de/web/api/angebote/fahrplan'
+ : 'https://int.bahn.de/web/api/angebote/fahrplan';
+ $req = {
+ abfahrtsHalt => $conf{from}->id,
+ ankunftsHalt => $conf{to}->id,
+ anfrageZeitpunkt => $dt->strftime('%Y-%m-%dT%H:%M:00'),
+ ankunftSuche => $conf{arrival} ? 'ANKUNFT' : 'ABFAHRT',
+ klasse => $conf{first_class} ? 'KLASSE_1' : 'KLASSE_2',
+ produktgattungen => \@mots,
+ reisende => [
+ {
+ typ => 'ERWACHSENER',
+ ermaessigungen => [
+ {
+ art => 'KEINE_ERMAESSIGUNG',
+ klasse => 'KLASSENLOS'
+ },
+ ],
+ alter => [],
+ anzahl => 1,
+ }
+ ],
+ schnelleVerbindungen => \1,
+ sitzplatzOnly => \0,
+ bikeCarriage => \0,
+ reservierungsKontingenteVorhanden => \0,
+ nurDeutschlandTicketVerbindungen => \0,
+ deutschlandTicketVorhanden => \0
+ };
+ }
+ elsif ($conf{offers}) {
+ $req_url
+ = $self->{language} eq 'de'
+ ? 'https://www.bahn.de/web/api/angebote/recon'
+ : 'https://int.bahn.de/web/api/angebote/recon';
+ $req = {
+ klasse => $conf{first_class} ? 'KLASSE_1' : 'KLASSE_2',
+ ctxRecon => $conf{offers}{recon},
+ reisende => [
+ {
+ typ => 'ERWACHSENER',
+ ermaessigungen => [
+ {
+ art => 'KEINE_ERMAESSIGUNG',
+ klasse => 'KLASSENLOS'
+ },
+ ],
+ alter => [],
+ anzahl => 1,
+ }
+ ],
+ reservierungsKontingenteVorhanden => \0,
+ nurDeutschlandTicketVerbindungen => \0,
+ deutschlandTicketVorhanden => \0
+ };
+ }
for my $via ( @{ $conf{via} } ) {
my $via_stop = { id => $via->{stop}->id };
@@ -184,7 +215,12 @@ sub new {
}
$self->{raw_json} = $json->decode($content);
- $self->parse_connections;
+ if ($conf{from} and $conf{to}) {
+ $self->parse_connections;
+ }
+ elsif ($conf{offers}) {
+ $self->parse_offers;
+ }
}
return $self;
@@ -258,7 +294,6 @@ sub post_with_cache {
);
if ( $reply->is_error ) {
- say $reply->status_line;
return ( undef, $reply->status_line );
}
my $content = $reply->content;
@@ -294,6 +329,16 @@ sub parse_connections {
}
}
+sub parse_offers {
+ my ($self) = @_;
+
+ for my $offer (@{$self->{raw_json}{verbindungen}[0]{reiseAngebote} // []}) {
+ push(@{$self->{offers}}, Travel::Routing::DE::DBRIS::Offer->new(
+ json => $offer
+ ));
+ }
+}
+
# }}}
# {{{ Public Functions
@@ -305,7 +350,12 @@ sub errstr {
sub connections {
my ($self) = @_;
- return @{ $self->{connections} };
+ return @{ $self->{connections} // []};
+}
+
+sub offers {
+ my ($self) = @_;
+ return @{$self->{offers} // [] };
}
# }}}
diff --git a/lib/Travel/Routing/DE/DBRIS/Connection.pm b/lib/Travel/Routing/DE/DBRIS/Connection.pm
index b090e01..8062929 100644
--- a/lib/Travel/Routing/DE/DBRIS/Connection.pm
+++ b/lib/Travel/Routing/DE/DBRIS/Connection.pm
@@ -18,7 +18,7 @@ Travel::Routing::DE::DBRIS::Connection->mk_ro_accessors(
sched_dep rt_dep dep
sched_arr rt_arr arr
occupancy occupancy_first occupancy_second
- price price_unit
+ price price_unit recon
)
);
@@ -35,6 +35,7 @@ sub new {
// -1,
is_unscheduled => $json->{isAlternativeVerbindung},
id => $json->{tripId},
+ recon => $json->{ctxRecon},
price => $json->{angebotsPreis}{betrag},
price_unit => $json->{angebotsPreis}{waehrung},
strptime_obj => $strptime,
diff --git a/lib/Travel/Routing/DE/DBRIS/Offer.pm b/lib/Travel/Routing/DE/DBRIS/Offer.pm
new file mode 100644
index 0000000..47bf543
--- /dev/null
+++ b/lib/Travel/Routing/DE/DBRIS/Offer.pm
@@ -0,0 +1,39 @@
+package Travel::Routing::DE::DBRIS::Offer;
+
+use strict;
+use warnings;
+use 5.020;
+use utf8;
+
+use parent 'Class::Accessor';
+
+our $VERSION = '0.03';
+
+Travel::Routing::DE::DBRIS::Offer->mk_ro_accessors(
+ qw(class name price price_unit));
+
+sub new {
+ my ( $obj, %opt ) = @_;
+
+ my $json = $opt{json};
+
+ my $ref = {
+ class => $json->{klasse} =~ s{KLASSE_}{}r,
+ name => $json->{name},
+ price => $json->{preis}{betrag},
+ price_unit => $json->{preis}{waehrung},
+ conditions => $json->{konditionsAnzeigen},
+ };
+
+ bless( $ref, $obj );
+
+ return $ref;
+}
+
+sub conditions {
+ my ($self) = @_;
+
+ return @{ $self->{conditions} // [] };
+}
+
+1;