MT#13903 "topup_interval" start mode impl

The prior "topup" start mode for balance intervals
(contract_balances) creates intervals for each
top-up using a voucher, resulting in dynamic length.

This new "topup_interval" start mode will just align
the *first* balance interval upon the topup. Subsequent
intervals use the constant interval unit+count
specified in the profile package.

Melita user story is completely covered now.

Change-Id: I0a8b8d73a7fbf054d0aa8b2b1e73a54609fdeee0
changes/93/2293/1
Rene Krenn 10 years ago
parent f7d5dc51de
commit d54bd5d360

@ -89,6 +89,26 @@ has_field 'free_time_spent' => (
},
);
has_field 'topup_count' => (
type => 'Integer',
#label => 'Free-Time Balance',
#required => 1,
element_attr => {
rel => ['tooltip'],
title => ['The number of top-ups performed in this interval.']
},
);
has_field 'timely_topup_count' => (
type => 'Integer',
#label => 'Free-Time Balance',
#required => 1,
element_attr => {
rel => ['tooltip'],
title => ['The number of top-ups performed in the \'timely\' span of this interval.']
},
);
1;
# vim: set tabstop=4 expandtab:

@ -104,7 +104,8 @@ has_field 'balance_interval_start_mode' => (
options => [
{ value => 'create', label => 'upon customer creation' },
{ value => '1st', label => '1st day of month' },
{ value => 'topup', label => 'restart interval upon top-up' },
{ value => 'topup_interval', label => 'start interval upon top-up' },
{ value => 'topup', label => 'new interval for each top-up' },
],
element_attr => {
rel => ['tooltip'],

@ -105,7 +105,8 @@ has_field 'balance_interval_start_mode' => (
options => [
{ value => 'create', label => 'upon customer creation' },
{ value => '1st', label => '1st day of month' },
{ value => 'topup', label => 'restart interval upon top-up' },
{ value => 'topup_interval', label => 'start interval upon top-up' },
{ value => 'topup', label => 'new interval for each top-up' },
],
element_attr => {
rel => ['tooltip'],

@ -23,18 +23,20 @@ use constant _DEFAULT_INITIAL_BALANCE => 0.0;
use constant _TOPUP_START_MODE => 'topup';
use constant _1ST_START_MODE => '1st';
use constant _CREATE_START_MODE => 'create';
#use constant _TOPUP_INTERVAL_START_MODE => 'topup_interval';
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 _DEFAULT_START_MODE => '1st';
use constant _DEFAULT_PROFILE_INTERVAL_UNIT => 'week';
use constant _DEFAULT_PROFILE_INTERVAL_UNIT => 'month';
use constant _DEFAULT_PROFILE_INTERVAL_COUNT => 1;
use constant _DEFAULT_PROFILE_FREE_TIME => 0;
use constant _DEFAULT_PROFILE_FREE_CASH => 0.0;
#use constant _DEFAULT_NOTOPUP_DISCARD_INTERVALS => undef;
sub get_contract_balance {
my %params = @_;
my($c,$contract,$now,$schema,$stime,$etime) = @params{qw/c contract now schema stime etime/};
@ -75,35 +77,35 @@ sub resize_actual_contract_balance {
} elsif (!defined $old_package && defined $new_package) {
$old_start_mode = _DEFAULT_START_MODE;
$new_start_mode = $new_package->balance_interval_start_mode if $new_package->balance_interval_start_mode ne _DEFAULT_START_MODE;
$create_next_balance = _TOPUP_START_MODE eq $new_package->balance_interval_start_mode && $is_topup;
$create_next_balance = (_TOPUP_START_MODE eq $new_package->balance_interval_start_mode ||
_TOPUP_INTERVAL_START_MODE eq $new_package->balance_interval_start_mode) && $is_topup;
} elsif (defined $old_package && defined $new_package) {
if ($old_package->balance_interval_start_mode ne $new_package->balance_interval_start_mode) { #&& $old_package->id != $new_package->id ?
if ($old_package->balance_interval_start_mode ne $new_package->balance_interval_start_mode) {
$old_start_mode = $old_package->balance_interval_start_mode;
$new_start_mode = $new_package->balance_interval_start_mode;
$create_next_balance = _TOPUP_START_MODE eq $new_package->balance_interval_start_mode && $is_topup;
$create_next_balance = (_TOPUP_START_MODE eq $new_package->balance_interval_start_mode ||
_TOPUP_INTERVAL_START_MODE eq $new_package->balance_interval_start_mode) && $is_topup;
} elsif (_TOPUP_START_MODE eq $new_package->balance_interval_start_mode && $is_topup) {
$old_start_mode = _TOPUP_START_MODE;
$new_start_mode = _TOPUP_START_MODE;
$create_next_balance = 1;
} elsif (_TOPUP_INTERVAL_START_MODE eq $new_package->balance_interval_start_mode && $is_topup
&& NGCP::Panel::Utils::DateTime::is_infinite_future($actual_balance->end)) {
$old_start_mode = _TOPUP_INTERVAL_START_MODE;
$new_start_mode = _TOPUP_INTERVAL_START_MODE;
$create_next_balance = 1;
}
#} elsif (_TOPUP_INTERVAL_START_MODE eq $new_package->balance_interval_start_mode && $is_topup) {
# $old_start_mode = _TOPUP_INTERVAL_START_MODE;
# $new_start_mode = _TOPUP_INTERVAL_START_MODE;
# xx$create_next_balance = 1;
#}
}
if ($old_start_mode && $new_start_mode && $actual_balance->start < $now) {
my $end_of_resized_interval = _get_resized_interval_end(ctime => $now,
create_timestamp => $contract->create_timestamp // $contract->modify_timestamp,
start_mode => $new_start_mode);
start_mode => $new_start_mode,
is_topup => $is_topup);
my $resized_balance_values = _get_resized_balance_values(schema => $schema,
balance => $actual_balance,
old_start_mode => $old_start_mode,
new_start_mode => $new_start_mode,
#old_start_mode => $old_start_mode,
#new_start_mode => $new_start_mode,
etime => $end_of_resized_interval);
#try {
# $schema->txn_do(sub {
@ -115,7 +117,7 @@ sub resize_actual_contract_balance {
if ($create_next_balance) {
$actual_balance = catchup_contract_balances(schema => $schema,
contract => $contract,
old_package => $old_package,
old_package => $new_package, #$old_package,
now => $end_of_resized_interval->clone->add(seconds => 1),
);
}
@ -136,6 +138,8 @@ sub resize_actual_contract_balance {
#};
}
return $actual_balance;
}
@ -149,13 +153,23 @@ sub catchup_contract_balances {
$now //= $contract->modify_timestamp;
$old_package = $contract->profile_package if !exists $params{old_package};
my ($start_mode,$interval_unit,$interval_value,$carry_over_mode,$has_package);
my ($start_mode,$interval_unit,$interval_value,$carry_over_mode,$has_package,$notopup_expiration);
if (defined $contract->contact->reseller_id && $old_package) {
$start_mode = $old_package->balance_interval_start_mode;
$interval_unit = $old_package->balance_interval_unit;
$interval_value = $old_package->balance_interval_value;
$carry_over_mode = $old_package->carry_over_mode;
my $notopup_discard_intervals = $old_package->notopup_discard_intervals;
if ($notopup_discard_intervals) {
#take the start of the latest interval where a topup occured,
#add the allowed number+1 of the current package' intervals.
#the balance is discarded if the start of the next package
#exceed this calculated expiration date.
my $last_balance_w_topup = $contract->contract_balances->search({ topup_count => { '>' => 0 } },{ order_by => { '-desc' => 'end'},})->first;
$last_balance_w_topup = $contract->contract_balances->search(undef,{ order_by => { '-asc' => 'start'},})->first unless $last_balance_w_topup;
$notopup_expiration = _add_interval($last_balance_w_topup->start,$interval_unit,$notopup_discard_intervals + 1) if $last_balance_w_topup;
}
$has_package = 1;
} else {
$start_mode = _DEFAULT_START_MODE;
@ -186,16 +200,17 @@ sub catchup_contract_balances {
interval_unit => $interval_unit,
interval_value => $interval_value,
create => $contract->create_timestamp // $contract->modify_timestamp);
my $balance_values = _get_balance_values(schema => $schema,
stime => $stime,
etime => $etime,
start_mode => $start_mode,
#start_mode => $start_mode,
contract => $contract,
profile => $profile,
carry_over_mode => $carry_over_mode,
last_balance => $last_balance,
last_profile => $last_profile,
notopup_expiration => $notopup_expiration,
);
$last_profile = $profile;
@ -280,7 +295,8 @@ sub topup_contract_balance {
&& ($timely_duration_unit = $old_package->timely_duration_unit)
&& ($timely_duration_value = $old_package->timely_duration_value)) {
my $timely_end;
if (_TOPUP_START_MODE ne $old_package->balance_interval_start_mode) {
#if (_TOPUP_START_MODE ne $old_package->balance_interval_start_mode) {
if (!NGCP::Panel::Utils::DateTime::is_infinite_future($balance->end)) {
$timely_end = $balance->end;
} else {
$timely_end = _add_interval($balance->start,$old_package->balance_interval_unit,$old_package->balance_interval_value,
@ -292,6 +308,9 @@ sub topup_contract_balance {
$is_timely = ($now >= $timely_start && $now <= $timely_end ? 1 : 0);
}
$balance->update({ topup_count => $balance->topup_count + 1,
timely_topup_count => $balance->timely_topup_count + $is_timely});
$balance = resize_actual_contract_balance(c => $c,
contract => $contract,
old_package => $old_package,
@ -300,9 +319,7 @@ sub topup_contract_balance {
is_topup => 1,
);
$balance->update({ cash_balance => $balance->cash_balance + $topup_amount,
topup_count => $balance->topup_count + 1,
timely_topup_count => $balance->timely_topup_count + $is_timely});
$balance->update({ cash_balance => $balance->cash_balance + $topup_amount });
$balance->discard_changes();
return $balance;
@ -341,7 +358,7 @@ sub create_initial_contract_balance {
my $balance_values = _get_balance_values(schema => $schema,
stime => $stime,
etime => $etime,
start_mode => $start_mode,
#start_mode => $start_mode,
now => $now,
profile => $profile,
initial_balance => $initial_balance, # * 100.0,
@ -372,20 +389,20 @@ sub create_initial_contract_balance {
sub _get_resized_balance_values {
my %params = @_;
my ($c,$balance,$old_start_mode,$new_start_mode,$etime,$schema) = @params{qw/c balance old_start_mode new_start_mode etime schema/};
my ($c,$balance,$etime,$schema) = @params{qw/c balance etime schema/};
$schema //= $c->model('DB');
my ($cash_balance, $free_time_balance) = ($balance->cash_balance,$balance->free_time_balance);
my $contract = $balance->contract;
my $contract_create = $contract->create_timestamp // $contract->modify_timestamp;
if ($balance->start <= $contract_create && $balance->end >= $contract_create) {
if ($balance->start <= $contract_create && (NGCP::Panel::Utils::DateTime::is_infinite_future($balance->end) || $balance->end >= $contract_create)) {
my $bm = get_actual_billing_mapping(schema => $schema, contract => $contract, now => $contract_create); #now => $balance->start); #end); !?
my $profile = $bm->billing_mappings->first->billing_profile;
my $old_ratio = _get_free_ratio($contract_create,$old_start_mode,$balance->start,$balance->end);
my $old_ratio = _get_free_ratio($contract_create,$balance->start,$balance->end);
my $old_free_cash = $old_ratio * ($profile->interval_free_cash // _DEFAULT_PROFILE_FREE_CASH);
my $old_free_time = $old_ratio * ($profile->interval_free_time // _DEFAULT_PROFILE_FREE_TIME);
my $new_ratio = _get_free_ratio($contract_create,$new_start_mode,$balance->start,$etime);
my $new_ratio = _get_free_ratio($contract_create,$balance->start,$etime);
my $new_free_cash = $new_ratio * ($profile->interval_free_cash // _DEFAULT_PROFILE_FREE_CASH);
my $new_free_time = $new_ratio * ($profile->interval_free_time // _DEFAULT_PROFILE_FREE_TIME);
$cash_balance = $new_free_cash - $old_free_cash;
@ -398,7 +415,7 @@ sub _get_resized_balance_values {
sub _get_balance_values {
my %params = @_;
my($c, $profile, $last_profile, $contract, $last_balance, $stime, $etime, $initial_balance, $carry_over_mode, $now, $start_mode, $schema) = @params{qw/c profile last_profile contract last_balance stime etime initial_balance carry_over_mode now start_mode schema/};
my($c, $profile, $last_profile, $contract, $last_balance, $stime, $etime, $initial_balance, $carry_over_mode, $now, $notopup_expiration, $schema) = @params{qw/c profile last_profile contract last_balance stime etime initial_balance carry_over_mode now notopup_expiration schema/};
$schema //= $c->model('DB');
$now //= $contract->create_timestamp // $contract->modify_timestamp;
@ -406,15 +423,17 @@ sub _get_balance_values {
my $ratio;
if ($last_balance) {
if (_CARRY_OVER_MODE eq $carry_over_mode || (_CARRY_OVER_TIMELY_MODE eq $carry_over_mode && $last_balance->timely_topup_count > 0)) {
if ((_CARRY_OVER_MODE eq $carry_over_mode
|| (_CARRY_OVER_TIMELY_MODE eq $carry_over_mode && $last_balance->timely_topup_count > 0)
) && (!$notopup_expiration || $stime < $notopup_expiration)) {
#if (!defined $last_profile) {
# my $bm_last = get_actual_billing_mapping(schema => $schema, contract => $contract, now => $last_balance->start); #end); !?
# $last_profile = $bm_last->billing_mappings->first->billing_profile;
#}
my $contract_create = $contract->create_timestamp // $contract->modify_timestamp;
$ratio = 1.0;
if ($last_balance->start <= $contract_create && $last_balance->end >= $contract_create) {
$ratio = _get_free_ratio($contract_create,$start_mode,$last_balance->start,$last_balance->end);
if ($last_balance->start <= $contract_create && $last_balance->end >= $contract_create) { #$last_balance->end is never +inf here
$ratio = _get_free_ratio($contract_create,$last_balance->start,$last_balance->end);
}
my $old_free_cash = $ratio * ($last_profile->interval_free_cash // _DEFAULT_PROFILE_FREE_CASH);
$cash_balance = $last_balance->cash_balance;
@ -426,7 +445,7 @@ sub _get_balance_values {
$ratio = 1.0;
} else {
$cash_balance = (defined $initial_balance ? $initial_balance : _DEFAULT_INITIAL_BALANCE);
$ratio = _get_free_ratio($now,$start_mode,$stime, $etime);
$ratio = _get_free_ratio($now,$stime, $etime);
}
my $free_cash = $ratio * ($profile->interval_free_cash // _DEFAULT_PROFILE_FREE_CASH);
@ -445,8 +464,8 @@ sub _get_balance_values {
}
sub _get_free_ratio {
my ($now,$start_mode,$stime,$etime) = @_;
if (_TOPUP_START_MODE ne $start_mode) {
my ($now,$stime,$etime) = @_;
if (!NGCP::Panel::Utils::DateTime::is_infinite_future($etime)) {
my $ctime;
if (defined $now) {
$ctime = ($now->clone->truncate(to => 'day') > $stime ? $now->clone->truncate(to => 'day') : $now);
@ -468,29 +487,29 @@ sub _get_balance_interval_start_end {
my ($stime,$etime,$ctime) = (undef,undef,$now // NGCP::Panel::Utils::DateTime::current_local);
unless ($last_etime) {
unless ($last_etime) { #initial interval
$stime = _get_interval_start($ctime,$start_mode);
} else {
$stime = $last_etime->clone->add(seconds => 1);
}
if (defined $stime) { #lets crash in the create statement
if (_TOPUP_START_MODE ne $start_mode) {
$etime = _add_interval($stime,$interval_unit,$interval_value,_START_MODE_PRESERVE_EOM->{$start_mode} ? $create : undef)->subtract(seconds => 1);
} else {
$etime = NGCP::Panel::Utils::DateTime::infinite_future;
}
#if (_TOPUP_START_MODE eq $start_mode) {
# $etime = NGCP::Panel::Utils::DateTime::infinite_future;
#} elsif (_TOPUP_INTERVAL_START_MODE eq $start_mode) {
# if ($first_balance) {
# $etime = _add_interval($stime,$interval_unit,$interval_value,_START_MODE_PRESERVE_EOM->{$start_mode} ? $first_balance->end : undef)->subtract(seconds => 1);
# } else {
# $etime = NGCP::Panel::Utils::DateTime::infinite_future;
# }
#} else {
if (defined $stime) {
#if (_TOPUP_START_MODE ne $start_mode) {
# $etime = _add_interval($stime,$interval_unit,$interval_value,_START_MODE_PRESERVE_EOM->{$start_mode} ? $create : undef)->subtract(seconds => 1);
#}
#} else {
# $etime = NGCP::Panel::Utils::DateTime::infinite_future;
#}
if (_TOPUP_START_MODE eq $start_mode) {
$etime = NGCP::Panel::Utils::DateTime::infinite_future;
} elsif (_TOPUP_INTERVAL_START_MODE eq $start_mode) {
if ($last_etime) {
$etime = _add_interval($stime,$interval_unit,$interval_value)->subtract(seconds => 1); #no eom preserve, since we don't store the begin of the first interval
} else { #initial interval
$etime = NGCP::Panel::Utils::DateTime::infinite_future;
}
} else {
$etime = _add_interval($stime,$interval_unit,$interval_value,_START_MODE_PRESERVE_EOM->{$start_mode} ? $create : undef)->subtract(seconds => 1);
}
}
return ($stime,$etime);
@ -498,7 +517,7 @@ sub _get_balance_interval_start_end {
sub _get_resized_interval_end {
my (%params) = @_;
my ($ctime, $create, $start_mode) = @params{qw/ctime create_timestamp start_mode/};
my ($ctime, $create, $start_mode,$is_topup) = @params{qw/ctime create_timestamp start_mode is_topup/};
if (_CREATE_START_MODE eq $start_mode) {
my $start_of_next_interval;
if ($ctime->day >= $create->day) {
@ -520,11 +539,14 @@ sub _get_resized_interval_end {
} elsif (_TOPUP_START_MODE eq $start_mode) {
return $ctime->clone; #->add(seconds => 1);
#return NGCP::Panel::Utils::DateTime::infinite_future;
}
#} elsif (_TOPUP_INTERVAL_START_MODE eq $start_mode) {
# return $ctime->clone; #->add(seconds => 1);
# #return NGCP::Panel::Utils::DateTime::infinite_future;
#}
} elsif (_TOPUP_INTERVAL_START_MODE eq $start_mode) {
#return $ctime->clone; #->add(seconds => 1);
if ($is_topup) {
return $ctime->clone; #->add(seconds => 1);
} else {
return NGCP::Panel::Utils::DateTime::infinite_future;
}
}
return undef;
}
@ -536,10 +558,9 @@ sub _get_interval_start {
return $ctime->clone->truncate(to => 'month');
} elsif (_TOPUP_START_MODE eq $start_mode) {
return $ctime->clone; #->truncate(to => 'day');
} elsif (_TOPUP_INTERVAL_START_MODE eq $start_mode) {
return $ctime->clone; #->truncate(to => 'day');
}
#} elsif (_TOPUP_INTERVAL_START_MODE eq $start_mode) {
# return $ctime->clone; #->truncate(to => 'day');
#}
return undef;
}
@ -551,7 +572,8 @@ sub _add_interval {
return $from->clone->add(weeks => $interval_value);
} elsif ('month' eq $interval_unit) {
my $to = $from->clone->add(months => $interval_value, end_of_month => 'preserve');
#'preserve' mode correction:
#DateTime's "preserve" mode would get from 30.Jan to 30.Mar, when adding 2 months
#When adding 1 month two times, we get 28.Mar or 29.Mar, so we adjust:
if (defined $align_eom_dt
&& $to->day > $align_eom_dt->day
&& $from->day == NGCP::Panel::Utils::DateTime::last_day_of_month($from)) {

@ -161,7 +161,7 @@ my $profile_map = {};
my $billingprofile = _create_billing_profile("test_default");
if (_get_allow_fake_client_time()) {
{
my $network_a = _create_billing_network_a();
my $network_b = _create_billing_network_b();
@ -175,57 +175,77 @@ if (_get_allow_fake_client_time()) {
my $profile_gold_a = _create_billing_profile('GOLD_NETWORK_A');
my $profile_gold_b = _create_billing_profile('GOLD_NETWORK_B');
my $base_package = _create_base_profile_package($profile_base_any,$profile_base_a,$profile_base_b,$network_a,$network_b);
my $silver_package = _create_silver_profile_package($base_package,$profile_silver_a,$profile_silver_b,$network_a,$network_b);
my $extension_package = _create_extension_profile_package($base_package,$profile_silver_a,$profile_silver_b,$network_a,$network_b);
my $gold_package = _create_gold_profile_package($base_package,$profile_gold_a,$profile_gold_b,$network_a,$network_b);
_set_time(NGCP::Panel::Utils::DateTime::from_string('2015-06-03 13:00:00'));
_set_time(NGCP::Panel::Utils::DateTime::from_string('2015-06-05 13:00:00'));
my $customer_A = _create_customer($base_package);
my $subscriber_A = _create_subscriber($customer_A);
my $v_silver_1 = _create_voucher(10,'SILVER1'.$t,undef,$silver_package);
my $v_extension_1 = _create_voucher(2,'EXTENSION1'.$t,undef,$extension_package);
my $v_gold_1 = _create_voucher(20,'GOLD1'.$t,undef,$gold_package);
_set_time(NGCP::Panel::Utils::DateTime::from_string('2015-06-03 13:00:00'));
my $customer_x = _create_customer($base_package);
my $subscriber_x = _create_subscriber($customer_x);
_set_time(NGCP::Panel::Utils::DateTime::from_string('2015-06-21 13:00:00'));
_perform_topup_voucher($subscriber_x,$v_silver_1);
_perform_topup_voucher($subscriber_A,$v_silver_1);
_set_time(NGCP::Panel::Utils::DateTime::from_string('2015-07-21 13:00:00'));
_set_time(NGCP::Panel::Utils::DateTime::from_string('2015-10-01 13:00:00'));
_check_interval_history($customer_x,[
{ start => '~2015-06-03 13:00:00', stop => '~2015-06-21 13:00:00', cash => 0, profile => $profile_base_b->{id} },
{ start => '~2015-06-21 13:00:00', stop => $infinite_future, cash => 8, profile => $profile_silver_b->{id} },
_check_interval_history($customer_A,[
{ start => '~2015-06-05 13:00:00', stop => '~2015-06-21 13:00:00', cash => 0, profile => $profile_base_b->{id} },
{ start => '~2015-06-21 13:00:00', stop => '~2015-07-21 13:00:00', cash => 8, profile => $profile_silver_b->{id} },
{ start => '~2015-07-21 13:00:00', stop => '~2015-08-21 13:00:00', cash => 0, profile => $profile_silver_b->{id} },
{ start => '~2015-08-21 13:00:00', stop => '~2015-09-21 13:00:00', cash => 0, profile => $profile_silver_b->{id} },
{ start => '~2015-09-21 13:00:00', stop => '~2015-10-21 13:00:00', cash => 0, profile => $profile_silver_b->{id} },
]);
_set_time(NGCP::Panel::Utils::DateTime::from_string('2015-06-05 13:00:00'));
my $customer_B = _create_customer($base_package);
my $subscriber_B = _create_subscriber($customer_B);
my $v_silver_2 = _create_voucher(10,'SILVER2'.$t,undef,$silver_package);
my $v_extension_1 = _create_voucher(2,'EXTENSION1'.$t,undef,$extension_package);
#_set_time(NGCP::Panel::Utils::DateTime::from_string('2015-06-03 13:00:00'));
#my $customer_y = _create_customer($base_package);
#my $subscriber_y = _create_subscriber($customer_y);
_set_time(NGCP::Panel::Utils::DateTime::from_string('2015-06-27 13:00:00'));
#_set_time(NGCP::Panel::Utils::DateTime::from_string('2015-03-04 13:00:00'));
_perform_topup_voucher($subscriber_B,$v_silver_2);
#_perform_topup_voucher($subscriber,$v_extension_1);
_set_time(NGCP::Panel::Utils::DateTime::from_string('2015-07-27 12:00:00'));
_perform_topup_voucher($subscriber_B,$v_extension_1);
_set_time(NGCP::Panel::Utils::DateTime::from_string('2015-10-01 13:00:00'));
_check_interval_history($customer_B,[
{ start => '~2015-06-05 13:00:00', stop => '~2015-06-27 13:00:00', cash => 0, profile => $profile_base_b->{id} },
{ start => '~2015-06-27 13:00:00', stop => '~2015-07-27 13:00:00', cash => 8, profile => $profile_silver_b->{id} },
{ start => '~2015-07-27 13:00:00', stop => '~2015-08-27 13:00:00', cash => 8, profile => $profile_silver_b->{id} },
{ start => '~2015-08-27 13:00:00', stop => '~2015-09-27 13:00:00', cash => 0, profile => $profile_silver_b->{id} },
{ start => '~2015-09-27 13:00:00', stop => '~2015-10-27 13:00:00', cash => 0, profile => $profile_silver_b->{id} },
]);
_set_time(NGCP::Panel::Utils::DateTime::from_string('2015-06-05 13:00:00'));
my $customer_C = _create_customer($base_package);
my $subscriber_C = _create_subscriber($customer_C);
my $v_gold_1 = _create_voucher(20,'GOLD1'.$t,undef,$gold_package);
_set_time(NGCP::Panel::Utils::DateTime::from_string('2015-07-02 13:00:00'));
_perform_topup_voucher($subscriber_C,$v_gold_1);
_set_time(NGCP::Panel::Utils::DateTime::from_string('2015-10-01 13:00:00'));
_check_interval_history($customer_C,[
{ start => '~2015-06-05 13:00:00', stop => '~2015-07-02 13:00:00', cash => 0, profile => $profile_base_b->{id} },
{ start => '~2015-07-02 13:00:00', stop => '~2015-08-02 13:00:00', cash => 15, profile => $profile_gold_b->{id} },
{ start => '~2015-08-02 13:00:00', stop => '~2015-09-02 13:00:00', cash => 15, profile => $profile_gold_b->{id} },
{ start => '~2015-09-02 13:00:00', stop => '~2015-10-02 13:00:00', cash => 15, profile => $profile_gold_b->{id} },
]);
# #my $voucher = _create_voucher(10,'A'.$t);
#
# #my $customer = _create_customer();
#
# #$voucher = _create_voucher(11,'B'.$t,$customer);
#
# my $prof_package_topup20 = _create_profile_package('topup');
#
# my $voucher = _create_voucher(20,'C'.$t,undef,$prof_package_topup20);
_set_time();
}
my $prof_package_create30d = _create_profile_package('create','day',30);
my $prof_package_1st30d = _create_profile_package('1st','day',30);
@ -235,18 +255,18 @@ if (_get_allow_fake_client_time()) {
my $prof_package_create2w = _create_profile_package('create','week',2);
my $prof_package_1st2w = _create_profile_package('1st','week',2);
my $prof_package_topup = _create_profile_package('topup');
my $prof_package_topup = _create_profile_package('topup');
{
_set_time(NGCP::Panel::Utils::DateTime::from_string('2014-12-30 13:00:00'));
my $customer_topup = _create_customer($prof_package_topup); #create closest to now
my $customer_wo = _create_customer();
my $customer_create1m = _create_customer($prof_package_create1m);
_set_time(NGCP::Panel::Utils::DateTime::from_string('2015-04-02 02:00:00'));
_check_interval_history($customer_topup,[
{ start => '~2014-12-30 13:00:00', stop => $infinite_future},
]);
@ -403,44 +423,75 @@ if (_get_allow_fake_client_time()) {
{ start => '~2014-10-04 13:00:00', stop => $infinite_future},
],NGCP::Panel::Utils::DateTime::from_string($t1));
my $voucher = _create_voucher(10,'topup_start_mode_test'.$t,$customer,$prof_package_create1m);
my $voucher1 = _create_voucher(10,'topup_start_mode_test1'.$t,$customer);
my $voucher2 = _create_voucher(10,'topup_start_mode_test2'.$t,$customer,$prof_package_create1m);
my $subscriber = _create_subscriber($customer);
#_check_interval_history($customer,[
# { start => '2014-10-01 00:00:00', stop => '~2014-10-04 13:00:00'},
# { start => '~2014-10-04 13:00:00', stop => $infinite_future},
#],NGCP::Panel::Utils::DateTime::from_string($t1));
$t1 = $ts;
$ts = '2014-10-23 13:00:00';
_set_time(NGCP::Panel::Utils::DateTime::from_string($ts));
_perform_topup_voucher($subscriber,$voucher);
_check_interval_history($customer,[
{ start => '~2014-10-04 13:00:00', stop => $infinite_future},
],NGCP::Panel::Utils::DateTime::from_string($t1));
_perform_topup_voucher($subscriber,$voucher1);
_check_interval_history($customer,[
{ start => '2014-10-01 00:00:00', stop => '~2014-10-04 13:00:00'},
{ start => '~2014-10-04 13:00:00', stop => '2014-10-06 23:59:59'},
{ start => '~2014-10-04 13:00:00', stop => '~2014-10-23 13:00:00'},
{ start => '~2014-10-23 13:00:00', stop => $infinite_future},
],NGCP::Panel::Utils::DateTime::from_string($t1));
$t1 = $ts;
$ts = '2014-12-09 13:00:00';
$ts = '2014-11-29 13:00:00';
_set_time(NGCP::Panel::Utils::DateTime::from_string($ts));
_check_interval_history($customer,[
{ start => '~2014-10-04 13:00:00', stop => '2014-10-06 23:59:59'},
{ start => '2014-10-07 00:00:00', stop => '2014-11-06 23:59:59'},
{ start => '2014-11-07 00:00:00', stop => '2014-12-06 23:59:59'},
{ start => '2014-12-07 00:00:00', stop => '2015-01-06 23:59:59'},
{ start => '~2014-10-23 13:00:00', stop => $infinite_future},
],NGCP::Panel::Utils::DateTime::from_string($t1));
_perform_topup_voucher($subscriber,$voucher2);
_check_interval_history($customer,[
{ start => '~2014-10-23 13:00:00', stop => '2014-12-06 23:59:59'},
],NGCP::Panel::Utils::DateTime::from_string($t1));
$customer = _switch_package($customer);
_check_interval_history($customer,[
{ start => '~2014-10-04 13:00:00', stop => '2014-10-06 23:59:59'},
{ start => '2014-10-07 00:00:00', stop => '2014-11-06 23:59:59'},
{ start => '2014-11-07 00:00:00', stop => '2014-12-06 23:59:59'},
{ start => '2014-12-07 00:00:00', stop => '2014-12-31 23:59:59'},
{ start => '~2014-10-23 13:00:00', stop => '2014-11-30 23:59:59', cash => 20},
],NGCP::Panel::Utils::DateTime::from_string($t1));
_set_time();
}
{
_set_time(NGCP::Panel::Utils::DateTime::from_string('2015-01-30 13:00:00'));
my $package = _create_profile_package('create','month',1,3);
my $customer = _create_customer($package);
my $subscriber = _create_subscriber($customer);
my $v_notopup = _create_voucher(10,'notopup'.$t);
_set_time(NGCP::Panel::Utils::DateTime::from_string('2015-02-17 13:00:00'));
_perform_topup_voucher($subscriber,$v_notopup);
_set_time(NGCP::Panel::Utils::DateTime::from_string('2015-06-01 13:00:00'));
_check_interval_history($customer,[
{ start => '2015-01-30 00:00:00', stop => '2015-02-27 23:59:59', cash => 10, topups => 1 }, #topup
{ start => '2015-02-28 00:00:00', stop => '2015-03-29 23:59:59', cash => 10, topups => 0 },
{ start => '2015-03-30 00:00:00', stop => '2015-04-29 23:59:59', cash => 10, topups => 0 },
{ start => '2015-04-30 00:00:00', stop => '2015-05-29 23:59:59', cash => 10, topups => 0 },
{ start => '2015-05-30 00:00:00', stop => '2015-06-29 23:59:59', cash => 0, topups => 0 },
#{ start => '2015-06-30 00:00:00', stop => '2015-07-29 23:59:59', cash => 0, topups => 0 },
]);
_set_time();
}
if (_get_allow_delay_commit()) {
_set_time(NGCP::Panel::Utils::DateTime::current_local->subtract(months => 3));
_create_customers_threaded(3);
@ -543,7 +594,7 @@ sub _check_interval_history {
#my @got_interval_history = ();
my $i = 0;
my $limit = '';
my $error = 0;
my $ok = 1;
my @intervals;
$limit = '&start=' . DateTime::Format::ISO8601->parse_datetime($limit_dt) if defined $limit_dt;
my $label = 'interval history of contract with ' . ($customer->{profile_package_id} ? 'package ' . $package_map->{$customer->{profile_package_id}}->{name} : 'no package') . ': ';
@ -559,7 +610,7 @@ sub _check_interval_history {
is($selfuri, $nexturi, $label . "check _links.self.href of collection");
my $colluri = URI->new($selfuri);
$error = ok($collection->{total_count} == $total_count, $label . "check 'total_count' of collection") || $error;
$ok = ok($collection->{total_count} == $total_count, $label . "check 'total_count' of collection") && $ok;
my %q = $colluri->query_form;
ok(exists $q{page} && exists $q{rows}, $label . "check existence of 'page' and 'row' in 'self'");
@ -604,7 +655,7 @@ sub _check_interval_history {
#my $fetched = delete $page_items->{$interval->{id}};
#delete $fetched->{content};
#is_deeply($interval,$fetched,$label . "compare fetched and embedded item deeply");
$error = _compare_interval($interval,$expected_interval_history->[$i],$label) || $error;
$ok = _compare_interval($interval,$expected_interval_history->[$i],$label) && $ok;
delete $interval->{'_links'};
push(@intervals,$interval);
$i++
@ -614,47 +665,58 @@ sub _check_interval_history {
} while($nexturi);
ok($i == $total_count,$label . "check if all expected items are listed");
diag(Dumper(\@intervals)) if $error;
diag(Dumper(\@intervals)) if !$ok;
}
sub _compare_interval {
my ($got,$expected,$label) = @_;
my $error = 0;
my $ok = 1;
if ($expected->{start}) {
#is(NGCP::Panel::Utils::DateTime::from_string($got->{start}),NGCP::Panel::Utils::DateTime::from_string($expected->{start}),$label . "check interval " . $got->{id} . " start timestmp");
if (substr($expected->{start},0,1) eq '~') {
$error = _is_ts_approx($got->{start},$expected->{start},$label . "check interval " . $got->{id} . " start timestamp") || $error;
$ok = _is_ts_approx($got->{start},$expected->{start},$label . "check interval " . $got->{id} . " start timestamp") && $ok;
} else {
$error = is($got->{start},$expected->{start},$label . "check interval " . $got->{id} . " start timestmp") || $error;
$ok = is($got->{start},$expected->{start},$label . "check interval " . $got->{id} . " start timestmp") && $ok;
}
}
if ($expected->{stop}) {
#is(NGCP::Panel::Utils::DateTime::from_string($got->{stop}),NGCP::Panel::Utils::DateTime::from_string($expected->{stop}),$label . "check interval " . $got->{id} . " stop timestmp");
if (substr($expected->{stop},0,1) eq '~') {
$error = _is_ts_approx($got->{stop},$expected->{stop},$label . "check interval " . $got->{id} . " stop timestamp") || $error;
$ok = _is_ts_approx($got->{stop},$expected->{stop},$label . "check interval " . $got->{id} . " stop timestamp") && $ok;
} else {
$error = is($got->{stop},$expected->{stop},$label . "check interval " . $got->{id} . " stop timestmp") || $error;
$ok = is($got->{stop},$expected->{stop},$label . "check interval " . $got->{id} . " stop timestmp") && $ok;
}
}
if ($expected->{cash}) {
$error = is($got->{cash_balance},$expected->{cash},$label . "check interval " . $got->{id} . " cash balance") || $error;
$ok = is($got->{cash_balance},$expected->{cash},$label . "check interval " . $got->{id} . " cash balance") && $ok;
}
if ($expected->{profile}) {
$error = is($got->{profile_id},$expected->{profile_id},$label . "check interval " . $got->{id} . " billing profile") || $error;
$ok = is($got->{profile_id},$expected->{profile_id},$label . "check interval " . $got->{id} . " billing profile") && $ok;
}
if ($expected->{topups}) {
$ok = is($got->{topup_count},$expected->{topups},$label . "check interval " . $got->{id} . " topup count") && $ok;
}
if ($expected->{timely_topups}) {
$ok = is($got->{timely_topup_count},$expected->{timely_topups},$label . "check interval " . $got->{id} . " timely topup count") && $ok;
}
return $ok;
}
sub _is_ts_approx {
my ($got,$expected,$label) = @_;
$got = NGCP::Panel::Utils::DateTime::from_string($got);
$expected = NGCP::Panel::Utils::DateTime::from_string(substr($expected,1));
my $lower = $expected->clone->subtract(seconds => 5);
my $upper = $expected->clone->add(seconds => 5);
my $epsilon = 10;
my $lower = $expected->clone->subtract(seconds => $epsilon);
my $upper = $expected->clone->add(seconds => $epsilon);
return ok($got >= $lower && $got <= $upper,$label . ' approximately (' . $got . ')');
}
@ -759,20 +821,21 @@ sub _get_rfc_1123_now {
sub _create_profile_package {
my ($start_mode,$interval_unit,$interval_value) = @_;
my ($start_mode,$interval_unit,$interval_value,$notopup_discard_intervals) = @_;
$req = HTTP::Request->new('POST', $uri.'/api/profilepackages/');
$req->header('Content-Type' => 'application/json');
$req->header('Prefer' => 'return=representation');
$req->header('X-Fake-Clienttime' => _get_rfc_1123_now());
my $name = $start_mode . ($interval_unit ? '/' . $interval_value . ' ' . $interval_unit : '');
$req->content(JSON::to_json({
name => "test '" . $name . "' profile package " . $t,
description => "test profile package description " . $t,
name => "test '" . $name . "' profile package " . (scalar keys %$package_map) . '_' . $t,
description => "test profile package description " . (scalar keys %$package_map) . '_' . $t,
reseller_id => $default_reseller_id,
initial_profiles => [{ profile_id => $billingprofile->{id}, }, ],
balance_interval_start_mode => $start_mode,
($interval_unit ? (balance_interval_value => $interval_value,
balance_interval_unit => $interval_unit,) : ()),
notopup_discard_intervals => $notopup_discard_intervals,
}));
$res = $ua->request($req);
is($res->code, 201, "POST test profilepackage - '" . $name . "'");
@ -845,7 +908,7 @@ sub _create_base_profile_package {
initial_profiles => [{ profile_id => $profile_base_any->{id}, },
{ profile_id => $profile_base_a->{id}, network_id => $network_a->{id} },
{ profile_id => $profile_base_b->{id}, network_id => $network_b->{id} }],
balance_interval_start_mode => 'topup',
balance_interval_start_mode => 'topup_interval',
balance_interval_value => 1,
balance_interval_unit => 'month',
carry_over_mode => 'carry_over_timely',
@ -878,7 +941,7 @@ sub _create_silver_profile_package {
description => "silver test profile package description " . $t,
reseller_id => $default_reseller_id,
initial_profiles => $base_package->{initial_profiles},
balance_interval_start_mode => 'topup',
balance_interval_start_mode => 'topup_interval',
balance_interval_value => 1,
balance_interval_unit => 'month',
carry_over_mode => 'carry_over_timely',
@ -916,7 +979,7 @@ sub _create_extension_profile_package {
description => "extension test profile package description " . $t,
reseller_id => $default_reseller_id,
initial_profiles => $base_package->{initial_profiles},
balance_interval_start_mode => 'topup',
balance_interval_start_mode => 'topup_interval',
balance_interval_value => 1,
balance_interval_unit => 'month',
carry_over_mode => 'carry_over_timely',
@ -954,7 +1017,7 @@ sub _create_gold_profile_package {
description => "gold test profile package description " . $t,
reseller_id => $default_reseller_id,
initial_profiles => $base_package->{initial_profiles},
balance_interval_start_mode => 'topup',
balance_interval_start_mode => 'topup_interval',
balance_interval_value => 1,
balance_interval_unit => 'month',
carry_over_mode => 'carry_over',

Loading…
Cancel
Save