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.
153 lines
5.1 KiB
153 lines
5.1 KiB
#!/usr/bin/perl
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use Email::Sender::Simple qw(sendmail);
|
|
use Sipwise::Provisioning::Billing;
|
|
|
|
my %LOCK = (
|
|
none => undef,
|
|
foreign => 1,
|
|
outgoing => 2,
|
|
incoming => 3,
|
|
global => 4,
|
|
0 => 'none',
|
|
1 => 'foreign',
|
|
2 => 'outgoing',
|
|
3 => 'incoming',
|
|
4 => 'global',
|
|
);
|
|
|
|
my $conf = Sipwise::Provisioning::Config->new()->get_config();
|
|
|
|
my $o = Sipwise::Provisioning::Billing->new();
|
|
my $db = $o->{database};
|
|
|
|
my $a = $db->sql_get_all_arrayref(<<"!");
|
|
SELECT 'profile_limit' as type, cdr.source_account_id, SUM(cdr.source_customer_cost) AS daily_cost, bpinfo.contract_id,
|
|
bpinfo.fraud_daily_limit, bpinfo.fraud_daily_lock, bpinfo.fraud_daily_notify
|
|
FROM (
|
|
SELECT contracts.id as contract_id,
|
|
billing_profiles.fraud_daily_limit, billing_profiles.fraud_daily_lock, billing_profiles.fraud_daily_notify
|
|
FROM billing.contracts
|
|
JOIN billing.billing_mappings ON contracts.id = billing_mappings.contract_id
|
|
JOIN billing.billing_profiles
|
|
ON (billing_profiles.id =
|
|
(SELECT m.billing_profile_id
|
|
FROM billing.billing_mappings m
|
|
WHERE ((m.start_date IS NULL) OR (m.start_date <= NOW()))
|
|
AND ((m.end_date IS NULL) OR (m.end_date >= NOW()))
|
|
AND (m.contract_id = contracts.id)
|
|
ORDER BY m.start_date DESC LIMIT 1
|
|
)
|
|
)
|
|
WHERE (contracts.status = 'active')
|
|
AND (billing_profiles.fraud_daily_limit IS NOT NULL)
|
|
AND (billing_profiles.fraud_daily_limit > 0)
|
|
) as bpinfo
|
|
JOIN accounting.cdr ON cdr.source_account_id = bpinfo.contract_id
|
|
WHERE (DATEDIFF(FROM_UNIXTIME(cdr.start_time), CURDATE()) = 0)
|
|
GROUP BY cdr.source_account_id
|
|
HAVING (daily_cost > bpinfo.fraud_daily_limit)
|
|
|
|
UNION ALL
|
|
|
|
SELECT 'account_limit' as type, cdr.source_account_id, SUM(cdr.source_customer_cost) AS daily_cost,
|
|
contracts.id,
|
|
contract_fraud_preferences.fraud_daily_limit, contract_fraud_preferences.fraud_daily_lock,
|
|
contract_fraud_preferences.fraud_daily_notify
|
|
FROM accounting.cdr
|
|
JOIN billing.contracts ON cdr.source_account_id = contracts.id
|
|
JOIN billing.contract_fraud_preferences ON contracts.id = contract_fraud_preferences.contract_id
|
|
WHERE (contracts.status = 'active')
|
|
AND (DATEDIFF(FROM_UNIXTIME(cdr.start_time), CURDATE()) = 0)
|
|
GROUP BY cdr.source_account_id
|
|
!
|
|
|
|
my $x = {};
|
|
for my $e (@{ $a }) {
|
|
if(exists $x->{$e->{id}}) {
|
|
if($x->{$e->{id}}->{type} eq 'profile_limit' && $e->{type} eq 'account_limit') {
|
|
|
|
# if account limit hits and it has lock and/or notify, mark for action
|
|
if(defined $e->{fraud_daily_limit} and
|
|
int($e->{daily_cost}) >= int($e->{fraud_daily_limit}) and
|
|
($e->{fraud_daily_lock} || $e->{fraud_daily_notify})) {
|
|
|
|
$x->{$e->{id}} = $e;
|
|
} else {
|
|
# we have account fraud prefs set, but either the limit is not reached
|
|
# or no actions are necessary, let it slip through, overriding
|
|
# billing profile fraud settings
|
|
delete $x->{$e->{id}};
|
|
}
|
|
}
|
|
} else {
|
|
# if account or billing profile limit hits and it has lock and/or notify,
|
|
# mark for action
|
|
if(defined $e->{fraud_daily_limit} and
|
|
int($e->{daily_cost}) >= int($e->{fraud_daily_limit}) and
|
|
($e->{fraud_daily_lock} || $e->{fraud_daily_notify})) {
|
|
|
|
$x->{$e->{id}} = $e;
|
|
}
|
|
}
|
|
}
|
|
|
|
for my $e (values %{ $x }) {
|
|
$e->{fraud_daily_lock} and
|
|
$o->lock_voip_account({id => $e->{id}, lock => $LOCK{$e->{fraud_daily_lock}}});
|
|
|
|
$e->{fraud_daily_notify} or next;
|
|
|
|
my $subs = $db->sql_get_all_arrayref(<<"!", $e->{id});
|
|
SELECT s.username, d.domain, s.external_id
|
|
FROM voip_subscribers s
|
|
LEFT JOIN domains d ON d.id = s.domain_id
|
|
WHERE s.contract_id = ?
|
|
AND s.status != 'terminated'
|
|
!
|
|
|
|
my $cur = sprintf('%.2f', $e->{daily_cost} / 100);
|
|
my $max = sprintf('%.2f', $e->{fraud_daily_limit} / 100);
|
|
|
|
my ($subject, $body);
|
|
if ($e->{fraud_daily_lock}) {
|
|
$body = "Account ID " . $e->{id} . " has been locked due to exceeding the configured" . "\n"
|
|
. "daily credit balance threshold ($cur >= $max ) in the "
|
|
. ($e->{type} eq 'profile_limit' ? 'billing profile' : 'account settings') . "\n\n";
|
|
$subject = 'Account ID ' . $e->{id} . ' locked by daily fraud detection';
|
|
}
|
|
else {
|
|
$body = "Account ID " . $e->{id} . " is currently exceeding the configured daily credit balance" . "\n"
|
|
. "threshold ($cur >= $max) in the "
|
|
. ($e->{type} eq 'profile_limit' ? 'billing profile' : 'account settings') . ",\n"
|
|
. "but has not been locked due to configuration.\n\n";
|
|
$subject = 'Account ID ' . $e->{id} . ' exceeding daily fraud detection limit';
|
|
}
|
|
|
|
if (!$subs || !@$subs) {
|
|
$body .= "There are no affected subscribers.\n";
|
|
}
|
|
else {
|
|
$body .= "Affected subscribers:\n";
|
|
for my $s (@$subs) {
|
|
$body .= "\t$s->{username}\@$s->{domain}".
|
|
($s->{external_id} ? " (external ID '$s->{external_id}')"
|
|
: '') . "\n";
|
|
}
|
|
}
|
|
|
|
sendmail ( Email::Simple->create(
|
|
header => [
|
|
To => $e->{fraud_daily_notify},
|
|
From => $$conf{adminmail},
|
|
Subject => $subject,
|
|
],
|
|
body => $body,
|
|
));
|
|
}
|
|
|
|
1;
|