mirror of
https://gitlab.com/t6353/sharee.bike.git
synced 2024-11-15 23:26:34 +01:00
440 lines
17 KiB
Perl
Executable file
440 lines
17 KiB
Perl
Executable file
package Pricing;
|
||
#
|
||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||
# Copyright (c) Rainer Gümpelein, TeilRad GmbH
|
||
#
|
||
#Rental counting and pricing methods
|
||
#
|
||
#perl -cw
|
||
use lib qw(/var/www/copri-bike/shareeapp-operator/src);
|
||
#
|
||
use strict;
|
||
use warnings;
|
||
use POSIX;
|
||
use CGI; # only for debugging
|
||
use Scalar::Util qw(looks_like_number);
|
||
use DateTime;
|
||
use DateTime::Format::Pg;
|
||
|
||
use Lib::Config;
|
||
use Mod::Libenz;
|
||
use Mod::DBtank;
|
||
use Mod::Callib;
|
||
use Mod::Basework;
|
||
use Data::Dumper;
|
||
|
||
my $cf = new Config;
|
||
my $lb = new Libenz;
|
||
my $dbt = new DBtank;
|
||
my $cal = new Callib;
|
||
my $bw = new Basework;
|
||
|
||
sub new {
|
||
my $class = shift;
|
||
my $self = {};
|
||
bless($self,$class);
|
||
return $self;
|
||
}
|
||
|
||
my $dbh = "";
|
||
|
||
sub only_first_free(){
|
||
my $self = shift;
|
||
my $ctpos = shift;
|
||
my %varenv = $cf->envonline();
|
||
|
||
my $pref = {
|
||
table => "contenttrans",
|
||
table_pos => "contenttranspos",
|
||
fetch => "one",
|
||
template_id => "218",#Faktura tpl_id
|
||
ca_id => "=::$ctpos->{ca_id}",
|
||
c_id => "!=::$ctpos->{c_id}",
|
||
#txt10 => "IN::('available','canceled')",
|
||
int10 => "IN::('1','6')",
|
||
"ct.close_time" => "is::null",
|
||
};
|
||
$pref = { %$pref, time_range => "start_time >= '$ctpos->{start_time}' and start_time < '$ctpos->{end_time}' and start_time != end_time" };
|
||
|
||
my $record = $dbt->collect_post($dbh,$pref);
|
||
return $record;
|
||
|
||
}
|
||
|
||
#new counting rental time in hours method (last sharee_pricing)
|
||
sub counting_rental {
|
||
my $self = shift;
|
||
my $varenv = shift;
|
||
my $ctpos = shift;
|
||
my $todo = shift;
|
||
my $today4db = strftime("%Y-%m-%d %H:%M:%S",localtime(time));
|
||
|
||
my $return = {};
|
||
my $logging = {};
|
||
$logging->{ID} = "c_id:$ctpos->{c_id}/ct_id:$ctpos->{ct_id}/ca_id:$ctpos->{ca_id}";
|
||
|
||
my $computed_end_time = $ctpos->{end_time} || $today4db;
|
||
$computed_end_time = $today4db if($ctpos->{int10} && $ctpos->{int10} == 3);
|
||
|
||
|
||
my $dt0 = DateTime::Format::Pg->parse_datetime($ctpos->{start_time});
|
||
my $dt1 = DateTime::Format::Pg->parse_datetime($computed_end_time);
|
||
my $dur01 = $dt0->subtract_datetime($dt1);
|
||
my ($durhh,$durmm) = $dur01->in_units( 'hours','minutes' );
|
||
$durhh = sprintf('%.2d',$durhh);
|
||
$durmm = sprintf('%.2d',$durmm);
|
||
|
||
|
||
#calculates rental time range in hours
|
||
my ($start_datetime,$end_datetime,$hours) = $cal->contenttranspos_dating($ctpos->{c_id},$ctpos->{start_time},"$computed_end_time","$today4db");
|
||
$logging->{hours_input} = $hours;
|
||
$logging->{tariff} = "$ctpos->{txt04} - $ctpos->{int09}";
|
||
|
||
my $price = 2; #FIXME to real val. must be not 0
|
||
$price = sprintf('%.2f',$ctpos->{int02}) if($ctpos->{int02} && $ctpos->{int02} > 0);
|
||
my $total = 0;
|
||
|
||
my $days_pricemax = $ctpos->{int17} || 9;
|
||
$logging->{days_pricemax} = $days_pricemax;
|
||
#example my $days_pricemax = 5; #konrad max 15,- € bike/day depends on 3,- €/hour
|
||
|
||
#calculate if rental hours greater than hours for max daily_price
|
||
my $days_hour4price = $days_pricemax / $price;
|
||
$logging->{days_hour4price} = $days_hour4price;
|
||
my $real_hours = $hours;
|
||
|
||
if($ctpos->{int16} && $ctpos->{int16} > 0){#z.b. 30 Min/Gratis --> 0.5
|
||
my $ctpos_freed = $self->only_first_free($ctpos);
|
||
#Bsp 1h = 60min , 60*0,02 = 1,2min
|
||
if(!$ctpos_freed->{c_id} || $real_hours <= 0.02){
|
||
$hours -= $ctpos->{int16};
|
||
$logging->{hours_freed} = $hours;
|
||
}else{
|
||
$logging->{hours_freed} = "Not freed because of (!$ctpos_freed->{c_id} && $ctpos->{int16} || $real_hours <= 0.02)";
|
||
}
|
||
}
|
||
|
||
#If available then take saved hours
|
||
if($ctpos->{int10} && $ctpos->{int10} == 1 && $todo eq "readonly"){
|
||
if($ctpos->{int03} && $ctpos->{int03} > 0){
|
||
$hours = $ctpos->{int03};
|
||
$total = $hours * $price if(looks_like_number($hours) && looks_like_number($price));
|
||
}else{
|
||
$hours = 0;
|
||
$total = 0;
|
||
}
|
||
}
|
||
#jede angebrochene Std.
|
||
elsif(looks_like_number($hours) && $hours > 0){
|
||
if($days_hour4price > 0 && $hours >= $days_hour4price && $hours <= 24){
|
||
$logging->{_hours_lower24} = "$days_hour4price > 0 && $hours >= $days_hour4price && $hours <= 24";
|
||
$logging->{__hours_lower24} = $hours;
|
||
$hours = $days_hour4price;
|
||
$logging->{hours_lower24} = $hours;
|
||
}
|
||
elsif($days_hour4price > 0 && $hours >= 24){
|
||
$logging->{hours_greate24} = "$days_hour4price > 0 && $hours >= 24";
|
||
my $days = $hours / 24;
|
||
my $days_int = $days;
|
||
my $dez = 0;
|
||
($days_int,$dez) = split(/\./, $days) if($days =~ /\.\d/);
|
||
my $days_hour = $days_int * 24;
|
||
my $rest = $hours - $days_hour;
|
||
$rest = $days_hour4price if($rest > $days_hour4price);
|
||
$hours = ($days_int * $days_hour4price) + $rest;
|
||
$logging->{hours_compute} = "$hours = ($days_int * $days_hour4price) + $rest";
|
||
}
|
||
|
||
$logging->{hours_preround} = $hours;
|
||
$hours = $lb->round_half($hours);
|
||
$logging->{hours_postround} = $hours;
|
||
$total = $hours * $price if(looks_like_number($hours) && looks_like_number($price));
|
||
}else{
|
||
$hours = 0;
|
||
}
|
||
$total = sprintf('%.2f', $total);
|
||
#Bsp 1h = 60min , 60*0,02 = 1,2min
|
||
$hours = "0" if($real_hours <= 0.02);
|
||
|
||
$return->{start_time} = "$ctpos->{start_time}";
|
||
$return->{end_time} = "$computed_end_time";
|
||
$return->{real_hours} = "$real_hours";
|
||
$return->{computed_hours} = "$hours";
|
||
$return->{unit_price} = "$price";
|
||
$return->{total_price} = "$total";
|
||
|
||
$bw->log("hour computed:",$logging,"");
|
||
return $return;
|
||
}#end counting_rental
|
||
|
||
#all other values returned by user_bikes_occupied
|
||
sub fetch_rentalfeed {
|
||
my $self = shift;
|
||
my $varenv = shift;
|
||
my $ctpos = shift;
|
||
|
||
my $bike_group = "$dbt->{operator}->{$varenv->{dbname}}->{oprefix}$ctpos->{int12}" || "";
|
||
|
||
my $return = {};
|
||
$return->{bike_group} = ["$bike_group"];
|
||
$return->{station} = "$dbt->{operator}->{$varenv->{dbname}}->{oprefix}$ctpos->{int04}";#TODO save with prefix
|
||
$return->{uri_operator} = "$varenv->{wwwhost}";#TODO, should be DB select
|
||
$return->{bike} = "$dbt->{operator}->{$varenv->{dbname}}->{oprefix}$ctpos->{barcode}";
|
||
$return->{state} = "$dbt->{copri_conf}->{bike_state}->{$ctpos->{int10}}" || "";
|
||
$return->{bike_charge} = "$ctpos->{int19}" if($ctpos->{int19});
|
||
$return->{description} = "$ctpos->{txt01}";
|
||
$return->{request_time} = "$ctpos->{itime}";
|
||
$return->{system} = "Ilockit" if($ctpos->{int11} && $ctpos->{int11} == 2);
|
||
$return->{system} = "sigo" if($ctpos->{int11} && $ctpos->{int11} == 3);
|
||
|
||
if($ctpos->{int11}){
|
||
#$return->{gps} = "$ctpos->{txt06}";#end_gps
|
||
($return->{gps}->{latitude},$return->{gps}->{longitude}) = split(/,/,$ctpos->{txt06});
|
||
|
||
#if($ctpos->{txt10} =~ /requested|occupied/)
|
||
if($ctpos->{int10} == 2 || $ctpos->{int10} == 3){
|
||
$return->{tariff_description}->{name} = "$ctpos->{txt04}";
|
||
$return->{tariff_description}->{number} = "$ctpos->{int09}";
|
||
$return->{tariff_description}->{eur_per_hour} = "$ctpos->{int02}" || "0";
|
||
$return->{tariff_description}->{max_eur_per_day} = "$ctpos->{int17}" || "0";
|
||
$return->{tariff_description}->{free_hours} = "$ctpos->{int16}" if($ctpos->{int16} && $ctpos->{int16} > 0);
|
||
$return->{tariff_description}->{abo_eur_per_month} = "$ctpos->{int15}" if($ctpos->{int15} && $ctpos->{int15} > 0);
|
||
$return->{tariff_description}->{track_info} = "Ich stimme der Speicherung (Tracking) meiner Fahrstrecke zwecks wissenschaftlicher Auswertung und Berechnung der CO2-Einsparung zu!" if($ctpos->{int25});
|
||
$return->{tariff_description}->{operator_agb} = "Mit der Mietrad Anmietung wird folgender Betreiber <a href='$varenv->{wwwhost}/site/agb.html' target='_blank'>AGB</a> zugestimmt (als Demo sharee AGB)." if($ctpos->{ca_id} == 1842 || $ctpos->{ca_id} == 5781);
|
||
|
||
$return->{Ilockit_GUID} = "$ctpos->{txt17}" if($ctpos->{int11} == 2);
|
||
$return->{Ilockit_ID} = "$ctpos->{txt18}" if($ctpos->{int11} == 2);
|
||
#$return->{gps} = "$ctpos->{txt06}";#start_gps
|
||
($return->{gps}->{latitude},$return->{gps}->{longitude}) = split(/,/,$ctpos->{txt06});
|
||
$return->{lock_state} = "locked" if($ctpos->{int20} == 1);
|
||
$return->{lock_state} = "unlocked" if($ctpos->{int20} == 2);
|
||
$return->{lock_state} = "locking" if($ctpos->{int20} == 3);
|
||
$return->{lock_state} = "unlocking" if($ctpos->{int20} == 4);
|
||
}
|
||
}
|
||
return $return;
|
||
}
|
||
|
||
|
||
#
|
||
#last
|
||
sub sharee_pricing(){
|
||
my $self = shift;
|
||
my $ctpos = shift;
|
||
my $todo = shift;
|
||
my %varenv = $cf->envonline();
|
||
my $today4db = strftime("%Y-%m-%d %H:%M:%S",localtime(time));
|
||
|
||
my $return = {};
|
||
my $logging = {};
|
||
$logging->{ID} = "c_id:$ctpos->{c_id}/ct_id:$ctpos->{ct_id}/ca_id:$ctpos->{ca_id}";
|
||
|
||
my $computed_end_time = $ctpos->{end_time} || $today4db;
|
||
$computed_end_time = $today4db if($ctpos->{int10} && $ctpos->{int10} == 3);
|
||
|
||
#calculates rental time range in hours
|
||
my ($start_datetime,$end_datetime,$hours) = $cal->contenttranspos_dating($ctpos->{c_id},$ctpos->{start_time},"$computed_end_time","$today4db");
|
||
$logging->{hours_input} = $hours;
|
||
$logging->{tariff} = "$ctpos->{txt04} - $ctpos->{int09}";
|
||
|
||
my $bike_group = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}$ctpos->{int12}" || "";
|
||
my $days_pricemax = $ctpos->{int17} || 9;
|
||
$logging->{days_pricemax} = $days_pricemax;
|
||
|
||
my $price = 2; #FIXME to real val. must be not 0
|
||
$price = sprintf('%.2f',$ctpos->{int02}) if($ctpos->{int02} && $ctpos->{int02} > 0);
|
||
my $total = 0;
|
||
|
||
#my $days_pricemax = "4.5";#TINK max 9,- € bike/day depends on 2,- €/hour
|
||
#my $days_pricemax = 5; #KonRad max 15,- € bike/day depends on 3,- €/hour
|
||
my $days_hour4price = $days_pricemax / $price;
|
||
$logging->{days_hour4price} = $days_hour4price;
|
||
my $real_hours = $hours;
|
||
|
||
if($ctpos->{int16} && $ctpos->{int16} > 0){#z.b. 30 Min/Gratis --> 0.5
|
||
my $ctpos_freed = $self->only_first_free($ctpos);
|
||
#Bsp 1h = 60min , 60*0,02 = 1,2min
|
||
if(!$ctpos_freed->{c_id} || $real_hours <= 0.02){
|
||
$hours -= $ctpos->{int16};
|
||
$logging->{hours_freed} = $hours;
|
||
}else{
|
||
$logging->{hours_freed} = "Not freed because of (!$ctpos_freed->{c_id} && $ctpos->{int16} || $real_hours <= 0.02)";
|
||
}
|
||
}
|
||
|
||
#If available then take saved hours
|
||
if($ctpos->{int10} && $ctpos->{int10} == 1 && $todo eq "readonly"){
|
||
if($ctpos->{int03} && $ctpos->{int03} > 0){
|
||
$hours = $ctpos->{int03};
|
||
$total = $hours * $price if(looks_like_number($hours) && looks_like_number($price));
|
||
}else{
|
||
$hours = 0;
|
||
$total = 0;
|
||
}
|
||
}
|
||
#jede angebrochene Std.
|
||
elsif(looks_like_number($hours) && $hours > 0){
|
||
if($days_hour4price > 0 && $hours >= $days_hour4price && $hours <= 24){
|
||
$logging->{_hours_lower24} = "$days_hour4price > 0 && $hours >= $days_hour4price && $hours <= 24";
|
||
$logging->{__hours_lower24} = $hours;
|
||
$hours = $days_hour4price;
|
||
$logging->{hours_lower24} = $hours;
|
||
}
|
||
elsif($days_hour4price > 0 && $hours >= 24){
|
||
$logging->{hours_greate24} = "$days_hour4price > 0 && $hours >= 24";
|
||
my $days = $hours / 24;
|
||
my $days_int = $days;
|
||
my $dez = 0;
|
||
($days_int,$dez) = split(/\./, $days) if($days =~ /\.\d/);
|
||
my $days_hour = $days_int * 24;
|
||
my $rest = $hours - $days_hour;
|
||
$rest = $days_hour4price if($rest > $days_hour4price);
|
||
$hours = ($days_int * $days_hour4price) + $rest;
|
||
$logging->{hours_compute} = "$hours = ($days_int * $days_hour4price) + $rest";
|
||
}
|
||
|
||
$logging->{hours_preround} = $hours;
|
||
$hours = $lb->round_half($hours);
|
||
$logging->{hours_postround} = $hours;
|
||
$total = $hours * $price if(looks_like_number($hours) && looks_like_number($price));
|
||
}else{
|
||
$hours = 0;
|
||
}
|
||
$total = sprintf('%.2f', $total);
|
||
#Bsp 1h = 60min , 60*0,02 = 1,2min
|
||
$hours = "0" if($real_hours <= 0.02);
|
||
|
||
$return->{real_hours} = "$real_hours";
|
||
$return->{computed_hours} = "$hours";
|
||
$return->{unit_price} = "$price";
|
||
$return->{total_price} = "$total";
|
||
$return->{bike_group} = ["$bike_group"];
|
||
|
||
|
||
$return->{station} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}$ctpos->{int04}";#TODO save with prefix
|
||
$return->{uri_operator} = "$varenv{wwwhost}";#TODO, should be DB select
|
||
$return->{bike} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}$ctpos->{barcode}";
|
||
$return->{state} = "$dbt->{copri_conf}->{bike_state}->{$ctpos->{int10}}" || "";
|
||
$return->{bike_charge} = "$ctpos->{int19}" if($ctpos->{int19});
|
||
$return->{description} = "$ctpos->{txt01}";
|
||
$return->{request_time} = "$ctpos->{itime}";
|
||
$return->{start_time} = "$ctpos->{start_time}";
|
||
$return->{end_time} = "$computed_end_time";
|
||
$return->{system} = "Ilockit" if($ctpos->{int11} && $ctpos->{int11} == 2);
|
||
$return->{system} = "sigo" if($ctpos->{int11} && $ctpos->{int11} == 3);
|
||
|
||
if($ctpos->{int11}){
|
||
#$return->{gps} = "$ctpos->{txt06}";#end_gps
|
||
($return->{gps}->{latitude},$return->{gps}->{longitude}) = split(/,/,$ctpos->{txt06});
|
||
|
||
#if($ctpos->{txt10} =~ /requested|occupied/)
|
||
if($ctpos->{int10} == 2 || $ctpos->{int10} == 3){
|
||
$return->{tariff_description}->{name} = "$ctpos->{txt04}";
|
||
$return->{tariff_description}->{number} = "$ctpos->{int09}";
|
||
$return->{tariff_description}->{eur_per_hour} = "$ctpos->{int02}" || "0";
|
||
$return->{tariff_description}->{max_eur_per_day} = "$ctpos->{int17}" || "0";
|
||
$return->{tariff_description}->{free_hours} = "$ctpos->{int16}" if($ctpos->{int16} && $ctpos->{int16} > 0);
|
||
$return->{tariff_description}->{abo_eur_per_month} = "$ctpos->{int15}" if($ctpos->{int15} && $ctpos->{int15} > 0);
|
||
$return->{tariff_description}->{track_info} = "Ich stimme der Speicherung (Tracking) meiner Fahrstrecke zwecks wissenschaftlicher Auswertung und Berechnung der CO2-Einsparung zu!" if($ctpos->{int25});
|
||
$return->{tariff_description}->{operator_agb} = "Mit der Mietrad Anmietung wird folgender Betreiber <a href='$varenv{wwwhost}/site/agb.html' target='_blank'>AGB</a> zugestimmt (als Demo sharee AGB)." if($ctpos->{ca_id} == 1842 || $ctpos->{ca_id} == 5781);
|
||
|
||
$return->{Ilockit_GUID} = "$ctpos->{txt17}" if($ctpos->{int11} == 2);
|
||
$return->{Ilockit_ID} = "$ctpos->{txt18}" if($ctpos->{int11} == 2);
|
||
#$return->{gps} = "$ctpos->{txt06}";#start_gps
|
||
($return->{gps}->{latitude},$return->{gps}->{longitude}) = split(/,/,$ctpos->{txt06});
|
||
$return->{lock_state} = "locked" if($ctpos->{int20} == 1);
|
||
$return->{lock_state} = "unlocked" if($ctpos->{int20} == 2);
|
||
$return->{lock_state} = "locking" if($ctpos->{int20} == 3);
|
||
$return->{lock_state} = "unlocking" if($ctpos->{int20} == 4);
|
||
}
|
||
}
|
||
$bw->log("hour computed:",$logging,"");
|
||
return $return;
|
||
}
|
||
|
||
#CO2 calculator
|
||
#Bsp Berechnungen:
|
||
# Pkw:
|
||
# Distanz * CO2-Emission Pkw / 100 km
|
||
# 8.760 km * 20 kg CO2 / 100 km = 1.752 kg CO2
|
||
# Pedelec:
|
||
# Distanz * CO2-Emission Pedelec / 100 km
|
||
# 10.950 km * 0,546 kg CO2 / 100 km = 62 kg CO2
|
||
#
|
||
# Aus der Differenz zwischen der CO2-Emission Pkw und der CO2-Emission Pedelec ergibt sich das Einsparpotenzial:
|
||
# 1.752 kg CO2 – 62 kg CO2 = 1.690 kg CO2, also rund 1,7 t CO2 pro Jahr
|
||
#
|
||
sub co2calc {
|
||
my $self = shift;
|
||
my $ctpos = shift;
|
||
my $co2diff = 0;
|
||
|
||
my $co2pkw = $ctpos->{int26} * 20 / 100;
|
||
my $co2ped = $ctpos->{int26} * 0.546 / 100;
|
||
$co2diff = $co2pkw - $co2ped;
|
||
$co2diff = sprintf('%.2f',$co2diff);
|
||
$co2diff =~ s/\./,/;
|
||
|
||
return $co2diff;
|
||
}
|
||
|
||
#calculates sprit saving
|
||
sub sprit2calc {
|
||
my $self = shift;
|
||
my $ctpos = shift;
|
||
|
||
my $einzel = $ctpos->{int02};
|
||
my $menge = $ctpos->{int03};
|
||
my $rabatt_val = $ctpos->{int07} || 0;
|
||
my $gesamt = 0;
|
||
if($rabatt_val != 0 && $einzel && $menge){
|
||
my $rabatt_eur = $rabatt_val;
|
||
#if int08 != 1 alias €
|
||
$rabatt_eur = $einzel * $menge * $rabatt_val/100 if($ctpos->{int08} != 1);
|
||
$gesamt = $einzel * $menge - $rabatt_eur;
|
||
}elsif($einzel && $menge){
|
||
$gesamt = $einzel * $menge;
|
||
}
|
||
|
||
my $sprit_price = 0;
|
||
$sprit_price = $ctpos->{int26} * 0.3 if($ctpos->{int26} != 0);
|
||
$sprit_price -= $gesamt;
|
||
$sprit_price = sprintf('%.2f',$sprit_price);
|
||
$sprit_price =~ s/\./,/;
|
||
|
||
return $sprit_price;
|
||
}
|
||
|
||
|
||
#computes position price and rabatt
|
||
sub price2calc {
|
||
my $self = shift;
|
||
my $ctpos = shift;
|
||
|
||
my $gesamt = 0;
|
||
my $rabatt = "";
|
||
my $einzel = $ctpos->{int02};
|
||
my $menge = $ctpos->{int03};
|
||
my $rabatt_val = $ctpos->{int07} || 0;
|
||
if($rabatt_val != 0 && $einzel && $menge){
|
||
my $rabatt_eur = $rabatt_val;
|
||
#if int08 != 1 alias €
|
||
$rabatt_eur = $einzel * $menge * $rabatt_val/100 if($ctpos->{int08} != 1);
|
||
$gesamt = $einzel * $menge - $rabatt_eur;
|
||
}elsif($einzel && $menge){
|
||
$gesamt = $einzel * $menge;
|
||
}
|
||
|
||
if($ctpos->{int07} && $ctpos->{int07} > 0 && $menge > 0){
|
||
$rabatt = "-" . $ctpos->{int07};
|
||
if($ctpos->{int08} == 1){
|
||
$rabatt .= " €";
|
||
}else{
|
||
$rabatt =~ s/\.00//;
|
||
$rabatt .= " %";
|
||
}
|
||
}
|
||
|
||
return ($gesamt,$rabatt);
|
||
}
|
||
1;
|