Booking calendar (beta intern) for calendar bike reservation

This commit is contained in:
ragu 2024-05-07 08:15:54 +02:00
parent 030091de20
commit d5a98d0c54
26 changed files with 1127 additions and 144 deletions

View file

@ -15,6 +15,43 @@ html,body {
text-align: center;
}
/* Style the buttons that are used to open and close the accordion panel */
.accordion {
text-align:left;
padding:0;
background-color: white;
border: none;
cursor: pointer;
text-decoration: none;
outline: none;
transition: 0.4s;
}
.active, .accordion:hover {
color: #b2acac;
}
/* Style the accordion panel. Note: hidden by default */
.panel {
font-weight:normal;
padding:14px 0px 0 4px;
max-height: 0;
transition: max-height 0.5s ease-out;
overflow: hidden;
}
#scroll-top-wrapper a:hover {
color: gray;
}
#scroll-top-wrapper {
visibility:visible;
cursor:pointer;
opacity: 1.0;
text-decoration:underline;
padding: 10px;
}
.tdint {
padding:0.3em 0.5em;
vertical-align: top;

View file

@ -8,10 +8,11 @@ use warnings;
use CGI::Carp qw(fatalsToBrowser);
use CGI ':standard';
use Mod::DBtank;
use Tpl::CalReserv;
use Data::Dumper;
my $dbt = new DBtank;
my $dbt = new DBtank;
my $calres = new CalReserv;
sub new {
my $class = shift;
@ -40,19 +41,11 @@ sub tpl(){
}
my $bgcolor1 = $dbt->{primary}->{$varenv->{dbname}}->{bgcolor1};
if($users_sharee->{c_id} && (!$R::sharee_edit || $R::sharee_edit ne "delete_account2") && ($users_sharee->{c_id} eq $varenv->{superu_id} || $dbt->{copri_conf}->{stage} eq "test" || $users_sharee->{txt08} eq "sigo\@sharee.bike")){
#show it only in testmode
if($users_sharee->{c_id} && $node_meta->{tpl_id} == 302004 && ($users_sharee->{c_id} eq $varenv->{superu_id} || $dbt->{copri_conf}->{stage} eq "test")){
my $coo = $q->cookie('domcookie') || $q->param('sessionid') || "";
#my $api_test = "sharee_fr01"; my $bike="FR1538";
#my $api_test = "sharee_fr01"; my $bike="FR1005";#E-Lastenrad (bike_group=300101, bike_node=300102)
my $api_test = "sharee_fr01"; my $bike="FR4781";#Tracking and BVB test
#my $api_test = "sharee_kn"; my $bike="KN1011";
#my $api_test = "sharee_wue"; my $bike="WUE5525";
#my $api_test = "sharee_sx"; my $bike="S3X1001";
#my $api_test = "sharee_ren"; my $bike="REN2";
my $api_test = "sharee_fr01"; my $bike="FR4781";# test
print $q->div({-style=>'float:right;text-align:right;height:25px;padding:6px 15px;background-color:white'},$q->a({-style=>"background-color:#ffffff;color:#$bgcolor1;", -href=>"$varenv->{metahost}/src/scripts/tests/index.pl?sessionid=$coo\&api_test=$api_test\&bike=$bike\&user_test=$users_sharee->{txt08}", -target=>'_blank'}," [ tests --> $api_test ] "),"$users_sharee->{txt08}",$q->a({-style=>"color:#$bgcolor1;", -href=>"logout_sharee$session"},"logout")),"\n";
}
print "<div class='container'>\n";
@ -60,8 +53,6 @@ sub tpl(){
$self->tplselect($q,$node_meta,$users_dms,$mode,$varenv,$users_sharee,$feedb);
print "</div>\n";
print "</div>\n";
#print "<script src='$varenv->{js_bootstrap}'></script>\n";
}
#2021-05-05 changed to Mlogic
@ -76,30 +67,36 @@ sub tplselect(){
my $feedb = shift || "";
$q->import_names('R');
my $sort = "";
my $lang = "de";
my $tpl_id = $node_meta->{tpl_id};
if($node_meta->{main_id}){
if($tpl_id == 2){
if($node_meta->{tpl_id} == 2){
require "Tpl/Anmelden.pm";
&Anmelden::tpl($node_meta,$users_dms,$mode,$varenv,$users_sharee,$feedb);
}elsif($tpl_id == 302 || $tpl_id == 302008){
}elsif($node_meta->{tpl_id} == 302 || $node_meta->{tpl_id} == 302008){
require "Tpl/FormEdit.pm";
&FormEdit::tpl($node_meta,$users_dms,$mode,$varenv,$users_sharee,$feedb);
}elsif($tpl_id == 302004){
}elsif($node_meta->{tpl_id} == 302004){
require "Tpl/RentalData.pm";
&RentalData::tpl($node_meta,$users_dms,$varenv,$users_sharee,$feedb);
}elsif($tpl_id == 308){
}elsif($node_meta->{tpl_id} == 308){
require "Tpl/PayoneSelect.pm";
&PayoneSelect::tpl($q,$node_meta,$users_dms,$varenv,$users_sharee,$feedb);
}elsif($tpl_id == 197){
}elsif($node_meta->{tpl_id} == 314){
#CalendarReserv CalReserv (ex. MapReserv_v2)
$calres->tpl($q,$node_meta,$users_dms,$varenv,$users_sharee,$feedb);
#}elsif($node_meta->{tpl_id} == 315){
#CalendarBikes CalReserv iframe
#$calres->tpl($q,$node_meta,$users_dms,$varenv,$users_sharee,$feedb);
}elsif($node_meta->{tpl_id} == 197){
require "Tpl/Contact.pm";
&Contact::tpl($node_meta,$users_dms,$mode,$varenv,$users_sharee,$feedb);
}
print "<script src='$varenv->{metahost}/js/rentalator.js' type='text/JAVASCRIPT'></script>";
}
my $debug = "Mlogic --> (users_sharee->{c_id}: $users_sharee->{c_id} | ct_table: $node_meta->{ct_table} | parent_id: $node_meta->{parent_id} | main_id: $node_meta->{main_id} | tpl_id: $node_meta->{tpl_id} | u_id: $users_dms->{u_id} | mode: $mode)";
print $q->div({-style=>'position:fixed;bottom:0%;right:2%;z-index:10;font-size:13px;'},"$debug"),"\n" if($users_sharee->{c_id} eq $varenv->{superu_id});
my $debug = "Mlogic --> (users_sharee->{c_id}: $users_sharee->{c_id} | ct_table: $node_meta->{ct_table} | parent_id: $node_meta->{parent_id} | main_id: $node_meta->{main_id} | tpl_id: $node_meta->{tpl_id})";
print $q->div({-style=>'position:fixed;bottom:0%;right:2%;z-index:10;font-size:13px;'},"$debug"),"\n" if($users_sharee->{c_id} eq $varenv->{superu_id} || $dbt->{copri_conf}->{stage} eq "test");
}

View file

@ -134,12 +134,14 @@ if(1==1){
my $mstyle_1_5="";
my $mstyle_2="";
my $mstyle_3="";
my $mstyle_4="";
if($node_meta->{main_id} == $node1->{$id1}->{main_id}){
$mstyle_1 .= "background-color: #$hgcolor1;" if("$node1->{$id1}->{node_name}" eq "$varenv->{accounting_1}");
$mstyle_1_5 .= "background-color: #$hgcolor1;" if("$node1->{$id1}->{node_name}" eq "$varenv->{accounting_1_5}");
$mstyle_2 .= "background-color: #$hgcolor1;" if("$node1->{$id1}->{node_name}" eq "$varenv->{accounting_2}");
$mstyle_3 .= "background-color: #$hgcolor1;" if("$node1->{$id1}->{node_name}" eq "$varenv->{accounting_3}");
$mstyle_4 .= "background-color: #$hgcolor1;" if("$node1->{$id1}->{node_name}" eq "$varenv->{accounting_4}");
#sharee AGB
if(!$users_sharee->{int14}){
@ -154,6 +156,10 @@ if(1==1){
print $q->li($q->a({-style=>"$mstyle_1_5",-title=>"$varenv->{accounting_1_5}", -href=>"/$viewsel[0]/Account/$varenv->{accounting_1_5}$session"}, $q->img({-src=>"$varenv->{metahost}/img/Account_Zahlungsart.svg"}))),"\n";
print $q->li($q->a({-style=>"$mstyle_2",-title=>"$varenv->{accounting_2}", -href=>"/$viewsel[0]/Account/$varenv->{accounting_2}$session"}, $q->img({-src=>"$varenv->{metahost}/img/Account_Kontoverbindung.svg"}))),"\n";
print $q->li($q->a({-style=>"$mstyle_3",-title=>"$varenv->{accounting_3}", -href=>"/$viewsel[0]/Account/$varenv->{accounting_3}$session"}, $q->img({-src=>"$varenv->{metahost}/img/Account_Verleihdaten.svg"}))),"\n";
#Calendar Reservation beta
if($users_sharee->{c_id} && $dbt->{copri_conf}->{betau_id}->{$users_sharee->{c_id}}){
print $q->li($q->a({-style=>"$mstyle_4",-title=>"$varenv->{accounting_4}", -href=>"/$viewsel[0]/Account/$varenv->{accounting_4}$session"}, $q->span({-class=>"bi bi-calendar3", -style=>"font-size: 2rem;width:3rem;padding-top:0.4rem;"}))),"\n";
}
}
else{
print $q->li($q->a({-style=>"$mstyle_1",-title=>"$varenv->{accounting_1}", -href=>"/$viewsel[0]/Account/$varenv->{accounting_1}$session"}, $q->img({-src=>"$varenv->{metahost}/img/Account_Kundendaten.svg"}))),"\n";

View file

@ -0,0 +1,634 @@
package CalReserv;
#
# SPDX-License-Identifier: AGPL-3.0-or-later
# Copyright (c) Rainer Gümpelein, TeilRad GmbH
#
#Bike calendar-reservation
#
use strict;
use warnings;
use POSIX;
use CGI ':standard';
use Scalar::Util qw(looks_like_number);
use JSON;
use DateTime;
use DateTime::Format::Strptime;
use DateTime::Format::Pg;
use LWP::UserAgent;
use Mod::Basework;
use Mod::DBtank;
use Mod::Buttons;
use Tpl::AccountSubmenu;
use Data::Dumper;
sub new {
my $class = shift;
my $self = {};
bless($self,$class);
return $self;
}
sub tpl {
my $self = shift;
my $q = shift;
my $node_meta = shift;
my $users_dms = shift || "";
my $varenv = shift;
my $users_sharee = shift || "";
my $feedb = shift || "";
my $bw = new Basework;
my $dbt = new DBtank;
my $but = new Buttons;
my $submenu = new AccountSubmenu;
my $path = $q->path_info();
my $dbh = "";
my $red = "#c83434";
my $coo = $q->cookie(-name=>'domcookie') || $R::sessionid;
my $session="";
my $session_and="";
if($R::sessionid && length($R::sessionid) > 20 && !$q->cookie(-name=>'domcookie')){
$session = "?sessionid=$R::sessionid";
$session_and = "&sessionid=$R::sessionid";
}
my $bike = $q->escapeHTML($R::bike) || "";
my $bgcolor1 = "009899";#sharee
$bgcolor1 = $dbt->{website}->{$varenv->{syshost}}->{bgcolor1} if($dbt->{website}->{$varenv->{syshost}}->{bgcolor1});
$bgcolor1 = $dbt->{merchant_ids}->{$varenv->{merchant_id}}->{bgcolor1} if($dbt->{merchant_ids}->{$varenv->{merchant_id}}->{bgcolor1});
my $initMap = "48.741246, 11.210390";
my $map_zoom = 7;
my $project = "all";
my $uri_server = $dbt->{primary}->{sharee_primary}->{primaryApp};
my $timestamp = DateTime->now( time_zone => "Europe/Berlin" );
my $dt0 = DateTime->now( time_zone => "Europe/Berlin" );
my $dt1 = DateTime->now( time_zone => "Europe/Berlin" );
my $strp = DateTime::Format::Strptime->new(
pattern => '%Y-%m-%dT%H:%M',
locale => 'de_DE',
time_zone => 'Europe/Berlin',
on_error => 'croak',
);
my $reserv_starttime = $R::reserv_starttime || "";
my $reserv_endtime = $R::reserv_endtime || "";
if($reserv_starttime && $reserv_starttime =~ /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/){
$dt0 = $strp->parse_datetime($reserv_starttime);
$reserv_starttime = $dt0->datetime;
}
if($reserv_endtime && $reserv_endtime =~ /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/){
$dt1 = $strp->parse_datetime($reserv_endtime);
$reserv_endtime = $dt1->datetime;
}
if($dt0 < $timestamp){
$dt0 = $strp->parse_datetime($timestamp);
$reserv_starttime = $dt0->datetime;
$reserv_starttime =~ s/:00$//;
$dt1 = $strp->parse_datetime($timestamp);
$dt1->add( hours => 4);
$reserv_endtime = $dt1->datetime;
$reserv_endtime =~ s/:00$//;
}
if(!$reserv_starttime || $reserv_starttime !~ /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/){
$dt0 = $strp->parse_datetime($timestamp);
$reserv_starttime = $dt0->datetime;
$reserv_starttime =~ s/:00$//;
}
if(!$reserv_endtime || $reserv_endtime !~ /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/){
$dt1 = $strp->parse_datetime($timestamp);
$dt1->add( hours => 3);
$reserv_endtime = $dt1->datetime;
$reserv_endtime =~ s/:00$//;
}
print "<div id='Contentapp'>\n";
#subMenue--------
$submenu->tpl($node_meta,$users_dms,$varenv,$users_sharee,$feedb);
#-----------------
print $q->start_form(-name=>'calreservscreen', -action=>""),"\n";
print $q->hidden(-name=>"sessionid",-override=>1,-value=>"$R::sessionid") if($R::sessionid);
print $q->hidden(-name=>"calreserv",-override=>1,-value=>"1");#to get uri_operator by GBFSout
#Station select by map
my $icon_green = "Open_Green.png";
my $icon_red = "Open_Red.png";
my $icon_blue = "Open_Blue.png";
$initMap =~ s/\s//g;
my ($lat,$lng) = split(/,/,$initMap);
if($R::select_station && $R::select_station =~ /LatLng\((\d+\.\d+),\s(\d+\.\d+)\)/){
$lat = $1;
$lng = $2;
}
print<<EOF
<link rel="stylesheet" href="https://unpkg.com/leaflet\@1.8.0/dist/leaflet.css"
integrity="sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ=="
crossorigin=""/>
<script src="https://unpkg.com/leaflet\@1.8.0/dist/leaflet.js"
integrity="sha512-BB3hKbKWOc9Ez/TAwyWxNXeoV9c1v6FIeYiBieIWkpLjauysF18NzgR1MBNBXf8/KABdlkX68nAhlwcDFLGPCQ=="
crossorigin=""></script>
<style>
#map {
height: 250px;
width: 100%;
}
</style>
EOF
;
print $q->div({-class=>'content_title3',-style=>''}, "$varenv->{cms}->{'iframe-calendar-reserv-intro'}->{txt}"),"\n";
#print $q->div({-style=>'padding:10px 0;'},"<b>Mietrad Reservierung</b>. Radstation in Karte auswählen, Fahrtbeginn und Fahrtende einstellen und verfügbares Mietrad buchen."),"\n";
print $q->div({-id=>"geolocatestate"},""),"\n";
print "<div style='margin:5px 0 15px; 0' id='map'></div>\n";
#print $q->div({-style=>'padding:15px 0;'},$q->b("Mietradstation: "),$q->span({-id=>"station_selected"},"")),"\n";
#with Station select $stations_json
my $list_options = "";
my %gbfs_station = ();
my %selected_station = ();
if(1==1){
my $rest_stations = "request=stations_available&calreserv=1&authcookie=$coo";
my $stations_json = fetchserver_json("",$uri_server,$rest_stations);
eval {
my $response_stations = {};
$response_stations = decode_json($stations_json);
foreach my $station (sort {$response_stations->{shareejson}->{stations}->{$a}->{station} cmp $response_stations->{shareejson}->{stations}->{$b}->{station} } keys (%{ $response_stations->{shareejson}->{stations} })) {
#print Dumper($response_stations->{shareejson}->{stations}->{$station});
$response_stations->{shareejson}->{stations}->{$station}->{gps}->{latitude} =~ s/0$//g;
$response_stations->{shareejson}->{stations}->{$station}->{gps}->{longitude} =~ s/0$//g;
$gbfs_station{$station}{LatLng} = "LatLng($response_stations->{shareejson}->{stations}->{$station}->{gps}->{latitude}, $response_stations->{shareejson}->{stations}->{$station}->{gps}->{longitude})";
$gbfs_station{$station}{name} = Encode::encode('utf-8', Encode::decode('iso-8859-1',$response_stations->{shareejson}->{stations}->{$station}->{description}));
$gbfs_station{$station}{station_id} = $response_stations->{shareejson}->{stations}->{$station}->{station};
if($R::select_station && $R::select_station eq $gbfs_station{$station}{LatLng}){
$selected_station{uri_operator} = $response_stations->{shareejson}->{stations}->{$station}->{uri_operator};
$selected_station{name} = $gbfs_station{$station}{name};
$selected_station{station_id} = $gbfs_station{$station}{station_id};
$list_options .= "<option value='$gbfs_station{$station}{LatLng}' selected>$gbfs_station{$station}{name} | $gbfs_station{$station}{station_id}</option>\n";
}else{
$list_options .= "<option value='$gbfs_station{$station}{LatLng}'>$gbfs_station{$station}{name} | $gbfs_station{$station}{station_id}</option>\n";
}
}
};
if ($@){
$bw->log("Failure, CalendarReserv station_information not valid","","");
warn $@;
}
print $q->label({-for=>'select_station', -class=>'form-label'},"<b>Mietradstation</b>"),"\n";
print "<div class='input-group mb-3'>\n";
#print $q->span({-class=>"input-group-text bi bi-record-circle", -style=>"font-size: 1.5rem;width:3rem;"},""),"\n";
#print $q->input({-id=>'select_station', -name=>'select_station', -type=>'text', -list=>'list-stations', -class=>'form-control', -style=>'max-width:500px;font-weight:bold;', -placeholder=>'Ort oder Stationname', -override=>1},""),"\n";
print "<select id='select_station' name='select_station' class='form-control' style='max-width:500px;' placeholder='Station Auswahl' override>";
print "<datalist id='list-stations'>\n";
print "$list_options\n";
print "</datalist>\n";
print "</select >";
#print $q->input({-type=>'reset',-value=>'Reset'},""),"\n";
print "</div>\n";
}
#end with Station select $stations_json
print "<script src='$varenv->{metahost}/js/rentalator.js' type='text/JAVASCRIPT'></script>";
print<<EOF
<script>
//document.getElementById('select_station').value = 'LatLng(47.976634, 7.825490)';
var map = L.map('map', { scrollWheelZoom: false }).setView([$lat, $lng], $map_zoom);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
var icon_green = L.icon({
iconUrl: '$varenv->{metahost}/img/$icon_green',
iconSize: [37, 37],
iconAnchor: [20, 37],
popupAnchor: [-2, -36]
//shadowUrl: 'marker-shadow.png',
//shadowSize: [68, 95],
//shadowAnchor: [22, 94]
});
var icon_red = L.icon({
iconUrl: '$varenv->{metahost}/img/$icon_red',
iconSize: [37, 37],
iconAnchor: [20, 37],
popupAnchor: [-2, -36]
});
//Only stations with bike_count
Promise.all([
fetch(
"$uri_server/GBFSout?request=stations_available&calreserv=1&authcookie=$coo"
)]).then(async ([response1]) => {
const responseData1 = await response1.json();
const data1 = responseData1.data.stations;
const layerGroup = L.featureGroup().addTo(map);
data1.forEach(({ lat, lon, name, bike_count, uri_operator, station_id: stationId }) => {
console.log('Station: ' + stationId , name, bike_count);
layerGroup.addLayer(
//L.marker([lat, lon], { icon:icon_green }).bindPopup(`<b>Station: \${name} \${stationId} </b><br />\${lat},\${lon}`).on('click', clickedGPS)
L.marker([lat, lon], { icon:icon_green }).bindPopup(`<b>Station</b> \${name} \${stationId}`).on('click', clickedGPS)
);
});
//disabled to setView on current location
//map.fitBounds(layerGroup.getBounds());
});
function clickedGPS(e) {
const select_station = document.querySelector('#select_station');
select_station.value = e.latlng
//station_selected.textContent = 'FR101'
console.log('clickedGPS:' + select_station.value);
}
function onLocationFound(e) {
console.log('onLocationFound:' + e.latlng);
const geolocatestate = document.querySelector('#geolocatestate');
var radius = e.accuracy;
//L.marker(e.latlng).addTo(map).bindPopup("You are within " + radius + " meters from this point").openPopup();
L.circle(e.latlng, radius).addTo(map);
geolocatestate.textContent = 'Stationen in Umgebung';
}
function onLocationError(e) {
alert(e.message);
}
function lastLocation() {
var latlng = L.latLng($lat, $lng);
console.log('lastLocation:' + latlng);
const geolocatestate = document.querySelector('#geolocatestate');
var radius = 5000;
L.marker(latlng, { icon:icon_green }).addTo(map).bindPopup(`<b>Station</b> $selected_station{name} | $selected_station{station_id}`).openPopup();
L.circle(latlng, radius).addTo(map);
geolocatestate.textContent = 'Station nach Auswahl';
}
if("$R::select_station"){
map.on('locationfound', lastLocation);
map.locate({setView: false, maxZoom: 16});
map.setView(L.latLng($lat, $lng), 11);
}else{
map.on('locationfound', onLocationFound);
map.on('locationerror', onLocationError);
map.locate({setView: true, maxZoom: 16});
}
</script>
EOF
;
#end Station select by map
#if(!$bike){
print "<div class='mb-3'>\n";
print $q->label({-for=>'reserv_starttime', -class=>'form-label'},"Fahrtbeginn"),"\n";
print $q->input({-id=>'reserv_starttime', -name=>'reserv_starttime',-type=>'datetime-local', -class=>'form-control', -style=>'max-width:230px;', -value=>"$reserv_starttime", -override=>1},""),"\n";
print $q->label({-for=>'reserv_endtime', -class=>'form-label', -style=>'padding-top:1em;'},"Fahrtende"),"\n";
print $q->input({-id=>'reserv_endtime', -name=>'reserv_endtime',-type=>'datetime-local', -class=>'form-control', -style=>'max-width:230px;', -value=>"$reserv_endtime", override=>1},""),"\n";
print "</div>\n";
#}
if(1==2){
print $q->div({-class=>"accordion bi bi-caret-down"}, "mehr Filter anzeigen"),"\n";
print "<div class='panel'>\n";
print "<div class='form-check' style='float:left;padding-right:15px;'>\n";
my $ecargo_checked = "checked";
$ecargo_checked = "" if($R::sharee_edit && !$R::ecargo);
print "<input class='form-check-input' type='checkbox' name='ecargo' value='1' id='ecargo' $ecargo_checked>\n";
print $q->label({-class=>"form-check-label", -for=>"ecargo",-style=>'padding-top:5px;'},"E-Lastenrad"),"\n";
print "</div>\n";
print "<div class='form-check' style='float:left;padding-right:15px;'>\n";
my $cargo_checked = "checked";
$cargo_checked = "" if($R::sharee_edit && !$R::cargo);
print "<input class='form-check-input' type='checkbox' name='cargo' value='1' id='cargo' $cargo_checked>\n";
print $q->label({-class=>"form-check-label", -for=>"cargo",-style=>'padding-top:5px;'},"Lastenrad"),"\n";
print "</div>\n";
print "<div class='form-check' style='float:left;padding-right:15px;'>\n";
my $city_checked = "checked";
$city_checked = "" if($R::sharee_edit && !$R::city);
print "<input class='form-check-input' type='checkbox' name='city' value='1' id='city' $city_checked>\n";
print $q->label({-class=>"form-check-label", -for=>"city",-style=>'padding-top:5px;'},"Stadtrad"),"\n";
print "</div>\n";
print "</div>\n";
}
if($R::sharee_edit =~ /calendar_bikes_available/ && $bike){
print $q->div({-style=>'margin:1em 0;text-align:center;clear:both;'},"<button type='submit' name='sharee_edit' value='calendar_bikes_available' class='btn btn-primary btn-lg btn-block' style='border:1px solid #$bgcolor1;background-color:#$bgcolor1;'>Fahrtzeit übernehmen</button>"),"\n";
print $q->hidden(-name=>"bike",-override=>1,-value=>"$bike");
}
my $but_search = "Suchen";
$but_search = "Erneut suchen" if($R::sharee_edit =~ /calendar_bikes_available/);
print $q->div({-style=>'margin:1em 0;text-align:center;clear:both;'},"<button type='submit' name='sharee_edit' value='calendar_bikes_available_all' class='btn btn-primary btn-lg btn-block' style='border:1px solid #$bgcolor1;background-color:#$bgcolor1;'>$but_search</button>"),"\n";
print $q->div({-id=>'reserved_bikes'},""),"\n";#not used
#$bikes_json
if($R::sharee_edit =~ /calendar_bikes_available/){
my $rest_bikes = "request=bikes_available&calreserv=1&reserv_starttime=$R::reserv_starttime&reserv_endtime=$R::reserv_endtime&authcookie=$coo&lang=de";
$rest_bikes .= "&station=$selected_station{station_id}" if($selected_station{station_id});
if($R::select_station && $R::select_station =~/LatLng\((\d+\.\d+), (\d+\.\d+)\)/){
my $Lat = $1;
my $Lng = $2;
$rest_bikes .= "&Lat=$Lat&Lng=$Lng";
$uri_server = $selected_station{uri_operator} if($selected_station{uri_operator});
}
my $list_title = "Mieträder an Station:";
if($R::sharee_edit ne "calendar_bikes_available_all" && $bike){
$list_title = "Mietrad an Station:";
$rest_bikes .= "&bike=$bike";
}
my $bikes_json = fetchserver_json("",$uri_server,$rest_bikes);
eval {
my $response_bikes = {};
$response_bikes = decode_json($bikes_json);
#bikes available
print $q->div({-class=>'content_title2',-style=>''},"$list_title $selected_station{name} | $selected_station{station_id}"),"\n" if(1 == 1);
foreach my $bike (sort {$response_bikes->{shareejson}->{bikes}->{$a}->{bike} cmp $response_bikes->{shareejson}->{bikes}->{$b}->{bike} } keys (%{ $response_bikes->{shareejson}->{bikes} })) {
#print "<div style='border:1px solid #$bgcolor1;margin:1em 0;max-width:550px;'>\n";
print $q->div({-style=>'padding:0.1em 0;margin:0.5em 0;background-color:#b6b6b6;'},""),"\n";
my $bike_image = "bike_Cargo_SoleHumanPowered_Two.png";
$bike_image = "bike_Cargo_SoleHumanPowered_Trike.png" if($response_bikes->{shareejson}->{bikes}->{$bike}->{bike_type}->{category} eq "cargo" && $response_bikes->{shareejson}->{bikes}->{$bike}->{bike_type}->{wheels} eq "3");
$bike_image = "bike_Cargo_Pedelec_Two.png" if($response_bikes->{shareejson}->{bikes}->{$bike}->{bike_type}->{category} eq "cargo" && $response_bikes->{shareejson}->{bikes}->{$bike}->{bike_type}->{engine});
$bike_image = "bike_City_SoleHumanPowered_Two.png" if($response_bikes->{shareejson}->{bikes}->{$bike}->{bike_type}->{category} eq "city");
print $q->div({-style=>'padding:0.5em;float:left;'},$q->img({-style=>'width:100px;', -src=>"$varenv->{metahost}/img/$bike_image"})),"\n";
print $q->div({-style=>'padding:0.5em;'},$q->span({-style=>'font-weight:bold;'},"$response_bikes->{shareejson}->{bikes}->{$bike}->{description} "),"$response_bikes->{shareejson}->{bikes}->{$bike}->{bike}"),"\n";
my $dts = $strp->parse_datetime($reserv_starttime);
my $start_loc = $dts->strftime("%d.%m.%Y %H:%M");
my $dte = $strp->parse_datetime($reserv_endtime);
my $end_loc = $dte->strftime("%d.%m.%Y %H:%M");
print $q->div({-style=>''},"Fahrtbeginn: $start_loc"),"\n";
print $q->div({-style=>''},"Fahrtende: $end_loc"),"\n";
print $q->div({-id=>"return_state_$bike",-style=>'color:green;'},""),"\n";
#collect timerange
my $set_starttime = "";
my $set_endtime = "";
my $j = 0;
my $dt2 = DateTime->now(time_zone => "Europe/Berlin");
my $dt3 = DateTime->now(time_zone => "Europe/Berlin");
my $dtnow = $strp->parse_datetime($timestamp);
$dtnow->add( minutes => 1);
$set_starttime = $dtnow->datetime;
my %blockedhash = ();
my %reservedhash = ();
my $sb = 100;#start blockedhash index . 1
my $eb = 100;#end blockedhash index . 2
my $sr = 100;#start reservedhash index . 1
my $er = 100;#end reservedhash index . 2
$blockedhash{$sb . '1'} = $set_starttime;
foreach my $rid (sort {$response_bikes->{shareejson}->{bikes}->{$bike}->{blocked}->{$a}->{start_time} cmp $response_bikes->{shareejson}->{bikes}->{$bike}->{blocked}->{$b}->{start_time} } keys (%{ $response_bikes->{shareejson}->{bikes}->{$bike}->{blocked} })) {
$j++;
$dt2 = DateTime::Format::Pg->parse_datetime($response_bikes->{shareejson}->{bikes}->{$bike}->{blocked}->{$rid}->{start_time});
$sr++;
$er++;
if($j==1){
$dt3 = DateTime::Format::Pg->parse_datetime($response_bikes->{shareejson}->{bikes}->{$bike}->{blocked}->{$rid}->{end_time});
}
if($j==1 && $dtnow < $dt3){
$set_endtime = $dt2->datetime;
$reservedhash{$sr . '1'} = $set_endtime;#reserv start_time
$reservedhash{$er . '2'} = $set_starttime;#reserv end_time
$dt3->add( minutes => 15);
$set_starttime = $dt3->datetime;
$blockedhash{$sb . '1'} = $set_starttime;
}else{
my $dt0 = DateTime::Format::Pg->parse_datetime($response_bikes->{shareejson}->{bikes}->{$bike}->{blocked}->{$rid}->{start_time});
my $dtend = $strp->parse_datetime($dt0);
$set_endtime = $dtend->datetime;
$reservedhash{$sr . '1'} = $set_endtime;#reserv start_time
$blockedhash{$eb . '2'} = $set_endtime;#blocked end_time
my $dt1 = DateTime::Format::Pg->parse_datetime($response_bikes->{shareejson}->{bikes}->{$bike}->{blocked}->{$rid}->{end_time});
my $dtstart = $strp->parse_datetime($dt1);
$set_starttime = $dtstart->datetime;
$reservedhash{$er . '2'} = $set_starttime;#reserv end_time
$sb++;
$eb++;
$dt1->add( minutes => 15);
$dtstart = $strp->parse_datetime($dt1);
$set_starttime = $dtstart->datetime;
$blockedhash{$sb . '1'} = $set_starttime;#blocked start_time
}
}
$dtnow->add( weeks => 4);
$set_endtime = $dtnow->datetime;
$blockedhash{$eb . '2'} = $set_endtime;
#print Dumper(\%reservedhash) . "<br />\n";
#print Dumper(\%blockedhash) . "<br />\n";
#end collect timerange
#view red flag if bike not available on selected rental timerange
my $reservindex = 0;
my $se = 0;
my $reservbut = 0;
foreach my $ri (sort keys %reservedhash){
if($ri =~ /(\d{3})(\d{1})/){
$reservindex = $1;
$se = $2;
}
if($ri =~ /^$reservindex/ && $se == 1){
my $dtx = $strp->parse_datetime($reservedhash{$ri});
my $end_ri = $ri + 1;
my $dty = $strp->parse_datetime($reservedhash{$end_ri});
if($dty >= $dt0 && $dty <= $dt1 && $dtx <= $dt1){
$reservbut = 1;
#print $q->div({-style=>'color:red;'},"Im gewähltem Zeitfenster nicht verfügbar"),"\n";
#print "$ri Von: $reservedhash{$ri}<br />\n";
#print "$end_ri Bis: $reservedhash{$end_ri}<br />\n";
}
}
}
#delete blockedhash with too small ranges
my $rangeindex = 0;
my $se = 0;
foreach my $ri (sort keys %blockedhash){
if($ri =~ /(\d{3})(\d{1})/){
$rangeindex = $1;
$se = $2;
}
if($ri =~ /^$rangeindex/ && $se == 1){
my $dtx = $strp->parse_datetime($blockedhash{$ri});
my $end_ri = $ri + 1;
my $dty = $strp->parse_datetime($blockedhash{$end_ri});
if($dty <= $dtx){
delete $blockedhash{$ri};
delete $blockedhash{$end_ri};
}
}
}
my $availability = "";
my $href = "";
#build availability links
foreach my $ri (sort keys %blockedhash){
if($ri =~ /(\d{3})(\d{1})/){
$rangeindex = $1;
$se = $2;
}
if($ri =~ /^$rangeindex/ && $se == 1){
$href = "/app/Account/CalendarReserv?sharee_edit=calendar_bikes_available&select_station=$R::select_station&bike=$bike&calreserv=1&authcookie=$coo&lang=de";
#print "$ri Von: $blockedhash{$ri}<br />\n";
my $dtx = $strp->parse_datetime($blockedhash{$ri});
my $start_loc = $dtx->strftime("%d.%m.%Y %H:%M");
$href .= "&reserv_starttime=$blockedhash{$ri}";
$availability .= "<div style='padding:20px 0;'>Von: $start_loc</div>\n";
}
if($ri =~ /^$rangeindex/ && $se == 2){
#print "$ri Bis: $blockedhash{$ri}<br />---<br />\n";
my $dty = $strp->parse_datetime($blockedhash{$ri});
my $end_loc = $dty->strftime("%d.%m.%Y %H:%M");
$href .= "&reserv_endtime=$blockedhash{$ri}";
$availability .= "<div style='padding:20px 0;'><a href='$href'>Zeitfenster übernehmen</a></div>\n
<div style='padding:20px 0;'>Bis: $end_loc</div>\n
<div style='padding:20px 0;border-bottom:1px solid silver;'></div>\n";
}
}
print <<EOF
<!-- Modal -->
<div class="modal fade" id="$bike" tabindex="-1" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Verfügbarkeit: $response_bikes->{shareejson}->{bikes}->{$bike}->{description} $response_bikes->{shareejson}->{bikes}->{$bike}->{bike}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="text-default">$availability</div>
</div>
</div>
</div>
</div>
EOF
;
if($reservbut){
print $q->div({-style=>'color:red;'},"Im gewähltem Zeitfenster nicht verfügbar"),"\n";
}else{
#Mietrad buchen
print $q->div({-id=>"button_reserv_$bike",-style=>'clear:both;text-align:center;display:block;'},"<span class='btn btn-primary' style='border:1px solid #$bgcolor1;background-color:#$bgcolor1;margin:0.5em;width:300px;' onclick='rental_request(\"$response_bikes->{shareejson}->{bikes}->{$bike}->{uri_operator}/APIjsonserver?request=booking_request&bike=$response_bikes->{shareejson}->{bikes}->{$bike}->{bike}&calreserv=1&reserv_starttime=$reserv_starttime&reserv_endtime=$reserv_endtime&authcookie=$coo\",\"$bike\",\"\")'>Mietrad buchen</span>"),"\n";
#Buchung stornieren
print $q->div({-id=>"button_cancel_$bike",-style=>'clear:both;text-align:center;display:none;'},"<span class='btn btn-outline-primary' style='border:1px solid #$bgcolor1;color:#$bgcolor1;margin:0.5em;width:300px;' onclick='rental_request(\"$response_bikes->{shareejson}->{bikes}->{$bike}->{uri_operator}/APIjsonserver?request=booking_update&bike=$response_bikes->{shareejson}->{bikes}->{$bike}->{bike}&state=canceled&reserv_starttime=$reserv_starttime&reserv_endtime=$reserv_endtime&authcookie=$coo\",\"$bike\",\"\")'>Buchung stornieren</span>"),"\n";
}
#Weitere Verfügbarkeit anzeigen
print $q->div({-id=>"button_availablbility_$bike",-style=>'clear:both;text-align:center;display:block;'},"<span class='btn btn-outline-primary' style='border:1px solid #$bgcolor1;color:#$bgcolor1;margin:0.5em;width:300px;' data-bs-toggle='modal' data-bs-target='#$bike'>Weitere Verfügbarkeit anzeigen</span>"),"\n";
#print Dumper($response_bikes->{shareejson}->{bikes}->{$bike}->{rental_description}->{tarif_elements});
foreach my $ele (%{ $response_bikes->{shareejson}->{bikes}->{$bike}->{rental_description}->{tarif_elements} }){
if($response_bikes->{shareejson}->{bikes}->{$bike}->{rental_description}->{tarif_elements}->{$ele}[0] && $response_bikes->{shareejson}->{bikes}->{$bike}->{rental_description}->{tarif_elements}->{$ele}[1]){
print $q->div({-style=>'padding:0.2em 0.5em;'},"$response_bikes->{shareejson}->{bikes}->{$bike}->{rental_description}->{tarif_elements}->{$ele}[0] : $response_bikes->{shareejson}->{bikes}->{$bike}->{rental_description}->{tarif_elements}->{$ele}[1]"),"\n";
}
}
#print "</div>\n";
}
#bikes_occupied
print $q->div({-style=>'padding:0.1em 0;margin:0.5em 0;background-color:#b6b6b6;'},""),"\n";
my $i = 0;
foreach my $rid (sort {$response_bikes->{shareejson}->{bikes_occupied}->{$a}->{start_time} cmp $response_bikes->{shareejson}->{bikes_occupied}->{$b}->{start_time} } keys (%{ $response_bikes->{shareejson}->{bikes_occupied} })) {
my $reserv_starttime = DateTime::Format::Pg->parse_datetime($response_bikes->{shareejson}->{bikes_occupied}->{$rid}->{start_time});
my $reserv_endtime = DateTime::Format::Pg->parse_datetime($response_bikes->{shareejson}->{bikes_occupied}->{$rid}->{end_time});
my $start_loc = $reserv_starttime->strftime("%d.%m.%Y %H:%M");
my $end_loc = $reserv_endtime->strftime("%d.%m.%Y %H:%M");
$i++;
my $oprefix = "";
$oprefix = $1 if($response_bikes->{shareejson}->{bikes_occupied}->{$rid}->{station} =~ /([A-Z]+)/i);
my $bike = $response_bikes->{shareejson}->{bikes_occupied}->{$rid}->{bike};
print $q->div({-style=>'padding:1em 0.5em;font-weight:bold;'},"Deine $oprefix Buchungen:"),"\n" if($i == 1);
#selector by $rid pos_id
print $q->div({-id=>"return_state_$rid"},""),"\n";
print $q->div({-id=>"button_cancel_$rid", -style=>'padding:0.2em 0.5em;color:green;display:block;'},"<span class='btn btn-outline-primary btn-sm' style='border:1px solid #$bgcolor1;color:#$bgcolor1;' onclick='rental_request(\"$response_bikes->{shareejson}->{bikes_occupied}->{$rid}->{uri_operator}/APIjsonserver?request=booking_update&bike=$bike&pos_id=$rid&state=canceled&authcookie=$coo\",\"\",\"$rid\")'>Buchung stornieren</span> $start_loc - $end_loc: $response_bikes->{shareejson}->{bikes_occupied}->{$rid}->{description} $bike an Station $response_bikes->{shareejson}->{bikes_occupied}->{$rid}->{station}"),"\n";
print $q->div({-id=>"button_reserv_$rid",-style=>'color:red;'},""),"\n";#dummy
}
};
if ($@){
$bw->log("Failure, CalendarReserv bike_json not valid","","");
warn $@;
}
}#end $bikes_json
print $q->end_form,"\n";
print $q->div({-id=>'scroll-top-wrapper'},"nach oben"),"\n" if($R::sharee_edit =~ /calendar_bikes_available/);
print $q->div({-style=>'position:fixed;bottom:2%;right:2%;z-index:10;font-size:13px;'},"--> $varenv->{syshost} | $varenv->{merchant_id} | $bgcolor1 | template -> $node_meta->{tpl_name},$node_meta->{tpl_id}"),"\n" if($users_sharee->{c_id} eq $dbt->{copri_conf}->{superu_id} || $dbt->{copri_conf}->{stage} eq "test");
print "</div>\n";
}
#requestor
sub fetchserver_json {
my $self = shift;
my $uri_server = shift || "";
my $rest = shift || "";
my $server_request = "$uri_server/APIjsonserver?$rest";
my $ua = LWP::UserAgent->new;
$ua->agent("sharee CalReserv");
my $req = HTTP::Request->new(GET => "$server_request");
$req->content_type('application/x-www-form-urlencoded');
$req->content($rest);
#Pass request to the user agent and get a response back
my $res = $ua->request($req);
#SSL certificate must be valid
#print Dumper($res);
# Check the outcome of the response
if ($res->is_success) {
#print $res->content;
return $res->content;
#print $res->status_line, "\n";
}else {
return "";
#print $res->status_line, "\n";
}
}
1;

View file

@ -335,7 +335,7 @@ EOF
print $q->div("&nbsp");
foreach my $opid (keys(%$ctadrcoupon)){
if($ctadrcoupon->{$opid}->{txt15}){
print $q->div("$bonus_saved $ctadrcoupon->{$opid}->{oprefix}-$ctadrcoupon->{$opid}->{txt15}"),"\n";
print $q->div("$bonus_saved $ctadrcoupon->{$opid}->{oprefix} $ctadrcoupon->{$opid}->{txt15}"),"\n";
}
}