sharee.bike/copri4/main/src/Mod/Pricing.pm
2022-04-12 11:21:19 +02:00

440 lines
17 KiB
Perl
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;