diff options
author | Daniel Friesel <derf@finalrewind.org> | 2019-09-13 23:39:28 +0200 |
---|---|---|
committer | Daniel Friesel <derf@finalrewind.org> | 2019-09-13 23:39:28 +0200 |
commit | 35cc18dfae9ba3436809d1b6e823362f2aa725ad (patch) | |
tree | 721dbebd0cee8d6838142af7d3dd00bf267129a4 | |
parent | 29d99fe140ad1ec9670b89cf33155c989024adfb (diff) |
add passenger rights heuristic for missed connections
-rwxr-xr-x | lib/Travelynx.pm | 1 | ||||
-rw-r--r-- | lib/Travelynx/Controller/Passengerrights.pm | 184 | ||||
-rw-r--r-- | templates/history.html.ep | 36 | ||||
-rw-r--r-- | templates/passengerrights.html.ep | 69 |
4 files changed, 264 insertions, 26 deletions
diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm index 44273e5..7d3548e 100755 --- a/lib/Travelynx.pm +++ b/lib/Travelynx.pm @@ -2890,6 +2890,7 @@ sub startup { $authed_r->get('/account/insight')->to('account#insight'); $authed_r->get('/ajax/status_card.html')->to('traveling#status_card'); $authed_r->get('/cancelled')->to('traveling#cancelled'); + $authed_r->get('/fgr')->to('passengerrights#list_candidates'); $authed_r->get('/account/password')->to('account#password_form'); $authed_r->get('/account/mail')->to('account#change_mail'); $authed_r->get('/export.json')->to('account#json_export'); diff --git a/lib/Travelynx/Controller/Passengerrights.pm b/lib/Travelynx/Controller/Passengerrights.pm index aab8d76..1188e19 100644 --- a/lib/Travelynx/Controller/Passengerrights.pm +++ b/lib/Travelynx/Controller/Passengerrights.pm @@ -4,6 +4,82 @@ use Mojo::Base 'Mojolicious::Controller'; use DateTime; use CAM::PDF; +sub mark_if_missed_connection { + my ( $self, $journey, $next_journey ) = @_; + + my $possible_delay + = ( $next_journey->{rt_departure}->epoch + - $journey->{sched_arrival}->epoch ) / 60; + my $wait_time + = ( $next_journey->{rt_departure}->epoch - $journey->{rt_arrival}->epoch ) + / 60; + if ( + $wait_time < 120 + and ( $possible_delay >= 120 + or ( $journey->{delay} < 60 and $possible_delay >= 60 ) ) + ) + { + $journey->{connection_missed} = 1; + $journey->{connection} = $next_journey; + $journey->{possible_delay} = $possible_delay; + $journey->{wait_time} = $wait_time; + return 1; + } + return 0; +} + +sub list_candidates { + my ($self) = @_; + + my $now = DateTime->now( time_zone => 'Europe/Berlin' ); + my $range_start = $now->clone->subtract( months => 12 ); + + my @journeys = $self->get_user_travels( + after => $range_start, + before => $now + ); + @journeys = grep { $_->{sched_arrival}->epoch and $_->{rt_arrival}->epoch } + @journeys; + + for my $i ( 0 .. $#journeys ) { + my $journey = $journeys[$i]; + + $journey->{delay} + = ( $journey->{rt_arrival}->epoch - $journey->{sched_arrival}->epoch ) + / 60; + + if ( $journey->{delay} < 3 or $journey->{delay} >= 120 ) { + next; + } + if ( $i > 0 ) { + $self->mark_if_missed_connection( $journey, $journeys[ $i - 1 ] ); + } + } + + @journeys = grep { $_->{delay} >= 60 or $_->{connection_missed} } @journeys; + + push( + @journeys, + map { $_->{cancelled} = 1; $_ } $self->get_user_travels( + after => $range_start, + before => $now, + cancelled => 1 + ) + ); + + @journeys + = sort { $b->{sched_departure}->epoch <=> $a->{sched_departure}->epoch } + @journeys; + + $self->respond_to( + json => { json => [@journeys] }, + any => { + template => 'passengerrights', + journeys => [@journeys] + } + ); +} + sub generate { my ($self) = @_; my $journey_id = $self->param('id'); @@ -34,44 +110,128 @@ sub generate { return; } + $journey->{delay} + = ( $journey->{rt_arrival}->epoch - $journey->{sched_arrival}->epoch ) + / 60; + + if ( $journey->{delay} < 120 ) { + my @connections = $self->get_user_travels( + uid => $uid, + after => $journey->{rt_arrival}, + before => $journey->{rt_arrival}->clone->add( hours => 2 ) + ); + if (@connections) { + $self->mark_if_missed_connection( $journey, $connections[-1] ); + } + } + my $pdf = CAM::PDF->new('public/static/pdf/fahrgastrechteformular.pdf'); + # from station $pdf->fillFormFields( 'S1F4', $journey->{from_name} ); - $pdf->fillFormFields( 'S1F7', $journey->{to_name} ); + + if ( $journey->{connection} ) { + + # to station + $pdf->fillFormFields( 'S1F7', $journey->{connection}{to_name} ); + + # missed connection in: + $pdf->fillFormFields( 'S1F22', $journey->{to_name} ); + + # last change in: + $pdf->fillFormFields( 'S1F24', $journey->{to_name} ); + } + else { + # to station + $pdf->fillFormFields( 'S1F7', $journey->{to_name} ); + } + if ( not $journey->{cancelled} ) { - $pdf->fillFormFields( 'S1F13', $journey->{type} ); - $pdf->fillFormFields( 'S1F14', $journey->{no} ); + + # arived with: TRAIN NO + if ( $journey->{connection} ) { + $pdf->fillFormFields( 'S1F13', $journey->{connection}{type} ); + $pdf->fillFormFields( 'S1F14', $journey->{connection}{no} ); + } + else { + $pdf->fillFormFields( 'S1F13', $journey->{type} ); + $pdf->fillFormFields( 'S1F14', $journey->{no} ); + } } + + # first delayed train: TRAIN NO $pdf->fillFormFields( 'S1F17', $journey->{type} ); $pdf->fillFormFields( 'S1F18', $journey->{no} ); + if ( $journey->{sched_departure}->epoch ) { + + # journey YYMMDD $pdf->fillFormFields( 'S1F1', $journey->{sched_departure}->strftime('%d') ); $pdf->fillFormFields( 'S1F2', $journey->{sched_departure}->strftime('%m') ); $pdf->fillFormFields( 'S1F3', $journey->{sched_departure}->strftime('%y') ); + + # sched departure HHMM $pdf->fillFormFields( 'S1F5', $journey->{sched_departure}->strftime('%H') ); $pdf->fillFormFields( 'S1F6', $journey->{sched_departure}->strftime('%M') ); + + # first delayed train: sched departure HHMM $pdf->fillFormFields( 'S1F19', $journey->{sched_departure}->strftime('%H') ); $pdf->fillFormFields( 'S1F20', $journey->{sched_departure}->strftime('%M') ); } if ( $journey->{sched_arrival}->epoch ) { - $pdf->fillFormFields( 'S1F8', - $journey->{sched_arrival}->strftime('%H') ); - $pdf->fillFormFields( 'S1F9', - $journey->{sched_arrival}->strftime('%M') ); + + # sched arrival HHMM + if ( $journey->{connection} ) { + + # TODO (needs plan data for non-journey trains) + } + else { + $pdf->fillFormFields( 'S1F8', + $journey->{sched_arrival}->strftime('%H') ); + $pdf->fillFormFields( 'S1F9', + $journey->{sched_arrival}->strftime('%M') ); + } } if ( $journey->{rt_arrival}->epoch and not $journey->{cancelled} ) { - $pdf->fillFormFields( 'S1F10', $journey->{rt_arrival}->strftime('%d') ); - $pdf->fillFormFields( 'S1F11', $journey->{rt_arrival}->strftime('%m') ); - $pdf->fillFormFields( 'S1F12', $journey->{rt_arrival}->strftime('%y') ); - $pdf->fillFormFields( 'S1F15', $journey->{rt_arrival}->strftime('%H') ); - $pdf->fillFormFields( 'S1F16', $journey->{rt_arrival}->strftime('%M') ); + + if ( $journey->{connection} ) { + + # arrival YYMMDD + $pdf->fillFormFields( 'S1F10', + $journey->{connection}{rt_arrival}->strftime('%d') ); + $pdf->fillFormFields( 'S1F11', + $journey->{connection}{rt_arrival}->strftime('%m') ); + $pdf->fillFormFields( 'S1F12', + $journey->{connection}{rt_arrival}->strftime('%y') ); + + # arrival HHMM + $pdf->fillFormFields( 'S1F15', + $journey->{connection}{rt_arrival}->strftime('%H') ); + $pdf->fillFormFields( 'S1F16', + $journey->{connection}{rt_arrival}->strftime('%M') ); + } + else { + # arrival YYMMDD + $pdf->fillFormFields( 'S1F10', + $journey->{rt_arrival}->strftime('%d') ); + $pdf->fillFormFields( 'S1F11', + $journey->{rt_arrival}->strftime('%m') ); + $pdf->fillFormFields( 'S1F12', + $journey->{rt_arrival}->strftime('%y') ); + + # arrival HHMM + $pdf->fillFormFields( 'S1F15', + $journey->{rt_arrival}->strftime('%H') ); + $pdf->fillFormFields( 'S1F16', + $journey->{rt_arrival}->strftime('%M') ); + } } $self->res->headers->content_type('application/pdf'); diff --git a/templates/history.html.ep b/templates/history.html.ep index a2f607a..607a356 100644 --- a/templates/history.html.ep +++ b/templates/history.html.ep @@ -7,20 +7,6 @@ </div> </div> -<div class="row"> - <div class="col s12 m12 l3 center-align"> - <a href="/cancelled" class="waves-effect waves-light btn"><i class="material-icons left">cancel</i> Zugausfälle</a> - </div> - <div class="col s12 m12 l1"> </div> - <div class="col s12 m12 l4 center-align"> - <a href="/journey/add" class="waves-effect waves-light btn"><i class="material-icons left">add</i> Neue Fahrt</a> - </div> - <div class="col s12 m12 l1"> </div> - <div class="col s12 m12 l3 center-align"> - <a href="/history.json" class="waves-effect waves-light btn"><i class="material-icons left">cloud</i> JSON-Export</a> - </div> -</div> - <h2>Nach Jahr</h2> %= include '_history_years', current => ''; % if(0) { @@ -41,6 +27,28 @@ </div> % } +<h2>Ausfälle und Verspätungen</h2> +<div class="row"> + <div class="col s12 m12 l5 center-align"> + <a href="/cancelled" class="waves-effect waves-light btn"><i class="material-icons left">cancel</i> Zugausfälle</a> + </div> + <div class="col s12 m12 l2"> </div> + <div class="col s12 m12 l5 center-align"> + <a href="/fgr" class="waves-effect waves-light btn"><i class="material-icons left">feedback</i> Fahrgastrechte</a> + </div> +</div> + +<h2>Rohdaten</h2> +<div class="row"> + <div class="col s12 m12 l5 center-align"> + <a href="/history.json" class="waves-effect waves-light btn"><i class="material-icons left">cloud</i> JSON-Export</a> + </div> + <div class="col s12 m12 l2"> </div> + <div class="col s12 m12 l5 center-align"> + <a href="/journey/add" class="waves-effect waves-light btn"><i class="material-icons left">add</i> Neue Fahrt</a> + </div> +</div> + % if (stash('statistics')) { %= include '_history_stats', stats => stash('statistics'); % } diff --git a/templates/passengerrights.html.ep b/templates/passengerrights.html.ep new file mode 100644 index 0000000..09c50d9 --- /dev/null +++ b/templates/passengerrights.html.ep @@ -0,0 +1,69 @@ +<h1>Fahrgastrechte</h1> +<div class="row"> + <div class="col s12"> + <p> + Gemäß der Fahrgastrechte im Eisenbahnverkehr besteht ab 60 Minuten + Verspätung am Ziel ein Entschädigungsanspruch gegenüber dem + Eisenbahnverkehrsunternehmen. Dieser kann mit dem + Fahrgastrechteformular geltend gemacht werden. + </p> + <p> + Die folgenden Zugfahrten sind wahrscheinliche Kandidaten dafür. + Details zur jeweiligen Zugfahrt sind bereits im Formular eingetragen. + </p> + </div> +</div> + +<div class="row"> + <div class="col s12"> + <table class="striped"> + <thead> + <tr> + <th>Datum</th> + <th>Zug</th> + <th>Grund</th> + <th>Formular</th> + </tr> + </thead> + <tbody> + % for my $journey (@{$journeys}) { + % my $detail_link = '/journey/' . $journey->{id}; + <tr> + <td><%= $journey->{sched_departure}->strftime('%d.%m.%Y') %></td> + <td><a href="<%= $detail_link %>"> + <%= $journey->{type} %> <%= $journey->{line} // $journey->{no} %> + → <%= $journey->{to_name} %> + % if ($journey->{connection}) { + <br/> + <%= $journey->{connection}{type} %> <%= $journey->{connection}{line} // $journey->{connection}{no} %> + → <%= $journey->{connection}{to_name} %> + % } + </a></td> + <td> + % if ($journey->{cancelled}) { + Ausfall + % } + % else { + %= sprintf('%+d', $journey->{delay}) + % if ($journey->{connection}) { + <br/> + %= sprintf('Mit Anschluss: %+d?', $journey->{possible_delay}) + % } + % } + </td> + <td> + % my $form_target = sprintf('/journey/passenger_rights/FGR %s %s %s.pdf', $journey->{sched_departure}->ymd, $journey->{type}, $journey->{no}); + %= form_for $form_target => (method => 'POST') => begin + %= csrf_field + %= hidden_field id => $journey->{id} + <button class="btn waves-effect waves-light grey darken-3" type="submit" name="action" value="generate"> + <i class="material-icons">file_download</i> + </button> + %= end + </td> + </tr> + % } + </tbody> + </table> + </div> +</div> |