MT#17795 populate balance before/after etc.

+added contract_balance_id's
+fix: get_call_costs calculates total call costs
 for cash_balance_interval only if no balance
 is available. which is not mandatory for
 post-paid *still under discussion*
 REMOVED FOR THIS CHANGE
+option to shuffle cdr batch to reduce lock waits
 when running multiple rateomats against same cdr
 table
+fix: free cash carry over calculation was
 wrong (typos only)
+fix: provider profile selection
 is now caller-IP based, so roaming should be
 properly supported here now as well
+reworked and cleanup provider "info" retrieval
 (billing profile and package, balance records)
+balance underrun checks that are performed after
 call costs were calculated will skip applying
 subscriber lock and adding underrun profile mappings,
 if preapid && out direction && a call cost record
 from swrate exists. this should avoid polluting
 the billing mappings table in the first.
+.t now use run_rateomat_threaded to work with
 perl's "prove"
+update/create statements are modified to be make
 it safe if multiple rateomat's are processing
 the same accounting.cdr table at the same time:
 UPDATE CDR .. WHERE id = ?
  AND rating_status = 'unrated'"
+rateomat termination behaviour: do not exit
 upon the first but a given number of failed cdrs
+reworked prepaid cost table preloading
+option to disable prepaid preference flag update
+prepared to take prepaid flag values from cdr,
 not profile
+prepaid costs processing testcase
+onnet full-scale testcase
+offnet full-scale testcase
+test case order and comments
+rateomat parallel execution testcase
+fix missing source/destination_lnp_prefix columns
 for duplication stmt
+writing profile package id, contract balance id, cash
 balance before/after, free time balance before/after
 fields to EAV tables
+extended onnet testcase to verify written EAV values
+extended offnet testcase to verify written EAV values
+freetime testcase

Change-Id: I3b08b2bb04adf2272d9400048ce45e3b709e7971
changes/91/4491/20
Rene Krenn 9 years ago
parent 698ee371d2
commit 19382e59e1

File diff suppressed because it is too large Load Diff

@ -48,6 +48,7 @@ our @EXPORT_OK = qw(
setup_subscriber
setup_package
to_pretty_json
cartesian_product
);
my ($netloc) = ($uri =~ m!^https?://(.*)/?.*$!);
@ -457,11 +458,11 @@ sub _compare_interval {
}
}
if ($expected->{cash}) {
if (defined $expected->{cash}) {
$ok = is($got->{cash_balance},$expected->{cash},$label . "check interval " . $got->{id} . " cash balance $got->{cash_balance} = $expected->{cash}") && $ok;
}
if ($expected->{debit}) {
if (defined $expected->{debit}) {
$ok = is($got->{cash_debit},$expected->{debit},$label . "check interval " . $got->{id} . " cash balance interval $got->{cash_debit} = $expected->{debit}") && $ok;
}
@ -469,14 +470,18 @@ sub _compare_interval {
$ok = is($got->{billing_profile_id},$expected->{profile},$label . "check interval " . $got->{id} . " billing profile id $got->{billing_profile_id} = $expected->{profile}") && $ok;
}
if ($expected->{topups}) {
if (defined $expected->{topups}) {
$ok = is($got->{topup_count},$expected->{topups},$label . "check interval " . $got->{id} . " topup count $got->{topup_count} = $expected->{topups}") && $ok;
}
if ($expected->{timely_topups}) {
if (defined $expected->{timely_topups}) {
$ok = is($got->{timely_topup_count},$expected->{timely_topups},$label . "check interval " . $got->{id} . " timely topup count $got->{timely_topup_count} = $expected->{timely_topups}") && $ok;
}
if (defined $expected->{id}) {
$ok = is($got->{id},$expected->{id},$label . "check interval " . $got->{id} . " id = $expected->{id}") && $ok;
}
return $ok;
}
@ -672,12 +677,13 @@ sub setup_subscriber {
}
sub setup_provider {
my ($domain_name,$rates,$networks,$provider_rate) = @_;
my ($domain_name,$rates,$networks,$provider_rate,$type) = @_;
my $provider = {};
$provider->{contact} = create_systemcontact();
$provider->{contract} = create_contract(
contact_id => $provider->{contact}->{id},
billing_profile_id => 1, #default profile id
type => $type // 'reseller',
);
$provider->{reseller} = create_reseller(
contract_id => $provider->{contract}->{id},
@ -696,7 +702,7 @@ sub setup_provider {
billing_profile_id => $provider->{profile}->{id},
);
} else {
ok(!$split_peak_parts,'provider rate required for split cdrs');
ok(!$split_peak_parts,'split_peak_parts disabled');
#use default billing profile id, which already comes with fees.
#$provider->{profile} = create_billing_profile(
# reseller_id => $provider->{reseller}->{id},
@ -719,10 +725,12 @@ sub setup_provider {
push(@{$provider->{subscriber_fees}},$profile_fee);
}
$provider->{networks} = [];
foreach my $network_blocks (@$networks) {
push(@{$provider->{networks}},create_billing_network(
blocks => $network_blocks,
));
if (defined $networks) {
foreach my $network_blocks (@$networks) {
push(@{$provider->{networks}},create_billing_network(
blocks => $network_blocks,
));
}
}
$provider->{customers} = [];
$provider->{packages} = [];
@ -734,11 +742,15 @@ sub _setup_fees {
my $prepaid = delete $params{prepaid};
my $peaktime_weekdays = delete $params{peaktime_weekdays};
my $peaktime_specials = delete $params{peaktime_special};
my $interval_free_time = delete $params{interval_free_time};
#my $interval_free_cash = delete $params{interval_free_cash};
my $profile = create_billing_profile(
reseller_id => $reseller->{id},
(defined $prepaid ? (prepaid => $prepaid) : ()),
(defined $peaktime_weekdays ? (peaktime_weekdays => $peaktime_weekdays) : ()),
(defined $peaktime_specials ? (peaktime_special => $peaktime_specials) : ()),
(defined $interval_free_time ? (interval_free_time => $interval_free_time) : ()),
#(defined $interval_free_cash ? (interval_free_cash => $interval_free_cash) : ()),
);
my $zone = create_billing_zone(
billing_profile_id => $profile->{id},
@ -768,4 +780,62 @@ sub to_pretty_json {
return JSON::to_json(shift, {pretty => 1}); # =~ s/(^\s*{\s*)|(\s*}\s*$)//rg =~ s/\n /\n/rg;
}
sub cartesian_product {
#Copyright (c) 2009 Philip R Brenan.
#This module is free software. It may be used, redistributed and/or
#modified under the same terms as Perl itself.
my $s = shift; # Subroutine to call to process each element of the product
my @C = @_; # Lists to be multiplied
my @c = (); # Current element of cartesian product
my @P = (); # Cartesian product
my $n = 0; # Number of elements in product
return 0 if @C == 0; # Empty product
@C == grep {ref eq 'ARRAY'} @C or die("Arrays of things required by cartesian");
# Generate each cartesian product when there are no prior cartesian products.
my $p; $p = sub {
if (@c < @C) {
for (@{$C[@c]}) {
push @c, $_;
&$p();
pop @c;
}
} else {
my $p = [ @c ];
push @P, bless $p if &$s(@$p);
}
};
# Generate each cartesian product allowing for prior cartesian products.
my $q; $q = sub {
if (@c < @C) {
for (@{$C[@c]}) {
push @c, $_;
&$q();
pop @c;
}
} else {
my $p = [ map {ref $_ eq __PACKAGE__ ? @$_ : $_} @c ];
push @P, bless $p if &$s(@$p);
}
};
# Determine optimal method of forming cartesian products for this call
if (grep { grep {ref $_ eq __PACKAGE__ } @$_ } @C) {
&$q();
} else {
&$p();
}
@P;
}
1;

@ -8,6 +8,7 @@ use Test::More;
#use IPC::System::Simple qw(capturex);
use Data::Dumper;
use Time::HiRes qw();
use Data::Rmap qw();
require Exporter;
@ -18,11 +19,26 @@ our @EXPORT_OK = qw(
create_cdrs
get_cdrs
get_cdrs_by_call_id
prepare_offnet_subsriber_info
prepare_cdr
check_cdr
check_cdrs
delete_cdrs
create_prepaid_costs_cdrs
get_prepaid_costs_cdrs
prepare_prepaid_costs_cdr
check_prepaid_costs_cdr
check_prepaid_costs_cdrs
delete_prepaid_costs_cdrs
get_usr_preferences
generate_call_id
decimal_to_string
check_cdr_time_balance_data
check_cdr_cash_balance_data
check_cdr_relation_data
get_cdr_time_balance_data
get_cdr_cash_balance_data
get_cdr_relation_data
);
$ENV{RATEOMAT_BILLING_DB_USER} //= 'root';
@ -46,7 +62,11 @@ my $provisioningdb_port = $ENV{RATEOMAT_PROVISIONING_DB_PORT} // '3306';
my $provisioningdb_user = $ENV{RATEOMAT_PROVISIONING_DB_USER} or die('Missing provisioning DB user setting.');
my $provisioningdb_pass = $ENV{RATEOMAT_PROVISIONING_DB_PASS};
my $t = time;
my %offnet_domain_subscriber_map = ();
my %cdr_map = ();
my %prepaid_costs_cdr_map = ();
END {
my @ids = keys %cdr_map;
@ -54,6 +74,11 @@ END {
my $deleted_cdrs = delete_cdrs(\@ids);
diag('teardown - cdr IDs ' . join(', ',map { $_->{id}; } @$deleted_cdrs) . ' deleted');
}
@ids = keys %prepaid_costs_cdr_map;
if ((scalar @ids) > 0) {
my $deleted_prepaid_costs = delete_prepaid_costs_cdrs(\@ids);
diag('teardown - cdr IDs ' . join(', ',map { $_->{cdr}->{id}; } @$deleted_prepaid_costs) . ' and prepaid costs records deleted');
}
}
sub run_rateomat {
@ -127,29 +152,6 @@ sub run_rateomat_threads {
return $result;
}
sub create_cdrs {
my ($cdrs) = @_;
my $is_ary = 'ARRAY' eq ref $cdrs;
my $result = ($is_ary ? [] : undef);
my $dbh;
eval {
$dbh = _connect_accounting_db();
if ($is_ary) {
_begin_transaction($dbh);
$result = _create_cdrs($dbh,$cdrs);
_commit_transaction($dbh);
} else {
$result = _create_cdr($dbh,@_);
}
};
if ($@) {
diag($@);
eval { _rollback_transaction($dbh); } if $is_ary;
}
_disconnect_db($dbh);
return $result;
}
sub _get_cli {
my $subscriber = shift;
my $pn = $subscriber->{primary_number};
@ -164,6 +166,23 @@ sub _random_string {
return join('',@chars[ map{ rand @chars } 1 .. $length ]);
}
sub prepare_offnet_subsriber_info {
my ($username_primary_number,$domain) = @_;
my $n = 1 + scalar keys %offnet_domain_subscriber_map;
Data::Rmap::rmap { $_ =~ s/<n>/$n/; $_ =~ s/<i>/$n/; $_ =~ s/<t>/$t/; } ($domain);
$n = 1 + (exists $offnet_domain_subscriber_map{$domain} ? scalar keys %{$offnet_domain_subscriber_map{$domain}} : 0);
Data::Rmap::rmap { $_ =~ s/<n>/$n/; $_ =~ s/<i>/$n/; $_ =~ s/<t>/$t/; } ($username_primary_number);
my $username;
if ('HASH' eq ref $username_primary_number) {
$username = $username_primary_number->{cc} . $username_primary_number->{ac} . $username_primary_number->{sn};
} else {
$username = $username_primary_number;
}
$offnet_domain_subscriber_map{$domain} = {} if not exists $offnet_domain_subscriber_map{$domain};
$offnet_domain_subscriber_map{$domain}->{$username} = 1;
return { username => $username, domain => $domain };
}
sub prepare_cdr {
my ($source_subscriber,
$source_peering_subsriber_info,
@ -173,12 +192,13 @@ sub prepare_cdr {
$dest_reseller,
$source_ip,
$time,
$duration) = @_;
return {
$duration,
@overrides) = @_;
my $cdr = {
#id => ,
#update_time => ,
source_user_id => ($source_subscriber ? $source_subscriber->{uuid} : '0'),
source_provider_id => $source_reseller->{contract_id},
source_provider_id => ($source_reseller ? $source_reseller->{contract_id} : '0'),
#source_external_subscriber_id => ,
#source_external_contract_id => ,
source_account_id => ($source_subscriber ? $source_subscriber->{customer_id} : '0'),
@ -198,15 +218,15 @@ sub prepare_cdr {
#source_gpp8 => ,
#source_gpp9 => ,
destination_user_id => ($dest_subscriber ? $dest_subscriber->{uuid} : '0'),
destination_provider_id => $dest_reseller->{contract_id},
destination_provider_id => ($dest_reseller ? $dest_reseller->{contract_id} : '0'),
#destination_external_subscriber_id => ,
#destination_external_contract_id => ,
destination_account_id => ($dest_subscriber ? $dest_subscriber->{customer_id} : '0'),
destination_user => ($dest_subscriber ? $dest_subscriber->{username} : $dest_peering_subsriber_info->{username}),
destination_domain => ($dest_subscriber ? $dest_subscriber->{domain} : $source_peering_subsriber_info->{domain}),
destination_user_dialed => ($dest_subscriber ? $dest_subscriber->{username} : $source_peering_subsriber_info->{username}),
destination_user_in => ($dest_subscriber ? $dest_subscriber->{username} : $source_peering_subsriber_info->{username}),
destination_domain_in => ($dest_subscriber ? $dest_subscriber->{domain} : $source_peering_subsriber_info->{domain}),
destination_domain => ($dest_subscriber ? $dest_subscriber->{domain} : $dest_peering_subsriber_info->{domain}),
destination_user_dialed => ($dest_subscriber ? $dest_subscriber->{username} : $dest_peering_subsriber_info->{username}),
destination_user_in => ($dest_subscriber ? $dest_subscriber->{username} : $dest_peering_subsriber_info->{username}),
destination_domain_in => ($dest_subscriber ? $dest_subscriber->{domain} : $dest_peering_subsriber_info->{domain}),
#destination_gpp0 => ,
#destination_gpp1 => ,
#destination_gpp2 => ,
@ -225,7 +245,7 @@ sub prepare_cdr {
init_time => $time,
start_time => $time,
duration => $duration,
call_id => '*TEST*'._random_string(26,'a'..'z','A'..'Z',0..9,'-','.'),
call_id => generate_call_id(),
#source_carrier_cost => ,
#source_reseller_cost => ,
#source_customer_cost => ,
@ -259,7 +279,58 @@ sub prepare_cdr {
#rating_status => 'unrated',
#exported_at => ,
#export_status => ,
@overrides
};
return $cdr;
}
sub prepare_prepaid_costs_cdr {
my ($source_subscriber,
$source_peering_subsriber_info,
$source_reseller,
$dest_subscriber,
$dest_peering_subsriber_info,
$dest_reseller,
$source_ip,
$time,
$duration,
$prepaid_cost,
$prepaid_free_time_used,
@overrides) = @_;
my $cdr = prepare_cdr($source_subscriber,
$source_peering_subsriber_info,
$source_reseller,
$dest_subscriber,
$dest_peering_subsriber_info,
$dest_reseller,
$source_ip,
$time,
$duration,
@overrides);
my ($S, $M, $H, $d, $m, $Y) = localtime($time);
return { cdr => $cdr,
prepaid_costs => {
#id =>
call_id => $cdr->{call_id},
cost => $prepaid_cost,
free_time_used => $prepaid_free_time_used // 0,
timestamp => sprintf("%04d-%02d-%02d %02d:%02d:%02d", $Y + 1900,$m + 1, $d, $H, $M, $S),
},
};
}
sub generate_call_id {
return '*TEST*'._random_string(26,'a'..'z','A'..'Z',0..9,'-','.');
}
sub decimal_to_string {
my $value = shift;
if (defined $value) {
return sprintf('%6f',$value);
} else {
return undef;
}
}
sub check_cdrs {
@ -285,6 +356,76 @@ sub check_cdr {
}
sub check_prepaid_costs_cdrs {
my ($label,$prepaid_costs_exists,%expected_map) = @_;
my $ok = 1;
foreach my $id (keys %expected_map) {
$ok = check_prepaid_costs_cdr($label,$id,$expected_map{$id},$prepaid_costs_exists) && $ok;
}
return $ok;
}
sub check_prepaid_costs_cdr {
my ($label,$id,$expected_cdr,$prepaid_costs_exists) = @_;
my $got_prepaid_costs_cdr = get_prepaid_costs_cdrs($id);
my $ok = 1;
foreach my $field (keys %$expected_cdr) {
$ok = is($got_prepaid_costs_cdr->{cdr}->{$field},$expected_cdr->{$field},$label . $field . ' = ' . $expected_cdr->{$field}) && $ok;
}
$ok = is(defined $got_prepaid_costs_cdr->{prepaid_costs} ? '1' : '0',$prepaid_costs_exists,$label . 'prepaid cost record ' . ($prepaid_costs_exists ? 'exists' : 'does not exist')) && $ok;
diag(Dumper({result_cdr => $got_prepaid_costs_cdr})) if !$ok;
return $ok;
}
sub create_cdrs {
my ($cdrs) = @_;
my $is_ary = 'ARRAY' eq ref $cdrs;
my $result = ($is_ary ? [] : undef);
my $dbh;
eval {
$dbh = _connect_accounting_db();
if ($is_ary) {
_begin_transaction($dbh);
$result = _create_cdrs($dbh,$cdrs);
_commit_transaction($dbh);
} else {
$result = _create_cdr($dbh,@_);
}
};
if ($@) {
diag($@);
eval { _rollback_transaction($dbh); } if $is_ary;
}
_disconnect_db($dbh);
return $result;
}
sub create_prepaid_costs_cdrs {
my ($cdrs) = @_;
my $is_ary = 'ARRAY' eq ref $cdrs;
my $result = ($is_ary ? [] : undef);
my $dbh;
eval {
$dbh = _connect_accounting_db();
if ($is_ary) {
_begin_transaction($dbh);
$result = _create_prepaid_costs_cdrs($dbh,$cdrs);
_commit_transaction($dbh);
} else {
$result = _create_prepaid_costs_cdr($dbh,@_);
}
};
if ($@) {
diag($@);
eval { _rollback_transaction($dbh); } if $is_ary;
}
_disconnect_db($dbh);
return $result;
}
sub _create_cdr {
my ($dbh,%values) = @_;
if ($dbh) {
@ -294,6 +435,19 @@ sub _create_cdr {
return undef;
}
sub _create_prepaid_costs_cdr {
my ($dbh,$values) = @_;
if ($dbh) {
if (_insert($dbh,'accounting.prepaid_costs',$values->{prepaid_costs})) {
my $id = _insert($dbh,'accounting.cdr',$values->{cdr});
return _get_prepaid_costs_cdr($dbh,$id,1) if ok($id,'cdr id '.$id.' with prepaid costs record created');
} else {
fail('creating prepaid costs for call_id '.$values->{prepaid_costs}->{call_id}.' record');
}
}
return { prepaid_costs => undef, cdr => undef };
}
sub _create_cdrs {
my ($dbh,$cdrs) = @_;
if ($dbh) {
@ -307,6 +461,23 @@ sub _create_cdrs {
return [];
}
sub _create_prepaid_costs_cdrs {
my ($dbh,$prepaid_costs_cdrs) = @_;
if ($dbh) {
my @ids = ();
foreach my $values (@$prepaid_costs_cdrs) {
if (_insert($dbh,'accounting.prepaid_costs',$values->{prepaid_costs})) {
my $id = _insert($dbh,'accounting.cdr',$values->{cdr});
push(@ids,$id) if $id;
} else {
fail('creating prepaid costs for call_id '.$values->{prepaid_costs}->{call_id}.' record');
}
}
return _get_prepaid_costs_cdrs($dbh,\@ids,1) if ok((scalar @ids) == (scalar @$prepaid_costs_cdrs),'cdrs id '.join(', ',@ids).' with prepaid costs records created');
};
return [];
}
sub get_cdrs {
my $ids = shift;
my $is_ary = 'ARRAY' eq ref $ids;
@ -323,6 +494,22 @@ sub get_cdrs {
return $result;
}
sub get_prepaid_costs_cdrs {
my $ids = shift;
my $is_ary = 'ARRAY' eq ref $ids;
my $result = ($is_ary ? [] : undef);
eval {
my $dbh = _connect_accounting_db();
$result = _get_prepaid_costs_cdrs($dbh,$ids) if $is_ary;
$result = _get_prepaid_costs_cdr($dbh,$ids) if !$is_ary;
_disconnect_db($dbh);
};
if ($@) {
diag($@);
}
return $result;
}
sub get_cdrs_by_call_id {
my $call_id = shift;
my $result = [];
@ -345,8 +532,28 @@ sub delete_cdrs {
eval {
$dbh = _connect_accounting_db();
_begin_transaction($dbh);
$result = _delete($dbh,'accounting.cdr',$ids) if $is_ary;
$result = _delete($dbh,'accounting.cdr',[ $ids ])->[0] if !$is_ary;
$result = _delete_cdrs($dbh,$ids) if $is_ary;
$result = _delete_cdrs($dbh,[ $ids ])->[0] if !$is_ary;
_commit_transaction($dbh);
};
if ($@) {
diag($@);
eval { _rollback_transaction($dbh); };
}
_disconnect_db($dbh);
return $result;
}
sub delete_prepaid_costs_cdrs {
my $ids = shift;
my $is_ary = 'ARRAY' eq ref $ids;
my $result = ($is_ary ? [] : undef);
my $dbh;
eval {
$dbh = _connect_accounting_db();
_begin_transaction($dbh);
$result = _delete_prepaid_costs_cdrs($dbh,$ids) if $is_ary;
$result = _delete_prepaid_costs_cdrs($dbh,[ $ids ])->[0] if !$is_ary;
_commit_transaction($dbh);
};
if ($@) {
@ -371,45 +578,26 @@ sub _get_cdr {
return $cdr;
}
sub get_usr_preferences {
my ($subscriber,$attribute) = @_;
my $usr_prefs = [];
my $dbh;
eval {
$dbh = _connect_provisioning_db();
_begin_transaction($dbh);
my $sth = $dbh->prepare('SELECT * FROM provisioning.voip_preferences WHERE attribute = ?')
or die("Error preparing select voip preferences statement: ".$dbh->errstr);
$sth->execute($attribute);
my $pref = $sth->fetchrow_hashref();
sub _get_prepaid_costs_cdr {
my ($dbh,$id,$created) = @_;
my $prepaid_costs_cdr = undef;
if ($dbh) {
my $sth = $dbh->prepare('SELECT * FROM accounting.cdr WHERE id = ?')
or die("Error preparing select cdr statement: ".$dbh->errstr);
$sth->execute($id);
my $cdr = $sth->fetchrow_hashref();
$sth->finish();
if (defined $pref && $pref->{id}) {
$sth = $dbh->prepare('SELECT id FROM provisioning.voip_subscribers WHERE uuid = ? LIMIT 1')
or die("Error preparing select voip subscribers statement: ".$dbh->errstr);
$sth->execute($subscriber->{uuid});
my ($prov_subscriber_id) = $sth->fetchrow_array();
if ($cdr) {
$sth = $dbh->prepare('SELECT * FROM accounting.prepaid_costs WHERE call_id = ?')
or die("Error preparing select prepaid_costs statement: ".$dbh->errstr);
$sth->execute($cdr->{call_id});
my $prepaid_costs = $sth->fetchrow_hashref();
$prepaid_costs_cdr = { cdr => $cdr, prepaid_costs => $prepaid_costs };
$prepaid_costs_cdr_map{$cdr->{id}} = $prepaid_costs_cdr if $created;
$sth->finish();
if ($prov_subscriber_id) {
$sth = $dbh->prepare('SELECT * FROM provisioning.voip_usr_preferences WHERE subscriber_id = ? AND attribute_id = ?')
or die("Error preparing select voip usr preferences statement: ".$dbh->errstr);
$sth->execute($prov_subscriber_id,$pref->{id});
$usr_prefs = $sth->fetchall_arrayref({});
$sth->finish();
} else {
die("cannot find prov subscriber '$subscriber->{uuid}'");
}
} else {
die("cannot find attribute '$attribute'");
}
_commit_transaction($dbh);
_disconnect_db($dbh);
};
if ($@) {
diag($@);
eval { _rollback_transaction($dbh); };
}
_disconnect_db($dbh);
return $usr_prefs;
return $prepaid_costs_cdr;
}
sub _get_cdrs {
@ -430,6 +618,31 @@ sub _get_cdrs {
return $cdrs;
}
sub _get_prepaid_costs_cdrs {
my ($dbh,$ids,$created) = @_;
my @result = ();
if ($dbh) {
my $sth = $dbh->prepare('SELECT * FROM accounting.cdr WHERE id IN ('.substr(',?' x scalar @$ids,1).') ORDER BY id')
or die("Error preparing select cdrs statement: ".$dbh->errstr);
$sth->execute(@$ids);
my $cdrs = $sth->fetchall_arrayref({});
$sth->finish();
my $prepaid_costs;
my $prepaid_costs_cdr;
foreach my $cdr (@$cdrs) {
$sth = $dbh->prepare('SELECT * FROM accounting.prepaid_costs WHERE call_id = ?')
or die("Error preparing select prepaid_costs statement: ".$dbh->errstr);
$sth->execute($cdr->{call_id});
$prepaid_costs = $sth->fetchrow_hashref();
$sth->finish();
$prepaid_costs_cdr = { cdr => $cdr, prepaid_costs => $prepaid_costs };
$prepaid_costs_cdr_map{$cdr->{id}} = $prepaid_costs_cdr if $created;
push(@result,$prepaid_costs_cdr);
}
}
return \@result;
}
sub _get_cdrs_by_callid {
my ($dbh,$call_id,$created) = @_;
my $cdrs = [];
@ -464,13 +677,14 @@ sub _insert {
}
return $id;
}
sub _delete {
my ($dbh,$table,$ids) = @_;
sub _delete_cdrs {
my ($dbh,$ids) = @_;
my $deleted = [];
if ($dbh) {
$deleted = _get_cdrs($dbh,$ids);
my $sth = $dbh->prepare('DELETE FROM ' . $table . ' WHERE id IN ('.substr(',?' x scalar @$ids,1).')')
or die("Error preparing delete statement: ".$dbh->errstr);
_delete_all_cdr_data($dbh,$ids);
my $sth = $dbh->prepare('DELETE FROM accounting.cdr WHERE id IN ('.substr(',?' x scalar @$ids,1).')')
or die("Error preparing delete cdrs statement: ".$dbh->errstr);
$sth->execute(@$ids);
$sth->finish();
foreach my $id (@$ids) {
@ -480,6 +694,278 @@ sub _delete {
return $deleted;
}
sub _delete_prepaid_costs_cdrs {
my ($dbh,$ids) = @_;
my $deleted = [];
if ($dbh) {
$deleted = _get_prepaid_costs_cdrs($dbh,$ids);
_delete_all_cdr_data($dbh,$ids);
my $sth = $dbh->prepare('DELETE cdr,prepaid_costs FROM '.
'accounting.cdr AS cdr '.
'LEFT JOIN accounting.prepaid_costs AS prepaid_costs ON cdr.call_id = prepaid_costs.call_id '.
'WHERE cdr.id IN ('.substr(',?' x scalar @$ids,1).')')
or die("Error preparing delete cdrs with prepaid costs statement: ".$dbh->errstr);
$sth->execute(@$ids);
$sth->finish();
foreach my $id (@$ids) {
delete $prepaid_costs_cdr_map{$id};
}
}
return $deleted;
}
sub get_cdr_relation_data {
my $label = shift;
my $cdr_id = shift;
my $direction = shift;
my $provider = shift;
my $relation = shift;
$label .= 'cdr id '.$cdr_id.' '.$direction.'_'.$provider.'_'.$relation.' ';
my $result = _get_cdr_relation_data($cdr_id,$direction,$provider,$relation);
is(scalar @$result,1,$label.'number of records '.(scalar @$result).' = 1');
return $result->[0]->{val};
}
sub get_cdr_cash_balance_data {
my $label = shift;
my $cdr_id = shift;
my $direction = shift;
my $provider = shift;
my $cash_balance = shift;
$label .= 'cdr id '.$cdr_id.' '.$direction.'_'.$provider.'_'.$cash_balance.' ';
my $result = _get_cdr_cash_balance_data($cdr_id,$direction,$provider,$cash_balance);
is(scalar @$result,1,$label.'number of records '.(scalar @$result).' = 1');
return { before => $result->[0]->{val_before}, after => $result->[0]->{val_after} };
}
sub get_cdr_time_balance_data {
my $label = shift;
my $cdr_id = shift;
my $direction = shift;
my $provider = shift;
my $time_balance = shift;
$label .= 'cdr id '.$cdr_id.' '.$direction.'_'.$provider.'_'.$time_balance.' ';
my $result = _get_cdr_time_balance_data($cdr_id,$direction,$provider,$time_balance);
is(scalar @$result,1,$label.'number of records '.(scalar @$result).' = 1');
return { before => $result->[0]->{val_before}, after => $result->[0]->{val_after} };
}
sub check_cdr_relation_data {
my $label = shift;
my $cdr_id = shift;
my $direction = shift;
my $provider = shift;
my $relation = shift;
my $expected = shift;
$label .= 'cdr id '.$cdr_id.' '.$direction.'_'.$provider.'_'.$relation.' ';
my $result = _get_cdr_relation_data($cdr_id,$direction,$provider,$relation);
if (defined $expected) {
if ((scalar @$result) == 1) {
return is($result->[0]->{val},$expected,$label.$result->[0]->{val}.' = '.$expected);
} else {
return is(scalar @$result,1,$label.'number of records '.(scalar @$result).' = 1');
}
} else {
return is(scalar @$result,0,$label.'number of records '.(scalar @$result).' = 0');
}
}
sub check_cdr_cash_balance_data {
my $label = shift;
my $cdr_id = shift;
my $direction = shift;
my $provider = shift;
my $relation = shift;
my $expected = shift;
$label .= 'cdr id '.$cdr_id.' '.$direction.'_'.$provider.'_'.$relation.' ';
my $result = _get_cdr_cash_balance_data($cdr_id,$direction,$provider,$relation);
if (defined $expected) {
if ((scalar @$result) == 1) {
return is($result->[0]->{val_before},decimal_to_string($expected->{before}),$label.'before '.$result->[0]->{val_before}.' = '.decimal_to_string($expected->{before})) &
is($result->[0]->{val_after},decimal_to_string($expected->{after}),$label.'after '.$result->[0]->{val_after}.' = '.decimal_to_string($expected->{after}));
} else {
return is(scalar @$result,1,$label.'number of records '.(scalar @$result).' = 1');
}
} else {
return is(scalar @$result,0,$label.'number of records '.(scalar @$result).' = 0');
}
}
sub check_cdr_time_balance_data {
my $label = shift;
my $cdr_id = shift;
my $direction = shift;
my $provider = shift;
my $relation = shift;
my $expected = shift;
$label .= 'cdr id '.$cdr_id.' '.$direction.'_'.$provider.'_'.$relation.' ';
my $result = _get_cdr_time_balance_data($cdr_id,$direction,$provider,$relation);
if (defined $expected) {
if ((scalar @$result) == 1) {
return is($result->[0]->{val_before},$expected->{before},$label.'before '.$result->[0]->{val_before}.' = '.$expected->{before}) &
is($result->[0]->{val_after},$expected->{after},$label.'after '.$result->[0]->{val_after}.' = '.$expected->{after});
} else {
return is(scalar @$result,1,$label.'number of records '.(scalar @$result).' = 1');
}
} else {
return is(scalar @$result,0,$label.'number of records '.(scalar @$result).' = 0');
}
}
sub _get_cdr_relation_data {
my $id = shift;
my $direction = shift;
my $provider = shift;
my $relation = shift;
my $result = undef;
eval {
my $dbh = _connect_accounting_db();
$result = _get_cdr_data($dbh,$id,'accounting.cdr_relation_data',[
{ type => $direction, table => 'accounting.cdr_direction', data_col => 'direction_id' },
{ type => $provider, table => 'accounting.cdr_provider', data_col => 'provider_id' },
{ type => $relation, table => 'accounting.cdr_relation', data_col => 'relation_id' },
]);
_disconnect_db($dbh);
};
if ($@) {
diag($@);
}
return $result;
}
sub _get_cdr_cash_balance_data {
my $id = shift;
my $direction = shift;
my $provider = shift;
my $cash_balance = shift;
my $result = undef;
eval {
my $dbh = _connect_accounting_db();
$result = _get_cdr_data($dbh,$id,'accounting.cdr_cash_balance_data',[
{ type => $direction, table => 'accounting.cdr_direction', data_col => 'direction_id' },
{ type => $provider, table => 'accounting.cdr_provider', data_col => 'provider_id' },
{ type => $cash_balance, table => 'accounting.cdr_cash_balance', data_col => 'cash_balance_id' },
]);
_disconnect_db($dbh);
};
if ($@) {
diag($@);
}
return $result;
}
sub _get_cdr_time_balance_data {
my $id = shift;
my $direction = shift;
my $provider = shift;
my $time_balance = shift;
my $result = undef;
eval {
my $dbh = _connect_accounting_db();
$result = _get_cdr_data($dbh,$id,'accounting.cdr_time_balance_data',[
{ type => $direction, table => 'accounting.cdr_direction', data_col => 'direction_id' },
{ type => $provider, table => 'accounting.cdr_provider', data_col => 'provider_id' },
{ type => $time_balance, table => 'accounting.cdr_time_balance', data_col => 'time_balance_id' },
]);
_disconnect_db($dbh);
};
if ($@) {
diag($@);
}
return $result;
}
sub _get_cdr_data {
my ($dbh,$id,$table,$dimensions) = @_;
my $cdr_data = undef;
if ($dbh) {
my $sth;
my @dimension_ids = ();
my $dimension_clause = '';
for my $dimension (@$dimensions) {
$sth = $dbh->prepare('SELECT id FROM '.$dimension->{table}.' WHERE type = ?')
or die("Error preparing select cdr data dimension statement: ".$dbh->errstr);
$sth->execute($dimension->{type});
my ($dimension_id) = $sth->fetchrow_array();
$sth->finish();
push(@dimension_ids,$dimension_id);
$dimension_clause .= ' AND ' . $dimension->{data_col} . ' = ?';
}
$sth = $dbh->prepare('SELECT * FROM '.$table.' WHERE cdr_id = ?' . $dimension_clause)
or die("Error preparing select cdr data statement: ".$dbh->errstr);
$sth->execute($id,@dimension_ids);
$cdr_data = $sth->fetchall_arrayref({});
$sth->finish();
}
return $cdr_data;
}
sub _delete_all_cdr_data {
my ($dbh,$ids) = @_;
_delete_cdr_data($dbh,$ids,'accounting.cdr_relation_data');
_delete_cdr_data($dbh,$ids,'accounting.cdr_cash_balance_data');
_delete_cdr_data($dbh,$ids,'accounting.cdr_time_balance_data');
}
sub _delete_cdr_data { # as long as no triggers are present
my ($dbh,$ids,$table) = @_;
if ($dbh) {
my $sth = $dbh->prepare('DELETE FROM '.$table.' WHERE cdr_id IN ('.substr(',?' x scalar @$ids,1).')')
or die("Error preparing delete cdr data statement: ".$dbh->errstr);
$sth->execute(@$ids);
if ($sth->rows > 0) {
diag($sth->rows . " cdr $table rows deleted");
}
$sth->finish();
}
}
sub get_usr_preferences {
my ($subscriber,$attribute) = @_;
my $usr_prefs = [];
my $dbh;
eval {
$dbh = _connect_provisioning_db();
_begin_transaction($dbh);
my $sth = $dbh->prepare('SELECT * FROM provisioning.voip_preferences WHERE attribute = ?')
or die("Error preparing select voip preferences statement: ".$dbh->errstr);
$sth->execute($attribute);
my $pref = $sth->fetchrow_hashref();
$sth->finish();
if (defined $pref && $pref->{id}) {
$sth = $dbh->prepare('SELECT id FROM provisioning.voip_subscribers WHERE uuid = ? LIMIT 1')
or die("Error preparing select voip subscribers statement: ".$dbh->errstr);
$sth->execute($subscriber->{uuid});
my ($prov_subscriber_id) = $sth->fetchrow_array();
$sth->finish();
if ($prov_subscriber_id) {
$sth = $dbh->prepare('SELECT * FROM provisioning.voip_usr_preferences WHERE subscriber_id = ? AND attribute_id = ?')
or die("Error preparing select voip usr preferences statement: ".$dbh->errstr);
$sth->execute($prov_subscriber_id,$pref->{id});
$usr_prefs = $sth->fetchall_arrayref({});
$sth->finish();
} else {
die("cannot find prov subscriber '$subscriber->{uuid}'");
}
} else {
die("cannot find attribute '$attribute'");
}
_commit_transaction($dbh);
_disconnect_db($dbh);
};
if ($@) {
diag($@);
eval { _rollback_transaction($dbh); };
}
_disconnect_db($dbh);
return $usr_prefs;
}
sub _connect_accounting_db {
my $dbh = DBI->connect("dbi:mysql:database=$accountingdb_name;host=$accountingdb_host;port=$accountingdb_port",
$accountingdb_user, $accountingdb_pass,

@ -0,0 +1,22 @@
use strict;
use Utils::Api qw();
use Utils::Rateomat qw();
use Test::More;
### testcase outline:
### rate-o-mat.pl invocation test
###
### this test verifies that ratomat can be properly invoked
### by the .t test scripts here. any further testcases can
### be skipped unless this one succeeds.
{
ok(Utils::Rateomat::run_rateomat_threads(1,5),"rate-o-mat executed");
}
done_testing();
exit;

@ -0,0 +1,121 @@
use strict;
use Utils::Api qw();
use Utils::Rateomat qw();
use Test::More;
### testcase outline:
### onnet calls between subscribers of multiple resellers
### are rated by multiple rateomat instances running
### concurrently
###
### this tests verify that ratomat can be run safely against
### one and the same accounting.cdr table.
{
my $number_of_rateomat_threads = 3;
my $rateomat_timeout = 60;
my $number_of_providers = 3;
my $number_of_subscribers_per_provider = 3;
my $balance = 0.0;
my %subscribers = ();
foreach (1..$number_of_providers) {
my $rate_interval = 30 + int(rand(31));
my $provider = create_provider($rate_interval);
my $caller_fee = $provider->{subscriber_fees}->[0];
foreach (1..$number_of_subscribers_per_provider) {
my $subscriber = Utils::Api::setup_subscriber($provider,$caller_fee->{profile},$balance,{ cc => 888, ac => '3<n>', sn => '<t>' });
$subscriber->{provider} = $provider;
$subscriber->{fee} = $caller_fee;
$subscriber->{rate_interval} = $rate_interval;
$subscribers{$subscriber->{customer}->{id}} = $subscriber;
}
}
my @caller_callee_matrix = ();
# add calls from each subscriber to each subscriber except itself:
Utils::Api::cartesian_product(sub {
my ($caller,$callee) = @_;
push(@caller_callee_matrix,{ caller => $caller, callee => $callee }) unless $caller->{customer}->{id} == $callee->{customer}->{id};
},[ values %subscribers ],[ values %subscribers ]);
## add calls from each subscriber to itself:
#Utils::Api::cartesian_product(sub {
# my ($caller,$callee) = @_;
# push(@caller_callee_matrix,{ caller => $caller, callee => $callee }) if $caller->{customer}->{id} == $callee->{customer}->{id};
#},[ values %subscribers ],[ values %subscribers ]);
# place calls by generating cdrs:
my @cdr_ids = map { $_->{id}; } @{ Utils::Rateomat::create_cdrs([ map {
Utils::Rateomat::prepare_cdr($_->{caller}->{subscriber},undef,$_->{caller}->{reseller},
$_->{callee}->{subscriber},undef,$_->{callee}->{reseller},
'192.168.0.1',Utils::Api::current_unix(),$_->{caller}->{rate_interval} + 1);
} @caller_callee_matrix ]) };
my $number_of_calls = ($number_of_providers * $number_of_subscribers_per_provider) * ($number_of_providers * $number_of_subscribers_per_provider - 1);
$ENV{RATEOMAT_BATCH_SIZE} = $number_of_calls; # ensure all rateomats grab all cdrs at once
$ENV{RATEOMAT_SHUFFLE_BATCH} = 1; # enable and see the speedup
if (ok((scalar @cdr_ids) == $number_of_calls,'there are '.$number_of_calls.' calls to rate')
&& ok(Utils::Rateomat::run_rateomat_threads($number_of_rateomat_threads, $rateomat_timeout),'rate-o-mat threads executed')) {
ok(Utils::Rateomat::check_cdrs('',
map {
my $cdr = Utils::Rateomat::get_cdrs($_);
my $caller = $subscribers{$cdr->{source_account_id}};
my $call_costs = $caller->{fee}->{fees}->[0]->{onpeak_init_rate} *
$caller->{fee}->{fees}->[0]->{onpeak_init_interval} +
$caller->{fee}->{fees}->[0]->{onpeak_follow_rate} *
$caller->{fee}->{fees}->[0]->{onpeak_follow_interval};
$caller->{call_costs} += $call_costs;
$_ => {
id => $_,
rating_status => 'ok',
source_customer_cost => Utils::Rateomat::decimal_to_string($call_costs),
destination_customer_cost => Utils::Rateomat::decimal_to_string(0.0),
source_reseller_cost => Utils::Rateomat::decimal_to_string(0.0),
destination_reseller_cost => Utils::Rateomat::decimal_to_string(0.0),
};
} @cdr_ids
),'cdrs were all processed');
foreach (keys %subscribers) {
my $caller = $subscribers{$_};
Utils::Api::check_interval_history("caller $_: ",$_,[
{ #cash => (100.0 * $balance - $caller->{call_costs})/100.0,
debit => $caller->{call_costs}/100.0,
},
]);
}
}
}
done_testing();
exit;
sub create_provider {
my $rate_interval = shift;
$rate_interval //= 60;
return Utils::Api::setup_provider('test<n>.com',
[ #rates:
{ #any
onpeak_init_rate => 2,
onpeak_init_interval => $rate_interval,
onpeak_follow_rate => 1,
onpeak_follow_interval => $rate_interval,
offpeak_init_rate => 2,
offpeak_init_interval => $rate_interval,
offpeak_follow_rate => 1,
offpeak_follow_interval => $rate_interval,
},
],
[ #billing networks:
]
);
}

@ -0,0 +1,77 @@
use strict;
use Utils::Api qw();
use Utils::Rateomat qw();
use Test::More;
### testcase outline:
### onnet prepaid calls with costs from prepaid costs
### table
###
### this tests verify that prepaid costs are properly
### cached and cleaned up.
my $provider = Utils::Api::setup_provider('test.com',
[ #rates:
{
prepaid => 1,
onpeak_init_rate => 2,
onpeak_init_interval => 60,
onpeak_follow_rate => 1,
onpeak_follow_interval => 30,
offpeak_init_rate => 2,
offpeak_init_interval => 60,
offpeak_follow_rate => 1,
offpeak_follow_interval => 30,
},
],
);
my $call_costs = ($provider->{subscriber_fees}->[0]->{fee}->{onpeak_init_rate} *
$provider->{subscriber_fees}->[0]->{fee}->{onpeak_init_interval} +
$provider->{subscriber_fees}->[0]->{fee}->{onpeak_follow_rate} *
$provider->{subscriber_fees}->[0]->{fee}->{onpeak_follow_interval})/100.0;
my $call_count = 3;
my $balance = $call_count * $call_costs;
my $profiles_setup = $provider->{subscriber_fees}->[0]->{profile};
my $caller = Utils::Api::setup_subscriber($provider,$profiles_setup,$balance,{ cc => 888, ac => '1<n>', sn => '<t>' });
#my $caller2 = Utils::Api::setup_subscriber($provider,$profiles_setup,$balance,{ cc => 888, ac => '1<n>', sn => '<t>' });
#my $caller3 = Utils::Api::setup_subscriber($provider,$profiles_setup,$balance,{ cc => 888, ac => '1<n>', sn => '<t>' });
my $callee = Utils::Api::setup_subscriber($provider,$profiles_setup,$balance,{ cc => 888, ac => '2<n>', sn => '<t>' });
foreach my $cache_size (($call_count - 1,$call_count)) {
diag('rateomat prepaid costs cache size: '.$cache_size);
$ENV{RATEOMAT_PREPAID_COSTS_CACHE} = $cache_size;
my @cdr_ids = map { $_->{cdr}->{id}; } @{ Utils::Rateomat::create_prepaid_costs_cdrs([ map {
Utils::Rateomat::prepare_prepaid_costs_cdr($caller->{subscriber},undef,$caller->{reseller},
$callee->{subscriber},undef,$callee->{reseller},
'192.168.0.1',Utils::Api::current_unix(),
$provider->{subscriber_fees}->[0]->{fee}->{onpeak_init_interval} + 1,
$call_costs,0);
} (1..$call_count)]) };
ok(Utils::Rateomat::check_prepaid_costs_cdrs('',1,
map { $_ => {
id => $_,
rating_status => 'unrated',
}; } @cdr_ids
),'cdrs and prepaid costs were all prepared');
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat_threads(1),'rate-o-mat executed')) {
ok(Utils::Rateomat::check_prepaid_costs_cdrs('',0,
map { $_ => {
id => $_,
rating_status => 'ok',
source_customer_cost => Utils::Rateomat::decimal_to_string($call_costs),
}; } @cdr_ids
),'cdrs were all processed');
Utils::Api::check_interval_history('',$caller->{customer}->{id},[
{ cash => $balance }, # rateomat must not touch balance
]);
}
}
done_testing();
exit;

@ -0,0 +1,296 @@
use strict;
use Utils::Api qw();
use Utils::Rateomat qw();
use Test::More;
### testcase outline:
### onnet prepaid/postpaid calls of callers to callees with both using
### dedicated reseller fees.
###
### this tests verify all combinations of prepaid/postpaid subscriber customers with
### balance > 0.0/no balance produce correct customer/reseller call cost, cash balance
### and cash balance interval values.
my $init_secs = 60;
my $follow_secs = 30;
my $provider_a = create_provider('testa.com');
my $provider_b = create_provider('testb.com');
my $total_caller_reseller_call_costs = 0.0;
my $total_callee_reseller_call_costs = 0.0;
# full matrix:
foreach my $prepaid ((0,1)) { # prepaid, postpaid
foreach my $balance ((0.0,10.0)) { # zero balance, enough balance
foreach my $prepaid_costs (0..1) { # prepaid: with prepaid_costs records and without (swrate down)
next if (!$prepaid && $prepaid_costs);
my $caller_fee = ($prepaid ? $provider_a->{subscriber_fees}->[1] : $provider_a->{subscriber_fees}->[0]);
my $caller1 = Utils::Api::setup_subscriber($provider_a,$caller_fee->{profile},$balance,{ cc => 888, ac => '1<n>', sn => '<t>' });
my $caller2 = Utils::Api::setup_subscriber($provider_a,$caller_fee->{profile},$balance,{ cc => 888, ac => '1<n>', sn => '<t>' });
my $caller3 = Utils::Api::setup_subscriber($provider_a,$caller_fee->{profile},$balance,{ cc => 888, ac => '1<n>', sn => '<t>' });
my $callee_fee = ($prepaid ? $provider_b->{subscriber_fees}->[1] : $provider_b->{subscriber_fees}->[0]);
my $callee = Utils::Api::setup_subscriber($provider_b,$callee_fee->{profile},$balance,{ cc => 888, ac => '2<n>', sn => '<t>' });
my $caller_call_costs = $caller_fee->{fees}->[0]->{onpeak_init_rate} *
$caller_fee->{fees}->[0]->{onpeak_init_interval} +
$caller_fee->{fees}->[0]->{onpeak_follow_rate} *
$caller_fee->{fees}->[0]->{onpeak_follow_interval};
my $caller_reseller_call_costs = $provider_a->{provider_fee}->{fees}->[0]->{onpeak_init_rate} *
$provider_a->{provider_fee}->{fees}->[0]->{onpeak_init_interval} +
$provider_a->{provider_fee}->{fees}->[0]->{onpeak_follow_rate} *
$provider_a->{provider_fee}->{fees}->[0]->{onpeak_follow_interval};
my $callee_call_costs = $callee_fee->{fees}->[1]->{onpeak_init_rate} *
$callee_fee->{fees}->[1]->{onpeak_init_interval} +
$callee_fee->{fees}->[1]->{onpeak_follow_rate} *
$callee_fee->{fees}->[1]->{onpeak_follow_interval};
my $callee_reseller_call_costs = $provider_b->{provider_fee}->{fees}->[1]->{onpeak_init_rate} *
$provider_b->{provider_fee}->{fees}->[1]->{onpeak_init_interval} +
$provider_b->{provider_fee}->{fees}->[1]->{onpeak_follow_rate} *
$provider_b->{provider_fee}->{fees}->[1]->{onpeak_follow_interval};
my @cdr_ids;
my $start_time = Utils::Api::current_unix() - 5;
if ($prepaid_costs) {
@cdr_ids = map { $_->{cdr}->{id}; } @{ Utils::Rateomat::create_prepaid_costs_cdrs([ map {
Utils::Rateomat::prepare_prepaid_costs_cdr($_->{subscriber},undef,$_->{reseller},
$callee->{subscriber},undef,$callee->{reseller},
'192.168.0.1',$start_time += 1,$init_secs + $follow_secs,
$caller_call_costs,0);
} ($caller1,$caller2,$caller3) ]) };
} else {
@cdr_ids = map { $_->{id}; } @{ Utils::Rateomat::create_cdrs([ map {
Utils::Rateomat::prepare_cdr($_->{subscriber},undef,$_->{reseller},
$callee->{subscriber},undef,$callee->{reseller},
'192.168.0.1',$start_time += 1,$init_secs + $follow_secs);
} ($caller1,$caller2,$caller3) ]) };
}
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat_threads(),'rate-o-mat executed')) {
my $no_balance = ($balance <= 0.0);
my $prepaid_label = ($prepaid ? ($prepaid_costs ? 'prepaid w prepaid costs, ' : 'prepaid w/o prepaid costs, ') : 'postpaid, ');
my $no_balance_label = ($no_balance ? 'no balance' : 'balance');
my $caller_cdr_map = {};
ok(Utils::Rateomat::check_cdrs($prepaid_label.$no_balance_label.': ',
map {
my $cdr = Utils::Rateomat::get_cdrs($_);
$caller_cdr_map->{$cdr->{source_account_id}} = $_;
$_ => { id => $_,
rating_status => 'ok',
source_customer_cost => Utils::Rateomat::decimal_to_string((($prepaid || $no_balance) ? $caller_call_costs : 0.0)),
destination_customer_cost => Utils::Rateomat::decimal_to_string((($prepaid || $no_balance) ? $callee_call_costs : 0.0)),
source_reseller_cost => Utils::Rateomat::decimal_to_string($caller_reseller_call_costs),
destination_reseller_cost => Utils::Rateomat::decimal_to_string($callee_reseller_call_costs),
};
} @cdr_ids
),'cdrs were all processed');
my $label = $prepaid_label.$no_balance_label.', caller 1: ';
my $contract_id = $caller1->{customer}->{id};
my $cash_balance = 100.0 * $balance - (($no_balance || $prepaid_costs) ? 0.0 : $caller_call_costs);
my $balance_id = Utils::Rateomat::get_cdr_relation_data($label,$caller_cdr_map->{$contract_id},'source','customer','contract_balance_id');
Utils::Api::check_interval_history($label,$contract_id,[
{ cash => $cash_balance/100.0,
debit => (($no_balance && !$prepaid_costs) ? $caller_call_costs : 0.0)/100.0,
id => $balance_id,
},
]);
Utils::Rateomat::check_cdr_cash_balance_data($label,$caller_cdr_map->{$contract_id},'source','customer','cash_balance',
{ before => ($prepaid_costs ? $cash_balance + $caller_call_costs : 100.0 * $balance), after => $cash_balance });
$label = $prepaid_label.$no_balance_label.', caller 2: ';
$contract_id = $caller2->{customer}->{id};
$balance_id = Utils::Rateomat::get_cdr_relation_data($label,$caller_cdr_map->{$contract_id},'source','customer','contract_balance_id');
Utils::Api::check_interval_history($label,$contract_id,[
{ cash => $cash_balance/100.0,
debit => (($no_balance && !$prepaid_costs) ? $caller_call_costs : 0.0)/100.0,
id => $balance_id,
},
]);
Utils::Rateomat::check_cdr_cash_balance_data($label,$caller_cdr_map->{$contract_id},'source','customer','cash_balance',
{ before => ($prepaid_costs ? $cash_balance + $caller_call_costs : 100.0 * $balance), after => $cash_balance });
$label = $prepaid_label.$no_balance_label.', caller 3: ';
$contract_id = $caller3->{customer}->{id};
$balance_id = Utils::Rateomat::get_cdr_relation_data($label,$caller_cdr_map->{$contract_id},'source','customer','contract_balance_id');
Utils::Api::check_interval_history($label,$contract_id,[
{ cash => $cash_balance/100.0,
debit => (($no_balance && !$prepaid_costs) ? $caller_call_costs : 0.0)/100.0,
id => $balance_id,
},
]);
Utils::Rateomat::check_cdr_cash_balance_data($label,$caller_cdr_map->{$contract_id},'source','customer','cash_balance',
{ before => ($prepaid_costs ? $cash_balance + $caller_call_costs : 100.0 * $balance), after => $cash_balance });
$label = $prepaid_label.$no_balance_label.', callee: ';
$contract_id = $callee->{customer}->{id};
$cash_balance = 100.0 * $balance - ($no_balance ? 0.0 : 3 * $callee_call_costs);
$balance_id = Utils::Rateomat::get_cdr_relation_data($label,$cdr_ids[0],'destination','customer','contract_balance_id');
Utils::Api::check_interval_history($label,$contract_id,[
{ cash => $cash_balance/100.0,
debit => ($no_balance ? 3 * $callee_call_costs : 0.0)/100.0,
id => $balance_id,
},
]);
my $bal = 100.0 * $balance;
my $bal_decrease = ($no_balance ? 0.0 : $callee_call_costs);
foreach (@cdr_ids) { # ensure id also orders cdrs by start_time
Utils::Rateomat::check_cdr_relation_data($label,$_,'destination','customer','contract_balance_id',$balance_id);
Utils::Rateomat::check_cdr_cash_balance_data($label,$_,'destination','customer','cash_balance',
{ before => $bal, after => $bal - $bal_decrease });
$bal -= $bal_decrease;
}
$label = $prepaid_label.$no_balance_label.', callers\' provider: ';
$contract_id = $provider_a->{contract}->{id};
$balance_id = Utils::Rateomat::get_cdr_relation_data($label,$cdr_ids[0],'source','reseller','contract_balance_id');
$total_caller_reseller_call_costs += 3 * $caller_reseller_call_costs;
Utils::Api::check_interval_history($label,$contract_id,[
{ debit => $total_caller_reseller_call_costs/100.0,
id => $balance_id,
},
]);
foreach (@cdr_ids) {
Utils::Rateomat::check_cdr_relation_data($label,$_,'source','carrier','contract_balance_id',undef);
Utils::Rateomat::check_cdr_relation_data($label,$_,'source','reseller','contract_balance_id',$balance_id);
}
$label = $prepaid_label.$no_balance_label.', callee\'s provider: ';
$contract_id = $callee->{reseller}->{contract_id};
$balance_id = Utils::Rateomat::get_cdr_relation_data($label,$cdr_ids[0],'destination','reseller','contract_balance_id');
$total_callee_reseller_call_costs += 3 * $callee_reseller_call_costs;
Utils::Api::check_interval_history($label,$contract_id,[
{ debit => $total_callee_reseller_call_costs/100.0,
id => $balance_id,
},
]);
foreach (@cdr_ids) {
Utils::Rateomat::check_cdr_relation_data($label,$_,'destination','carrier','contract_balance_id',undef);
Utils::Rateomat::check_cdr_relation_data($label,$_,'destination','reseller','contract_balance_id',$balance_id);
}
$label = $prepaid_label.$no_balance_label.' providers and subscriber must not have a profile package: ';
foreach (@cdr_ids) {
Utils::Rateomat::check_cdr_relation_data($label,$_,'source','carrier','profile_package_id',undef);
Utils::Rateomat::check_cdr_relation_data($label,$_,'source','reseller','profile_package_id',undef);
Utils::Rateomat::check_cdr_relation_data($label,$_,'source','customer','profile_package_id',undef);
Utils::Rateomat::check_cdr_relation_data($label,$_,'destination','carrier','profile_package_id',undef);
Utils::Rateomat::check_cdr_relation_data($label,$_,'destination','reseller','profile_package_id',undef);
Utils::Rateomat::check_cdr_relation_data($label,$_,'destination','customer','profile_package_id',undef);
}
$label = $prepaid_label.$no_balance_label.' providers and subscriber must have zero free time: ';
my $free_time_balance_before_after = { before => 0.0, after => 0.0 };
foreach (@cdr_ids) {
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'source','carrier','free_time_balance',undef);
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'source','reseller','free_time_balance',$free_time_balance_before_after);
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'source','customer','free_time_balance',$free_time_balance_before_after);
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'destination','carrier','free_time_balance',undef);
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'destination','reseller','free_time_balance',$free_time_balance_before_after);
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'destination','customer','free_time_balance',$free_time_balance_before_after);
}
$label = $prepaid_label.$no_balance_label.' providers must have zero balance: ';
my $cash_balance_before_after = { before => 0.0, after => 0.0 };
foreach (@cdr_ids) {
Utils::Rateomat::check_cdr_cash_balance_data($label,$_,'source','carrier','cash_balance',undef);
Utils::Rateomat::check_cdr_cash_balance_data($label,$_,'source','reseller','cash_balance',$cash_balance_before_after);
Utils::Rateomat::check_cdr_cash_balance_data($label,$_,'destination','carrier','cash_balance',undef);
Utils::Rateomat::check_cdr_cash_balance_data($label,$_,'destination','reseller','cash_balance',$cash_balance_before_after);
}
}
}
}
}
done_testing();
exit;
sub create_provider {
my $domain = shift;
return Utils::Api::setup_provider($domain,
[ #subscriber rates:
{ prepaid => 0,
fees => [{ #outgoing:
direction => 'out',
destination => '^8882.+',
onpeak_init_rate => 6,
onpeak_init_interval => $init_secs,
onpeak_follow_rate => 1,
onpeak_follow_interval => $follow_secs,
offpeak_init_rate => 6,
offpeak_init_interval => $init_secs,
offpeak_follow_rate => 1,
offpeak_follow_interval => $follow_secs,
},
{ #incoming:
direction => 'in',
destination => '.',
source => '^8881.+',
onpeak_init_rate => 5,
onpeak_init_interval => $init_secs,
onpeak_follow_rate => 1,
onpeak_follow_interval => $follow_secs,
offpeak_init_rate => 5,
offpeak_init_interval => $init_secs,
offpeak_follow_rate => 1,
offpeak_follow_interval => $follow_secs,
}]},
{ prepaid => 1,
fees => [{ #outgoing:
direction => 'out',
destination => '^8882.+',
onpeak_init_rate => 4,
onpeak_init_interval => $init_secs,
onpeak_follow_rate => 1,
onpeak_follow_interval => $follow_secs,
offpeak_init_rate => 4,
offpeak_init_interval => $init_secs,
offpeak_follow_rate => 1,
offpeak_follow_interval => $follow_secs,
},
{ #incoming:
direction => 'in',
destination => '.',
source => '^8881.+',
onpeak_init_rate => 3,
onpeak_init_interval => $init_secs,
onpeak_follow_rate => 1,
onpeak_follow_interval => $follow_secs,
offpeak_init_rate => 3,
offpeak_init_interval => $init_secs,
offpeak_follow_rate => 1,
offpeak_follow_interval => $follow_secs,
}]},
],
undef, # no billing networks in this test suite
# provider rate:
{ prepaid => 0,
fees => [{ #outgoing:
direction => 'out',
destination => '^888.+',
onpeak_init_rate => 2,
onpeak_init_interval => $init_secs,
onpeak_follow_rate => 1,
onpeak_follow_interval => $follow_secs,
offpeak_init_rate => 2,
offpeak_init_interval => $init_secs,
offpeak_follow_rate => 1,
offpeak_follow_interval => $follow_secs,
},
{ #incoming:
direction => 'in',
destination => '.',
source => '^888.+',
onpeak_init_rate => 1,
onpeak_init_interval => $init_secs,
onpeak_follow_rate => 1,
onpeak_follow_interval => $follow_secs,
offpeak_init_rate => 1,
offpeak_init_interval => $init_secs,
offpeak_follow_rate => 1,
offpeak_follow_interval => $follow_secs,
}]},
);
}

@ -0,0 +1,378 @@
use strict;
use Utils::Api qw();
use Utils::Rateomat qw();
use Test::More;
### testcase outline:
### prepaid/postpaid calls of onnet callers to offnet callees and
### offnet callers to onnet callees
###
### this tests verify all combinations of prepaid/postpaid subscriber customers with
### balance > 0.0/no balance produce correct customer/reseller call cost, cash balance
### and cash balance interval values.
my $init_secs = 60;
my $follow_secs = 30;
my @offnet_subscribers = (Utils::Rateomat::prepare_offnet_subsriber_info({ cc => 999, ac => '2<n>', sn => '<t>' },'somewhere.tld'),
Utils::Rateomat::prepare_offnet_subsriber_info({ cc => 999, ac => '2<n>', sn => '<t>' },'somewhere.tld'),
Utils::Rateomat::prepare_offnet_subsriber_info({ cc => 999, ac => '2<n>', sn => '<t>' },'somewhere.tld'));
#goto SKIP;
{
foreach my $ptype (('reseller')) { # 'sippeering'
my $prefix = "onnet $ptype caller calls offnet callees - ";
my $provider = create_subscriber($ptype);
my $is_carrier;
my $provider_type;
if ($ptype ne 'reseller') {
$provider_type = 'carrier';
$is_carrier = 1;
} else {
$provider_type = 'reseller';
$is_carrier = 0;
}
my $total_reseller_call_costs = 0.0;
foreach my $prepaid ((0,1)) { # prepaid, postpaid
foreach my $balance ((0.0,30.0)) { # zero balance, enough balance
my $caller_fee = ($prepaid ? $provider->{subscriber_fees}->[1] : $provider->{subscriber_fees}->[0]);
my $caller = Utils::Api::setup_subscriber($provider,$caller_fee->{profile},$balance,{ cc => 888, ac => '1<n>', sn => '<t>' });
my $caller_call_costs = $caller_fee->{fees}->[0]->{onpeak_init_rate} *
$caller_fee->{fees}->[0]->{onpeak_init_interval} +
$caller_fee->{fees}->[0]->{onpeak_follow_rate} *
$caller_fee->{fees}->[0]->{onpeak_follow_interval};
my $caller_reseller_call_costs = $provider->{provider_fee}->{fees}->[0]->{onpeak_init_rate} *
$provider->{provider_fee}->{fees}->[0]->{onpeak_init_interval} +
$provider->{provider_fee}->{fees}->[0]->{onpeak_follow_rate} *
$provider->{provider_fee}->{fees}->[0]->{onpeak_follow_interval};
my $callee_call_costs = 0;
my $callee_reseller_call_costs = 0;
my $start_time = Utils::Api::current_unix() - 5;
my @cdr_ids;
if ($prepaid) {
@cdr_ids = map { $_->{cdr}->{id}; } @{ Utils::Rateomat::create_prepaid_costs_cdrs([ map {
Utils::Rateomat::prepare_prepaid_costs_cdr($caller->{subscriber},undef,$caller->{reseller},
undef, $_ ,undef,
'192.168.0.1',$start_time += 1,$init_secs + $follow_secs,
$caller_call_costs,0);
} @offnet_subscribers ]) };
} else {
@cdr_ids = map { $_->{id}; } @{ Utils::Rateomat::create_cdrs([ map {
Utils::Rateomat::prepare_cdr($caller->{subscriber},undef,$caller->{reseller},
undef, $_ ,undef,
'192.168.0.1',$start_time += 1,$init_secs + $follow_secs);
} @offnet_subscribers ]) };
}
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat_threads(),'rate-o-mat executed')) {
my $no_balance = ($balance <= 0.0);
my $prepaid_label = ($prepaid ? 'prepaid, ' : 'postpaid, ');
my $no_balance_label = ($no_balance ? 'no balance' : 'balance');
ok(Utils::Rateomat::check_cdrs($prefix.$prepaid_label.$no_balance_label.': ',
map { $_ => {
id => $_,
rating_status => 'ok',
source_customer_cost => Utils::Rateomat::decimal_to_string((($prepaid || $no_balance) ? $caller_call_costs : 0.0)),
destination_customer_cost => Utils::Rateomat::decimal_to_string((($prepaid || $no_balance) ? $callee_call_costs : 0.0)),
'source_'.$provider_type.'_cost' => Utils::Rateomat::decimal_to_string($caller_reseller_call_costs),
'destination_'.$provider_type.'_cost' => Utils::Rateomat::decimal_to_string($callee_reseller_call_costs),
}; } @cdr_ids
),'cdrs were all processed');
my $label = $prefix.$prepaid_label.$no_balance_label.', caller: ';
my $cash_balance = 100.0 * $balance - (($no_balance || $prepaid) ? 0.0 : 3 * $caller_call_costs);
my $balance_id = Utils::Rateomat::get_cdr_relation_data($label,$cdr_ids[0],'source','customer','contract_balance_id');
Utils::Api::check_interval_history($label,$caller->{customer}->{id},[
{ cash => $cash_balance/100.0,
debit => (($no_balance && !$prepaid) ? 3 * $caller_call_costs : 0.0)/100.0,
id => $balance_id,
},
]);
my $bal = ($prepaid ? $cash_balance + $caller_call_costs : 100.0 * $balance);
my $bal_decrease = (($no_balance && !$prepaid) ? 0.0 : $caller_call_costs);
foreach (@cdr_ids) { # ensure id also orders cdrs by start_time
Utils::Rateomat::check_cdr_relation_data($label,$_,'source','customer','contract_balance_id',$balance_id);
Utils::Rateomat::check_cdr_cash_balance_data($label,$_,'source','customer','cash_balance',
{ before => $bal, after => $bal - $bal_decrease });
$bal -= $bal_decrease if !$prepaid;
}
$label = $prefix.$prepaid_label.$no_balance_label.', callers\' provider: ';
$balance_id = Utils::Rateomat::get_cdr_relation_data($label,$cdr_ids[0],'source',$provider_type,'contract_balance_id');
$total_reseller_call_costs += 3 * $caller_reseller_call_costs;
Utils::Api::check_interval_history($label,$provider->{contract}->{id},[
{ debit => $total_reseller_call_costs/100.0,
id => $balance_id,
},
]);
$label = $prefix.$prepaid_label.$no_balance_label.' providers and subscriber must not have a profile package: ';
foreach (@cdr_ids) {
Utils::Rateomat::check_cdr_relation_data($label,$_,'source','carrier','profile_package_id',undef);
Utils::Rateomat::check_cdr_relation_data($label,$_,'source','reseller','profile_package_id',undef);
Utils::Rateomat::check_cdr_relation_data($label,$_,'source','customer','profile_package_id',undef);
Utils::Rateomat::check_cdr_relation_data($label,$_,'destination','carrier','profile_package_id',undef);
Utils::Rateomat::check_cdr_relation_data($label,$_,'destination','reseller','profile_package_id',undef);
Utils::Rateomat::check_cdr_relation_data($label,$_,'destination','customer','profile_package_id',undef);
}
$label = $prefix.$prepaid_label.$no_balance_label.' providers and subscriber must have zero free time: ';
my $free_time_balance_before_after = { before => 0.0, after => 0.0 };
foreach (@cdr_ids) {
if ($is_carrier) {
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'source','carrier','free_time_balance',$free_time_balance_before_after);
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'source','reseller','free_time_balance',undef);
} else {
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'source','carrier','free_time_balance',undef);
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'source','reseller','free_time_balance',$free_time_balance_before_after);
}
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'source','customer','free_time_balance',$free_time_balance_before_after);
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'destination','carrier','free_time_balance',undef);
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'destination','reseller','free_time_balance',undef);
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'destination','customer','free_time_balance',undef);
}
$label = $prefix.$prepaid_label.$no_balance_label.' providers and destination customers must have zero balance: ';
my $cash_balance_before_after = { before => 0.0, after => 0.0 };
foreach (@cdr_ids) {
if ($is_carrier) {
Utils::Rateomat::check_cdr_cash_balance_data($label,$_,'source','carrier','cash_balance',$cash_balance_before_after);
Utils::Rateomat::check_cdr_cash_balance_data($label,$_,'source','reseller','cash_balance',undef);
} else {
Utils::Rateomat::check_cdr_cash_balance_data($label,$_,'source','carrier','cash_balance',undef);
Utils::Rateomat::check_cdr_cash_balance_data($label,$_,'source','reseller','cash_balance',$cash_balance_before_after);
}
Utils::Rateomat::check_cdr_cash_balance_data($label,$_,'destination','customer','cash_balance',undef);
Utils::Rateomat::check_cdr_cash_balance_data($label,$_,'destination','carrier','cash_balance',undef);
Utils::Rateomat::check_cdr_cash_balance_data($label,$_,'destination','reseller','cash_balance',undef);
}
}
}
}
}
}
#SKIP:
{
foreach my $ptype (('reseller')) { # 'sippeering'
my $prefix = "offnet callers call onnet $ptype callee - ";
my $provider = create_subscriber($ptype);
my $is_carrier;
my $provider_type;
if ($ptype ne 'reseller') {
$provider_type = 'carrier';
$is_carrier = 1;
} else {
$provider_type = 'reseller';
$is_carrier = 0;
}
my $total_reseller_call_costs = 0.0;
foreach my $prepaid ((0,1)) { # prepaid, postpaid
foreach my $balance ((0.0,30.0)) { # zero balance, enough balance
my $callee_fee = ($prepaid ? $provider->{subscriber_fees}->[1] : $provider->{subscriber_fees}->[0]);
my $callee = Utils::Api::setup_subscriber($provider,$callee_fee->{profile},$balance,{ cc => 888, ac => '2<n>', sn => '<t>' });
my $caller_call_costs = 0;
my $caller_reseller_call_costs = 0;
my $callee_call_costs = $callee_fee->{fees}->[1]->{onpeak_init_rate} *
$callee_fee->{fees}->[1]->{onpeak_init_interval} +
$callee_fee->{fees}->[1]->{onpeak_follow_rate} *
$callee_fee->{fees}->[1]->{onpeak_follow_interval};
my $callee_reseller_call_costs = $provider->{provider_fee}->{fees}->[1]->{onpeak_init_rate} *
$provider->{provider_fee}->{fees}->[1]->{onpeak_init_interval} +
$provider->{provider_fee}->{fees}->[1]->{onpeak_follow_rate} *
$provider->{provider_fee}->{fees}->[1]->{onpeak_follow_interval};
my $start_time = Utils::Api::current_unix() - 5;
my @cdr_ids = map { $_->{id}; } @{ Utils::Rateomat::create_cdrs([ map {
Utils::Rateomat::prepare_cdr(undef, $_ ,undef,
$callee->{subscriber},undef,$callee->{reseller},
'192.168.0.1',$start_time += 1,$init_secs + $follow_secs);
} @offnet_subscribers ]) };
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat_threads(),'rate-o-mat executed')) {
my $no_balance = ($balance <= 0.0);
my $prepaid_label = ($prepaid ? 'prepaid, ' : 'postpaid, ');
my $no_balance_label = ($no_balance ? 'no balance' : 'balance');
ok(Utils::Rateomat::check_cdrs($prefix.$prepaid_label.$no_balance_label.': ',
map { $_ => {
id => $_,
rating_status => 'ok',
source_customer_cost => Utils::Rateomat::decimal_to_string($caller_call_costs),
destination_customer_cost => Utils::Rateomat::decimal_to_string((($prepaid || $no_balance) ? $callee_call_costs : 0.0)),
'source_'.$provider_type.'_cost' => Utils::Rateomat::decimal_to_string($caller_reseller_call_costs),
'destination_'.$provider_type.'_cost' => Utils::Rateomat::decimal_to_string($callee_reseller_call_costs),
}; } @cdr_ids
),'cdrs were all processed');
my $label = $prefix.$prepaid_label.$no_balance_label.', callee: ';
my $cash_balance = 100.0 * $balance - ($no_balance ? 0.0 : 3 * $callee_call_costs);
my $balance_id = Utils::Rateomat::get_cdr_relation_data($label,$cdr_ids[0],'destination','customer','contract_balance_id');
Utils::Api::check_interval_history($label,$callee->{customer}->{id},[
{ cash => $cash_balance/100.0,
debit => ($no_balance ? 3 * $callee_call_costs : 0.0)/100.0,
id => $balance_id,
},
]);
my $bal = 100.0 * $balance;
my $bal_decrease = ($no_balance ? 0.0 : $callee_call_costs);
foreach (@cdr_ids) { # ensure id also orders cdrs by start_time
Utils::Rateomat::check_cdr_relation_data($label,$_,'destination','customer','contract_balance_id',$balance_id);
Utils::Rateomat::check_cdr_cash_balance_data($label,$_,'destination','customer','cash_balance',
{ before => $bal, after => $bal - $bal_decrease });
$bal -= $bal_decrease;
}
$label = $prefix.$prepaid_label.$no_balance_label.', callee\'s provider: ';
$balance_id = Utils::Rateomat::get_cdr_relation_data($label,$cdr_ids[0],'destination',$provider_type,'contract_balance_id');
$total_reseller_call_costs += 3 * $callee_reseller_call_costs;
Utils::Api::check_interval_history($label,$callee->{reseller}->{contract_id},[
{ debit => $total_reseller_call_costs/100.0,
id => $balance_id,
},
]);
$label = $prefix.$prepaid_label.$no_balance_label.' providers and subscriber must not have a profile package: ';
foreach (@cdr_ids) {
Utils::Rateomat::check_cdr_relation_data($label,$_,'source','carrier','profile_package_id',undef);
Utils::Rateomat::check_cdr_relation_data($label,$_,'source','reseller','profile_package_id',undef);
Utils::Rateomat::check_cdr_relation_data($label,$_,'source','customer','profile_package_id',undef);
Utils::Rateomat::check_cdr_relation_data($label,$_,'destination','carrier','profile_package_id',undef);
Utils::Rateomat::check_cdr_relation_data($label,$_,'destination','reseller','profile_package_id',undef);
Utils::Rateomat::check_cdr_relation_data($label,$_,'destination','customer','profile_package_id',undef);
}
$label = $prefix.$prepaid_label.$no_balance_label.' providers and subscriber must have zero free time: ';
my $free_time_balance_before_after = { before => 0.0, after => 0.0 };
foreach (@cdr_ids) {
if ($is_carrier) {
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'destination','carrier','free_time_balance',$free_time_balance_before_after);
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'destination','reseller','free_time_balance',undef);
} else {
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'destination','carrier','free_time_balance',undef);
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'destination','reseller','free_time_balance',$free_time_balance_before_after);
}
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'destination','customer','free_time_balance',$free_time_balance_before_after);
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'source','carrier','free_time_balance',undef);
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'source','reseller','free_time_balance',undef);
Utils::Rateomat::check_cdr_time_balance_data($label,$_,'source','customer','free_time_balance',undef);
}
$label = $prefix.$prepaid_label.$no_balance_label.' providers and destination customers must have zero balance: ';
my $cash_balance_before_after = { before => 0.0, after => 0.0 };
foreach (@cdr_ids) {
if ($is_carrier) {
Utils::Rateomat::check_cdr_cash_balance_data($label,$_,'destination','carrier','cash_balance',$cash_balance_before_after);
Utils::Rateomat::check_cdr_cash_balance_data($label,$_,'destination','reseller','cash_balance',undef);
} else {
Utils::Rateomat::check_cdr_cash_balance_data($label,$_,'destination','carrier','cash_balance',undef);
Utils::Rateomat::check_cdr_cash_balance_data($label,$_,'destination','reseller','cash_balance',$cash_balance_before_after);
}
Utils::Rateomat::check_cdr_cash_balance_data($label,$_,'source','customer','cash_balance',undef);
Utils::Rateomat::check_cdr_cash_balance_data($label,$_,'source','carrier','cash_balance',undef);
Utils::Rateomat::check_cdr_cash_balance_data($label,$_,'source','reseller','cash_balance',undef);
}
}
}
}
}
}
done_testing();
exit;
sub create_subscriber {
my $type = shift;
return Utils::Api::setup_provider('test<n>.com',
[ #subscriber rates:
{ prepaid => 0,
fees => [{ #outgoing:
direction => 'out',
destination => '^999.+',
onpeak_init_rate => 6,
onpeak_init_interval => $init_secs,
onpeak_follow_rate => 1,
onpeak_follow_interval => $follow_secs,
offpeak_init_rate => 6,
offpeak_init_interval => $init_secs,
offpeak_follow_rate => 1,
offpeak_follow_interval => $follow_secs,
},
{ #incoming:
direction => 'in',
destination => '.',
source => '^999.+',
onpeak_init_rate => 5,
onpeak_init_interval => $init_secs,
onpeak_follow_rate => 1,
onpeak_follow_interval => $follow_secs,
offpeak_init_rate => 5,
offpeak_init_interval => $init_secs,
offpeak_follow_rate => 1,
offpeak_follow_interval => $follow_secs,
}]},
{ prepaid => 1,
fees => [{ #outgoing:
direction => 'out',
destination => '^999.+',
onpeak_init_rate => 4,
onpeak_init_interval => $init_secs,
onpeak_follow_rate => 1,
onpeak_follow_interval => $follow_secs,
offpeak_init_rate => 4,
offpeak_init_interval => $init_secs,
offpeak_follow_rate => 1,
offpeak_follow_interval => $follow_secs,
},
{ #incoming:
direction => 'in',
destination => '.',
source => '^999.+',
onpeak_init_rate => 3,
onpeak_init_interval => $init_secs,
onpeak_follow_rate => 1,
onpeak_follow_interval => $follow_secs,
offpeak_init_rate => 3,
offpeak_init_interval => $init_secs,
offpeak_follow_rate => 1,
offpeak_follow_interval => $follow_secs,
}]},
],
undef, # no billing networks in this test suite
# provider rate:
{ prepaid => 0,
fees => [{ #outgoing:
direction => 'out',
destination => '^999.+',
onpeak_init_rate => 2,
onpeak_init_interval => $init_secs,
onpeak_follow_rate => 1,
onpeak_follow_interval => $follow_secs,
offpeak_init_rate => 2,
offpeak_init_interval => $init_secs,
offpeak_follow_rate => 1,
offpeak_follow_interval => $follow_secs,
},
{ #incoming:
direction => 'in',
destination => '.',
source => '^999.+',
onpeak_init_rate => 1,
onpeak_init_interval => $init_secs,
onpeak_follow_rate => 1,
onpeak_follow_interval => $follow_secs,
offpeak_init_rate => 1,
offpeak_init_interval => $init_secs,
offpeak_follow_rate => 1,
offpeak_follow_interval => $follow_secs,
}]},
$type
);
}

@ -5,6 +5,14 @@ use Utils::Api qw();
use Utils::Rateomat qw();
use Test::More;
### testcase outline:
### onnet calls that hit negative incoming fees, aka VAS
### (value added services) numbers
###
### this tests verify that rating with negative rates
### properly increase the destination customer's cash
### balance.
use Text::Table;
use Text::Wrap;
use Storable;
@ -62,15 +70,15 @@ my $tb = Text::Table->new("request", "response");
'192.168.0.1',$now->epoch,61),
]) };
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat(),'rate-o-mat executed')) {
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat_threads(),'rate-o-mat executed')) {
ok(Utils::Rateomat::check_cdrs('',
map { $_ => { id => $_, rating_status => 'ok', }; } @cdr_ids
),'cdrs were all processed');
Utils::Api::check_interval_history('negative fees - caller',$caller->{customer}->{id},[
Utils::Api::check_interval_history('negative fees - caller: ',$caller->{customer}->{id},[
{ cash => $balance - $caller_costs,
profile => $provider->{subscriber_fees}->[0]->{profile}->{id} },
]);
Utils::Api::check_interval_history('negative fees - callee',$callee->{customer}->{id},[
Utils::Api::check_interval_history('negative fees - callee: ',$callee->{customer}->{id},[
{ cash => $balance - $callee_costs,
profile => $provider->{subscriber_fees}->[0]->{profile}->{id} },
]);
@ -78,7 +86,7 @@ my $tb = Text::Table->new("request", "response");
}
print $tb->stringify;
#print $tb->stringify;
done_testing();
exit;
@ -102,6 +110,7 @@ sub create_provider {
{ #negative:
direction => 'in',
destination => '.',
source => '.',
onpeak_init_rate => -1*2,
onpeak_init_interval => 60,
onpeak_follow_rate => -1*1,

@ -0,0 +1,121 @@
use strict;
use Utils::Api qw();
use Utils::Rateomat qw();
use Test::More;
### testcase outline:
### onnet calls that consume profile's freetime
###
### this tests verify that rating correctly
### consumes up free time before cash balance.
my $init_secs = 50;
my $follow_secs = 20;
my $in_free_time = $init_secs + 20*$follow_secs;
my $out_free_time = $init_secs + 30*$follow_secs;
{
my $now = Utils::Api::get_now();
my $begin = $now->clone->truncate(to => 'month'); # prevent ratio
Utils::Api::set_time($begin);
my $provider = create_provider($in_free_time,$out_free_time);
my $balance = 5;
my $caller = Utils::Api::setup_subscriber($provider,$provider->{subscriber_fees}->[0]->{profile},$balance,{ cc => 888, ac => '1<n>', sn => '<t>' });
my $callee = Utils::Api::setup_subscriber($provider,$provider->{subscriber_fees}->[1]->{profile},$balance,{ cc => 888, ac => '2<n>', sn => '<t>' });
my $caller_costs = 2 * ($provider->{subscriber_fees}->[0]->{fees}->[0]->{onpeak_follow_rate} *
$provider->{subscriber_fees}->[0]->{fees}->[0]->{onpeak_follow_interval})/100.0;
my $callee_costs = 2 * ($provider->{subscriber_fees}->[1]->{fees}->[0]->{onpeak_follow_rate} *
$provider->{subscriber_fees}->[1]->{fees}->[0]->{onpeak_follow_interval})/100.0;
my $max_free_time = ($in_free_time, $out_free_time)[$in_free_time < $out_free_time];
my $call_duration = $follow_secs + $max_free_time + 1;
Utils::Api::set_time($begin->clone->add(seconds => $call_duration + 20));
my $start_time = Utils::Api::current_unix() - $call_duration - 1;
Utils::Api::set_time();
my @cdr_ids = map { $_->{id}; } @{ Utils::Rateomat::create_cdrs([
Utils::Rateomat::prepare_cdr($caller->{subscriber},undef,$caller->{reseller},
$callee->{subscriber},undef,$callee->{reseller},
'192.168.0.1',$start_time,$call_duration),
]) };
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat_threads(),'rate-o-mat executed')) {
ok(Utils::Rateomat::check_cdrs('',
map { $_ => {
id => $_,
rating_status => 'ok',
source_customer_free_time => $out_free_time,
destination_customer_free_time => $in_free_time,
}; } @cdr_ids
),'cdrs were all processed');
my $label = 'freetime - caller: ';
my $balance_id = Utils::Rateomat::get_cdr_relation_data($label,$cdr_ids[0],'source','customer','contract_balance_id');
Utils::Api::check_interval_history($label,$caller->{customer}->{id},[
{ (($in_free_time < $out_free_time) ? (cash => $balance - $caller_costs) : ()),
profile => $provider->{subscriber_fees}->[0]->{profile}->{id},
id => $balance_id,
},
]);
Utils::Rateomat::check_cdr_time_balance_data($label,$cdr_ids[0],'source','customer','free_time_balance',
{ before => $out_free_time, after => 0 });
$label = 'freetime - callee: ';
$balance_id = Utils::Rateomat::get_cdr_relation_data($label,$cdr_ids[0],'destination','customer','contract_balance_id');
Utils::Api::check_interval_history($label,$callee->{customer}->{id},[
{ (($in_free_time > $out_free_time) ? (cash => $balance - $callee_costs) : ()),
profile => $provider->{subscriber_fees}->[1]->{profile}->{id},
id => $balance_id,
},
]);
Utils::Rateomat::check_cdr_time_balance_data($label,$cdr_ids[0],'destination','customer','free_time_balance',
{ before => $in_free_time, after => 0 });
}
}
done_testing();
exit;
sub create_provider {
my ($free_time_in,$free_time_out) = @_;
return Utils::Api::setup_provider('test<n>.com',
[ #rates:
{ interval_free_time => $free_time_out,
fees => [
{
direction => 'out',
destination => '.',
onpeak_init_rate => 3,
onpeak_init_interval => $init_secs,
onpeak_follow_rate => 3,
onpeak_follow_interval => $follow_secs,
offpeak_init_rate => 2,
offpeak_init_interval => $init_secs,
offpeak_follow_rate => 2,
offpeak_follow_interval => $follow_secs,
use_free_time => 1,
},
]},
{ interval_free_time => $free_time_in,
fees => [
{
direction => 'in',
destination => '.',
source => '.',
onpeak_init_rate => 4,
onpeak_init_interval => $init_secs,
onpeak_follow_rate => 4,
onpeak_follow_interval => $follow_secs,
offpeak_init_rate => 2,
offpeak_init_interval => $init_secs,
offpeak_follow_rate => 2,
offpeak_follow_interval => $follow_secs,
interval_free_time => $free_time_in,
use_free_time => 1,
},
]},
],
[ #billing networks:
]
);
}

@ -5,25 +5,12 @@ use Utils::Api qw();
use Utils::Rateomat qw();
use Test::More;
#$ENV{CATALYST_SERVER} = https://127.0.0.1:4443
#$ENV{RATEOMAT_PL} = /home/rkrenn/sipwise/git/rate-o-mat/rate-o-mat.pl
#$ENV{CATALYST_SERVER}
#$ENV{API_USER}
#$ENV{API_USER}
#$ENV{RATEOMAT_PROVISIONING_DB_HOST}
#$ENV{RATEOMAT_PROVISIONING_DB_PORT}
#$ENV{RATEOMAT_PROVISIONING_DB_USER}
#$ENV{RATEOMAT_PROVISIONING_DB_PASS}
#$ENV{RATEOMAT_BILLING_DB_HOST}
#$ENV{RATEOMAT_BILLING_DB_PORT}
#$ENV{RATEOMAT_BILLING_DB_USER}
#$ENV{RATEOMAT_BILLING_DB_PASS}
#$ENV{RATEOMAT_ACCOUNTING_DB_HOST}
#$ENV{RATEOMAT_ACCOUNTING_DB_PORT}
#$ENV{RATEOMAT_ACCOUNTING_DB_USER}
#$ENV{RATEOMAT_ACCOUNTING_DB_PASS}
#$ENV{RATEOMAT_PL}
### testcase outline:
### onnet calls of callers with profile + billing
### network billing mappings
###
### this tests verify that rates are correctly choosen
### depending on the caller (source) ip.
my $provider = Utils::Api::setup_provider('test.com',
[ #rates:
@ -95,7 +82,7 @@ my @cdr_ids = map { $_->{id}; } @{ Utils::Rateomat::create_cdrs([
'10.0.0.97',Utils::Api::current_unix(),1),
]) };
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat(),'rate-o-mat executed')) {
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat_threads(),'rate-o-mat executed')) {
ok(Utils::Rateomat::check_cdrs('',
$cdr_ids[0] => {
id => $cdr_ids[0],

@ -5,6 +5,18 @@ use Utils::Api qw();
use Utils::Rateomat qw();
use Test::More;
use Data::Dumper;
### testcase outline:
### onnet calls of a caller with and without profile packages to check
### the correct creation of billing.contract_balance records ("catchup")
###
### the tests verify, that a correct history of balance interval records
### (contract_balance records) are created while rating a cdr. beside the
### default case of customer with no package, all combinations of interval
### start modes and interval duration units are covered.
### note: since it also includes minute-based balance intervals, this tests
### takes longer time to complete
#goto SKIP;
{ #no package:
my $now = Utils::Api::get_now();
@ -34,7 +46,7 @@ use Data::Dumper;
'192.168.0.1',$now->epoch,1),
]) };
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat(),'rate-o-mat executed')) {
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat_threads(),'rate-o-mat executed')) {
ok(Utils::Rateomat::check_cdrs('',
$cdr_ids[0] => {
id => $cdr_ids[0],
@ -126,7 +138,7 @@ use Data::Dumper;
'192.168.0.1',$last_call_ts->epoch,1),
]) };
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat(),'rate-o-mat executed')) {
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat_threads(),'rate-o-mat executed')) {
ok(Utils::Rateomat::check_cdrs('',
$cdr_ids[0] => {
id => $cdr_ids[0],
@ -242,7 +254,7 @@ use Data::Dumper;
'192.168.0.1',$call_ts->epoch,$call_minutes*60),
]) };
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat(),'rate-o-mat executed')) {
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat_threads(),'rate-o-mat executed')) {
ok(Utils::Rateomat::check_cdrs('',
$cdr_ids[0] => {
id => $cdr_ids[0],
@ -315,7 +327,7 @@ use Data::Dumper;
'192.168.0.1',$call_ts->epoch,$call_minutes*60),
]) };
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat(),'rate-o-mat executed')) {
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat_threads(),'rate-o-mat executed')) {
ok(Utils::Rateomat::check_cdrs('',
$cdr_ids[0] => {
id => $cdr_ids[0],

@ -5,6 +5,14 @@ use Utils::Api qw();
use Utils::Rateomat qw();
use Test::More;
### testcase outline:
### onnet calls of a caller with profile packages specifying "underrun"
### settings.
###
### the tests verify, that subscriber underrun lock levels and underrun
### profile are correctly applied when balance was discarded during catchup,
### or call costs decrease the balance so it drops below the thresholds.
Utils::Api::set_time(Utils::Api::get_now->subtract(months => 5));
#provider contract needs to be created in the past as well:
my $provider = create_provider();
@ -56,7 +64,7 @@ my $lock_level = 4;
'192.168.0.1',$now->epoch,1),
]) };
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat(),'rate-o-mat executed')) {
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat_threads(),'rate-o-mat executed')) {
ok(Utils::Rateomat::check_cdrs('',
map { $_ => { id => $_, rating_status => 'ok', }; } @cdr_ids
),'cdrs were all processed');
@ -115,7 +123,7 @@ my $lock_level = 4;
'192.168.0.1',$now->epoch,1),
]) };
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat(),'rate-o-mat executed')) {
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat_threads(),'rate-o-mat executed')) {
ok(Utils::Rateomat::check_cdrs('',
map { $_ => { id => $_, rating_status => 'ok', }; } @cdr_ids
),'cdrs were all processed');

@ -6,6 +6,15 @@ use Utils::Rateomat qw();
use Test::More;
use Storable qw();
### testcase outline:
### onnet calls of a caller with profile packages specifying settings to
### discard the cash balance.
###
### the tests verify, that balance is properly discarded (set to 0 euro)
### for all combinations of interval start modes and carry over modes,
### which also depends on topups performed.
### note: this tests takes longer time to complete
Utils::Api::set_time(Utils::Api::get_now->subtract(months => 5));
#provider contract needs to be created in the past as well:
my $provider = create_provider();
@ -54,8 +63,8 @@ foreach my $start_mode ('create','1st') {
Utils::Api::set_time($within_first_interval);
Utils::Api::perform_topup($caller_topup->{subscriber},$amount);
my $within_first_topup = $begin->clone->add(days => ($interval_days - $timely_days / 2));
Utils::Api::set_time($within_first_topup);
my $within_first_timely = $begin->clone->add(days => ($interval_days - $timely_days / 2));
Utils::Api::set_time($within_first_timely);
Utils::Api::perform_topup($caller_timelytopup->{subscriber},$amount);
Utils::Api::set_time();
@ -85,7 +94,7 @@ foreach my $start_mode ('create','1st') {
'192.168.0.1',$now->epoch,1),
]) };
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat(),'rate-o-mat executed')) {
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat_threads(),'rate-o-mat executed')) {
ok(Utils::Rateomat::check_cdrs('',
map { $_ => { id => $_, rating_status => 'ok', }; } @cdr_ids
),'cdrs were all processed');
@ -96,12 +105,14 @@ foreach my $start_mode ('create','1st') {
stop => Utils::Api::datetime_to_string($begin->add(days => $interval_days)->clone->subtract(seconds => 1)),
}; } 1..4;
if ('carry_over' eq $carry_over_mode) {
Utils::Api::check_interval_history($label . ' no topup: ',$caller_notopup->{customer}->{id},[
if (not Utils::Api::check_interval_history($label . ' no topup: ',$caller_notopup->{customer}->{id},[
set_cash($intervals[0],$amount - $costs),
set_cash($intervals[1],$amount - $costs),
set_cash($intervals[2],0),
set_cash($intervals[3],0),
]);
]) ){
print "FAIL due to bug";
}
Utils::Api::check_interval_history($label . ' topup: ',$caller_topup->{customer}->{id},[
set_cash($intervals[0],2*$amount - $costs),
set_cash($intervals[1],2*$amount - $costs),
@ -209,7 +220,7 @@ foreach my $carry_over_mode ('carry_over','carry_over_timely') {
'192.168.0.1',$call_time->epoch,1),
]) };
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat(),'rate-o-mat executed')) {
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat_threads(),'rate-o-mat executed')) {
ok(Utils::Rateomat::check_cdrs('',
map { $_ => { id => $_, rating_status => 'ok', }; } @cdr_ids
),'cdrs were all processed');

@ -5,6 +5,13 @@ use Utils::Api qw();
use Utils::Rateomat qw();
use Test::More;
### testcase outline:
### first onnet calls of a caller with hourly-based balance intervals starting
### after DST (daylight saving time) barriers
###
### this short tests verify that created contract_balance records show a
### correct gap in their hourly balance intervals.
if ('Europe/Vienna' eq Utils::Api::get_now->time_zone->name) {
Utils::Api::set_time(Utils::Api::datetime_from_string('2015-03-01 00:00:00'));
@ -49,7 +56,7 @@ if ('Europe/Vienna' eq Utils::Api::get_now->time_zone->name) {
'192.168.0.1',$now->epoch,1),
]) };
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat(),'rate-o-mat executed')) {
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat_threads(),'rate-o-mat executed')) {
ok(Utils::Rateomat::check_cdrs('',
map { $_ => { id => $_, rating_status => 'ok', }; } @cdr_ids
),'cdrs were all processed');
@ -81,7 +88,7 @@ if ('Europe/Vienna' eq Utils::Api::get_now->time_zone->name) {
'192.168.0.1',$now->epoch,1),
]) };
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat(),'rate-o-mat executed')) {
if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat_threads(),'rate-o-mat executed')) {
ok(Utils::Rateomat::check_cdrs('',
map { $_ => { id => $_, rating_status => 'ok', }; } @cdr_ids
),'cdrs were all processed');

@ -5,6 +5,15 @@ use Utils::Api qw();
use Utils::Rateomat qw();
use Test::More;
### testcase outline:
### onnet calls of callers with profiles using different
### onpeak/offpeak rates
###
### this tests verify that offpeak/onpeak rates are correctly
### chosen depending call start time. for alternating offpeak/onpeak
### phases during a single call, another new cdr has to be created
### per peaktime fragment with each rateomat loop ("split peak parts").
$ENV{RATEOMAT_SPLIT_PEAK_PARTS} = 1;
#use Text::Table;
@ -70,7 +79,7 @@ $ENV{RATEOMAT_SPLIT_PEAK_PARTS} = 1;
my %cdr_id_map = ();
my $onpeak = 0; #call starts offpeak
my $i = 1;
while (defined $cdr && ok(Utils::Rateomat::run_rateomat(),'rate-o-mat executed')) {
while (defined $cdr && ok(Utils::Rateomat::run_rateomat_threads(),'rate-o-mat executed')) {
$cdr = Utils::Rateomat::get_cdrs($cdr->{id});
$cdr_id_map{$cdr->{id}} = $cdr;
Utils::Rateomat::check_cdr('cdr was processed: ',$cdr->{id},{ rating_status => 'ok' });

@ -2,9 +2,14 @@
use strict;
#use Time::Local qw(timegm timelocal);
use POSIX qw(mktime);
use Test::More;
### testcase outline:
### unit test for rateomat's add_interval sub
###
### this tests check the add_interval method in detail,
### in particular mktime's rollover with args like month=99
my $t1 = '2015-99-99 99:99:99';
my $t2 = from_epoch(to_epoch($t1));
is($t2,'2023-06-11 04:40:39');
@ -29,10 +34,10 @@ sub to_epoch {
}
sub from_epoch {
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(shift);
return sprintf "%4d-%02d-%02d %02d:%02d:%02d",$year+1900,$mon+1,$mday,$hour,$min,$sec;
}
sub add_interval {
@ -40,11 +45,11 @@ sub add_interval {
my $to_time;
my ($from_year,$from_month,$from_day,$from_hour,$from_minute,$from_second) = (localtime($from_time))[5,4,3,2,1,0];
if($unit eq "minute") {
$to_time = mktime($from_second,$from_minute + $count,$from_hour,$from_day,$from_month,$from_year);
$to_time = mktime($from_second,$from_minute + $count,$from_hour,$from_day,$from_month,$from_year);
} elsif($unit eq "hour") {
$to_time = mktime($from_second,$from_minute,$from_hour + $count,$from_day,$from_month,$from_year);
} elsif($unit eq "day") {
$to_time = mktime($from_second,$from_minute,$from_hour,$from_day + $count,$from_month,$from_year);
$to_time = mktime($from_second,$from_minute,$from_hour,$from_day + $count,$from_month,$from_year);
} elsif($unit eq "week") {
$to_time = mktime($from_second,$from_minute,$from_hour,$from_day + 7*$count,$from_month,$from_year);
} elsif($unit eq "month") {
@ -65,4 +70,4 @@ sub add_interval {
die("Invalid interval unit '$unit' in $src");
}
return $to_time;
}
}

@ -1,74 +0,0 @@
use strict;
use Utils::Api qw();
use Utils::Rateomat qw();
use Test::More;
{
Utils::Rateomat::run_rateomat_threads(3,6);
}
#{
# my $provider = create_provider();
# my $profile = $provider->{subscriber_fees}->[0]->{profile};
# my $balance = 5;
# my $caller = Utils::Api::setup_subscriber($provider,$profile,$balance,{ cc => 888, ac => '1<n>', sn => '<t>' });
# my $callee = Utils::Api::setup_subscriber($provider,$profile,$balance,{ cc => 888, ac => '2<n>', sn => '<t>' });
# my $caller_costs = ($provider->{subscriber_fees}->[0]->{fees}->[0]->{onpeak_init_rate} *
# $provider->{subscriber_fees}->[0]->{fees}->[0]->{onpeak_init_interval} +
# $provider->{subscriber_fees}->[0]->{fees}->[0]->{onpeak_follow_rate} *
# $provider->{subscriber_fees}->[0]->{fees}->[0]->{onpeak_follow_interval})/100.0;
# my $callee_costs = ($provider->{subscriber_fees}->[0]->{fees}->[1]->{onpeak_init_rate} *
# $provider->{subscriber_fees}->[0]->{fees}->[1]->{onpeak_init_interval} +
# $provider->{subscriber_fees}->[0]->{fees}->[1]->{onpeak_follow_rate} *
# $provider->{subscriber_fees}->[0]->{fees}->[1]->{onpeak_follow_interval})/100.0; #negative!
#
# my $now = Utils::Api::get_now();
# my @cdr_ids = map { $_->{id}; } @{ Utils::Rateomat::create_cdrs([
# Utils::Rateomat::prepare_cdr($caller->{subscriber},undef,$caller->{reseller},
# $callee->{subscriber},undef,$callee->{reseller},
# '192.168.0.1',$now->epoch,61),
# ]) };
#
# if (ok((scalar @cdr_ids) > 0 && Utils::Rateomat::run_rateomat(),'rate-o-mat executed')) {
# ok(Utils::Rateomat::check_cdrs('',
# map { $_ => { id => $_, rating_status => 'ok', }; } @cdr_ids
# ),'cdrs were all processed');
# Utils::Api::check_interval_history('negative fees - caller',$caller->{customer}->{id},[
# { cash => $balance - $caller_costs,
# profile => $provider->{subscriber_fees}->[0]->{profile}->{id} },
# ]);
# Utils::Api::check_interval_history('negative fees - callee',$callee->{customer}->{id},[
# { cash => $balance - $callee_costs,
# profile => $provider->{subscriber_fees}->[0]->{profile}->{id} },
# ]);
# }
#
#}
done_testing();
exit;
sub create_provider {
my $rate_interval = shift;
$rate_interval //= 60;
return Utils::Api::setup_provider('test<n>.com',
[ #rates:
{ #any
onpeak_init_rate => 2,
onpeak_init_interval => $rate_interval,
onpeak_follow_rate => 1,
onpeak_follow_interval => $rate_interval,
offpeak_init_rate => 2,
offpeak_init_interval => $rate_interval,
offpeak_follow_rate => 1,
offpeak_follow_interval => $rate_interval,
},
],
[ #billing networks:
]
);
}
Loading…
Cancel
Save