You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bulk-processor/lib/NGCP/BulkProcessor/Projects/Disaster/Balances/Contracts.pm

341 lines
12 KiB

package NGCP::BulkProcessor::Projects::Disaster::Balances::Contracts;
use strict;
## no critic
use threads::shared qw();
#use List::Util qw();
use DateTime qw();
use NGCP::BulkProcessor::Projects::Disaster::Balances::Settings qw(
$dry
$skip_errors
$fix_contract_balance_gaps_multithreading
$fix_contract_balance_gaps_numofthreads
);
#$set_preference_bulk_numofthreads
use NGCP::BulkProcessor::Logging qw (
getlogger
processing_info
processing_debug
);
use NGCP::BulkProcessor::LogError qw(
rowprocessingerror
rowprocessingwarn
);
use NGCP::BulkProcessor::Dao::mr38::billing::contracts qw();
use NGCP::BulkProcessor::Dao::mr38::billing::contract_balances qw();
use NGCP::BulkProcessor::Dao::mr38::billing::billing_mappings qw();
use NGCP::BulkProcessor::ConnectorPool qw(
get_xa_db
);
use NGCP::BulkProcessor::ConnectorPool qw(
destroy_dbs
);
use NGCP::BulkProcessor::Utils qw(threadid);
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(
fix_contract_balance_gaps
);
sub fix_contract_balance_gaps {
my $static_context = {};
my $result = _fix_contract_balance_gaps_checks($static_context);
destroy_dbs();
my $warning_count :shared = 0;
return ($result && NGCP::BulkProcessor::Dao::mr38::billing::contracts::process_records(
static_context => $static_context,
process_code => sub {
my ($context,$records,$row_offset) = @_;
my $rownum = $row_offset;
foreach my $contract (@$records) {
$rownum++;
next unless _reset_fix_contract_balance_gaps_context($context,$contract,$rownum);
_fix_contract_balance_gaps($context);
}
#return 0;
return 1;
},
init_process_context_code => sub {
my ($context)= @_;
$context->{db} = &get_xa_db();
$context->{error_count} = 0;
$context->{warning_count} = 0;
# below is not mandatory..
_check_insert_tables();
},
uninit_process_context_code => sub {
my ($context)= @_;
undef $context->{db};
destroy_dbs();
{
lock $warning_count;
$warning_count += $context->{warning_count};
}
},
load_recursive => 0,
multithreading => $fix_contract_balance_gaps_multithreading,
numofthreads => $fix_contract_balance_gaps_numofthreads,
),$warning_count);
}
sub _check_insert_tables {
#NGCP::BulkProcessor::Dao::mr38::provisioning::voip_usr_preferences::check_table();
}
sub _fix_contract_balance_gaps {
my ($context) = @_;
eval {
$context->{db}->db_begin();
my $last_balance = undef;
foreach my $contract_balance (sort NGCP::BulkProcessor::Dao::mr38::billing::contract_balances::sort_by_end @{$context->{contract_balances}}) {
#print " " . $contract_balance->{id} . " " . $contract_balance->{_start} . ' ' . $contract_balance->{_end} . "\n";
if (defined $last_balance) {
my $gap_start = $last_balance->{_end}->clone->add(seconds => 1);
my $gap_end = $contract_balance->{_start};
my $date_comparison = DateTime->compare($gap_start, $gap_end);
if ($date_comparison > 0) {
if ($skip_errors) {
_warn($context,"($context->{rownum}) " . 'contract balances overlap for contract id ' . $context->{contract}->{id} . ' detected: '.
$gap_start . ' - ' . $gap_end);
} else {
_error($context,"($context->{rownum}) " . 'contract balances overlap for contract id ' . $context->{contract}->{id} . ' detected: '.
$gap_start . ' - ' . $gap_end);
}
} elsif ($date_comparison < 0) {
_info($context,"($context->{rownum}) " . 'contract balances gap for contract id ' . $context->{contract}->{id} . ' detected: '.
$gap_start . ' - ' . $gap_end);
_insert_contract_balances($context,$gap_start,$gap_end->clone->subtract(seconds => 1),$contract_balance);
}
}
$last_balance = $contract_balance;
}
if ($dry) {
$context->{db}->db_rollback(0);
} else {
$context->{db}->db_commit();
}
};
my $err = $@;
if ($err) {
eval {
$context->{db}->db_rollback(1);
};
if ($skip_errors) {
_warn($context,"($context->{rownum}) " . 'database error with contract id ' . $context->{contract}->{id} . ': ' . $err);
} else {
_error($context,"($context->{rownum}) " . 'database error with contract id ' . $context->{contract}->{id} . ': ' . $err);
}
}
}
sub _insert_contract_balances {
my ($context,$gap_start,$gap_end,$contract_balance) = @_;
my $start = $gap_start;
my $last_end;
my $end;
while (($end = $start->clone->add(months => 1)->subtract(seconds => 1)) <= $gap_end) {
my $billing_mapping = NGCP::BulkProcessor::Dao::mr38::billing::billing_mappings::findby_contractid_ts($context->{db},$context->{contract}->{id},$start)->[0];
if (defined $billing_mapping) {
#todo: check if billing profile is postpaid, has zero free_time and free_cash.
#todo: contracts with profile packages defining intervals other than 1 month are not supported atm.
#todo: dynamically choose mr38/4x contract_balance table dao.
$last_end = $end;
#_insert_contract_balances($context,$gap_start,$gap_end,$contract_balance,$billing_mapping);
my $id = NGCP::BulkProcessor::Dao::mr38::billing::contract_balances::insert_row($context->{db},{
contract_id => $context->{contract}->{id},
start => $context->{db}->datetime_to_string($start),
end => $context->{db}->datetime_to_string($end),
cash_balance => 0,
free_time_balance => 0,
});
_info($context,"($context->{rownum}) " . 'contract balance id ' . $id . ' for contract id ' . $context->{contract}->{id} . ' inserted: '.
$start . ' - ' . $end);
} else {
if ($skip_errors) {
_warn($context,"($context->{rownum}) " . 'no billing mapping for contract id ' . $context->{contract}->{id} . ', t = ' . $start . ' found ');
} else {
_error($context,"($context->{rownum}) " . 'no billing mapping for contract id ' . $context->{contract}->{id} . ', t = ' . $start . ' found ');
}
}
$start = $end->clone->add(seconds => 1);
}
if (not defined $last_end or DateTime->compare($last_end, $gap_end) != 0) {
if ($skip_errors) {
_warn($context,"($context->{rownum}) " . 'contract balances gap for contract id ' . $context->{contract}->{id} . ' cannot be filled with monthly intervals');
} else {
_error($context,"($context->{rownum}) " . 'contract balances gap for contract id ' . $context->{contract}->{id} . ' cannot be filled with monthly intervals');
}
}
}
sub _fix_contract_balance_gaps_checks {
my ($context) = @_;
my $result = _checks($context);
return $result;
}
sub _reset_fix_contract_balance_gaps_context {
my ($context,$contract,$rownum) = @_;
my $result = _reset_context($context,$contract,$rownum);
$context->{contract_balances} = NGCP::BulkProcessor::Dao::mr38::billing::contract_balances::findby_contractid($context->{db},$context->{contract}->{id});
#$context->{barring_profile} = $imported_subscriber->{barring_profile};
#$context->{ncos_level} = $context->{ncos_level_map}->{$context->{barring_profile}};
#delete $context->{adm_ncos_id_preference_id};
return $result;
}
sub _checks {
my ($context) = @_;
my $result = 1;
#my $optioncount = 0;
#eval {
# $optioncount = NGCP::BulkProcessor::Projects::Migration::IPGallery::Dao::import::FeatureOption::countby_subscribernumber_option();
#};
#if ($@ or $optioncount == 0) {
# rowprocessingerror(threadid(),'please import subscriber features first',getlogger(__PACKAGE__));
# $result = 0; #even in skip-error mode..
#}
#my $userpasswordcount = 0;
#eval {
# $userpasswordcount = NGCP::BulkProcessor::Projects::Migration::IPGallery::Dao::import::UsernamePassword::countby_fqdn();
#};
#if ($@ or $userpasswordcount == 0) {
# rowprocessingerror(threadid(),'please import user passwords first',getlogger(__PACKAGE__));
# $result = 0; #even in skip-error mode..
#}
#my $subscribercount = 0;
#my $subscriber_barring_profiles = [];
#eval {
# $subscribercount = NGCP::BulkProcessor::Projects::Migration::IPGallery::Dao::import::Subscriber::countby_subscribernumber();
# $subscriber_barring_profiles = NGCP::BulkProcessor::Projects::Migration::IPGallery::Dao::import::Subscriber::list_barringprofiles();
#};
#if ($@ or $subscribercount == 0) {
# rowprocessingerror(threadid(),'please import subscribers first',getlogger(__PACKAGE__));
# $result = 0; #even in skip-error mode..
#}
return $result;
}
sub _reset_context {
my ($context,$contract,$rownum) = @_;
my $result = 1;
$context->{rownum} = $rownum;
$context->{contract} = $contract;
#$context->{cli} = $imported_subscriber->subscribernumber();
#$context->{e164} = {};
#$context->{e164}->{cc} = substr($context->{cli},0,3);
#$context->{e164}->{ac} = '';
#$context->{e164}->{sn} = substr($context->{cli},3);
#$context->{subscriberdelta} = $imported_subscriber->{delta};
#my $userpassword = NGCP::BulkProcessor::Projects::Migration::IPGallery::Dao::import::UsernamePassword::findby_fqdn($context->{cli});
#if (defined $userpassword) {
# $context->{username} = (defined $subsciber_username_prefix ? $subsciber_username_prefix : '') . $userpassword->{username};
# $context->{password} = $userpassword->{password};
# $context->{userpassworddelta} = $userpassword->{delta};
#} else {
# # once full username+passwords is available:
# delete $context->{username};
# delete $context->{password};
# delete $context->{userpassworddelta};
# if ($context->{subscriberdelta} eq
# $NGCP::BulkProcessor::Projects::Migration::IPGallery::Dao::import::Subscriber::deleted_delta) {
#
# } else {
# $result &= 0;
#
# # for now, as username+passwords are incomplete:
# #$context->{username} = $context->{e164}->{sn};
# #$context->{password} = $context->{username};
# #$context->{userpassworddelta} = $NGCP::BulkProcessor::Projects::Migration::IPGallery::Dao::import::UsernamePassword::updated_delta;
#
# if ($skip_errors) {
# # for now, as username+passwords are incomplete:
# _warn($context,"($context->{rownum}) " . 'no username/password for subscriber found: ' . $context->{cli});
# } else {
# _error($context,"($context->{rownum}) " . 'no username/password for subscriber found: ' . $context->{cli});
# }
# }
#}
#
#delete $context->{billing_voip_subscriber};
#delete $context->{provisioning_voip_subscriber};
return $result;
}
sub _error {
my ($context,$message) = @_;
$context->{error_count} = $context->{error_count} + 1;
rowprocessingerror($context->{tid},$message,getlogger(__PACKAGE__));
}
sub _warn {
my ($context,$message) = @_;
$context->{warning_count} = $context->{warning_count} + 1;
rowprocessingwarn($context->{tid},$message,getlogger(__PACKAGE__));
}
sub _info {
my ($context,$message,$debug) = @_;
if ($debug) {
processing_debug($context->{tid},$message,getlogger(__PACKAGE__));
} else {
processing_info($context->{tid},$message,getlogger(__PACKAGE__));
}
}
1;