From cee33486f662855ae25d6088f2146703d03d3327 Mon Sep 17 00:00:00 2001 From: Rene Krenn Date: Tue, 20 Mar 2018 23:32:57 +0100 Subject: [PATCH] TT#34013 save contract_balances in the contract's tz Change-Id: I23b4dc82ba8f0a3e535d6c43a195d97704fe69a5 --- lib/NGCP/Panel/Controller/Contact.pm | 3 +- .../Panel/Form/ProfilePackage/Reseller.pm | 6 +- lib/NGCP/Panel/Utils/DateTime.pm | 18 +++++ lib/NGCP/Panel/Utils/ProfilePackages.pm | 66 +++++++++++++------ 4 files changed, 70 insertions(+), 23 deletions(-) diff --git a/lib/NGCP/Panel/Controller/Contact.pm b/lib/NGCP/Panel/Controller/Contact.pm index eb50b4576e..90dc9f089f 100644 --- a/lib/NGCP/Panel/Controller/Contact.pm +++ b/lib/NGCP/Panel/Controller/Contact.pm @@ -93,6 +93,7 @@ sub create :Chained('list_contact') :PathPart('create') :Args(0) { delete $form->values->{reseller}; } $form->values->{country} = $form->values->{country}{id}; + $form->values->{timezone} = $form->values->{timezone}{name} || undef; my $contact = $c->stash->{contacts}->create($form->values); delete $c->session->{created_objects}->{reseller}; $c->session->{created_objects}->{contact} = { id => $contact->id }; @@ -307,7 +308,7 @@ sub ajax_list_contacts{ NGCP::Panel::Utils::Datatables::process( $c, $c->stash->{contacts}->search_rs( - $reseller_query->[0], + $reseller_query->[0], $reseller_query->[1] ? $reseller_query->[1] : { prefetch=>"contracts" } diff --git a/lib/NGCP/Panel/Form/ProfilePackage/Reseller.pm b/lib/NGCP/Panel/Form/ProfilePackage/Reseller.pm index 1421eef854..1817b357e3 100644 --- a/lib/NGCP/Panel/Form/ProfilePackage/Reseller.pm +++ b/lib/NGCP/Panel/Form/ProfilePackage/Reseller.pm @@ -105,8 +105,10 @@ has_field 'balance_interval_start_mode' => ( type => 'Select', label => 'Balance Interval Start', options => [ - { value => '1st', label => '1st day of month' }, - { value => 'create', label => 'upon customer creation' }, + { value => '1st', label => '1st day of month, at 00:00 system time' }, + { value => '1st_tz', label => '1st day of month, at 00:00 contract time' }, + { value => 'create', label => 'customer creation date, at 00:00 system time' }, + { value => 'create_tz', label => 'customer creation date, at 00:00 contract time' }, { value => 'topup_interval', label => 'start interval upon top-up' }, { value => 'topup', label => 'new interval for each top-up' }, ], diff --git a/lib/NGCP/Panel/Utils/DateTime.pm b/lib/NGCP/Panel/Utils/DateTime.pm index 39b30d5f89..ba097c80d5 100644 --- a/lib/NGCP/Panel/Utils/DateTime.pm +++ b/lib/NGCP/Panel/Utils/DateTime.pm @@ -64,6 +64,24 @@ sub infinite_past { #$dt->epoch calls should be okay if perl >= 5.12.0 } +sub convert_tz { + my ($dt,$from_tz,$to_tz,$c) = @_; + #use Data::Dumper; + #$c->log->debug("converting $dt from '". Dumper($from_tz) ."' to $to_tz'") if $c; + $c->log->debug("converting $dt from '$from_tz' to '$to_tz'") if $c; + $from_tz = 'local' if (not defined $from_tz or lc($from_tz) eq 'system'); + $to_tz = 'local' if (not defined $to_tz or lc($to_tz) eq 'system'); + $dt = $dt->clone; #do not touch the original + return $dt if (is_infinite($dt) or $from_tz eq $to_tz); + my $tz = $dt->time_zone; #save away the original tz the dt was marked with + $dt->set_time_zone("floating") unless $tz->is_floating;; #unmark + $dt->set_time_zone($from_tz); #set "from" tz + $dt->set_time_zone($to_tz); #convert to "to" tz + $dt->set_time_zone("floating"); #unmark + $dt->set_time_zone($tz) unless $tz->is_floating; #mark again with the original tz + return $dt; +} + sub is_infinite_past { my $dt = shift; return $dt->year <= 1000; diff --git a/lib/NGCP/Panel/Utils/ProfilePackages.pm b/lib/NGCP/Panel/Utils/ProfilePackages.pm index 0343493859..626431484a 100644 --- a/lib/NGCP/Panel/Utils/ProfilePackages.pm +++ b/lib/NGCP/Panel/Utils/ProfilePackages.pm @@ -25,12 +25,17 @@ use constant _DEFAULT_INITIAL_BALANCE => 0.0; use constant _TOPUP_START_MODE => 'topup'; use constant _1ST_START_MODE => '1st'; +use constant _1ST_TZ_START_MODE => '1st_tz'; use constant _CREATE_START_MODE => 'create'; +use constant _CREATE_TZ_START_MODE => 'create_tz'; use constant _TOPUP_INTERVAL_START_MODE => 'topup_interval'; -use constant _START_MODE_PRESERVE_EOM => { _TOPUP_START_MODE . '' => 0, - _1ST_START_MODE . '' => 0, - _CREATE_START_MODE . '' => 1}; +use constant _START_MODE_PRESERVE_EOM => { + _TOPUP_START_MODE . '' => 0, + _1ST_START_MODE . '' => 0, + _1ST_TZ_START_MODE . '' => 0, + _CREATE_START_MODE . '' => 1, + _CREATE_TZ_START_MODE . '' => 1}; use constant _DEFAULT_START_MODE => '1st'; use constant _DEFAULT_PROFILE_INTERVAL_UNIT => 'month'; @@ -127,7 +132,9 @@ sub resize_actual_contract_balance { my $end_of_resized_interval = _get_resized_interval_end(ctime => $now, create_timestamp => NGCP::Panel::Utils::DateTime::set_local_tz($contract->create_timestamp // $contract->modify_timestamp), start_mode => $new_start_mode, - is_topup => $is_topup); + is_topup => $is_topup, + tz => $contract->timezone, + c => $c,); my $resized_balance_values = _get_resized_balance_values(schema => $schema, balance => $actual_balance, #old_start_mode => $old_start_mode, @@ -213,6 +220,7 @@ sub catchup_contract_balances { $now //= NGCP::Panel::Utils::DateTime::set_local_tz($contract->modify_timestamp); $old_package = $contract->profile_package if !exists $params{old_package}; my $contract_create = NGCP::Panel::Utils::DateTime::set_local_tz($contract->create_timestamp // $contract->modify_timestamp); + my $tz = $contract->timezone; $suppress_underrun //= 0; $topup_amount //= 0.0; $profiles_added //= 0; @@ -277,7 +285,9 @@ PREPARE_BALANCE_CATCHUP: #now => $start_of_next_interval, interval_unit => $interval_unit, interval_value => $interval_value, - create => $contract_create); + create => $contract_create, + tz => $tz, + c => $c,); my $balance_values = _get_balance_values(schema => $schema, c => $c, stime => $stime, @@ -612,7 +622,9 @@ PREPARE_BALANCE_INITIAL: start_mode => $start_mode, interval_unit => $interval_unit, interval_value => $interval_value, - create => NGCP::Panel::Utils::DateTime::set_local_tz($contract->create_timestamp // $contract->modify_timestamp),); + create => NGCP::Panel::Utils::DateTime::set_local_tz($contract->create_timestamp // $contract->modify_timestamp), + tz => $contract->timezone, + c => $c,); my $balance_values = _get_balance_values(schema => $schema, c => $c, stime => $stime, @@ -773,12 +785,12 @@ sub get_free_ratio { sub _get_balance_interval_start_end { my (%params) = @_; - my ($now,$start_mode,$last_etime,$interval_unit,$interval_value,$create) = @params{qw/now start_mode last_etime interval_unit interval_value create/}; + my ($now,$start_mode,$last_etime,$interval_unit,$interval_value,$create,$tz,$c) = @params{qw/now start_mode last_etime interval_unit interval_value create tz c/}; my ($stime,$etime,$ctime) = (undef,undef,$now // NGCP::Panel::Utils::DateTime::current_local); unless ($last_etime) { #initial interval - $stime = _get_interval_start($ctime,$start_mode); + $stime = _get_interval_start($ctime,$start_mode,$tz,$c); } else { $stime = _add_second($last_etime->clone,1); } @@ -807,8 +819,8 @@ sub _get_balance_interval_start_end { sub _get_resized_interval_end { my (%params) = @_; - my ($ctime, $create, $start_mode,$is_topup) = @params{qw/ctime create_timestamp start_mode is_topup/}; - if (_CREATE_START_MODE eq $start_mode) { + my ($ctime, $create, $start_mode,$is_topup,$tz,$c) = @params{qw/ctime create_timestamp start_mode is_topup tz c/}; + if (_CREATE_START_MODE eq $start_mode or _CREATE_TZ_START_MODE eq $start_mode) { my $start_of_next_interval; if ($ctime->day >= $create->day) { #e.g. ctime=30. Jan 2015 17:53, create=30. -> 28. Feb 2015 00:00 @@ -823,9 +835,16 @@ sub _get_resized_interval_end { $start_of_next_interval = $ctime->clone->set(day => $create->day)->truncate(to => 'day'); } } + if ($tz and _CREATE_TZ_START_MODE eq $start_mode) { + $start_of_next_interval = NGCP::Panel::Utils::DateTime::convert_tz($start_of_next_interval,$tz->name,'local',$c); + } + return $start_of_next_interval->subtract(seconds => 1); + } elsif (_1ST_START_MODE eq $start_mode or _1ST_TZ_START_MODE eq $start_mode) { + my $start_of_next_interval = $ctime->clone->truncate(to => 'month')->add(months => 1); + if ($tz and _1ST_TZ_START_MODE eq $start_mode) { + $start_of_next_interval = NGCP::Panel::Utils::DateTime::convert_tz($start_of_next_interval,$tz->name,'local',$c); + } return $start_of_next_interval->subtract(seconds => 1); - } elsif (_1ST_START_MODE eq $start_mode) { - return $ctime->clone->truncate(to => 'month')->add(months => 1)->subtract(seconds => 1); } elsif (_TOPUP_START_MODE eq $start_mode) { return $ctime->clone; #->add(seconds => 1); #return NGCP::Panel::Utils::DateTime::infinite_future; @@ -841,17 +860,24 @@ sub _get_resized_interval_end { } sub _get_interval_start { - my ($ctime,$start_mode) = @_; - if (_CREATE_START_MODE eq $start_mode) { - return $ctime->clone->truncate(to => 'day'); - } elsif (_1ST_START_MODE eq $start_mode) { - return $ctime->clone->truncate(to => 'month'); + my ($ctime,$start_mode,$tz,$c) = @_; + my $convert = 0; + my $start = undef; + if (_CREATE_START_MODE eq $start_mode or _CREATE_TZ_START_MODE eq $start_mode) { + $start = $ctime->clone->truncate(to => 'day'); + $convert = 1 if _CREATE_TZ_START_MODE eq $start_mode; + } elsif (_1ST_START_MODE eq $start_mode or _1ST_TZ_START_MODE eq $start_mode) { + $start = $ctime->clone->truncate(to => 'month'); + $convert = 1 if _1ST_TZ_START_MODE eq $start_mode; } elsif (_TOPUP_START_MODE eq $start_mode) { - return $ctime->clone; #->truncate(to => 'day'); + $start = $ctime->clone; #->truncate(to => 'day'); } elsif (_TOPUP_INTERVAL_START_MODE eq $start_mode) { - return $ctime->clone; #->truncate(to => 'day'); + $start = $ctime->clone; #->truncate(to => 'day'); } - return undef; + if ($tz and $convert) { + $start = NGCP::Panel::Utils::DateTime::convert_tz($start,$tz->name,'local',$c); + } + return $start; } sub _add_interval {