package APIfunc; # # SPDX-License-Identifier: AGPL-3.0-or-later # Copyright (c) Rainer Gümpelein, TeilRad GmbH # #Server methods for sharee API # #perl -cw #use lib qw(/var/www/copri-bike/shareeapp-operator/src); # use strict; use warnings; use POSIX; use CGI; # only for debugging use JSON; use Digest::MD5 qw(md5 md5_hex); use Digest::SHA qw(sha256_base64); use Scalar::Util qw(looks_like_number); use DateTime; use DateTime::Format::Pg; use URI::Encode; use Config::General; use Lib::Config; use Mod::Libenz; use Mod::DBtank; use Mod::Callib; use Mod::Basework; use Mod::Pricing; #use Mod::APIsigclient;#no! use Data::Dumper; use Sys::Hostname; my $json = JSON->new->allow_nonref; my $cf = new Config; my $lb = new Libenz; my $dbt = new DBtank; my $cal = new Callib; my $bw = new Basework; my $pri = new Pricing; #my $si = new APIsigclient; sub new { my $class = shift; my $self = {}; bless($self,$class); return $self; } my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; my $now_date = strftime "%Y-%m-%d", localtime; my $lang="de"; my $owner=188;#via API my $dbh = ""; #fetch merchant_id by request or hostname sub fetch_merchant { my $self = shift; my $q = shift; my $varenv = shift; my $req_coo = shift || ""; my $req_merchant_id = shift || ""; my $return = { aowner => "", merchant_id => "", project_id => "" }; my $merchanized = 0; my $aowner = 0; while ((my $merchant_conf, my $value) = each %{ $dbt->{merchant_ids}}) { if($merchant_conf && (($req_coo && $req_coo =~ /$merchant_conf$/) || ($req_merchant_id && $req_merchant_id eq $merchant_conf))){ $merchanized = 1; $aowner = $value->{id}; $return->{aowner} = $value->{id}; $return->{merchant_id} = $merchant_conf; $return->{project_id} = $value->{project}; my $lat = ""; my $lng = ""; if($value->{initMap}){ $value->{initMap} =~ s/\s//g; ($lat,$lng) = split(/,/,$value->{initMap}) if($value->{initMap} && $value->{initMap} =~ /\d+,\d+/); } if($lat && $lng){ $return->{init_map}->{center}->{latitude} = $lat; $return->{init_map}->{center}->{longitude} = $lng; $return->{init_map}->{radius} = "2.9"; } #$bw->log("===> merchant select by $return->{project_id} session-cookie OR authcookie OR merchant_id: if($merchant_conf && (($req_coo && $req_coo =~ /$merchant_conf/) || ($req_merchant_id && $req_merchant_id eq $merchant_conf))){",$return->{merchant_id},""); #last; } } if(!$merchanized){ if($varenv->{syshost} eq "shareeapp-primary" || $varenv->{syshost} eq "shareedms-primary"){ $aowner = $dbt->{primary}->{sharee_primary}->{owner}; $return->{aowner} = $dbt->{primary}->{sharee_primary}->{owner}; $return->{merchant_id} = $dbt->{primary}->{sharee_primary}->{merchant_id}; $return->{project_id} = $dbt->{primary}->{sharee_primary}->{project}; $merchanized = 1; #$bw->log("===> merchant select by $return->{project_id} primary dbname: sharee_primary:",$return->{merchant_id},""); } elsif($varenv->{syshost} =~ /shareeapp-(\w+)/ || $varenv->{syshost} =~ /shareedms-(\w+)/){ $aowner = $dbt->{operator}->{$varenv->{dbname}}->{owner}; $return->{aowner} = $dbt->{operator}->{$varenv->{dbname}}->{owner}; $return->{merchant_id} = $dbt->{operator}->{$varenv->{dbname}}->{merchant_id}; $return->{project_id} = $dbt->{operator}->{$varenv->{dbname}}->{project}; $merchanized = 1; #$bw->log("===> merchant select by $return->{project_id} operator dbname=$varenv->{dbname}:",$return->{merchant_id},""); } elsif($varenv->{syshost} =~ /shareeweb-/){ $aowner = $dbt->{website}->{$varenv->{syshost}}->{owner}; $return->{aowner} = $dbt->{website}->{$varenv->{syshost}}->{owner}; $return->{merchant_id} = $dbt->{website}->{$varenv->{syshost}}->{merchant_id}; $return->{project_id} = $dbt->{website}->{$varenv->{syshost}}->{project}; $merchanized = 1; #$bw->log("===> merchant select by $return->{project_id} website syshost=$varenv->{syshost}:",$return->{merchant_id},""); } } return ($aowner,$return); } #helper to get template sub get_node_meta { my $self = shift; my $viewsel = shift; my $ndesc = $dbt->get_node_meta($dbh,$viewsel); return $ndesc; } #helper to get node sub get_node { my $self = shift; my $main_id = shift; my $ndesc = $dbt->get_node($dbh,$main_id); return $ndesc; } #helper to get DMS users (used by servicetool) sub select_dmsusers { my $self = shift; my $u_id = shift || 0; my $sqlcon = shift || ""; my $users = $dbt->select_users($dbh,$u_id,$sqlcon); return $users; } #node_select sub template_select(){ my $self = shift; my $node = shift; my $return={}; #category means node.main_id. #template_id from contentpos.template_id #finally get tpl_order of contentpos if(ref($node) eq "HASH"){ my $node_record = $dbt->fetch_rel4tpl4nd($dbh,$node); my @tpl_order = split /,/,$node_record->{tpl_order}; foreach (@tpl_order){ my ($key,$val,$size,$interval) = split /=/,$_; $return->{$key} = ["$val","$size","$interval"]; } return ($return,$node_record); }else{ return "Failure 4003: category OR template must be defined as integer"; } }#end node_select #Search one by key sub service_work_search(){ my $self = shift; my $bike = shift || ""; my $station = shift || ""; my $history = shift || 0; my $search = shift || ""; my $bike_id = $1 if($bike =~ /(\d+)/); my $station_id = $1 if($station =~ /(\d+)/); my $dt1 = DateTime->now; my $return={}; my $pref = { table => "content", table_pos => "contentpos", fetch => "one", catch => "content_contentpos", keyfield => "c_id", }; if(looks_like_number($bike_id)){ $pref->{barcode} = "=::" . $bike_id; } if(looks_like_number($station_id)){ $pref->{int04} = "=::" . $station_id; } $pref = { %$pref, mtime => ">=::(now() - interval '$history day')" } if($history > 0); $pref = { %$pref, $search->{key} => "ilike::$search->{val}" } if(ref($search) eq "HASH" && $search->{key}); my $pos_record = $dbt->collect_post($dbh,$pref); return $pos_record; } #service_select by service_id=service-c_id sub service_select { my $self = shift; my $q = shift; my $auth = shift; my $service_id = shift || ""; my $interval = shift || ""; my $pos_record = {}; my $return = {}; my $bike = ""; my $station = ""; $bike = $1 if($q->param('bike') =~ /(\d+)/); $station = $1 if($q->param('station') =~ /(\d+)/); my $cpref = {}; my $c_table = "content"; my $pos_table = "contentpos"; my $template_id_pos = ""; #all this just get the right pos template_id if($q->param('request') eq "service_done" || $q->param('request') eq "service_work" || $q->param('request') eq "bikes_all"){ if(looks_like_number($bike)){ $cpref = { table => "$c_table", fetch => "one", template_id => "205", barcode => "=::" . $q->escapeHTML($bike), }; } if(looks_like_number($station)){ $cpref = { table => "$c_table", fetch => "one", template_id => "225", int04 => "=::" . $q->escapeHTML($station), }; } if($q->param('request') eq "bikes_all"){ $cpref = { table => "$c_table", fetch => "one", template_id => "205", }; } if($q->param('request') eq "bikes_all" && looks_like_number($station)){ $cpref = { table => "$c_table", fetch => "one", template_id => "205", }; } } elsif($q->param('request') eq "user_feedback"){ $c_table = "contentadr"; $pos_table = "contentadrpos"; $template_id_pos = 601;#feedback template_id $cpref = { table => "$c_table", fetch => "one", template_id => "202", c_id => "$auth->{c_id}", }; } elsif($q->param('request') eq "user_minianswer"){ $c_table = "contentadr"; $pos_table = "contentadrpos"; $template_id_pos = 602;#miniquery answer template_id $cpref = { table => "$c_table", fetch => "one", template_id => "202", c_id => "$auth->{c_id}", }; } #get real pos.template_id by parent_id=$crecord->{main_id} my $crecord = $dbt->fetch_record($dbh,$cpref); #will be only done if article (bike or station) exists in DB if(ref($crecord) eq "HASH" && $crecord->{c_id} && $crecord->{main_id}){ my $subrelnode = $dbt->get_subrelnode($dbh,$crecord->{main_id},$template_id_pos); #get service template to return template formated contentpos my ($tpl_order,$node_template) = $self->template_select($subrelnode); my @tpl_order = split /,/,$node_template->{tpl_order}; #only used by serviceapp if($q->param('request') ne "user_feedback" && $q->param('request') ne "user_minianswer"){ my $pref = { table => "$c_table", table_pos => "$pos_table", fetch => "all", catch => "content_contentpos", keyfield => "c_id", }; #Because of different contentpos.template_id in Flot Service we use it only on all others else bikes_all requests if($q->param('request') ne "bikes_all"){ $pref->{template_id} = "$node_template->{template_id}"; } if(looks_like_number($q->param('service_id')) && $q->param('request') ne "service_done"){ $pref->{c_id} = "=::" . $q->escapeHTML($q->param('service_id')); }elsif(looks_like_number($service_id) && $q->param('request') ne "service_done"){ $pref->{c_id} = "=::" . $service_id; }elsif(looks_like_number($bike)){ $pref->{barcode} = "=::" . $q->escapeHTML($bike); }elsif(looks_like_number($station)){ $pref->{int04} = "=::" . $q->escapeHTML($station); } if($cal->checkdate_time($q->param('timestamp'))){ $pref->{mtime} = "<=::" . $q->escapeHTML($q->param('timestamp')); } if(looks_like_number($interval) && $interval > 0){ if($interval == 30){ #get timestamp from 10. Aufgaben $pref->{txt01} = "cp.txt01 like '%' and cp.txt01 != 'NaN'"; $bw->log("service_select collect_post to get timestamp of tenth Aufgabe",$pref,""); my $pos_record10 = $dbt->collect_post($dbh,$pref,"10"); foreach my $id (sort { $pos_record10->{$b}->{c_id} <=> $pos_record10->{$a}->{c_id} } keys (%$pos_record10)){ $pref->{mtime} = ">=::$pos_record10->{$id}->{mtime}"; } delete $pref->{txt01}; }else{ $pref->{mtime} = ">=::(now() - interval '$interval day')"; } #if service saved by servicetool fetch user saved services <= 1day if($q->param('request') eq "service_done"){ $pref->{owner} = $auth->{c_id}; } } $bw->log("service_select collect_post with interval $interval",$pref,""); $pos_record = $dbt->collect_post($dbh,$pref); my $pos_count = 0; foreach my $id (sort { $pos_record->{$a}->{barcode} <=> $pos_record->{$b}->{barcode} } keys (%$pos_record)){ foreach (@tpl_order){ my ($key,$val,$size,$interval) = split /=/,$_; $pos_count++ if($key =~ /mtime/ && $pos_record->{$id}->{$key}); $return->{$id}->{$key} = $pos_record->{$id}->{$key} || ""; } } #only used on service init if($pos_table eq "contentpos" && !$pos_count){ foreach (@tpl_order){ my ($key,$val,$size,$interval) = split /=/,$_; if($key eq "txt01"){ $return->{1}->{$key} = "::erledigt::"; $pos_record->{1}->{$key} = "::erledigt::"; }else{ $return->{1}->{$key} = "1"; $pos_record->{1}->{$key} = "1"; } } $return->{1}->{barcode} = "$bike"; $return->{1}->{cc_id} = "$crecord->{c_id}"; $return->{1}->{mtime} = "$crecord->{mtime}"; $return->{1}->{owner} = "$crecord->{owner}"; $return->{1}->{template_id} = "$node_template->{template_id}"; $pos_record->{1}->{barcode} = $bike; $pos_record->{1}->{cc_id} = $crecord->{c_id}; $pos_record->{1}->{mtime} = $crecord->{mtime}; $pos_record->{1}->{owner} = $crecord->{owner}; $pos_record->{1}->{template_id} = $node_template->{template_id}; } $bw->log("service_select with node_template: $node_template->{template_id} and pos_record:","",""); } return ($return,$pos_record,$node_template,$crecord); }#end if($crecord) else{ return ("","","",""); } }#end service_select #service_insert sub service_insert(){ my $self = shift; my $q = shift; my $auth = shift; my $node_template = shift || ""; my $crecord = shift || {}; my $owner = shift || 0; my $return={}; #insert pos with cc_id my $c_id = 0; if($q->param('request') eq "service_done" && ref($crecord) eq "HASH" && $crecord->{c_id} > 0){ my $insert = { table => "contentpos", cc_id => $crecord->{c_id}, barcode => $crecord->{barcode}, int04 => $crecord->{int04}, owner => $auth->{c_id}, template_id => $node_template->{template_id}, mtime => "now()", }; $c_id = $dbt->insert_contentoid($dbh,$insert,""); } if($q->param('request') eq "user_feedback" && ref($crecord) eq "HASH" && $crecord->{c_id} > 0){ my $bike_id = ""; my $insert = { table => "contentadrpos", ca_id => $crecord->{c_id}, txt01 => $auth->{txt01}, txt08 => $auth->{txt08}, owner => $owner, template_id => $node_template->{template_id}, mtime => "now()", }; if($q->param('bike') =~ /(\d+)/){ my $bike = $q->escapeHTML($q->param('bike')); my $bike_id = $bike; $bike_id =~ s/S[1-9]X/SX/; $bike_id = $1 if($bike_id =~ /(\d+)/); $insert->{barcode} = $bike_id; $c_id = $dbt->insert_contentoid($dbh,$insert,""); #if bike_broken then also to contentpos if(!$q->param('bike_broken')){ my $cpref = { table => "content", fetch => "one", template_id => "205", barcode => "$bike_id", }; my $crecord_content = $dbt->fetch_record($dbh,$cpref); if(ref($crecord_content) eq "HASH" && $crecord_content->{c_id} && $crecord_content->{main_id}){ my $subrelnode = $dbt->get_subrelnode($dbh,$crecord_content->{main_id},""); my ($tpl_order,$node_template_contentpos) = $self->template_select($subrelnode); my $insert_contentpos = { table => "contentpos", cc_id => $crecord_content->{c_id}, #int03 => $c_id, #yes, c_id from contentadrpos to make backlink barcode => $crecord_content->{barcode}, int04 => $crecord_content->{int04}, owner => $owner, template_id => $node_template_contentpos->{template_id}, mtime => "now()", }; #$update->{int01} = 1 if($q->param('bike_broken'));#TODO. what should else be done if bike_broken $insert_contentpos->{txt01} = $q->escapeHTML($q->param('message')) if($q->param('message')); my $c_id_contentpos = $dbt->insert_contentoid($dbh,$insert_contentpos,""); } } } } if($q->param('request') eq "user_minianswer" && ref($crecord) eq "HASH" && $crecord->{c_id} > 0){ my $insert = { table => "contentadrpos", #ca_id => $crecord->{c_id},#have to be anonym owner => $owner, template_id => $node_template->{template_id}, mtime => "now()", }; $c_id = $dbt->insert_contentoid($dbh,$insert,""); } return $c_id; }#end service_insert #service_update sub service_update(){ my $self = shift; my $q = shift; my $auth = shift; my $node_template = shift; my $c_id = shift || ""; my $action = shift || ""; my $return={}; my $update = {}; my $bike = $q->escapeHTML($q->param('bike')) || ""; my $bike_id = $bike; $bike_id =~ s/S[1-9]X/SX/; $bike_id = $1 if($bike_id =~ /(\d+)/); my $pref = { table => "contenttrans", table_pos => "contenttranspos", fetch => "one", template_id => "218",#Mietjournal tpl_id barcode => $bike_id, ca_id => "$auth->{c_id}", "ct.close_time" => "is::null", int10 => "1", end_time => ">=::(now() - interval '5 min')", }; my $ctpos = { c_id => 0 }; if($q->param('request') eq "service_done"){ $c_id = $q->param('service_id') if($q->param('service_id')); $update = { table => "contentpos", owner => $auth->{c_id}, mtime => "now()", }; }elsif($q->param('request') eq "user_feedback"){ $update = { table => "contentadrpos", mtime => "now()", int01 => 0, }; $update->{int01} = 1 if($q->param('bike_broken')); $update->{txt02} = $q->escapeHTML($q->param('message')) if($q->param('message')); $ctpos = $dbt->collect_post($dbh,$pref) if($bike_id); if($ctpos->{c_id} > 0){ my $update_pos = { table => "contenttranspos", mtime => "now()", int27 => 1,#ok marker for rental end ack }; #update sig int28 counter $update_pos->{int28} = 2 if($ctpos->{int28} && $ctpos->{int28} == 3); #update bike charge on pos and content if(looks_like_number($q->param('charge_current_bars'))){ my $max_bars = 5; my $current_percent = $bw->battery_percent($max_bars,$q->param('charge_current_bars')); $update_pos->{int19} = $current_percent; #NO, because of service_work should also be deleted if > 50% #$self->service_automatic($q,$current_percent) if($current_percent <= 50); #update also bike charge my $update_bike = { table => "content", mtime => "now()", int19 => "$update_pos->{int19}", }; my $record_bike = { c_id => 0 }; $record_bike->{c_id} = $ctpos->{cc_id} if($ctpos->{cc_id}); $dbt->update_record($dbh,$update_bike,$record_bike) if($record_bike->{c_id} > 0); } $dbt->update_record($dbh,$update_pos,$ctpos); } }elsif($q->param('request') eq "user_minianswer"){ $update = { table => "contentadrpos", mtime => "now()", }; $update->{txt01} = $q->escapeHTML($q->param('q1')) if($q->param('q1')); $update->{txt02} = $q->escapeHTML($q->param('q2')) if($q->param('q2')); $update->{txt03} = $q->escapeHTML($q->param('q3')) if($q->param('q3')); #just a assumption my $last_used_operator = $auth->{txt19}; if($last_used_operator){ my $dbh_operator = $dbt->dbconnect_extern("$last_used_operator"); my $postref = { table => "contenttrans", table_pos => "contenttranspos", fetch => "one", ca_id => "$auth->{c_id}", end_time => ">=::(now() - interval '5 min')", }; my $post_record = { c_id => 0 }; $post_record = $dbt->collect_post($dbh_operator,$postref); $update->{int02} = $post_record->{int26} if($post_record->{int26}); $update->{txt10} = $dbt->{operator}->{$last_used_operator}->{oprefix}; #to update sig int28 counter my $update_pos = { table => "contenttranspos", mtime => "now()", int28 => "1", }; $dbt->update_record($dbh_operator,$update_pos,$post_record) if($post_record->{c_id}); #user_miniquest_count on operator #my $adref = { # table => "contentadr", # fetch => "one", # template_id => "202", # c_id => "$auth->{c_id}", # }; #my $auth_op = $dbt->fetch_record($dbh_operator,$adref); my $user_miniquest_count = $auth->{int23} || 0; if($user_miniquest_count <= 3){ $user_miniquest_count++; my $update23 = { table => "contentadr", int23 => $user_miniquest_count, atime => "now()", }; my $rows = $dbt->update_record($dbh,$update23,$auth); } } } my $record = { c_id => $c_id }; $node_template->{tpl_order} .= ",txt09=Wartungsarbeiten"; my @tpl_order = split /,/,$node_template->{tpl_order}; if($action){ my ($key,$val) = split /=/,$action; $update->{$key} = $val if($key =~ /txt1\d/);#logging redistribution and charge service action }elsif($q->param('work_id')){ foreach (@tpl_order){ my ($key,$val,$size) = split /=/,$_; #key validation will be done by update_record if($key eq "txt01" && $q->param('work_id') eq "$key" && $q->param('work_val') =~ /::erledigt::/){ my $pref_pos = { table => "contentpos", fetch => "one", c_id => $c_id, }; my $record_pos = $dbt->fetch_tablerecord($dbh,$pref_pos) if($c_id); if($record_pos->{txt01} ne "NaN"){ $update->{$key} = $q->escapeHTML($q->param('work_val')) . " " . $record_pos->{txt01} if($record_pos->{txt01} !~ /::erledigt::/); }else{ $update->{$key} = $q->escapeHTML($q->param('work_val')); } } elsif($key eq "txt01" && $q->param('work_id') eq "$key" && $q->param('work_val') !~ /\w/){ $update->{$key} = "NaN"; } elsif($q->param('work_id') eq "$key"){ $update->{$key} = $q->escapeHTML($q->param('work_val')); } } } my $rows = $dbt->update_record($dbh,$update,$record) if($record->{c_id} > 0); return $rows; }#end service_update #bike_update for state update after servíce_work (cronjob) OR service_done sub bikestate_update(){ my $self = shift; my $auth = shift; my $c_id = shift || ""; my $state = shift || ""; my $update_hash = shift || ""; my %varenv = $cf->envonline(); my $return={}; my $update = { table => "content", owner => $auth->{c_id}, mtime => "now()", }; #set state only if defined $update->{int10} = $state if($state); #moving bike to station if(ref($update_hash) eq "HASH" && looks_like_number($update_hash->{int04})){ $update->{int04} = "$update_hash->{int04}"; } #set smartlock_battery_charge if(ref($update_hash) eq "HASH" && looks_like_number($update_hash->{int14})){ $update->{int14} = "$update_hash->{int14}"; } #set bike_battery_charge if(ref($update_hash) eq "HASH" && looks_like_number($update_hash->{int19})){ $update->{int19} = "$update_hash->{int19}"; } $bw->log("bikestate_update bike to state c_id $c_id | $update->{int04} | $state | auth:$auth->{c_id}",$update,""); my $record = { c_id => $c_id }; my $rows = $dbt->update_record($dbh,$update,$record) if($record->{c_id} > 0); return $rows; }#bikestate_update #feedback response --> obsolet sub feedback_response { my $self = shift; my $pos_record = shift; my $node_template = shift; my %varenv = $cf->envonline(); my @tpl_order = split /,/,$node_template->{tpl_order}; my $return = {}; foreach my $id (sort { $pos_record->{$a}->{mtime} cmp $pos_record->{$b}->{mtime} } keys (%$pos_record)){ foreach (@tpl_order){ my ($key,$val,$size) = split /=/,$_; $return->{feedback_id} = "$pos_record->{$id}->{c_id}" if($key eq "c_id"); $return->{bike} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}$pos_record->{$id}->{barcode}" if($key eq "barcode"); $return->{bike_broken} = "$pos_record->{$id}->{int01}" || "" if($key eq "int01"); $return->{message} = "$pos_record->{$id}->{txt02}" || "" if($key eq "txt02"); } } return $return; } #service_work copy from service_select sub service_work { my $self = shift; my $pos_record = shift; my $article_all = shift || ""; my $history = shift || 0; my $node_template = shift || {}; my %varenv = $cf->envonline(); my $dt1 = DateTime->now; my $return={}; my $mapref = { int09 => 1, }; #my $users_map = $dbt->users_map($dbh,$mapref);#get serviceAPP users my $users_map = $dbt->users_map($dbh,"");#get all serviceAPP users (also without service key) my $channel_map = $dbt->channel_map(); my @tpl_order = (); @tpl_order = split /,/,$node_template->{tpl_order} if(ref($node_template) eq "HASH" && $node_template->{tpl_order}); #because of different templates we need template grouping #not safe, pos template_id have to be defined before any service has done! #keep in mind, on pos tables there isn't any relation. That's because history pos.template_id will be selected my $pref = { table => "content", table_pos => "contentpos", }; my $template_group = $dbt->pos_template_group($dbh,$pref); #$bw->log(" template_group",$template_group,""); my $node = {}; my $op_return = {}; foreach my $cid (sort { $article_all->{$a}->{barcode} <=> $article_all->{$b}->{barcode} } keys(%$article_all)){ my $i=0; my $j=0; my $article = $article_all->{$cid}->{barcode}; my $tpl_keyseen = ""; foreach my $id (sort { $pos_record->{$a}->{mtime} cmp $pos_record->{$b}->{mtime} } keys (%$pos_record)){ $i++; if($article_all->{$cid}->{c_id} == $pos_record->{$id}->{cc_id}){ $article = $article_all->{$cid}->{barcode} if($article_all->{$cid}->{template_id} && $article_all->{$cid}->{template_id} == 205);# bike template_id $article = $article_all->{$cid}->{int04} if($article_all->{$cid}->{template_id} && $article_all->{$cid}->{template_id} == 225);# station template_id if(1==1){ if($pos_record->{$id}->{template_id} && $template_group->{$pos_record->{$id}->{template_id}}){ #$bw->log("$article --> service_work template on id: $id used:",$template_group->{$pos_record->{$id}->{template_id}}->{tpl_id},""); @tpl_order = split /,/,$template_group->{$pos_record->{$id}->{template_id}}->{tpl_order}; $node->{template_id} = "$pos_record->{$id}->{template_id}"; }elsif(1==1){#on init use node tpl #$bw->log("$article --> service_work template on id: $id used node_template:",$node->{template_id},""); my $tpl = $dbt->get_tpl($dbh,$node_template->{template_id}); @tpl_order = split /,/,$tpl->{tpl_order}; $node->{template_id} = "$tpl->{tpl_id}"; } foreach (@tpl_order){ my ($key,$val,$size,$interval,$service_type) = split /=/,$_; $service_type = 0 if(!looks_like_number($service_type)); my $erledigt = 0; $erledigt = 1 if(!$history && $pos_record->{$id}->{txt01} && $pos_record->{$id}->{txt01} !~ /::erledigt::/); $erledigt = 1 if($history && $pos_record->{$id}->{txt01} && $pos_record->{$id}->{txt01} =~ /::erledigt::/); #service integer collect if($key =~ /int/ && looks_like_number($pos_record->{$id}->{$key})){ $tpl_keyseen .= "$key|"; my $u_name = $users_map->{$pos_record->{$id}->{owner}}->{txt01} || $channel_map->{$pos_record->{$id}->{owner}} || $pos_record->{$id}->{owner}; my $dt2 = DateTime::Format::Pg->parse_datetime($pos_record->{$id}->{mtime}); my $time_over = "0"; if(looks_like_number($interval) && $interval > 0){ my $dt2_over = $dt2->add( days => $interval ); $time_over = "1" if($dt1 > $dt2_over); } my $key_change = $key; if($history && $history > 0){ my $dtstamp = $pos_record->{$id}->{mtime}; $dtstamp = $dt2->epoch(); $key_change .= "_" . $dtstamp; } $return->{$article}->{$key_change}->{service_id} = "$pos_record->{$id}->{c_id}"; $return->{$article}->{$key_change}->{work_id} = "$key"; $return->{$article}->{$key_change}->{work_name} = "$val"; $return->{$article}->{$key_change}->{interval} = "$interval"; $return->{$article}->{$key_change}->{time_over} = "$time_over"; $return->{$article}->{$key_change}->{service_type} = "$service_type"; $return->{$article}->{$key_change}->{work_val} = "$pos_record->{$id}->{$key}"; $return->{$article}->{$key_change}->{mtime} = "$pos_record->{$id}->{mtime}"; $return->{$article}->{$key_change}->{user_name} = "$u_name"; $return->{$article}->{$key_change}->{owner} = "$pos_record->{$id}->{owner}"; #servive multi todo collect }elsif($key eq "txt01" && $pos_record->{$id}->{$key} && $pos_record->{$id}->{$key} ne "NaN" && $erledigt){ $j++; $tpl_keyseen .= "$key|"; my $u_name = $users_map->{$pos_record->{$id}->{owner}}->{txt01} || $channel_map->{$pos_record->{$id}->{owner}} || $pos_record->{$id}->{owner}; my $dt2 = DateTime::Format::Pg->parse_datetime($pos_record->{$id}->{mtime}); my $time_over = "0"; if(looks_like_number($interval) && $interval > 0){ my $dt2_over = $dt2->add( days => $interval ); $time_over = "1" if($dt1 > $dt2_over); } my $key_change = $key; if($history && $history > 0){ my $dtstamp = $pos_record->{$id}->{mtime}; $dtstamp = $dt2->epoch(); $key_change .= "_" . $dtstamp; }elsif($j > 1){ #appending counter on multiple todos $key_change .= "_" . $j; } my $work_val = "$pos_record->{$id}->{$key}"; $work_val = "" if($pos_record->{$id}->{$key} eq "::new_task::"); $return->{$article}->{$key_change}->{service_id} = "$pos_record->{$id}->{c_id}"; $return->{$article}->{$key_change}->{work_id} = "$key"; $return->{$article}->{$key_change}->{work_name} = "$val"; $return->{$article}->{$key_change}->{interval} = "$interval"; $return->{$article}->{$key_change}->{time_over} = "$time_over"; $return->{$article}->{$key_change}->{service_type} = "$service_type"; $return->{$article}->{$key_change}->{work_val} = "$work_val"; $return->{$article}->{$key_change}->{mtime} = "$pos_record->{$id}->{mtime}"; $return->{$article}->{$key_change}->{user_name} = "$u_name"; $return->{$article}->{$key_change}->{owner} = "$pos_record->{$id}->{owner}"; } } } } } #set init values if(!$history && scalar(@tpl_order) > 1){ $bw->log("set service init values by @tpl_order","",""); $bw->log("tpl_keyseen",$tpl_keyseen,""); $tpl_keyseen =~ s/\|$//; foreach (@tpl_order){ my ($key,$val,$size,$interval,$service_type) = split /=/,$_; $service_type = 0 if(!looks_like_number($service_type)); if($key =~ /int|txt/ && (!$tpl_keyseen || $key !~ /$tpl_keyseen/)){ $return->{$article}->{$key}->{service_id} = "1"; $return->{$article}->{$key}->{work_id} = "$key"; $return->{$article}->{$key}->{work_name} = "$val"; $return->{$article}->{$key}->{interval} = "$interval"; $return->{$article}->{$key}->{time_over} = "1";#2021-06-23 if not seen then time_over $return->{$article}->{$key}->{service_type} = "$service_type"; $return->{$article}->{$key}->{work_val} = "1" if($key =~ /int/); $return->{$article}->{$key}->{work_val} = "::erledigt::" if($key =~ /txt/); $return->{$article}->{$key}->{mtime} = "2023-02-16 00:00"; $return->{$article}->{$key}->{user_name} = "init"; $return->{$article}->{$key}->{owner} = "188"; } } #}else{ #$return->{response_state} = "Failure 3099: history to short OR template fails"; } } return ($return,$node); }#end service_work #bike reservation sub booking_request(){ my $self = shift; my $q = shift; my $varenv = shift; my $auth = shift;#app API auth my $bike = shift || 0;#app API request my $ct_bike = shift || {}; my $ct_tariff = shift || {}; my $sig_book = shift || {}; my $owner = shift || 0; my $state = $q->escapeHTML($q->param('state')) || ""; my $lock_state = $q->escapeHTML($q->param('lock_state')) || ""; my $dbh = ""; my $pos_id=""; my $now_dt = strftime "%Y-%m-%d %H:%M", localtime; my $response_state = "OK"; my $response_text = ""; #state and lock_state is only defined if requestes incl. occupied $bw->log("log booking_request bike=$bike, auth=$auth->{c_id}, state=$state, lock_state=$lock_state, tarif=$ct_tariff->{barcode}",$auth->{txt08},""); my $update_adr = { table => "contentadr", mtime => "now()", owner => "$owner", c_id => "$auth->{c_id}", }; my $pref = { table => "contenttrans", fetch => "one", main_id => 300008, template_id => 218, int10 => "$auth->{c_id}", state => "null", close_time => "is::null", }; #if bike and tariff if($ct_bike->{barcode} && $ct_tariff->{barcode}){ my $ctt = {}; my $rentable_check=0; $rentable_check = $bw->isuser_rentable($auth,$varenv); $bw->log("booking_request isuser_rentable:",$rentable_check,""); if($rentable_check == 2){ #to get if station only for A-A journay my $pref_station = { table => "content", fetch => "one", template_id => "225", int04 => $ct_bike->{int04}, }; my $ct_station = {}; $ct_station = $dbt->fetch_record($dbh,$pref_station) if($ct_bike->{int04}); #get invoice $ctt = $dbt->fetch_record($dbh,$pref) if($auth->{c_id}); if(!$ctt->{c_id}){ my $ct_id = $dbt->insert_contenttrans($dbh,$auth,"300008","218","----","$owner"); $pref->{c_id} = $ct_id; $ctt = $dbt->fetch_record($dbh,$pref) if($pref->{c_id}); } $bw->log("booking_request used invoice c_id:",$ctt->{c_id},""); #if invoice exist if($ctt->{c_id}){ #if payment-type prepaid, then check whether balance positive my $sum_balance = 0; if($auth->{int03} && $auth->{int03} == 3){ my $dbh_primary = $dbt->dbconnect_extern($dbt->{primary}->{sharee_primary}->{database}->{dbname}); my $adref = { table => "contentadr", fetch => "one", c_id => "$auth->{c_id}", }; my $auth_prim = $dbt->fetch_tablerecord($dbh_primary,$adref); #get prepaid balance, like in users App RentalData #collects all open (not captured) positions incl. primary-prepaid to get saldo my ($cttpos,$operator_hash) = $self->user_rentals_history($q,$auth_prim,0,1); foreach my $id (keys(%$cttpos)){ if($cttpos->{$id}->{int35} && $cttpos->{$id}->{start_time} && $cttpos->{$id}->{end_time}){ my $pricing = { total_price => 0 }; ($pricing, my $counting) = $pri->counting_rental($varenv,$cttpos->{$id}); $sum_balance += $pricing->{total_price}; }else{ my $total_price = 0; ($total_price,my $rabatt) = $pri->price2calc($cttpos->{$id}); #prepaid * -1 $total_price *= -1 if($cttpos->{$id}->{template_id} && $cttpos->{$id}->{template_id} == 219); $sum_balance += $total_price; } } $bw->log("booking_request prepaid balance sum: $sum_balance, userID: $auth->{c_id} ",$sum_balance,""); } #Rental is only permitted if sum_balance <= 0 (in primary prepaid context positive) if($sum_balance <= 1){ #2 = "requested" $pos_id = $dbt->insert_pos($dbh,$ctt->{c_id},$ct_bike,$ct_station,$auth,$ct_tariff,$now_dt,$bike,"2",$owner,$sig_book); $bw->log("booking_request insert_pos:",$pos_id,""); if($pos_id){ $response_state = "OK, bike " . $bike . " succesfully requested"; $response_text = "Rad $bike wurde erfolgreich für 15 Min. reserviert"; $bw->log("booking_request insert contenttranspos pos_id: $pos_id\n","",""); my $update_ctt = { table => "contenttrans", c_id => $ctt->{c_id}, }; $dbt->update_one($dbh,$update_ctt,"start_time='$now_dt'"); #BVB once auto-coupon until 2023-08-31 #disabled if(1==2 && $varenv->{dbname} eq "sharee_bvb"){ #BVB 3-Stunden-Freifahrt my $auto_coupon = "123"; my $pref_co = { table => "content", fetch => "one", template_id => "224", int03 => ">::0", barcode => "$auto_coupon", }; my $ct_co = { c_id => 0 }; $ct_co = $dbt->fetch_record($dbh,$pref_co); $ct_co->{int02} *= -1 if($ct_co->{int02} > 0);#coupon price must be negate my $pos_co = { table => "contenttranspos", fetch => "one", ca_id => "$auth->{c_id}", template_id => "224", barcode => "$auto_coupon", }; my $co_pos = { c_id => 0 }; $co_pos = $dbt->fetch_tablerecord($dbh,$pos_co); if($ct_co->{c_id} && !$co_pos->{c_id}){ $pos_id = $dbt->insert_pos($dbh,$ctt->{c_id},$ct_co,"",$auth,"","","","0",$owner); $dbt->update_content4comp($dbh,$ct_co->{c_id},"-","1"); } }#end BVB auto-coupon }else{ $response_state="Failure 1007: booking request fails"; $response_text="Entschuldigung, es ist ein Fehler aufgetreten. Bitte kontaktieren Sie unsere hotline damit wir das Problem lösen können"; } }else{ $response_state="Failure 1593: rental is prohibited because of prepaid balance - $sum_balance"; $response_text="Bitte überprüfen Sie Ihren Prepaid/Vorkasse Kontostand, aktuell: - $sum_balance €. Nur bei positiven Kontostand können wir das Mietradsystem für Sie freischalten."; }#end if $sum_balance } }elsif($rentable_check == 1){ $response_state="Failure 1006: rental is prohibited because of user profil"; $response_text="Bitte überprüfen Sie Ihre Profildaten auf Vollständigkeit, nur dann können wir das Mietradsystem für Sie freischalten"; }else{ my $vde = $auth->{int12} || 1; $dbt->update_one($dbh,$update_adr,"int12=$vde"); $response_state="Failure 1005: user-account deactivated because of user profil"; $response_text="Bitte überprüfen Sie Ihre Profildaten auf Vollständigkeit, nur dann können wir das Mietradsystem für Sie freischalten"; } } my $return = { bike => "$bike", pos_id => "$pos_id", state => "requested", response_state => "$response_state", response_text => "$response_text" }; $bw->log("booking_request response_state:",$return,""); return $return; } #booking_cancel changed to booking_update sub booking_update(){ my $self = shift; my $q = shift; my $varenv = shift; my $auth = shift; my $owner = shift || 0; my $sig_book = shift || {}; my $dbh = ""; my $state = $q->escapeHTML($q->param('state')) || ""; my $lock_state = $q->escapeHTML($q->param('lock_state')) || ""; my $rows = 0; my $user_agent = $q->user_agent(); #my $bike = $q->param('bike'); #my $bike_id = $1 if($q->escapeHTML($q->param('bike')) =~ /(\d+)/); my $bike = $q->escapeHTML($q->param('bike')) || ""; my $bike_id = $bike; $bike_id =~ s/S[1-9]X/SX/; $bike_id = $1 if($bike_id =~ /(\d+)/); my $state_key = 0; my $state_text = ""; while (my ($key, $value) = each %{ $dbt->{copri_conf}->{bike_state} }) { if($state eq $value){ $state_key = $key; $state_text = "beendet" if($state eq "available"); $state_text = "gestartet" if($state eq "occupied"); } } my $booking_values = { bike => "$bike", state => "", lock_state => "", #station_lock_state => "", co2saving => "", response_state => "OK 1017: No update", response_text => "Der Mietstatus wurde nicht geändert.", }; my $record_pos = { c_id => 0 }; my $booking_pos = { table => "contenttranspos", fetch => "one", barcode => $bike_id, ca_id => $auth->{c_id}, int10 => "IN::('3','2')", }; $record_pos = $dbt->fetch_tablerecord($dbh,$booking_pos) if($bike_id > 0 && $auth->{c_id} > 0); if(!$record_pos->{c_id}){ $booking_values->{response_state} = "Failure 758: Can not find bike " . $q->param('bike') . " rental or reservation on varenv-dbname: $varenv->{dbname}"; $booking_values->{response_text} = "Keine Miete oder Reservierung zu Rad " . $q->param('bike') . " gefunden."; } my $pref_cc = { table => "content", fetch => "one", template_id => "205", barcode => $bike_id, }; my $record_cc = { c_id => 0 }; $record_cc = $dbt->fetch_record($dbh,$pref_cc) if($q->param('bike')); my $update_cc = { table => "content", mtime => "now()", owner => "$owner", }; my $gps_data = { gps => "", latitude => "", longitude => "", gps_age_minutes => 60, gps_accuracy => 0, geo_distance => 1000000, }; #old if($q->param('gps')){ my $gps_input = $q->param('gps'); $gps_input =~ s/\s//g; $gps_data->{latitude} = $q->escapeHTML($1) if($gps_input =~ /^(\d+\.\d+),\d+/); $gps_data->{longitude} = $q->escapeHTML($1) if($gps_input =~ /\d+,(\d+\.\d+)$/); $gps_data->{gps} = "$gps_data->{latitude},$gps_data->{longitude}" if($gps_data->{latitude} && $gps_data->{longitude}); } #new if($q->param('latitude') && $q->param('longitude')){ my $latitude_in = $q->param('latitude'); my $longitude_in = $q->param('longitude'); $gps_data->{latitude} = $1 if($latitude_in =~ /(\d+\.\d+)/); $gps_data->{longitude} = $1 if($longitude_in =~ /(\d+\.\d+)/); $gps_data->{gps} = "$gps_data->{latitude},$gps_data->{longitude}" if($gps_data->{latitude} && $gps_data->{longitude}); } my $gps_age = 0; $gps_age = $1 if($q->param('gps_age') && $q->param('gps_age') =~ /^(\d+)/);#in milisec $gps_data->{gps_age_minutes} = $gps_age / 1000 / 60 if($gps_age); $gps_data->{gps_accuracy} = $1 if($q->param('gps_accuracy') && $q->param('gps_accuracy') =~ /^(\d+)/);#in meters my $update_pos = { table => "contenttranspos", mtime => "now()", }; my $lock_charge = $q->param('voltage') || ""; my $gps_age_minutes = ""; $gps_age_minutes = $gps_data->{gps_age_minutes} if($q->param('gps_age')); my $logvalues = "pos_id=$record_pos->{c_id}, state=$state, lock_state=$lock_state, lock_charge=$lock_charge, gps=$gps_data->{gps}, gps_age_minutes=$gps_age_minutes"; my $logging = "log booking_update bike=$bike, userID=$auth->{c_id}, $logvalues"; $bw->log("$logging",$auth->{c_id},""); my $log_stamp = strftime "%d.%m.%Y %H:%M:%S", localtime; $update_pos->{txt24} = $record_pos->{txt24} . "\n- $log_stamp $logvalues"; $dbt->update_record($dbh,$update_pos,$record_pos); my $Ilockit_GUID = ""; $Ilockit_GUID = $q->escapeHTML($q->param('Ilockit_GUID')) if($q->param('Ilockit_GUID') && $q->param('Ilockit_GUID') =~ /\w+-\w+-\w+-\w+$/); #$update_pos->{txt17} = $Ilockit_GUID if($Ilockit_GUID); $update_cc->{txt17} = $Ilockit_GUID if($Ilockit_GUID); #2022-10-02 manage lock_state before state if($lock_state && $lock_state =~ /locking|locked|unlocking|unlocked/ && $record_pos->{cc_id} && $record_pos->{cc_id} > 0){ $booking_values = $self->smartlock($q,$varenv,$auth,$owner,$record_pos,$record_cc,$gps_data,$booking_values); my $booking_pos = { table => "contenttranspos", fetch => "one", c_id => "$record_pos->{c_id}", }; $record_pos = $dbt->fetch_tablerecord($dbh,$booking_pos); my $if_gps = $gps_data->{gps} || ""; $bw->log("log smartlock lock_state=$bike $lock_state, int10=$record_pos->{int10}, int20=$record_pos->{int20}, if_gps=$if_gps",$booking_values,""); } #6 = "canceled"|3 = "occupied"|1 = "available" if($state_key && ($state_key == 6 || $state_key == 3 || $state_key == 1) && $record_pos->{cc_id} && $record_pos->{cc_id} > 0){ #set rent state if lock_system 2=Ilockit || 3=sigo if($record_pos->{int11} && ($record_pos->{int11} == 2 || $record_pos->{int11} == 3)){ if($user_agent && $user_agent !~ /axios/){#keep device info if sig push $update_pos->{txt21} = $q->escapeHTML($q->param('user_device')) if($q->param('user_device')); $update_pos->{txt26} = $q->escapeHTML($user_agent) if($user_agent); $update_pos->{txt27} = $q->escapeHTML($q->param('app_debug')) if($q->param('app_debug')); } #if($state eq canceled && $record_pos.state eq requested && $record_pos.lock_state eq locked) if($state_key == 6 && $record_pos->{int10} == 2 && $record_pos->{int20} == 1){ $rows = $dbt->delete_content($dbh,"contenttranspos",$record_pos->{c_id}); if($rows > 0){ $update_cc->{int10} = 1 if($record_cc->{int10} == 2);#only if still requested $booking_values->{response_state} = "OK: canceled bike " . $q->param('bike'); $booking_values->{response_text} = "Rad " . $q->param('bike') . " wurde erfolgreich storniert"; $booking_values->{state} = "available"; }else{ $booking_values->{response_state} = "Failure 2002: cancel bike " . $q->param('bike') . " fails, bike not requested"; $booking_values->{response_text} = "Keine Reservierung zu Rad " . $q->param('bike') . " gefunden."; } }else{ #prevent reset occupied values OR only if genkey defined #if(($state eq "occupied" && $record_pos->{txt10} =~ /requested/) || ($state eq "occupied" && $record_pos->{txt10} =~ /occupied/ && $q->param('genkey') eq "1")) if(($state_key == 3 && $record_pos->{int10} == 2) || ($state_key == 3 && $record_pos->{int10} == 3 && $q->param('genkey') eq "1")){ $update_pos->{start_time} = "now()"; $update_pos->{end_time} = "now()"; $update_pos->{txt05} = "$record_cc->{txt06}";#pos start GPS from content end GPS $update_pos->{int06} = "$record_cc->{int04}";#pos start station from content station $update_pos->{txt12} = "$dbt->{operator}->{$varenv->{dbname}}->{oprefix}";#pos start station prefix $update_pos->{int21} = $gps_data->{gps_age_minutes}; $update_pos->{int22} = $gps_data->{gps_accuracy}; $update_pos->{owner} = "$owner"; $update_pos->{int10} = 3; $update_pos->{txt11} = "$sig_book->{rentalId}" if($sig_book->{rentalId}); $update_pos->{txt22} = "$sig_book->{bikeId}" if($sig_book->{bikeId}); $rows = $dbt->update_record($dbh,$update_pos,$record_pos); if($rows > 0){ $booking_values->{response_state} = "OK: occupied bike " . $q->param('bike'); $booking_values->{response_text} = "Rad " . $q->param('bike') . " Miete gestartet. "; $update_cc->{int10} = 3; #$update_cc->{int04} = "null";#Because of servicetool, we hav to be keep the station } #fraud_rental sms_message if($auth->{txt29} && $auth->{txt29} =~ /Betrug/){ $bw->log("$varenv->{basedir}/src/scripts/sms_message.pl $varenv->{syshost} fraud_rental '' $record_pos->{c_id}",$record_pos->{c_id},""); system("$varenv->{basedir}/src/scripts/sms_message.pl $varenv->{syshost} fraud_rental '' $record_pos->{c_id} &"); } #rental end only if locked #if(state eq available && $record_pos.lock_state eq locked and pos-state 2=requested or 3=occupied }elsif($state_key == 1 && $record_pos->{int20} == 1 && ($record_pos->{int10} == 2 || $record_pos->{int10} == 3)){ #client GPS must have. sigo ist done without client gps if(($gps_data->{gps} && $gps_data->{gps_age_minutes} <= 3) || ($record_pos->{int11} == 3)){ #geofencing for Ilockit my $geo_distance_next = 100000; my $station_next = 0; my $geo_debug=""; my $rows_end = 0; my ($stations,$stations_raw) = $self->stations_available($q,$varenv,$auth,$record_pos,""); foreach my $id (sort { $stations_raw->{$a}->{barcode} <=> $stations_raw->{$b}->{barcode} } keys (%$stations_raw)){ my $latitude_station = $1 if($stations_raw->{$id}->{txt06} =~ /^(\d+\.\d+)/); my $longitude_station = $1 if($stations_raw->{$id}->{txt06} =~ /(\d+\.\d+)$/); if((!looks_like_number($gps_data->{latitude}) || !looks_like_number($gps_data->{longitude})) && ($record_pos->{int11} != 3)){ $geo_debug .= "ERROR no user GPS: $stations_raw->{$id}->{int04}|$gps_data->{latitude},$gps_data->{longitude},$latitude_station,$longitude_station --> $gps_data->{geo_distance} Meter\n"; }elsif((looks_like_number($gps_data->{latitude}) && looks_like_number($gps_data->{longitude}) && looks_like_number($latitude_station) && looks_like_number($longitude_station)) || ($record_pos->{int11} == 3)){ $update_pos->{owner_end} = "$owner"; $update_pos->{end_time} = "now()"; $gps_data->{geo_distance} = $lb->geo_fencing($gps_data->{latitude},$gps_data->{longitude},$latitude_station,$longitude_station); #sigo development workaround without geofence if(($gps_data->{geo_distance} <= $stations_raw->{$id}->{int06}) || ($record_pos->{int11} == 3)){ $geo_distance_next = $gps_data->{geo_distance}; #end-Station $update_pos->{int04} = $stations_raw->{$id}->{int04}; $update_cc->{int04} = $stations_raw->{$id}->{int04}; $update_pos->{int10} = 1; $update_pos->{txt11} = "$sig_book->{rentalId}" if($sig_book->{rentalId}); $update_cc->{txt06} = "$gps_data->{gps}";#end content coordinates $update_pos->{txt06} = "$gps_data->{gps}";#end pos coordinates $update_pos->{int21} = $gps_data->{gps_age_minutes}; $update_pos->{int22} = $gps_data->{gps_accuracy}; $update_pos->{int23} = $gps_data->{geo_distance}; $update_pos->{int26} = "$sig_book->{distance}" if($sig_book->{distance}); $update_pos->{int28} = "$sig_book->{station_lock_state}" if($sig_book->{station_lock_state}); #end-Station prefix $update_pos->{txt13} = "$dbt->{operator}->{$varenv->{dbname}}->{oprefix}"; $update_cc->{txt13} = "$dbt->{operator}->{$varenv->{dbname}}->{oprefix}"; #return after booking_update #in real, we know freed accountable rentals only on rental end's my $adjust_freedtime = 1; $pri->count_freedrental($q,$varenv,$auth->{c_id},$record_pos,$adjust_freedtime); my ($pricing,$counting) = $pri->counting_rental($varenv,$record_pos); #int03 only used for tarif counting backwards compatibility $update_pos->{int03} = "$pricing->{computed_hours}" if(looks_like_number($pricing->{computed_hours})); $update_pos->{int38} = "$counting->{int38}" if(looks_like_number($counting->{int38})); $update_pos->{int39} = "$counting->{int39}" if(looks_like_number($counting->{int39})); $update_pos->{int40} = "$counting->{int40}" if(looks_like_number($counting->{int40})); $update_pos->{int41} = "$counting->{int41}" if(looks_like_number($counting->{int41})); $rows_end = $dbt->update_record($dbh,$update_pos,$record_pos); if($rows_end > 0){ $update_cc->{int10} = 1; $booking_values->{response_state} = "OK: available bike " . $q->param('bike'); $booking_values->{response_text} = "Danke! Die Miete Rad " . $q->param('bike') . " wurde beendet."; } $geo_debug .= "Matching station: $stations_raw->{$id}->{barcode}|$gps_data->{latitude},$gps_data->{longitude},$latitude_station,$longitude_station --> $gps_data->{geo_distance} Meter\n"; last; } #out of geofence else{ if($gps_data->{geo_distance} <= $geo_distance_next){ $geo_distance_next = $gps_data->{geo_distance}; $station_next = "$dbt->{operator}->{$varenv->{dbname}}->{oprefix}$stations_raw->{$id}->{int04}"; } #2021-10-13 changed to save last gps @all $update_cc->{txt06} = "$gps_data->{gps}";#end content coordinates $update_pos->{txt06} = "$gps_data->{gps}";#end pos coordinates $update_pos->{int21} = $gps_data->{gps_age_minutes}; $update_pos->{int22} = $gps_data->{gps_accuracy}; $update_pos->{int23} = $gps_data->{geo_distance}; #end-Station prefix $update_pos->{txt13} = "$dbt->{operator}->{$varenv->{dbname}}->{oprefix}"; $update_cc->{txt13} = "$dbt->{operator}->{$varenv->{dbname}}->{oprefix}"; #return after booking_update my ($pricing,$counting) = $pri->counting_rental($varenv,$record_pos); #int03 only used for tarif counting backwards compatibility $update_pos->{int03} = "$pricing->{computed_hours}" if(looks_like_number($pricing->{computed_hours})); $update_pos->{int38} = "$counting->{int38}" if(looks_like_number($counting->{int38})); $update_pos->{int39} = "$counting->{int39}" if(looks_like_number($counting->{int39})); $update_pos->{int40} = "$counting->{int40}" if(looks_like_number($counting->{int40})); $update_pos->{int41} = "$counting->{int41}" if(looks_like_number($counting->{int41})); $rows_end = $dbt->update_record($dbh,$update_pos,$record_pos); $geo_debug .= "Out of station distance: $stations_raw->{$id}->{int04}|rows_end:$rows_end|$gps_data->{latitude},$gps_data->{longitude},$latitude_station,$longitude_station --> $geo_distance_next Meter ($geo_distance_next <= $gps_data->{geo_distance}) station_next: $station_next\n"; if($record_pos->{int42} == 1){ $booking_values->{response_state} = "Failure 2179: bike " . $q->param('bike') . " out of GEO fencing. $geo_distance_next meter distance to A-A station $station_next ."; $booking_values->{response_text} = "Achtung! Dieses Mietrad darf nur an der Station zurück gegeben werden an der es ausgeliehen wurde. Die Miete zu Rad " . $q->param('bike') . " kann nicht $state_text werden. $geo_distance_next Meter Entfernung zur A-A Station $station_next . Falls Sie sich doch an der Station befinden, dann wiederholen Sie \"Miete beenden\"."; }else{ $booking_values->{response_state} = "Failure 2178: bike " . $q->param('bike') . " out of GEO fencing. $geo_distance_next meter distance to next station $station_next ."; $booking_values->{response_text} = "Achtung! Ihr aktueller Standort liegt außerhalb einer für das Mietende freigegebenen Radstation. Die Miete zu Rad " . $q->param('bike') . " kann nicht $state_text werden. $geo_distance_next Meter Entfernung zur nächsten Station $station_next . Falls Sie sich doch an einer Station befinden, dann wiederholen Sie \"Miete beenden\"."; } } }else{ $geo_debug .= "ERROR no station GPS: $stations_raw->{$id}->{int04}|$gps_data->{latitude},$gps_data->{longitude},$latitude_station,$longitude_station --> $gps_data->{geo_distance} Meter\n"; } } $booking_values->{geo_distance} = "$geo_distance_next"; #print "$geo_debug\n"; $bw->log("GEOfencing geo_debug:$geo_debug",$q,""); #end if gps && gps_age <= 3 and not sigo }elsif($record_pos->{int11} != 3){ if(!$gps_data->{gps}){ $booking_values->{response_state} = "Failure 2245: No GPS data, state change forbidden."; $booking_values->{response_text} = "Fehler! Keine GPS Standortdaten, Die Miete Rad " . $q->param('bike') . " kann wegen fehlendem GPS nicht $state_text werden. Bitte aktivieren Sie das GPS."; }else{ $booking_values->{response_state} = "Failure 2246: GPS age with $gps_data->{gps_age_minutes} minutes too old, state change forbidden."; $booking_values->{response_text} = "Fehler! GPS Daten sind mit $gps_data->{gps_age_minutes} Minuten zu alt. Die Miete Rad " . $q->param('bike') . " kann aufgrund nicht aktueller GPS nicht $state_text werden. Bitte aktivieren Sie das GPS."; } } #end if($state eq "available" && $record_pos.state eq occupied || $record_pos.lock_state ne locked }elsif($state_key == 6 && ($record_pos->{int10} == 3 || $record_pos->{int20} != 1)){ $booking_values->{response_state} = "Failure 2012: occupied bike " . $q->param('bike') . " cannot be state $state and $lock_state"; $booking_values->{response_text} = "Rad " . $q->param('bike') . " ist in Benutzung und kann somit nicht storniert werden."; }elsif($state_key == 3 && $record_pos->{int10} == 1){ $booking_values->{response_state} = "Failure 2016: available bike " . $q->param('bike') . " have to be at first reserved, thats because cannot be $state"; $booking_values->{response_text} = "Rad " . $q->param('bike') . " wurde nicht reserviert und kann somit nicht gemietet werden."; }else{ $booking_values->{response_state} = "Failure 2035: bike " . $q->param('bike') . " state change to state $state and $lock_state not possible."; $booking_values->{response_text} = "Fehler! Der Mietstatus zu Rad " . $q->param('bike') . " kann mit dem vorhandenen Status \"state:$state and lock_state:$lock_state\" nicht geändert werden."; } #contenttrans my $update_ct = { table => "contenttrans", mtime => "now()", owner => "$owner", }; my $record_ct->{c_id} = $record_pos->{ct_id}; $dbt->update_record($dbh,$update_ct,$record_ct); } #end Ilockit || sigo }else{ $bw->log("smartlock type not defined, int11:",$record_pos->{int11},""); } #update bike content $bw->log("check ct_state on update_cc 2.",$update_cc,""); $dbt->update_record($dbh,$update_cc,$record_cc); }#end if $state =~ /canceled|occupied|available/ #fetch final booking state after request if($record_pos->{c_id} && $record_pos->{c_id} > 0){ my $booking_pos = { table => "contenttranspos", fetch => "one", c_id => "$record_pos->{c_id}", }; my $booking = $dbt->fetch_tablerecord($dbh,$booking_pos); if(ref($booking) eq "HASH" && $booking->{ct_name}){ #deprecated $booking_values->{bike} = "$dbt->{operator}->{$varenv->{dbname}}->{oprefix}$booking->{barcode}"; $booking_values->{state} = "$dbt->{copri_conf}->{bike_state}->{$booking->{int10}}"; $booking_values->{lock_state} = "$dbt->{copri_conf}->{lock_state}->{$booking->{int20}}"; #new object after rental end $booking_values->{bike_returned} = {}; if($booking->{int10} == 1){ $booking_values->{bike_returned}->{bike} = "$dbt->{operator}->{$varenv->{dbname}}->{oprefix}$booking->{barcode}"; $booking_values->{bike_returned}->{station} = "$dbt->{operator}->{$varenv->{dbname}}->{oprefix}$booking->{int04}"; $booking_values->{bike_returned}->{state} = "$dbt->{copri_conf}->{bike_state}->{$booking->{int10}}"; $booking_values->{bike_returned}->{lock_state} = "$dbt->{copri_conf}->{lock_state}->{$booking->{int20}}"; my ($pricing,$counting) = $pri->counting_rental($varenv,$booking); if($pricing->{real_clock} && $pricing->{real_clock} =~ /[1-9]/){ my $time_unit = $dbt->time_format($varenv,$pricing->{real_clock}); $booking_values->{bike_returned}->{real_clock} = "$time_unit";#2023-09-12 } if($pricing->{total_price} && $pricing->{total_price} > 0){ $pricing->{total_price} =~ s/\./,/ if($lang eq "de"); $booking_values->{bike_returned}->{total_price} = "$pricing->{total_price} €";#2023-09-12 } #fetch tracking distance on Ilockit cloud by summary trip if(tracking && deviceId && available) if($booking->{int25} == 1){ $bw->log("get co2saving",$booking->{c_id},""); #if system=ilockit && clouid if($record_pos->{int11} == 2 && $booking->{int13}){ sleep 2;#hopefully get distance in 2 sec. system("$varenv->{basedir}/src/scripts/Ilockit_trackingcloud.pl $varenv->{syshost} get_tripsum $booking->{c_id}"); $booking = $dbt->fetch_tablerecord($dbh,$booking_pos); #try it again with 20sec sleep if(!$booking->{int26}){ $bw->log("$varenv->{basedir}/src/scripts/Ilockit_trackingcloud.pl $varenv->{syshost} get_tripsum $booking->{c_id} 20",$booking->{c_id},""); system("$varenv->{basedir}/src/scripts/Ilockit_trackingcloud.pl $varenv->{syshost} get_tripsum $booking->{c_id} 20 &"); $booking = $dbt->fetch_tablerecord($dbh,$booking_pos); } } my $co2saving = ""; $booking->{int26} = 10 if(!$booking->{int26} && ($auth->{c_id} == 5781 || $auth->{c_id} == 38883 || $auth->{c_id} == 37974));#10 km test if($booking->{int26}){ $co2saving = "Einsparung: "; my $co2diff = $pri->co2calc($booking); #my $sprit_price = $pri->sprit2calc($booking); $co2saving .= "$co2diff kg CO2, "; #$co2saving .= "$sprit_price EUR " if($sprit_price !~ /-/); $booking->{int26} =~ s/\./,/; $co2saving .= "bei einer Strecke von $booking->{int26} KM"; $booking_values->{co2saving} = $co2saving; $booking_values->{bike_returned}->{distance} = "$booking->{int26} km";#2023-09-12 $booking_values->{bike_returned}->{co2saving} = "$co2diff kg CO2";#2023-09-12 } } } #user_miniquest_count on operator my $dbh_primary = $dbt->dbconnect_extern($dbt->{primary}->{sharee_primary}->{database}->{dbname}); my $adref = { table => "contentadr", fetch => "one", template_id => "202", c_id => "$auth->{c_id}", }; my $auth_prim = $dbt->fetch_record($dbh_primary,$adref); if($booking->{int10} == 1 && $dbt->{operator}->{$varenv->{dbname}}->{project} eq "Bayern" && $auth_prim->{int23} < 4){ $bw->log("user_miniquery user ID $auth_prim->{c_id} exist count:",$auth_prim->{int23},""); $booking_values->{user_miniquery} = $dbt->evaluationsfragen($dbh); #user_miniquest_count my $user_miniquest_count = $auth_prim->{int23} || 0; if($user_miniquest_count <= 3){ $user_miniquest_count++; my $update23 = { table => "contentadr", int23 => $user_miniquest_count, atime => "now()", }; $rows = $dbt->update_record($dbh,$update23,$auth_prim) if($auth_prim->{c_id} && !$dbt->{copri_conf}->{betau_id}->{$auth_prim->{c_id}}); } }#end mini_quest #reponse-log if($booking_values->{response_text}){ my $response_log = $booking->{txt29} . "\n- $log_stamp $booking_values->{response_text}"; $dbt->update_one($dbh,$booking_pos,"txt29='$response_log'"); } } } return ($rows,$booking_values); } #end booking_update # #smartlock state on request update sub smartlock { my $self = shift; my $q = shift; my $varenv = shift; my $auth = shift; my $owner = shift || 0; my $record_pos = shift || {}; my $record_cc = shift || {}; my $gps_data = shift || {}; my $booking_values = shift || {}; my $user_agent = $q->user_agent(); my $dbh = ""; #content my $update_cc = { table => "content", mtime => "now()", owner => "$owner", }; $update_cc->{txt28} = $q->escapeHTML($q->param('firmware')) if($q->param('firmware')); #only by system=Ilockit if($record_pos->{int11} eq "2" && $q->param('voltage') && $q->param('voltage') =~ /(\d+)/){ $update_cc->{int14} = $1; $self->service_automatic($q,"") if($1 <= 60); } my $update_pos = { table => "contenttranspos", mtime => "now()", int24 => 0, }; if($user_agent && $user_agent !~ /axios/){#keep device info if sig push $update_pos->{int14} = $q->escapeHTML($q->param('voltage')) if($q->param('voltage')); $update_pos->{txt21} = $q->escapeHTML($q->param('user_device')) if($q->param('user_device')); $update_pos->{txt26} = $q->escapeHTML($user_agent) if($user_agent); $update_pos->{txt27} = $q->escapeHTML($q->param('app_debug')) if($q->param('app_debug')); $update_pos->{txt28} = $q->escapeHTML($q->param('firmware')) if($q->param('firmware')); } my $lock_value = 0; if($q->param('lock_state') eq "locked"){ $lock_value = 1; $update_cc->{int20} = "$lock_value"; $update_pos->{int20} = "$lock_value"; $update_pos->{end_time} = "now()"; $update_cc->{txt06} = $gps_data->{gps};#end content coordinates $update_pos->{txt06} = $gps_data->{gps};#end pos coordinates $update_pos->{int21} = $gps_data->{gps_age_minutes}; $update_pos->{int22} = $gps_data->{gps_accuracy}; $update_pos->{int23} = "null";# only computed on rental-end $booking_values->{response_state} = "OK: bike " . $q->param('bike') . " locked confirmed. "; $booking_values->{response_text} = "Schloss schließen von Rad " . $q->param('bike') . " bestätigt. "; }elsif($q->param('lock_state') eq "unlocked"){ $lock_value = 2; $update_cc->{int20} = "$lock_value"; $update_pos->{int20} = "$lock_value"; $booking_values->{response_state} = "OK: bike " . $q->param('bike') . " unlocked confirmed. "; $booking_values->{response_text} = "Schloss öffnen von Rad " . $q->param('bike') . " bestätigt. "; }elsif($q->param('lock_state') eq "locking"){ $lock_value = 3; $update_cc->{int20} = "$lock_value"; $update_pos->{int20} = "$lock_value"; $booking_values->{response_state} = "OK: bike " . $q->param('bike') . " locking in progress. "; $booking_values->{response_text} = "Schloss schließen von Rad " . $q->param('bike') . " ist im Prozess. Bitte warten bis das smartlock vollständig geschlossen wurde und das Schloss schließen bestätigt wird. "; if($varenv->{dbname} ne "sharee_lv" && !$record_pos->{int32}){ $bw->log("$varenv->{basedir}/src/scripts/sms_message.pl $varenv->{syshost} locking_progress $auth->{c_id} $record_pos->{c_id}",$record_pos->{c_id},""); system("$varenv->{basedir}/src/scripts/sms_message.pl $varenv->{syshost} locking_progress $auth->{c_id} $record_pos->{c_id} &"); } $update_pos->{int32} = $record_pos->{int32} + 1;#sms_message sent marker }elsif($q->param('lock_state') eq "unlocking"){ $lock_value = 4; $update_cc->{int20} = "$lock_value"; $update_pos->{int20} = "$lock_value"; $booking_values->{response_state} = "OK: bike " . $q->param('bike') . " unlocking in progress. "; $booking_values->{response_text} = "Schloss öffnen von Rad " . $q->param('bike') . " ist im Prozess. "; } $dbt->update_record($dbh,$update_pos,$record_pos); $dbt->update_record($dbh,$update_cc,$record_cc); return $booking_values; }#end smartlock # #dedicated service insert automatic sub service_automatic { my $self = shift; my $q = shift || ""; my $current_percent = shift || 0; my $station_id = ""; my $bike_id = ""; $station_id = $1 if($q->param('station') =~ /(\d+)/);#could be also 0 $bike_id = $1 if($q->param('bike') && $q->param('bike') =~ /(\d+)/); my $authraw = { c_id => $owner };#default sys API my $charge = ""; if(looks_like_number($q->param('voltage'))){ $charge = "Achtung, Schloss-Akku Ladung " . $q->param('voltage') . "%"; } if(looks_like_number($q->param('charge_current_bars'))){ $charge = "Achtung, Fahr-Akku Ladung " . $current_percent . "%"; } my $response = {}; if(looks_like_number($bike_id) || looks_like_number($station_id)){ $q->param(-name=>'request',-value=>"service_done"); $q->param(-name=>'work_id',-value=>"txt01"); $q->param(-name=>'work_val',-value=>"$charge"); my $article = looks_like_number($bike_id) || looks_like_number($station_id); #insert only new dataset if mtime > 10 days (my $xresponse->{$article}, my $pos_record, my $node_template, my $crecord) = $self->service_select($q,$authraw,"","10"); my $service_id = ""; foreach my $id (sort { $pos_record->{$a}->{barcode} <=> $pos_record->{$b}->{barcode} } keys (%$pos_record)){ $service_id = $pos_record->{$id}->{c_id} if($pos_record->{$id}->{c_id} > 1); } if(!$service_id){ $crecord->{int04} = "null";#empty station ($response->{service_id}) = $self->service_insert($q,$authraw,$node_template,$crecord); $bw->log("service_automatic insert ($response->{service_id}) ",$response,""); my $rows = $self->service_update($q,$authraw,$node_template,$response->{service_id}); }elsif($service_id){ my $rows = $self->service_update($q,$authraw,$node_template,$service_id); } } } #user rentals_history sub user_rentals_history(){ my $self = shift; my $q = shift || ""; my $auth = shift; my $daily = shift || 0; my $allop = shift || 0; my %varenv = $cf->envonline(); my $today = strftime("%Y-%m-%d",localtime(time)); my %operator_hash = (); my $record_all = {}; if($auth->{c_id}){ my $pref = { table => "contenttrans", table_pos => "contenttranspos", fetch => "all", keyfield => "c_id", ca_id => "$auth->{c_id}", }; if($daily > 0){ $pref->{start_time} = ">=::$today"; }elsif(looks_like_number($q->param('month')) && $q->param('month') > 0){ my $month = $q->param('month'); $pref->{mtime} = ">=::(now() - interval '$month month')"; }else{ #2024-01-08 list not succesfully captured positions by also using ct.int14 >= 1 $pref->{'ct.state'} = "is::null";# OR ct.int14 >= 1 #$pref->{'ct.int14'} = "is::null"; } if($allop || $varenv{dbname} eq $dbt->{primary}->{sharee_primary}->{database}->{dbname}){ #$bw->log("user_rentals_history userID: $auth->{c_id} with operators",$auth->{txt17},""); if($auth->{txt17}){ if($auth->{txt17} =~ /\w\s\w/){ %operator_hash = map { $_ => "$dbt->{operator}{$_}->{operatorApp}" } split(/\s+/,$auth->{txt17}); }else{ $operator_hash{$auth->{txt17}} = "$dbt->{operator}{$auth->{txt17}}->{operatorApp}"; } #adding primary to get prepaid $operator_hash{sharee_primary} = "$dbt->{primary}{sharee_primary}->{primaryApp}" if($allop); foreach my $sharee_operator (keys (%operator_hash)){ #$bw->log("operator_hash sharee_operator: $sharee_operator",$sharee_operator,""); my $dbh_operator = ""; $dbh_operator = $dbt->dbconnect_extern("$sharee_operator"); if($dbh_operator){ my $cttpos = $dbt->collect_post($dbh_operator,$pref); $record_all = { %$record_all, %$cttpos }; } } } }else{ $record_all = $dbt->collect_post($dbh,$pref); } } return ($record_all,\%operator_hash); }#end user_rental_history #last used rental to feedback sub rental_to_feedback{ my $self = shift; my $varenv = shift; my $auth = shift; my $dbh = ""; my $pref = { table => "contenttrans", table_pos => "contenttranspos", fetch => "one", template_id => "218", ca_id => "$auth->{c_id}", "ct.close_time" => "is::null", int10 => "1", int11 => "3",#sig system int28 => "3",#set count on sig rental_end end_time => ">=::(now() - interval '5 min')", }; my $ctpos = { c_id => 0 }; $ctpos = $dbt->collect_post($dbh,$pref); my $show_dialog = {}; if($dbt->{operator}->{$varenv->{dbname}}->{project} eq "Bayern"){ my $dbh_primary = $dbt->dbconnect_extern($dbt->{primary}->{sharee_primary}->{database}->{dbname}); my $adref = { table => "contentadr", fetch => "one", template_id => "202", c_id => "$auth->{c_id}", }; my $auth_prim = $dbt->fetch_record($dbh_primary,$adref); if(!$auth_prim->{int23} || $auth_prim->{int23} < 4){ $bw->log("user_miniquery via user ID $auth_prim->{c_id} exist count:",$auth_prim->{int23},""); $show_dialog->{user_miniquery} = $dbt->evaluationsfragen($dbh); } $show_dialog->{co2saving} = ""; $ctpos->{int26} = 10 if(!$ctpos->{int26} && ($auth->{c_id} == 5781 || $auth->{c_id} == 38883));#10 km test if($ctpos->{int26}){ my $co2saving = "Einsparung: "; my $co2diff = $pri->co2calc($ctpos); #my $sprit_price = $pri->sprit2calc($ctpos); $co2saving .= "$co2diff kg CO2, "; #$co2saving .= "$sprit_price EUR " if($sprit_price !~ /-/); $ctpos->{int26} =~ s/\./,/; $co2saving .= "bei einer Strecke von $ctpos->{int26} KM"; $show_dialog->{co2saving} = $co2saving; } } return ($ctpos,$show_dialog); }#end rental_to_feedback #user bikes occupied sub user_bikes_occupied { my $self = shift; my $dbh = shift; my $auth = shift; my $show_dialog = shift || ""; my $station = shift || ""; my $pref = { table => "contenttrans", table_pos => "contenttranspos", fetch => "all", template_id => "218",#Faktura tpl_id keyfield => "c_id", ca_id => "$auth->{c_id}", int10 => "IN::('3','2')", "ct.close_time" => "is::null", }; $pref->{int06} = $station if($station);#pos start-station my $record = {}; $record = $dbt->collect_post($dbh,$pref) if($auth->{c_id}); return $record; }#end user_bikes_occupied #rentals #called by user_bikes_occupied (bikes_occupied object) sub rentals(){ my $self = shift; my $varenv_prim = shift; my $record = shift; my $auth = shift || ""; my $withkey = shift || 0; my %varenv = $cf->envonline(); my $today4db = strftime("%Y-%m-%d %H:%M:%S",localtime(time)); my $return = {}; foreach my $id (sort { $record->{$a}->{end_time} cmp $record->{$b}->{end_time} } keys (%$record)){ my $pricing->{$id} = {}; my $counting = {}; #adjusting freed time rental by called bikes_occupied #further_freedtime_available will be 0 if no further freed_time my $adjust_freedtime = 1; my $further_freedtime_available = 1; $further_freedtime_available = $pri->count_freedrental("rentals by user_bikes_occupied",\%varenv,$auth->{c_id},$record->{$id},$adjust_freedtime); $return->{$id}->{further_freedtime_available} = "$further_freedtime_available"; ($pricing->{$id}, $counting) = $pri->counting_rental(\%varenv,$record->{$id}); #$bw->log("rentals-rentalog",$pricing->{$id}->{rentalog},""); $pricing->{$id}->{rentalog} = "";#just for debuggiog, removed to reduce data in json my $return_feed->{$id} = $pri->fetch_rentalfeed($varenv_prim,\%varenv,$record->{$id},$pricing->{$id},$further_freedtime_available); $return->{$id} = { %{ $pricing->{$id} }, %{ $return_feed->{$id} } }; my $bike_id = $return->{$id}->{bike}; $bike_id = $1 if($bike_id =~ /(\d+)/); #generate always new ilockit keys. if($withkey && $record->{$id}->{int11} && $record->{$id}->{int11} == 2){ my @K_select = (); @K_select = `cd /var/www/copri4/main/src/scripts && export CLASSPATH='.:/usr/share/java:/usr/share/java/postgresql.jar' && java Ilockauth $varenv{dbname} $bike_id`; $bw->log("rentals java Ilockauth $bike_id | syshost:$varenv{syshost}",\@K_select,""); foreach(@K_select){ my ($K_key,$K_val) = split(/ = /, $_); $K_val =~ s/\n//g; $return->{$id}->{K_seed} = "$K_val" if($K_key eq "K_seed"); $return->{$id}->{K_a} = "$K_val" if($K_key eq "K_a" && $auth->{int19} && $auth->{int19} == 1); $return->{$id}->{K_u} = "$K_val" if($K_key eq "K_u"); } } $bw->log("user_bikes_occupied rentals bike $return->{$id}->{bike} | station $return->{$id}->{station} | state $return->{$id}->{state}, auth:$auth->{c_id}",$return->{$id}->{c_id},""); } return $return; }#end rentals #bikes_available sub bikes_available(){ my $self = shift; my $q = shift; my $varenv_prim = shift; my $varenv = shift; my $auth = shift; my $authed = 0; my $lang = "de"; my $station = $q->escapeHTML($q->param('station')) || ""; my $station_id = ""; $station_id = $1 if($station =~ /(\d+)$/); #to get A-A key for text my $pref_st = { table => "content", fetch => "all", keyfield => "int04", template_id => "225", int10 => "1", }; my $record_st = {}; $pref_st->{int04} = "$station_id" if($station_id); $record_st = $dbt->fetch_record($dbh,$pref_st); my $bike = $q->escapeHTML($q->param('bike')) || ""; my $bike_id = $bike; $bike_id =~ s/S[1-9]X/SX/; $bike_id = $1 if($bike_id =~ /(\d+)/); #my $users_serviceapp = $dbt->select_users($dbh,$auth->{c_id},"and int09=1"); my $return={}; my $pref = { table => "content", fetch => "all", keyfield => "barcode", template_id => "205", int10 => "1",#1 = "available" }; my $tariff_content = {}; my $adrtarif_hash = {}; $authed = 1 if(ref($auth) eq "HASH" && $auth->{c_id} > 0); (my $bike_group,my $bike_node,my $user_tour,$tariff_content,$adrtarif_hash) = $self->fetch_tariff($varenv->{dbname},$auth,$q->param('authcookie')); $bw->log("$varenv->{dbname} bikes_available bike_group:",$bike_group,""); #print Dumper($bike_group); #print Dumper($bike_node); my $main_ids = join(",",@{$bike_node}); $main_ids =~ s/[a-z_-]+//ig;#should work also without Trenner $pref = { %$pref, main_id => "IN::($main_ids)" }; if(looks_like_number($station_id)){ $pref = { %$pref, int04 => "=::" . $station_id }; } if(looks_like_number($bike_id)){ $pref = { %$pref, barcode => "=::" . $bike_id }; } my $record = {}; $record = $dbt->fetch_record($dbh,$pref) if(ref($bike_node) eq "ARRAY" && @{$bike_node}[0]); my $op_return = {}; my $td_template = $dbt->rental_description_template($varenv_prim); #return list of occupied/requested bikes my $adjust_freedtime = 0; my $further_freedtime_available = 1; my ($cttpos,$operator_hash) = $self->user_rentals_history($q,$auth,1,0); foreach my $id (sort { lc($cttpos->{$b}->{itime}) cmp lc($cttpos->{$a}->{itime}) } keys(%$cttpos)){ $further_freedtime_available = $pri->count_freedrental("rentals by bikes_available",$varenv,$auth->{c_id},$cttpos->{$id},$adjust_freedtime); } foreach my $id (sort { $record->{$a}->{barcode} <=> $record->{$b}->{barcode} } keys (%$record)){ $return->{$id}->{authed} = "$authed"; $return->{$id}->{station} = "$dbt->{operator}->{$varenv->{dbname}}->{oprefix}$record->{$id}->{int04}"; $return->{$id}->{aa_ride} = "0"; $return->{$id}->{aa_ride} = "1" if($record_st->{$record->{$id}->{int04}}->{int42}); $return->{$id}->{uri_operator} = "$dbt->{operator}->{$varenv->{dbname}}->{operatorApp}"; ($return->{$id}->{gps}->{latitude},$return->{$id}->{gps}->{longitude}) = split(/,/,$record->{$id}->{txt06}); $return->{$id}->{bike} = "$dbt->{operator}->{$varenv->{dbname}}->{oprefix}$record->{$id}->{barcode}"; my $description = $q->unescapeHTML($record->{$id}->{txt01}) || ""; $return->{$id}->{description} = "$description"; #$return->{$id}->{description} = Encode::encode('utf-8', Encode::decode('iso-8859-1', $description)); $return->{$id}->{state} = "$dbt->{copri_conf}->{bike_state}->{$record->{$id}->{int10}}"; $return->{$id}->{lock_state} = "$dbt->{copri_conf}->{lock_state}->{$record->{$id}->{int20}}"; #defaults $return->{$id}->{bike_group} = []; $return->{$id}->{bike_type}->{category} = "city"; $return->{$id}->{bike_type}->{wheels} = "2"; #for station_type_id mapping if($record->{$id}->{type_id}){ $return->{$id}->{bike_group} = ["$dbt->{operator}->{$varenv->{dbname}}->{oprefix}$record->{$id}->{type_id}"]; if($record->{$id}->{type_id} == 300101){ $return->{$id}->{bike_type}->{category} = "cargo"; $return->{$id}->{bike_type}->{wheels} = "2"; $return->{$id}->{bike_type}->{wheels} = "3" if($record->{$id}->{txt01} =~ /drei|trike/i); if($record->{$id}->{energy_id} || $record->{$id}->{txt01} =~ /E-/i){ $return->{$id}->{bike_type}->{engine}->{manufacturer} = "dummy"; my $max_bars = 5; my $current_bars = 0; my $charge_view_hidden = 0;#1=hide charge view #$charge_view_hidden = 0 if($dbt->{operator}->{$varenv->{dbname}}->{oprefix} =~ /BVB|FR|KN/); my $backend_accessible = 1; $backend_accessible = 0 if($record->{$id}->{int11} eq "2");#for asking user #$backend_accessible = 0 if($dbt->{operator}->{$varenv->{dbname}}->{oprefix} =~ /BVB|FR|KN/);#for asking user $return->{$id}->{bike_type}->{battery}->{charge_max_bars} = "$max_bars"; $return->{$id}->{bike_type}->{battery}->{charge_current_bars} = "$current_bars"; $return->{$id}->{bike_type}->{battery}->{charge_current_percent} = "0"; $return->{$id}->{bike_type}->{battery}->{hidden} = "$charge_view_hidden"; $return->{$id}->{bike_type}->{battery}->{backend_accessible} = "$backend_accessible"; if($record->{$id}->{int19}){ $current_bars = $bw->battery_bars($max_bars,$record->{$id}->{int19}); $return->{$id}->{bike_type}->{battery}->{charge_current_bars} = "$current_bars"; $return->{$id}->{bike_type}->{battery}->{charge_current_percent} = "$record->{$id}->{int19}"; } } } } if($record->{$id}->{int11} eq "2"){ $return->{$id}->{system} = "Ilockit"; $return->{$id}->{Ilockit_GUID} = "$record->{$id}->{txt17}"; $return->{$id}->{Ilockit_ID} = "$record->{$id}->{txt18}"; }elsif($record->{$id}->{int11} eq "3"){ $return->{$id}->{system} = "sigo"; } #2022-12-29 smartlock_type $return->{$id}->{smartlock_type}->{engine}->{manufacturer} = "$dbt->{copri_conf}->{lock_system}->{$record->{$id}->{int11}}"; $return->{$id}->{smartlock_type}->{battery}->{charge_current_percent} = "$record->{$id}->{int14}"; if(ref($tariff_content) eq "HASH"){ foreach my $tid (sort { $tariff_content->{$a}->{barcode} <=> $tariff_content->{$b}->{barcode} } keys (%$tariff_content)){ my $unit_price1 = $tariff_content->{$tid}->{int35}; my $unit_price2 = $tariff_content->{$tid}->{int36}; my $max_fee = $tariff_content->{$tid}->{int17}; my $unit_time = $tariff_content->{$tid}->{time01}; my $free_time = $tariff_content->{$tid}->{time02}; if($lang eq "de"){ $unit_price1 =~ s/\./,/ if(looks_like_number($unit_price1)); $unit_price2 =~ s/\./,/ if(looks_like_number($unit_price2)); $max_fee =~ s/\./,/ if(looks_like_number($max_fee)); } foreach my $atid (keys (%$adrtarif_hash)){ #print "if($record->{$id}->{main_id} == $tariff_content->{$tid}->{int12} && $atid == $tariff_content->{$tid}->{barcode}){\n"; if($record->{$id}->{main_id} == $tariff_content->{$tid}->{int12} && $atid == $tariff_content->{$tid}->{barcode}){ $bw->log("bikes_available for user c_id: $auth->{c_id} if($record->{$id}->{main_id} == $tariff_content->{$tid}->{int12} && $atid == $tariff_content->{$tid}->{barcode}) on BIKE:",$return->{$id}->{bike},""); $return->{$id}->{rental_description}->{name} = "$tariff_content->{$tid}->{ct_name}"; $return->{$id}->{rental_description}->{id} = "$tariff_content->{$tid}->{barcode}"; $return->{$id}->{rental_description}->{tarif_type} = "$adrtarif_hash->{$tariff_content->{$tid}->{barcode}}"; $return->{$id}->{rental_description}->{reserve_timerange} = "15"; $return->{$id}->{rental_description}->{reserve_timerange} = "30" if($record->{$id}->{int11} == 3);#sig timeout time $return->{$id}->{rental_description}->{rental_info}->{1} = ["Tracking","$varenv_prim->{cms}->{'info-tracking-degree'}->{txt}"] if($record->{$id}->{int25}); $return->{$id}->{rental_description}->{rental_info}->{2} = ["AAFahrten","$varenv_prim->{cms}->{'info-aa-ride'}->{txt}"] if($record_st->{$record->{$id}->{int04}}->{int42}); #$return->{$id}->{rental_description}->{rental_info}->{3} = ["Lowcharge","Die Akkukapazität war zuletzt niedrig. Bitte überprüfen sie vor der Fahrt die Ladung am Fahrraddisplay. Die Miete kann innerhalb 5 Minuten kostenlos abgebrochen werden."] if($record->{$id}->{energy_id} && (!$record->{$id}->{int19} || $record->{$id}->{int19} < 20)); my $i = 0; foreach my $td (sort keys (%$td_template)){ my $time_unit = "Min"; #print "$tid|$tariff_content->{$tid}->{barcode}|$tariff_content->{$tid}->{int35}|$tariff_content->{$tid}->{time02}\n"; if($td_template->{$td}->{int35} && looks_like_number($tariff_content->{$tid}->{int35})){ $time_unit = $dbt->time_format($varenv_prim,$tariff_content->{$tid}->{time01}) if($tariff_content->{$tid}->{time01} =~ /[1-9]/); $return->{$id}->{rental_description}->{tarif_elements}->{$td} = ["$td_template->{$td}->{int35}","$unit_price1 € / $time_unit"]; }elsif($td_template->{$td}->{int36} && $tariff_content->{$tid}->{int36} && $tariff_content->{$tid}->{int36} > 0){ $time_unit = $dbt->time_format($varenv_prim,$tariff_content->{$tid}->{time01}) if($tariff_content->{$tid}->{time01} =~ /[1-9]/); $return->{$id}->{rental_description}->{tarif_elements}->{$td} = ["$td_template->{$td}->{int36}", "$unit_price2 € / $time_unit"]; }elsif($td_template->{$td}->{int17} && $tariff_content->{$tid}->{int17} && $tariff_content->{$tid}->{int17} > 0){ $return->{$id}->{rental_description}->{tarif_elements}->{$td} = ["$td_template->{$td}->{int17}","$max_fee € / 24 $varenv_prim->{cms}->{'unit-hour'}->{txt}"]; }elsif($td_template->{$td}->{time02}){ if($tariff_content->{$tid}->{time02} =~ /[1-9]/){ if($further_freedtime_available == 1 || !$auth->{c_id}){ $time_unit = $dbt->time_format($varenv_prim,$tariff_content->{$tid}->{time02}); $time_unit .= " / $varenv_prim->{cms}->{'unit-day'}->{txt}" if($dbt->{operator}->{$varenv->{dbname}}->{project} ne "Konstanz"); $return->{$id}->{rental_description}->{tarif_elements}->{$td} = ["$td_template->{$td}->{time02}","$time_unit"]; } }else{ delete $return->{$id}->{rental_description}->{tarif_elements}->{$td}; } } }#end foreach my $td (sort keys (%$td_template)) } }#end foreach my $atid (keys (%$adrtarif_hash)) } } $op_return->{$dbt->{operator}->{$varenv->{dbname}}->{oprefix} . $id} = $return->{$id}; } return $op_return; }#end bikes_available #bikes_all sub bikes_all(){ my $self = shift; my $q = shift; my $varenv = shift; my $auth = shift || {}; my $stations_allraw = shift || ""; #my $users_serviceapp = $dbt->select_users($dbh,$auth->{c_id},"and int09=1"); my $return={}; my $pref = { table => "content", fetch => "all", keyfield => "barcode", template_id => "205", }; my ($bike_group,$bike_node,$user_tour,$tariff_content,$adrtarif_hash) = $self->fetch_tariff($varenv->{dbname},$auth,$q->param('authcookie')); my $main_ids = join(",",@{$bike_node}); $main_ids =~ s/[a-z_]+//ig; $pref->{main_id} = "IN::($main_ids)"; my $station_id = ""; my $bike_id = ""; #$station_id = $1 if($q->param('station') && $q->param('station') =~ /(\d+)/);#doesn't get 0 $station_id = $1 if($q->param('station') =~ /(\d+)/); $bike_id = $1 if($q->param('bike') && $q->param('bike') =~ /(\d+)/); $pref->{int04} = "=::$station_id" if(looks_like_number($station_id)); if(looks_like_number($bike_id)){ $pref->{ barcode} = "=::$bike_id"; #2022-12-02 not select occupied bikes in servicetool by direct select-bike $pref->{int10} = "!=::3"; #}else{ #2023-05-23 not select requested and occupied bikes in servicetool by list-bikes? #$pref->{int10} = "IN::(1,4,5,6)"; } my $record = {}; #on servicetool only stations on user_tour #$bw->log("stations_service_tour of adr c_id: $auth->{c_id}",$stations_allraw,""); my @stations_service_tour = (); #shareetool if(!$pref->{int04} && $q->param('authcookie') && $dbt->{merchant_ids}->{$varenv->{merchant_id}}->{id} && $dbt->{merchant_ids}->{$varenv->{merchant_id}}->{id} == 187){ my $stations = ""; if(ref($stations_allraw) eq "HASH" && scalar(@{$user_tour} >= 1)){ foreach my $id (sort { $stations_allraw->{$a}->{int04} <=> $stations_allraw->{$b}->{int04} } keys (%$stations_allraw)){ push(@stations_service_tour, $stations_allraw->{$id}->{int04}) if(looks_like_number($stations_allraw->{$id}->{int04})); } $stations = join(",",@stations_service_tour); $stations =~ s/[a-z_]+//ig; $pref->{int04} = "IN::($stations)" if($stations || $stations eq "0"); } } $bw->log("sub bikes_all with user_tour ($station_id) @stations_service_tour",$pref,""); $record = $dbt->fetch_record($dbh,$pref) if(ref($bike_node) eq "ARRAY" && @{$bike_node}[0]); my $bikes_on_station = {}; my $op_return = {}; foreach my $id (sort { $record->{$a}->{barcode} <=> $record->{$b}->{barcode} } keys (%$record)){ if(1==1){ $bikes_on_station->{$record->{$id}->{int04}}->{bike_ist} += 1; $return->{$id}->{uri_operator} = "$dbt->{operator}->{$varenv->{dbname}}->{operatorApp}"; $return->{$id}->{station} = "$dbt->{operator}->{$varenv->{dbname}}->{oprefix}$record->{$id}->{int04}"; ($return->{$id}->{gps}->{latitude},$return->{$id}->{gps}->{longitude}) = split(/,/,$record->{$id}->{txt06}); $return->{$id}->{bike} = "$dbt->{operator}->{$varenv->{dbname}}->{oprefix}$record->{$id}->{barcode}"; my $description = $q->unescapeHTML($record->{$id}->{txt01}) || ""; $return->{$id}->{description} = "$description"; #$return->{$id}->{description} = Encode::encode('utf-8', Encode::decode('iso-8859-1', $description)); $return->{$id}->{state} = "$dbt->{copri_conf}->{bike_state}->{$record->{$id}->{int10}}"; $return->{$id}->{service_state} = "0"; $return->{$id}->{lock_state} = "$dbt->{copri_conf}->{lock_state}->{$record->{$id}->{int20}}"; #defaults $return->{$id}->{bike_group} = []; $return->{$id}->{bike_type}->{category} = "city"; $return->{$id}->{bike_type}->{wheels} = "2"; #for station_type_id mapping if($record->{$id}->{type_id}){ $return->{$id}->{bike_group} = ["$dbt->{operator}->{$varenv->{dbname}}->{oprefix}$record->{$id}->{type_id}"]; if($record->{$id}->{type_id} == 300101){ $return->{$id}->{bike_type}->{category} = "cargo"; $return->{$id}->{bike_type}->{wheels} = "2"; $return->{$id}->{bike_type}->{wheels} = "3" if($record->{$id}->{txt01} =~ /drei|trike/i); if($record->{$id}->{energy_id} || $record->{$id}->{txt01} =~ /E-/i){ $return->{$id}->{bike_type}->{engine}->{manufacturer} = "dummy"; my $max_bars = 5; my $current_bars = 0; my $charge_view_hidden = 0;#1=hide charge view #$charge_view_hidden = 0 if($dbt->{operator}->{$varenv->{dbname}}->{oprefix} =~ /BVB|FR|KN/); my $backend_accessible = 1;#1=battery charge from backend, 0=asking user $backend_accessible = 0 if($record->{$id}->{int11} eq "2");#for asking user #$backend_accessible = 0 if($dbt->{operator}->{$varenv->{dbname}}->{oprefix} =~ /BVB|FR|KN/);#for asking user $return->{$id}->{bike_type}->{battery}->{charge_max_bars} = "$max_bars"; $return->{$id}->{bike_type}->{battery}->{charge_current_bars} = "$current_bars"; $return->{$id}->{bike_type}->{battery}->{charge_current_percent} = "0"; $return->{$id}->{bike_type}->{battery}->{hidden} = "$charge_view_hidden"; $return->{$id}->{bike_type}->{battery}->{backend_accessible} = "$backend_accessible"; if($record->{$id}->{int19}){ $current_bars = $bw->battery_bars($max_bars,$record->{$id}->{int19}); $return->{$id}->{bike_type}->{battery}->{charge_current_bars} = "$current_bars"; $return->{$id}->{bike_type}->{battery}->{charge_current_percent} = "$record->{$id}->{int19}"; } } } } if($record->{$id}->{int11} eq "2"){ $return->{$id}->{system} = "Ilockit"; $return->{$id}->{Ilockit_GUID} = "$record->{$id}->{txt17}"; $return->{$id}->{Ilockit_ID} = "$record->{$id}->{txt18}"; #shareetool servicetool #if($q->param('authcookie') && $dbt->{merchant_ids}->{$varenv->{merchant_id}}->{id} && $dbt->{merchant_ids}->{$varenv->{merchant_id}}->{id} == 187 && scalar(@{$user_tour} >= 1)){ if($q->param('authcookie') && $varenv->{merchant_id} && $varenv->{merchant_id} eq $dbt->{appsframe}->{shareetool}->{merchant_id} && scalar(@{$user_tour} >= 1)){ #2023-01-18 temporarly for Konstanz deactivated if(${$user_tour}[0] !~ /KN\d/){ my @service_code = split(/\s/,$record->{$id}->{txt23}); $return->{$id}->{service_code} = [@service_code]; } } }elsif($record->{$id}->{int11} eq "3"){ $return->{$id}->{system} = "sigo"; } #2022-12-29 smartlock_type $return->{$id}->{smartlock_type}->{engine}->{manufacturer} = "$dbt->{copri_conf}->{lock_system}->{$record->{$id}->{int11}}"; $return->{$id}->{smartlock_type}->{battery}->{charge_current_percent} = "$record->{$id}->{int14}"; $op_return->{$dbt->{operator}->{$varenv->{dbname}}->{oprefix} . $id} = $return->{$id}; } } return ($op_return,$record,$bikes_on_station); }#end bikes_all #station caching for each tarif sub stations_caching { my $self = shift; my $q = shift || ""; my $varenv = shift; my $auth = shift || ""; my $tariff = { table => "content", fetch => "all", keyfield => "barcode", template_id => "210",#Tariff tpl_id }; my $tariff_all = $dbt->fetch_record($dbh,$tariff); if(ref($tariff_all) eq "HASH"){ foreach my $cachme (keys (%$tariff_all)){ $self->stations_available($q,$varenv,$auth,"",$cachme); } } return; } #stations_available sub stations_available(){ my $self = shift; my $q = shift || ""; my $varenv = shift; my $auth = shift || ""; my $record_pos = shift || {}; my $cachme = shift || 0; my $authed = 0; $authed = 1 if(ref($auth) eq "HASH" && $auth->{c_id}); my $authcookie = $q->param('authcookie') || $q->cookie('domcookie'); my ($bike_group,$bike_node,$user_tour,$tariff_content,$adrtarif_hash) = $self->fetch_tariff($varenv->{dbname},$auth,$authcookie,$cachme); #$bw->log("fetch_tariff adrtarif_hash from $varenv->{dbname}\n",$adrtarif_hash,""); #station_group and bike_group alias bike nodes.type_id my $station_group = ""; $station_group = $record_pos->{int29} if(ref($record_pos) eq "HASH" && $record_pos->{int29}); #station_bike_node and bike_node alias bike nodes.main_id my $station_bike_node = ""; $station_bike_node = $record_pos->{int12} if(ref($record_pos) eq "HASH" && $record_pos->{int12}); #for AA rentals take end- from start-station. my $aa_station = 0; $aa_station = $record_pos->{int06} if(ref($record_pos) eq "HASH" && $record_pos->{int06} && $record_pos->{int42}); my $return = {}; my $pref = { table => "content", fetch => "all", keyfield => "int04", template_id => "225", int10 => "1",#1 = "available" }; #select by bike.type_id bike-group on booking update, to get available stations on bike return by filter logic my $pref_sql = ""; if(ref($record_pos) eq "HASH" && $record_pos->{int29}){ foreach my $type_id (@{$bike_group}){ #service user can redistribute to all if($auth->{int09} && !$dbt->{copri_conf}->{betau_id}->{$auth->{c_id}}){ $pref_sql = ""; } #A-A rental #on rental-end select only station which is the same as on start and A-A elsif($station_group && $type_id =~ /(\d+)/ && $aa_station){ my $group_id = $1; if($group_id == $station_group){ $pref_sql = " and ct.int04 = $aa_station and ct.int42=1"; } } #A-B rental #on rental-end select only stations which are in ststion_group and be A-B elsif($station_group && $type_id =~ /(\d+)/){ my $group_id = $1; if($group_id == $station_group){ $pref_sql = " and ct.txt25 like '%$group_id%' and (ct.int42=0 OR ct.int42 is null)"; } } } } #select by bike.main_id Flot only if no booking update, to keep private/hidden Tarif logic else{ $pref_sql .= " and ("; foreach my $main_id (@{$bike_node}){ if($main_id =~ /(\d+)/){ my $node_id = $1; $pref_sql .= " ct.txt24 like '%$node_id%' OR"; } } $pref_sql =~ s/OR$//; $pref_sql .= ")"; } $pref_sql = "" if($pref_sql !~ /\d/); $bw->log("stations_available --> rental station_bike_node:$station_bike_node|rental aa_station:$aa_station|user has access to bike_node:@{$bike_node}|user has access to bike_group:@{$bike_group}|!$auth->{int09} && !$dbt->{copri_conf}->{betau_id}->{$auth->{c_id}}|pref_sql:\n",$pref_sql,""); my $record = {}; $record = $dbt->fetch_record($dbh,$pref,$pref_sql) if(ref($bike_node) eq "ARRAY" && @{$bike_node}[0]); #bike_count my $bpref = { table => "content", fetch => "all", keyfield => "barcode", template_id => "205", int10 => "1", }; my $record_bikes = {}; $record_bikes = $dbt->fetch_record($dbh,$bpref,""); my $hotline_hash = { table => "contentuser", fetch => "one", template_id => 197, c_id => "1", }; my $hotline_data = $dbt->fetch_record($dbh,$hotline_hash); my $op_return = {}; foreach my $id (sort { $record->{$a}->{barcode} <=> $record->{$b}->{barcode} } keys (%$record)){ $record->{$id}->{txt06} =~ s/\s//g if($record->{$id}->{txt06}); if($record->{$id}->{txt06} && $record->{$id}->{txt06} =~ /\d+\.\d+\,\d+\.\d+/){ my $bike_count = 0; my @bike_ids = (); foreach my $b_id (keys (%$record_bikes)){ if($record->{$id}->{int04} == $record_bikes->{$b_id}->{int04}){ push @bike_ids,$dbt->{operator}->{$varenv->{dbname}}->{oprefix} . $record_bikes->{$b_id}->{barcode}; $bike_count++; } } $return->{$id}->{bike_count} = "$bike_count"; $return->{$id}->{bike_ids} = [@bike_ids]; $return->{$id}->{authed} = "$authed"; $return->{$id}->{capacity} = "$record->{$id}->{int05}" || "1"; $return->{$id}->{station} = "$dbt->{operator}->{$varenv->{dbname}}->{oprefix}$record->{$id}->{int04}"; $return->{$id}->{uri_operator} = "$dbt->{operator}->{$varenv->{dbname}}->{operatorApp}"; ($return->{$id}->{gps}->{latitude},$return->{$id}->{gps}->{longitude}) = split(/,/,$record->{$id}->{txt06}); my $description = $q->unescapeHTML($record->{$id}->{txt01}) || ""; $return->{$id}->{description} = "$description"; $return->{$id}->{state} = "$dbt->{copri_conf}->{bike_state}->{$record->{$id}->{int10}}"; $return->{$id}->{gps_radius} = "$record->{$id}->{int06}"; #new station category #defaults $return->{$id}->{station_type} = {}; my @station_group = (); if($record->{$id}->{txt25} && $record->{$id}->{txt25} =~ /\d\s\d/){ @station_group = split(/\s/,$record->{$id}->{txt25}); }elsif($record->{$id}->{txt25}){ @station_group = ("$record->{$id}->{txt25}"); } foreach(@station_group){ if($_ && $dbt->{copri_conf}->{type_id}->{$_}){ $return->{$id}->{station_type}->{$dbt->{copri_conf}->{type_id}->{$_}}->{bike_group} = "$dbt->{operator}->{$varenv->{dbname}}->{oprefix}$_"; my $bike_count2 = 0; foreach my $b_id (keys (%$record_bikes)){ if($record->{$id}->{int04} == $record_bikes->{$b_id}->{int04}){ $bike_count2++ if($_ == $record_bikes->{$b_id}->{type_id}); } } $return->{$id}->{station_type}->{$dbt->{copri_conf}->{type_id}->{$_}}->{bike_count} = "$bike_count2"; } } #deprecated $return->{$id}->{station_group} = ""; if($record->{$id}->{txt25}){ $record->{$id}->{txt25} =~ s/(\d+)/$dbt->{operator}->{$varenv->{dbname}}->{oprefix}$1/g; my @station_group = split(/\s/,$record->{$id}->{txt25}); $return->{$id}->{station_group} = [@station_group]; } $return->{$id}->{operator_data} = { "operator_name" => "", "operator_hours" => "", "operator_phone" => "", "operator_email" => "", }; $return->{$id}->{operator_data}->{operator_name} = Encode::encode('utf-8', Encode::decode('iso-8859-1',$hotline_data->{txt01})) if($hotline_data->{txt01}); $return->{$id}->{operator_data}->{operator_hours} = Encode::encode('utf-8', Encode::decode('iso-8859-1',$hotline_data->{txt84})) if($hotline_data->{txt84}); $return->{$id}->{operator_data}->{operator_phone} = $hotline_data->{txt07} if($hotline_data->{txt07}); $return->{$id}->{operator_data}->{operator_email} = $hotline_data->{txt08} if($hotline_data->{txt08}); $return->{$id}->{cached} = "0"; $return->{$id}->{withpub} = "0"; if($dbt->{operator}->{$varenv->{dbname}}->{cache_station} == 1 && $cachme){ $return->{$id}->{cached} = "1"; foreach my $tarif_key (keys(%$adrtarif_hash)){ $return->{$id}->{withpub}= "1" if($adrtarif_hash->{$tarif_key} == 2); } } $op_return->{$dbt->{operator}->{$varenv->{dbname}}->{oprefix} . $id} = $return->{$id}; } } #json caching if($dbt->{operator}->{$varenv->{dbname}}->{cache_station} == 1 && $cachme){ #order by sharing_type foreach my $tarif_key (keys(%$adrtarif_hash)){ my $stationsout = $json->pretty->encode($op_return); if($cachme){ #not public if($adrtarif_hash->{$tarif_key} == 3 || $adrtarif_hash->{$tarif_key} == 4){ $bw->log("tarif_key: $tarif_key, sharing_type: $adrtarif_hash->{$tarif_key} Trigger json-caching stations-$dbt->{operator}->{$varenv->{dbname}}->{oprefix}$tarif_key.json by cachme:$cachme","",""); open(CACHE,">$dbt->{copri_conf}->{basedir}/$dbt->{operator}->{$varenv->{dbname}}->{dir_app}/json/stations-$dbt->{operator}->{$varenv->{dbname}}->{oprefix}$tarif_key.json"); print CACHE $stationsout; close(CACHE); } #public else{ $bw->log("tarif_key: $tarif_key, sharing_type: $adrtarif_hash->{$tarif_key} Trigger json-caching stations-$dbt->{operator}->{$varenv->{dbname}}->{oprefix}.json by cachme:$cachme","",""); open(CACHE,">$dbt->{copri_conf}->{basedir}/$dbt->{operator}->{$varenv->{dbname}}->{dir_app}/json/stations-$dbt->{operator}->{$varenv->{dbname}}->{oprefix}.json"); print CACHE $stationsout; close(CACHE); } } } }#end caching return ($op_return, $record); }#end stations_available #stations_all (should only called by shareetool) sub stations_all(){ my $self = shift; my $q = shift || ""; my $varenv = shift; my $bikes_on_station = shift || {}; my $auth = shift || ""; my $authed = 0; $authed = 1 if(ref($auth) eq "HASH" && $auth->{c_id}); my ($bike_group,$bike_node,$user_tour,$tariff_content,$adrtarif_hash) = $self->fetch_tariff($varenv->{dbname},$auth,$q->param('authcookie')); my $return={}; my $pref = { table => "content", fetch => "all", keyfield => "int04", template_id => "225",#Station_liste }; my $station_id = ""; my $work_val_id = ""; $station_id = $1 if($q->param('station') =~ /(\d+)/);#could be also 0 $work_val_id = $1 if($q->param('work_val') && $q->param('work_val') =~ /(\d+)/); if(looks_like_number($station_id)){ $pref->{int04} = "=::$station_id"; }elsif($q->param('work_id') && $q->param('work_id') eq "int04" && $work_val_id){ $pref->{int04} = "=::$work_val_id"; } #if not shareetool then only available stations $pref->{int10} = 1 if(!$q->param('authcookie') || !$varenv->{merchant_id} || !$dbt->{merchant_ids}->{$varenv->{merchant_id}}->{id} || $dbt->{merchant_ids}->{$varenv->{merchant_id}}->{id} != 187); my $pref_sql = ""; $pref_sql .= " and ("; foreach(@{$bike_node}){ if($_ =~ /(\d+)/){ $pref_sql .= " ct.txt24 like '%$1%' OR"; } } $pref_sql =~ s/OR$//; $pref_sql .= ")"; $pref_sql = "" if($pref_sql !~ /\d/); my $record = {}; my $op_return = {}; my %user_tour = (); #on servicetool only stations on user_tour #shareetool #$bw->log("stations user_tour by merchant id $dbt->{merchant_ids}->{$varenv->{merchant_id}}->{id} on $varenv->{dbname}",$user_tour,""); if($q->param('authcookie') && $dbt->{merchant_ids}->{$varenv->{merchant_id}}->{id} && $dbt->{merchant_ids}->{$varenv->{merchant_id}}->{id} == 187){ if(scalar(@{$user_tour}) >= 1){ $pref_sql .= " AND ("; foreach(@{$user_tour}){ if($_ =~ /(\d+)/){ #$pref_sql .= " ct.int07=$1 OR"; $user_tour{$1} = 1; $pref_sql .= " ct.txt07 like '%$1%' OR"; } } $pref_sql =~ s/OR$//; $pref_sql .= ")"; $record = $dbt->fetch_record($dbh,$pref,$pref_sql) if(ref($bike_node) eq "ARRAY" && @{$bike_node}[0]); } } #only nececarry if amount of available bikes lower then bike_soll (like konrad) my $bike_ist_factor = 1; #($bike_ist_factor,my $bikes_all_onstation,my $bike_soll_all) = $self->bikes_soll($record,$bikes_on_station); #$bike_ist_factor = 1 if(!$bike_ist_factor || $bike_ist_factor > 1); foreach my $id (sort { $record->{$a}->{barcode} <=> $record->{$b}->{barcode} } keys (%$record)){ my $bike_soll = $record->{$id}->{int05} || 0;# * $bike_ist_factor; #my $bike_soll = $record->{$id}->{int05} * $bike_ist_factor; #$bike_soll = $lb->round_half($bike_soll); #$bike_soll =~ s/\.\d+//;#rounded integer #$return->{$id}->{bike_ist_faktor} = "$bike_ist_factor|$bikes_all_onstation|$bike_soll_all";#debug #"bike_ist_faktor" : "1.14|217|190", 2023-11-24 there are more bikes on station then soll $return->{$id}->{authed} = "$authed"; $return->{$id}->{station} = "$dbt->{operator}->{$varenv->{dbname}}->{oprefix}$record->{$id}->{int04}"; $return->{$id}->{service_tour} = ""; #hashed because of one station can have multi station tour #there is a restriction in servicetool because of service_tour assignment (can keep only one value) #keep in mind to select only users user_tour which in service_tour, #because there can only one station assignmemt. Should be array, also in shareetool! my %station_tour = (); if($record->{$id}->{txt07} && $record->{$id}->{txt07} =~ /\d\s\d/){ %station_tour = map { $_ => 1 } split(/\s+/,$record->{$id}->{txt07}); }elsif($record->{$id}->{txt07}){ $station_tour{$record->{$id}->{txt07}} = 1; } #if multi station tour defined then last numerical will assigend foreach my $stour (sort { $a <=> $b }keys (%user_tour)){ if($station_tour{$stour}){ $return->{$id}->{service_tour} = "$dbt->{operator}->{$varenv->{dbname}}->{oprefix}$stour"; } } $return->{$id}->{uri_operator} = "$dbt->{operator}->{$varenv->{dbname}}->{operatorApp}"; ($return->{$id}->{gps}->{latitude},$return->{$id}->{gps}->{longitude}) = split(/,/,$record->{$id}->{txt06}); if($record->{$id}->{description}){ my $description = $q->unescapeHTML($record->{$id}->{txt01}) || ""; $return->{$id}->{description} = "$description"; #$return->{$id}->{description} = Encode::encode('utf-8', Encode::decode('iso-8859-1', $description)); }else{ $return->{$id}->{description} = "---"; } $return->{$id}->{state} = "$dbt->{copri_conf}->{bike_state}->{$record->{$id}->{int10}}"; $return->{$id}->{bike_soll} = "$bike_soll" || "0"; $return->{$id}->{bike_ist} = "$bikes_on_station->{$id}->{bike_ist}" || "0"; $return->{$id}->{station_group} = ""; $return->{$id}->{gps_radius} = "$record->{$id}->{int06}"; if($record->{$id}->{txt25}){ $record->{$id}->{txt25} =~ s/(\d+)/$dbt->{operator}->{$varenv->{dbname}}->{oprefix}$1/g; my @station_group = split(/\s/,$record->{$id}->{txt25}); $return->{$id}->{station_group} = [@station_group]; } $op_return->{$dbt->{operator}->{$varenv->{dbname}}->{oprefix} . $id} = $return->{$id}; } return ($op_return,$record); }#end stations_all #collect all bike_ist sub bikes_soll(){ my $self = shift; my $record = shift; my $bikes_on_station = shift; my $bike_soll_all = 0; foreach my $id (sort { $record->{$a}->{barcode} <=> $record->{$b}->{barcode} } keys (%$record)){ $bike_soll_all += $record->{$id}->{int05}; } #my $bikes_on_station_ist->{bikes_all} = '0'; my $bikes_on_station_ist->{bikes_all_onstation} = '0'; if(ref($bikes_on_station) eq "HASH"){ foreach my $st (keys(%$bikes_on_station)){ #$bikes_on_station_ist->{bikes_all} += $bikes_on_station->{$st}->{bike_ist};#incl st.0 $bikes_on_station_ist->{bikes_all_onstation} += $bikes_on_station->{$st}->{bike_ist} if($st > 0); } } my $bike_ist_factor = 1; if(looks_like_number($bikes_on_station_ist->{bikes_all_onstation}) && $bikes_on_station_ist->{bikes_all_onstation} > 0 && looks_like_number($bike_soll_all) && $bike_soll_all > 0){ $bike_ist_factor = sprintf('%.2f',$bikes_on_station_ist->{bikes_all_onstation} / $bike_soll_all); } return ($bike_ist_factor,$bikes_on_station_ist->{bikes_all_onstation},$bike_soll_all); } #Collect Tarif to get users bike access ---------------------- sub fetch_tariff(){ my $self = shift; my $dbname = shift; my $adr = shift || {}; my $authcookie = shift || ""; my $cachme = shift || 0; my $merchant_id = ""; $merchant_id = $1 if($authcookie && $authcookie =~ /\w+_(\w+)$/); my $tariff_all = ""; my @user_tour = (); my $auth_operator = { c_id => 0, txt30 => "" }; #int18 # # 2 = "public" # 3 = "private" # 4 = "hidden-lv" # 5 = "public-bonus" # my $tariff = { table => "content", fetch => "all", keyfield => "barcode", template_id => "210",#Tariff tpl_id }; my ($nodes,$rows) = $dbt->collect_node($dbh,$dbt->{shareedms_conf}->{waren}); #public caching if($cachme eq "public"){ $tariff->{int18} = 2; $tariff_all = $dbt->fetch_record($dbh,$tariff); $bw->log("$dbname $cachme Tariff type for No operator registered user by int18:$tariff->{int18} select 1:",$tariff->{barcode},""); } elsif(looks_like_number($cachme) && $cachme > 0){ $tariff->{barcode} = $cachme; $tariff_all = $dbt->fetch_record($dbh,$tariff); if($tariff_all->{$cachme}->{int18} == 2 || $tariff_all->{$cachme}->{int18} == 5){ delete $tariff->{barcode}; $tariff->{int18} = 2; $tariff_all = $dbt->fetch_record($dbh,$tariff); }else{ $auth_operator = { txt30 => "$cachme" }; } $bw->log("$dbname $cachme Tariff type for No operator registered user by barcode:$tariff->{barcode} OR int18: $tariff->{int18} select 2:",$tariff->{barcode},""); } #if no primary address then only 2=public elsif((ref($adr) ne "HASH" || !$adr->{c_id}) && ($dbname ne "sharee_lv")){ $tariff->{int18} = 2; $tariff_all = $dbt->fetch_record($dbh,$tariff); $bw->log("$dbname Tariff type for No operator registered user by int18:$tariff->{int18} select 3:",$tariff->{barcode},""); } #select operators address to get users tarifnr array in txt30 elsif(ref($adr) eq "HASH" && $adr->{c_id}){ delete $tariff->{int18} if($tariff->{int18}); my $authref = { table => "contentadr", fetch => "one", template_id => "202", c_id => "=::$adr->{c_id}", }; $auth_operator = $dbt->fetch_record($dbh,$authref); #shareetool user_tour if($auth_operator->{c_id} && $merchant_id && $dbt->{merchant_ids}->{$merchant_id}->{id} && $dbt->{merchant_ids}->{$merchant_id}->{id} == 187){ my $users_serviceapp = $dbt->select_users($dbh,$auth_operator->{c_id},"and int09=1"); if($users_serviceapp->{int09} && $users_serviceapp->{txt07}){ $users_serviceapp->{txt07} =~ s/(\d+)/$dbt->{operator}->{$dbname}->{oprefix}$1/g; @user_tour = ($users_serviceapp->{txt07}); @user_tour = split(/\s/,$users_serviceapp->{txt07}) if($users_serviceapp->{txt07} =~ /\s/); } }#end user_tour #4=hidden if($dbname eq "sharee_lv"){ if($auth_operator->{txt30}){ $tariff->{int18} = 4; }else{ $tariff->{int18} = 9;#disables because not defined } } #else select all available user tarif entries $tariff_all = $dbt->fetch_record($dbh,$tariff); $bw->log("$dbname Tariff type for operator registered user with Tarif in txt30:$auth_operator->{txt30} with s-type int18:$tariff->{int18} select 4:",$auth_operator->{txt30},""); } #end operators address else{ $bw->log("$dbname Tariff type NO tariff_all 4:","",""); } my $oprefix = ""; $oprefix = "$dbt->{operator}->{$dbname}->{oprefix}" if($dbt->{operator}->{$dbname}->{oprefix}); #2023-03-13, just hash all tarif_type by tarif-Nr #collect setted user tarifs and available public tarifs my %tarif_hash = (); my %adrtarif_hash = (); my %bike_node = (); my %bike_group = (); if($auth_operator->{txt30} && $auth_operator->{txt30} =~ /\d\s\d/){ %tarif_hash = map { $_ => 1 } split(/\s+/,$auth_operator->{txt30}); }elsif($auth_operator->{txt30} && $auth_operator->{txt30} =~ /(\d+)/){ $tarif_hash{$1} = 1; } if(ref($tariff_all) eq "HASH"){ foreach my $rid (keys (%$tariff_all)){ #$bw->log("$dbname Tariff hash $auth_operator->{txt30}|$tariff_all->{$rid}->{barcode} --> $tarif_hash{$tariff_all->{$rid}->{barcode}}",\%tarif_hash,""); if(ref(\%tarif_hash) eq "HASH" && $tarif_hash{$tariff_all->{$rid}->{barcode}}){ foreach my $tk (keys(%tarif_hash)){ $bw->log("Tarif FOUND condition: $tk && $rid && $tariff_all->{$rid}->{barcode} == $tk","",""); if($tk && $rid && $tariff_all->{$rid}->{barcode} == $tk){ $adrtarif_hash{$tariff_all->{$rid}->{barcode}} = $tariff_all->{$rid}->{int18} if($tariff_all->{$rid}->{int18}); $bw->log("Tarif FOUND with merchant $merchant_id with user-id $auth_operator->{c_id} if($tariff_all->{$rid}->{int12}) (s-type:$tariff_all->{$rid}->{int18})",$tariff_all->{$rid}->{barcode},""); $bike_node{$oprefix . $tariff_all->{$rid}->{int12}} = 1;#sharee bike_node.main_id my $type_id = $nodes->{$tariff_all->{$rid}->{int12}}->{type_id} || ""; $bike_group{$oprefix . $type_id} = 1 if($type_id);#sharee bike_node.type_id } } }elsif($tariff_all->{$rid}->{int18} == 2){ $adrtarif_hash{$tariff_all->{$rid}->{barcode}} = $tariff_all->{$rid}->{int18}; $bw->log("Tarif FOUND with merchant $merchant_id without user-id! if($tariff_all->{$rid}->{int12}) (s-type:$tariff_all->{$rid}->{int18})",$tariff_all->{$rid}->{barcode},""); $bike_node{$oprefix . $tariff_all->{$rid}->{int12}} = 1;#sharee bike_node.main_id my $type_id = $nodes->{$tariff_all->{$rid}->{int12}}->{type_id} || ""; $bike_group{$oprefix . $type_id} = 1 if($type_id);#sharee bike_node.type_id } } } my @tarifnr = (); my @bike_node = (); my @bike_group = (); @tarifnr = keys %adrtarif_hash; @bike_node = keys %bike_node; @bike_group = keys %bike_group; $bw->log("Tarif FOUND FETCHED_Tarif by dbname:$dbname with merchant $merchant_id and optional userID $adr->{c_id} | bike_node:@bike_node | bike_group:@bike_group | user_tour:@user_tour | tarifnr: @tarifnr",\%adrtarif_hash,""); return (\@bike_group,\@bike_node,\@user_tour,$tariff_all,\%adrtarif_hash); }#end fetch_tariff #check and set user-bike rental tarif sub fetch_bike_tariff { my $self = shift; my $varenv = shift; my $auth = shift; my $bike = shift; my $owner = shift; my $bike_id = $bike || ""; $bike_id =~ s/S[1-9]X/SX/; $bike_id = $1 if($bike_id =~ /(\d+)/); my $main_ids = ""; my ($bike_group,$bike_node,$user_tour,$tariff_content,$adrtarif_hash) = $self->fetch_tariff($varenv->{dbname},$auth,""); $main_ids = join(",",@{$bike_node}); $main_ids =~ s/[a-z_]+//ig; my $ct_bike = {}; my $pref_cc = { table => "content", fetch => "one", main_id => "IN::($main_ids)", barcode => $bike_id, template_id => 205, #int10 => 1, }; $ct_bike = $dbt->fetch_record($dbh,$pref_cc) if($main_ids); #$tariff_nr in contentadr are saved by copri or user tarif-select!!! my $tariff_nr = ""; my @adr_tariff = (); if($auth->{txt30}){ @adr_tariff = ("$auth->{txt30}"); @adr_tariff = split(/\s+/,$auth->{txt30}) if($auth->{txt30} =~ /\w\s+\w/); } #This is the automatic user tariff setter if(ref($ct_bike) eq "HASH" && $ct_bike->{main_id}){ foreach my $id (keys (%$tariff_content)){ foreach(@adr_tariff){ $bw->log("booking_request adr_tariff array form $auth->{txt30}",$_,""); if($tariff_content->{$id}->{int12} && $tariff_content->{$id}->{int12} == $ct_bike->{main_id} && $tariff_content->{$id}->{barcode} && $_ == $tariff_content->{$id}->{barcode}){ $bw->log("booking_request tariff loop matches:",$tariff_content->{$id}->{barcode},""); $tariff_nr = $tariff_content->{$id}->{barcode}; } } } #if no tarif then update user account to fallback default public or private or hidden tarif if(!$tariff_nr){ my $update_adr = { table => "contentadr", mtime => "now()", owner => "$owner", c_id => "$auth->{c_id}", }; my @txt30 = (); foreach my $id (keys (%$tariff_content)){ # if($tariff_content->{$id}->{int18} && ($tariff_content->{$id}->{int18} == 2 || $tariff_content->{$id}->{int18} == 3 || $tariff_content->{$id}->{int18} == 4)){ #auto set tarif if requested bike matches flot if($tariff_content->{$id}->{int12} && $tariff_content->{$id}->{int12} == $ct_bike->{main_id} && $tariff_content->{$id}->{barcode}){ $bw->log("booking_request tariff loop matches:",$tariff_content->{$id}->{barcode},""); $tariff_nr = $tariff_content->{$id}->{barcode}; push(@txt30, "$tariff_content->{$id}->{barcode}"); } #add also other public tarif elsif($tariff_content->{$id}->{int18} && $tariff_content->{$id}->{int18} == 2 && $tariff_content->{$id}->{int12} && $tariff_content->{$id}->{barcode}){ push(@txt30, "$tariff_content->{$id}->{barcode}"); } } } $bw->log("booking_request NO user tariff defined, update user account to fallback default public or private or hidden",\@txt30,""); $dbt->update_one($dbh,$update_adr,"txt30='@txt30'"); }else{ $bw->log("booking_request user tariff selected",$tariff_nr,""); } } $bw->log("booking_request fetch_bike_tariff result ---> bike $ct_bike->{barcode} matching by bike_node: @{$bike_node} main_ids:$main_ids | bike_group by type_id:@{$bike_group} | Tarif selected: $tariff_nr",$tariff_content->{$tariff_nr}->{ct_name},""); return ($ct_bike,$tariff_content->{$tariff_nr}); }#fetch_bike_tariff #authout sub authout(){ my $self = shift; my $q = shift; my $coo = shift || ""; my %varenv = $cf->envonline(); my $dbh = ""; my $record = { c_id => 0 };#if fails my $return = { authcookie => "" };#if fails my $cgi_authcookie = $q->param('authcookie') || $coo || ""; #$bw->log("authout coo:$cgi_authcookie",$q,""); if($cgi_authcookie && length($cgi_authcookie) > 20){ my $authref = { table => "contentadr", fetch => "one", #keyfield => "c_id", template_id => "202", txt05 => "like::" . "%" . $q->escapeHTML($cgi_authcookie) . "%", }; $record = $dbt->fetch_record($dbh,$authref); if ($record->{c_id} > 0 && length($record->{txt05}) > 20){ my $all_authcookie = $record->{txt05}; my @check_cookies = split(/\|/,$record->{txt05}); foreach(@check_cookies){ #if(length($_) > 20 && $_ eq $cgi_authcookie){ if(length($_) > 20 && $_ =~ /$cgi_authcookie/){ $return = { authcookie => $_ }; $all_authcookie =~ s/$_//g;#delete authcookie if available $all_authcookie =~ s/\|$//; $all_authcookie =~ s/\|\|/\|/g; my $update = { table => "contentadr", txt05 => $all_authcookie, }; #print Dumper($update); my $rows = 0; $rows = $dbt->update_record($dbh,$update,$record); if($varenv{dbname} ne $dbt->{primary}->{sharee_primary}->{database}->{dbname}){ my $dbh_prim = $dbt->dbconnect_extern($dbt->{primary}->{sharee_primary}->{database}->{dbname}); $rows = $dbt->update_record($dbh_prim,$update,$record); } if($rows == 1){ $return = { authcookie => "1", user_id => "$record->{txt08}", user_group => [], }; $return = { %$return, debuglevel => "$record->{int11}" } if($record->{int11}); $return = { %$return, Ilockit_admin => "$record->{int19}" } if($record->{int19}); } } } } } return $return; }#end authout #auth_verify sub auth_verify(){ my $self = shift; my $q = shift; my $coo = shift || ""; my $userc_id = shift || ""; my $simple_op = shift || ""; my $cgi_authcookie = $q->param('authcookie') || $q->param('sessionid') || $coo; my $session_log = $q->param('sessionid') || ""; my $user_agent = $q->user_agent(); my $clientIP = $q->remote_addr(); my %varenv = (); $varenv{dbname} = ""; %varenv = $cf->envonline(); my $record = { c_id => 0 };#if fails my $return = { authcookie => "", merchant_id => "", user_tour => [], user_group => [] }; my $bike_group = ""; my $bike_node = ""; my $user_tour = ""; my $tariff_content = ""; my $adrtarif_hash = ""; $return->{merchant_id} = $1 if($cgi_authcookie && $cgi_authcookie =~ /\w+_(\w+)$/); my $netloc = $q->url(-base=>1); $bw->log("--> auth_verify on dbname $varenv{dbname},\n Starting with authcookie: $cgi_authcookie",$netloc,""); my $debug=0; my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; open(FILE,">>$varenv{logdir}/authcookie.log") if($debug); print FILE "\n*-->$now_dt $netloc | $varenv{dbname} | $cgi_authcookie\n" if($debug); if($cgi_authcookie && length($cgi_authcookie) > 30){ my $authref = { table => "contentadr", fetch => "one", template_id => "202", txt05 => "like::" . "%" . $q->escapeHTML($cgi_authcookie) . "%", }; my $auth_primary = { c_id => 0 }; my $auth_operator = { c_id => 0 }; $auth_operator = $dbt->fetch_record($dbh,$authref); $record = $auth_operator; #$bw->log("auth_verified on operator $varenv{dbname} anchor 1",$auth_operator->{c_id},""); #just part of operator-routing (sharee account management) if(!$simple_op && $varenv{dbname} ne $dbt->{primary}->{sharee_primary}->{database}->{dbname}){ #primary select my $dbh_primary = $dbt->dbconnect_extern($dbt->{primary}->{sharee_primary}->{database}->{dbname}); $auth_primary = $dbt->fetch_record($dbh_primary,$authref); if($auth_primary->{c_id} && $auth_primary->{c_id} > 0){ #$bw->log("auth_verified on primary anchor 2 by dbname $varenv{dbname}",$auth_primary->{c_id},""); print FILE "auth_verified on primary anchor 2 by dbname $varenv{dbname} | pri $auth_primary->{c_id}\n" if($debug); #On booking_request, user must be authenticated and addr must exist #At first insert/update Operator dbname array on primary if($q->param('request') && $q->param('request') eq "booking_request"){ #first, save operator array which are used my %operator_hash = ();#local DB $bw->log("booking_request auth_verified by dbname $varenv{dbname}",$auth_primary->{c_id},""); print FILE "booking_request auth_verified by dbname $varenv{dbname} | pri $auth_primary->{c_id}\n" if($debug); if($auth_primary->{txt17} && $auth_primary->{txt17} =~ /\w\s\w/){#append DB's %operator_hash = map { $_ => 1 } split(/\s+/,$auth_primary->{txt17}); }elsif($auth_primary->{txt17}){ $operator_hash{$auth_primary->{txt17}} = 1; } $operator_hash{$varenv{dbname}} = 1 if($varenv{dbname} ne "sharee_lv");#LastenVelo dbname will be only set by xml my @operator_array = keys %operator_hash; #$bw->log("auth_verified update operator keys by array: @operator_array",\%operator_hash,""); print FILE "auth_verified update operator keys by array: @operator_array | pri $auth_primary->{c_id}\n" if($debug); my $update_primary = { table => "contentadr", txt17 => "@operator_array",#operator ids txt19 => "$varenv{dbname}", atime => "now()", owner => "198",#update initiated by primary }; #if user_device if ($auth_primary->{c_id} > 0 && $q->param('user_device')){ $update_primary->{txt14} = $q->escapeHTML($session_log) if($session_log); $update_primary->{txt21} = $q->escapeHTML($q->param('user_device')) if($q->param('user_device')); $update_primary->{txt25} = $q->escapeHTML($clientIP) if($clientIP); $update_primary->{txt26} = $q->escapeHTML($user_agent) if($user_agent); } #first prepaid account check (not save because without rental history) if($auth_primary->{int03} == 3){ my $prepaidhash = { prepaid_total => 0 }; $prepaidhash = $pri->collect_prepaid($dbh_primary,$auth_primary) if($auth_primary->{c_id}); if(!$prepaidhash->{prepaid_total} || $prepaidhash->{prepaid_total} < 0){ my $vde = $auth_primary->{int12} || 1; $update_primary->{int12} = $vde; } $bw->log("auth_verify booking_request prepaid check",$update_primary,""); } my $rows = $dbt->update_record($dbh_primary,$update_primary,$auth_primary); $auth_primary = $dbt->fetch_record($dbh_primary,$authref); } #if user on operator not able to authenticate because of adr authcookie does not exist if(!$auth_operator->{c_id} || $auth_operator->{c_id} == 0 && $cgi_authcookie && length($cgi_authcookie) > 30){ #my $uid = 0; #($uid,my $sec,my $merchant) = split(/_/,$cgi_authcookie); $authref = { table => "contentadr", fetch => "one", template_id => "202", c_id => "=::$auth_primary->{c_id}", #c_id => "=::$uid", #txt05 => "like::" . "%" . $q->escapeHTML($cgi_authcookie) . "%" }; my $auth_operator3 = { c_id => 0 }; $auth_operator3 = $dbt->fetch_record($dbh,$authref);# if($uid); #$bw->log("auth_verified on operator anchor 3 by dbname $varenv{dbname}",$auth_operator3->{c_id},""); print FILE "auth_verified on operator anchor 3 by dbname $varenv{dbname} | op3 $auth_operator3->{c_id}\n" if($debug); #if user on operator available by userid c_id, then update authcookie if($auth_operator3->{c_id} && $auth_operator3->{c_id} > 0){ my $authcookies = $auth_operator3->{txt05} . "|" . $cgi_authcookie; #$bw->log("UPDATE adr on operator by dbname $varenv{dbname}",$auth_operator3->{c_id},""); print FILE "UPDATE adr on operator by dbname $varenv{dbname} | op3 $auth_operator3->{c_id}\n" if($debug); my $update = { table => "contentadr", #txt05 => "$authcookies",#authcookies txt05 => "$auth_primary->{txt05}",#authcookies atime => "now()", #mtime => "now()",#only set mtime on real user-data change owner => "198",#update initiated by primary }; my $rows = $dbt->update_record($dbh,$update,$auth_operator3); #else insert authenticated user from primary to operator # }elsif($auth_primary->{txt17} && $auth_primary->{txt17} =~ /$varenv{dbname}/){ #insert my $c_id = 0; if($auth_primary->{c_id} > 0){ $bw->log("INSERT adr from record_primary to operator by dbname $varenv{dbname}",$auth_primary->{c_id},""); print FILE "INSERT adr from record_primary to operator by dbname $varenv{dbname} | pri $auth_primary->{c_id}\n" if($debug); my $insert = { %$auth_primary, table => "contentadr", mtime => 'now()', owner => "198", }; $c_id = $dbt->insert_contentoid($dbh,$insert,"reset_adropkeys"); } }else{ #$bw->log("auth_verified on operator anchor 3 FAILS by dbname $varenv{dbname}. user seem not be activated",$auth_operator->{c_id},""); print FILE "auth_verified on operator anchor 3 FAILS by dbname $varenv{dbname}. user seem not be activated | op $auth_operator->{c_id}\n" if($debug); } } $auth_operator = $dbt->fetch_record($dbh,$authref); if($auth_operator->{c_id} && $auth_operator->{c_id} > 0){ $record = $auth_operator;#At first try using operator to get Tarif #$bw->log("auth_verified on operator anchor 2.2 by dbname $varenv{dbname}",$auth_operator->{c_id},""); print FILE "auth_verified on operator anchor 2.2 by dbname $varenv{dbname} | op $auth_operator->{c_id}\n" if($debug); }else{ $record = $auth_primary; #$bw->log("auth_verified on primary anchor 2.3 by dbname $varenv{dbname}",$auth_primary->{c_id},""); print FILE "auth_verified on primary anchor 2.3 by dbname $varenv{dbname} | pri $auth_primary->{c_id}\n" if($debug); } }else{# if($auth_primary->{c_id}) fails #$bw->log("auth_verified on primary anchor 4 FAILS by dbname $varenv{dbname}.",$auth_primary->{c_id},""); print FILE "auth_verified on primary anchor 4 FAILS by dbname $varenv{dbname} | pri $auth_primary->{c_id}\n" if($debug); } }elsif($varenv{dbname} eq $dbt->{primary}->{sharee_primary}->{database}->{dbname}){ $auth_primary = $dbt->fetch_record($dbh,$authref); #$bw->log("auth_verified on operator anchor 4 by dbname $varenv{dbname}",$auth_primary->{c_id},""); print FILE "auth_verified on operator anchor 4 by dbname $varenv{dbname} | pri $auth_primary->{c_id}\n" if($debug); $record = $auth_primary; }#end if($varenv{dbname} ne $dbt->{primary}->{sharee_primary}->{database}->{dbname}) if($varenv{dbname} ne $dbt->{primary}->{sharee_primary}->{database}->{dbname}){ ($bike_group,$bike_node,$user_tour,$tariff_content,$adrtarif_hash) = $self->fetch_tariff($varenv{dbname},$record,$q->param('authcookie')); } if($record->{c_id} > 0 && length($record->{txt05}) > 30){ my @check_cookies = split(/\|/,$record->{txt05}); foreach(@check_cookies){ if(length($_) > 30 && $_ =~ /$cgi_authcookie/){ $return->{authcookie} = $cgi_authcookie; $return->{user_id} = $record->{txt08}; $return->{user_group} = $bike_group;#yes, but deprecated $return->{user_tour} = $user_tour; $return->{debuglevel} = "$record->{int11}" if($record->{int11}); $return->{Ilockit_admin} = "$record->{int19}" if($record->{int19}); } } } }elsif($userc_id && looks_like_number($userc_id) && length($userc_id) >= 4){ my $authref = { table => "contentadr", fetch => "one", template_id => "202", c_id => "=::$userc_id", }; $record = $dbt->fetch_record($dbh,$authref); ($bike_group,$bike_node,$user_tour,$tariff_content,$adrtarif_hash) = $self->fetch_tariff($varenv{dbname},$record,$q->param('authcookie')); #maybe there isnt't any authcookie still available on confirm if ($record->{c_id} > 0){ $return->{user_id} = $record->{txt08}; $return->{user_group} = $bike_group;#yes, but deprecated $return->{user_tour} = $user_tour; $return->{debuglevel} = "$record->{int11}" if($record->{int11}); $return->{Ilockit_admin} = "$record->{int19}" if($record->{int19}); $return->{response_text} = "Danke, die Anmeldebestätigung war erfolgreich."; } }else{ #$bw->log("auth_verified on operator anchor FAILS by dbname $varenv{dbname}, no authcookie, dump \$q",$q,""); print FILE "auth_verified on operator anchor FAILS by dbname $varenv{dbname}, no authcookie\n" if($debug); } $return->{agb_checked} = "0"; $return->{agb_checked} = "1" if($record->{int14});#sharee AGB global my $last_used_operator = $record->{txt19};#check if this is primary and/or useable #$bw->log("last_used_operator selected by txt19:",$last_used_operator,""); if($last_used_operator){ my $dbh_operator = $dbt->dbconnect_extern("$last_used_operator"); my $hotline_hash = { table => "contentuser", fetch => "one", template_id => 197, c_id => "1", }; my $hotline_data = $dbt->fetch_record($dbh_operator,$hotline_hash); $return->{last_used_operator} = { "operator_name" => "", "operator_hours" => "", "operator_phone" => "", "operator_email" => "", }; $return->{last_used_operator}->{operator_name} = $hotline_data->{txt01} if($hotline_data->{txt01}); $return->{last_used_operator}->{operator_hours} = $hotline_data->{txt84} if($hotline_data->{txt84}); $return->{last_used_operator}->{operator_phone} = $hotline_data->{txt07} if($hotline_data->{txt07}); $return->{last_used_operator}->{operator_email} = $hotline_data->{txt08} if($hotline_data->{txt08}); } #$bw->log("auth_verify done on txt05 authcookies by dbname $varenv{dbname}:",$record->{txt05},""); #Servicetool only users with users.int09=1 #shareetool if($varenv{dbname} ne $dbt->{primary}->{sharee_primary}->{database}->{dbname} && $return->{merchant_id} && $dbt->{merchant_ids}->{$return->{merchant_id}}->{id} && $dbt->{merchant_ids}->{$return->{merchant_id}}->{id} == 187){ my $users_serviceapp = { u_id => 0 }; $users_serviceapp = $dbt->select_users($dbh,$record->{c_id},"and int09=1"); #$bw->log("users_serviceapp: $users_serviceapp->{u_id} && $varenv{dbname} && $return->{merchant_id} && $dbt->{merchant_ids}->{$return->{merchant_id}}->{id}","",""); if(!$users_serviceapp->{u_id} || $users_serviceapp->{u_id} == 0){ $record = { c_id => 0 }; $return = { c_id => 0 }; #$bw->log("reset auth_verify because of only Servicetool users access:",$record,""); } print FILE "users_serviceapp: $users_serviceapp->{u_id} | $return->{authcookie}\n" if($debug); } print FILE "final return: $return->{authcookie}\n" if($debug); close(FILE) if($debug); return ($return,$record); }#end auth_verify #authorization sub authorization(){ my $self = shift; my $q = shift; my $merchant_id = shift || $q->param('merchant_id') || ""; my $hw_id = shift || $q->param('hw_id') || ""; my $lang = shift || ""; my $aowner = shift || 0; $dbh = ""; my %varenv = $cf->envonline(); my $user_id = $q->param('user_id') || $q->param('txt08'); my $user_pw = $q->param('user_pw') || $q->param('txt04'); #print "user_pw:" . $q->param('user_pw') . "|txt04:" . $q->param('txt04') . "|user_pw:" . $q->param('user_pw'); my $pw_length = 8; my $record = { c_id => 0 };#if fails my $return = { authcookie => "" };#if fails #print "$hw_id | $merchant_id | $user_id | $user_pw\n";exit; if($user_id && length($user_id) >= 4 && $user_pw && length($user_pw) >= $pw_length && length($hw_id) >= 10 && length($merchant_id) >= 8){ my $authref = { table => "contentadr", fetch => "one", template_id => "202", txt08 => "ilike::" . $q->escapeHTML($user_id), int05 => "1", }; my $pass_name = $q->escapeHTML($user_pw); $pass_name =~ s/\s//g; my $pwmd5=md5_hex($pass_name) || ""; my $pwsha256=sha256_base64($pwmd5) || ""; $authref->{txt04} = "$pwsha256"; #Servicetool, only users with users.int09=1 #shareetool if($varenv{dbname} ne $dbt->{primary}->{sharee_primary}->{database}->{dbname} && $aowner && $aowner eq "187"){ my $users_serviceapp = { u_id => 0 }; $users_serviceapp = $dbt->select_users($dbh,$record->{c_id},"and int09=1"); $record = { c_id => 0 } if(!$users_serviceapp->{u_id}); }else{ #2021-10-13 because of keep DMS authcookie #2021-12-23 user must always be registered on sharee_primary $dbh = $dbt->dbconnect_extern($dbt->{primary}->{sharee_primary}->{database}->{dbname}) if($varenv{dbname} ne $dbt->{primary}->{sharee_primary}->{database}->{dbname}); $record = $dbt->fetch_record($dbh,$authref); } $return = $self->authcookie_manager($dbh,$q,$record,$merchant_id,$hw_id,$lang,$aowner); }else{ $bw->log("authorization fails because of failing condition: if($user_id && length($user_id) >= 4 && length($user_pw) >= $pw_length && length($hw_id) >= 10 && length($merchant_id) >= 8)","",""); } return $return; }#end authorization #manage authcookie sub authcookie_manager { my $self = shift; $dbh = shift; my $q = shift; my $record = shift || {}; my $merchant_id = shift || ""; my $hw_id = shift || ""; my $lang = shift || ""; my $aowner = shift || 0; my $user_agent = $q->user_agent(); my $clientIP = $q->remote_addr(); my $return = { authcookie => "" };#if fails my %varenv = $cf->envonline(); my $authcookie=md5_hex($record->{txt08}.$q->escapeHTML($hw_id)); $bw->log("generating authcookie with input: $record->{txt08}.$hw_id",$authcookie,""); $authcookie = $record->{c_id} . "_" . $authcookie . "_" . $q->escapeHTML($merchant_id); #if user_id && user_pw matched if ($record->{c_id} > 0 && length($authcookie) > 20){ my $update = { table => "contentadr", atime => "now()", int15 => "$aowner",#update on access #mtime => "now()", #owner => "198",#update initiated by primary }; $update->{txt11} = $q->escapeHTML($lang) if($lang); $update->{txt21} = $q->escapeHTML($q->param('user_device')) if($q->param('user_device')); $update->{txt25} = $q->escapeHTML($clientIP) if($clientIP); $update->{txt26} = $q->escapeHTML($user_agent) if($user_agent); my @registered_cookies; my $registered_cookies; my @check_cookies = split(/\|/,$record->{txt05}); #$bw->log("check_cookies","@check_cookies",""); @check_cookies = reverse(@check_cookies); my $i=0; foreach(@check_cookies){ $i++; #secure shortage cookies if(length($_) > 20 && $i < 8){#max 8 clients #$bw->log("$i < 8 cookies",$_,""); push @registered_cookies,$_; } } @registered_cookies = reverse(@registered_cookies); foreach(@registered_cookies){ $registered_cookies .= "$_|" if(length($_) > 20);#secure shortage cookies } $registered_cookies =~ s/\|$//; $bw->log("generated authcookie",$authcookie,""); #return still existing authcookie if($registered_cookies && $registered_cookies =~ /$authcookie/){ my $rows = $dbt->update_record($dbh,$update,$record); $return = { authcookie => "$authcookie", new_authcoo => "0", user_id => "$record->{txt08}", }; #return new generated authcookie }else{ my $all_authcookie = $authcookie; $all_authcookie = $registered_cookies . "|" . $authcookie if($registered_cookies); $update->{txt05} = $all_authcookie; my $rows = $dbt->update_record($dbh,$update,$record); #update also operator cookies if($varenv{dbname} eq $dbt->{primary}->{sharee_primary}->{database}->{dbname} && $record->{txt17}){ my $auth_primary = $record; my %operator_hash = (); if($auth_primary->{txt17} =~ /\w\s\w/){ %operator_hash = map { $_ => 1 } split(/\s+/,$auth_primary->{txt17}); }else{ $operator_hash{$auth_primary->{txt17}} = 1; } foreach my $sharee_operator (keys (%operator_hash)){ my $dbh_operator = $dbt->dbconnect_extern("$sharee_operator"); my $authref = { table => "contentadr", fetch => "one", template_id => "202", c_id => "$auth_primary->{c_id}", }; my $auth_operator = { c_id => 0 }; $auth_operator = $dbt->fetch_record($dbh_operator,$authref); #if user on operator available by userid c_id, then update authcookie if($auth_operator->{c_id}){ $bw->log("update adr from record_primary to operator \"$sharee_operator\" after new new_authcoo",$update,""); my $rows = $dbt->update_record($dbh_operator,$update,$auth_operator); } } } #end update operator cookies if($rows == 1){ $return = { authcookie => "$authcookie", new_authcoo => "1", user_id => "$record->{txt08}", }; } } } $return->{debuglevel} = "$record->{int11}" if($record->{int11}); $return->{Ilockit_admin} = "$record->{int19}" if($record->{int19}); $return->{agb_checked} = "0"; $return->{agb_checked} = "1" if($record->{int14});#sharee AGB global return $return; } 1;