TT#64701 remove customer_fraud_events.pm virtualview

Change-Id: I09b3c36945e9234aec330066ae8cb29cb8ccb831
(cherry picked from commit ed3ea31e07)
changes/83/32383/1
Rene Krenn 6 years ago
parent 714b2aa005
commit 6e77eff53e

@ -14,7 +14,7 @@ sub allowed_methods{
} }
sub api_description { sub api_description {
return 'Defines a list of customers with fraud limits above defined thresholds for a specific interval.'; return 'Defines a list of current fraud limit violations (the threshold for outgoing call costs per day/month was exceeded) of customers.';
}; };
sub query_params { sub query_params {
@ -22,18 +22,19 @@ sub query_params {
{ {
param => 'reseller_id', param => 'reseller_id',
description => 'Filter for fraud events belonging to a specific reseller', description => 'Filter for fraud events belonging to a specific reseller',
query => {
first => sub {
my $q = shift;
return { reseller_id => $q };
},
second => sub {},
}, },
{
param => 'contract_id',
description => 'Filter for fraud events of a specific contract',
}, },
{ {
param => 'interval', param => 'interval',
description => 'Interval filter. values: ["day", "month"].', description => 'Interval filter. values: ["day", "month"].',
}, },
{
param => 'date',
description => 'Date of the period (YYYY-MM-DD), defaults to current date.',
},
{ {
param => 'notify_status', param => 'notify_status',
description => 'Notify status filter. values: ["new", "notified"].', description => 'Notify status filter. values: ["new", "notified"].',
@ -41,6 +42,19 @@ sub query_params {
]; ];
} }
sub order_by_cols {
my ($self, $c) = @_;
my $cols = {
'contract_id' => 'contract_id',
'id' => 'id',
'interval' => 'interval',
'notified_at' => 'notified_at',
'notify_status' => 'notify_status',
'reseller_id' => 'reseller_id',
};
return $cols;
}
use parent qw/NGCP::Panel::Role::Entities NGCP::Panel::Role::API::CustomerFraudEvents/; use parent qw/NGCP::Panel::Role::Entities NGCP::Panel::Role::API::CustomerFraudEvents/;
sub resource_name{ sub resource_name{
@ -60,48 +74,4 @@ __PACKAGE__->set_config({
allowed_roles => [qw/admin reseller/], allowed_roles => [qw/admin reseller/],
}); });
sub GET :Allow {
my ($self, $c) = @_;
my $page = $c->request->params->{page} // 1;
my $rows = $c->request->params->{rows} // 10;
{
my $items = $self->item_rs($c);
(my $total_count, $items, my $items_rows) = $self->paginate_order_collection($c, $items);
my (@embedded, @links);
my $form = $self->get_form($c);
for my $item (@$items_rows) {
push @embedded, $self->hal_from_item($c, $item, $form);
push @links, Data::HAL::Link->new(
relation => 'ngcp:'.$self->resource_name,
href => sprintf('/%s%d-%s-%s', $c->request->path, $item->id, $item->interval, $item->interval_date),
);
}
push @links,
Data::HAL::Link->new(
relation => 'curies',
href => 'http://purl.org/sipwise/ngcp-api/#rel-{rel}',
name => 'ngcp',
templated => true,
),
Data::HAL::Link->new(relation => 'profile', href => 'http://purl.org/sipwise/ngcp-api/'),
$self->collection_nav_links($c, $page, $rows, $total_count, $c->request->path, $c->request->query_params);
my $hal = Data::HAL->new(
embedded => [@embedded],
links => [@links],
);
$hal->resource({
total_count => $total_count,
});
my $response = HTTP::Response->new(HTTP_OK, undef,
HTTP::Headers->new($hal->http_headers(skip_links => 1)), $hal->as_json);
$c->response->headers($response->headers);
$c->response->body($response->content);
return;
}
return;
}
1; 1;
# vim: set tabstop=4 expandtab:

@ -27,90 +27,8 @@ sub relation{
return 'http://purl.org/sipwise/ngcp-api/#rel-customerfraudevents'; return 'http://purl.org/sipwise/ngcp-api/#rel-customerfraudevents';
} }
sub query_params {
return [
{
param => 'interval',
description => 'Interval filter. values: ["day", "month"].',
},
{
param => 'notify_status',
description => 'Notify status filter. values: ["new", "notified"].',
},
];
}
__PACKAGE__->set_config({ __PACKAGE__->set_config({
allowed_roles => [qw/admin reseller/], allowed_roles => [qw/admin reseller/],
}); });
sub GET :Allow {
my ($self, $c, $id) = @_;
{
my $item = $self->item_by_id($c, $id);
last unless $self->resource_exists($c, customerfraudevent => $item);
my $hal = $self->hal_from_item($c, $item);
my $response = HTTP::Response->new(HTTP_OK, undef, HTTP::Headers->new(
(map { # XXX Data::HAL must be able to generate links with multiple relations
s|rel="(http://purl.org/sipwise/ngcp-api/#rel-resellers)"|rel="item $1"|r =~
s/rel=self/rel="item self"/r;
} $hal->http_headers),
), $hal->as_json);
$c->response->headers($response->headers);
$c->response->body($response->content);
return;
}
return;
}
sub PATCH :Allow {
my ($self, $c, $id) = @_;
my $schema = $c->model('DB');
my $guard = $schema->txn_scope_guard;
{
my $preference = $self->require_preference($c);
last unless $preference;
my $item = $self->item_by_id($c, $id);
my $json = $self->get_valid_patch_data(
c => $c,
id => 1, # TODO: allow non int ids in PATCH
media_type => 'application/json-patch+json',
ops => ["replace"],
);
last unless $json;
my $form = $self->get_form($c);
my $old_resource = $self->hal_from_item($c, $item)->resource;
my $resource = $self->apply_patch($c, $old_resource, $json);
last unless $resource;
$item = $self->update_item($c, $item, undef, $resource, $form);
last unless $item;
my $hal = $self->hal_from_item($c, $item);
last unless $hal;
$guard->commit;
if ('minimal' eq $preference) {
$c->response->status(HTTP_NO_CONTENT);
$c->response->header(Preference_Applied => 'return=minimal');
$c->response->body(q());
} else {
my $response = HTTP::Response->new(HTTP_OK, undef, HTTP::Headers->new(
$hal->http_headers,
), $hal->as_json);
$c->response->headers($response->headers);
$c->response->header(Preference_Applied => 'return=representation');
$c->response->body($response->content);
}
}
return;
}
1; 1;
# vim: set tabstop=4 expandtab:

@ -5,41 +5,59 @@ extends 'HTML::FormHandler';
has_field 'id' => ( has_field 'id' => (
type => 'PosInteger', type => 'PosInteger',
label => 'Customer', label => 'ID',
required => 1, required => 0,
element_attr => { element_attr => {
rel => ['tooltip'], rel => ['tooltip'],
title => ['Customer that a fraud event belongs to.'] title => ['ID of the period.']
}, },
); );
has_field 'interval' => ( has_field 'contract_id' => (
type => 'Text', type => 'PosInteger',
label => 'Interval', label => 'Contract',
required => 1, required => 0,
element_attr => { element_attr => {
rel => ['tooltip'], rel => ['tooltip'],
title => ['Interval of the fraud events.'] title => ['Contract ID of the customer/system contract causing the fraud event.']
}, },
); );
has_field 'interval_date' => ( has_field 'interval' => (
type => 'Text', type => 'Select',
label => 'Interval Date', label => 'Interval',
required => 1, required => 1,
options => [
{ label => 'current day', value => 'day' },
{ label => 'current month', value => 'month' },
],
element_attr => { element_attr => {
rel => ['tooltip'], rel => ['tooltip'],
title => ['Interval date of the fraud events.'] title => ['Period of the fraud event.']
}, },
); );
#has_field 'interval_date' => (
# type => 'Text',
# label => 'Interval Date',
# required => 1,
# element_attr => {
# rel => ['tooltip'],
# title => ['Interval date of the fraud events.']
# },
#);
has_field 'type' => ( has_field 'type' => (
type => 'Text', type => 'Select',
label => 'Type', label => 'Type',
required => 1, required => 1,
options => [
{ label => 'contract fraud preference', value => 'account_limit' },
{ label => 'billing_profile', value => 'profile_limit' },
],
element_attr => { element_attr => {
rel => ['tooltip'], rel => ['tooltip'],
title => ['Type of the fraud event.'] title => ['Origin of fraud setting in effect.']
}, },
); );
@ -65,56 +83,59 @@ has_field 'interval_limit' => (
); );
has_field 'interval_lock' => ( has_field 'interval_lock' => (
type => 'Integer', type => '+NGCP::Panel::Field::SubscriberLockSelect',
label => 'Interval Lock', label => 'Interval Lock',
required => 1, required => 1,
element_attr => { element_attr => {
rel => ['tooltip'], rel => ['tooltip'],
title => ['Lock type for the interval.'] title => ['Lock level to apply.']
}, },
); );
has_field 'interval_notify' => ( has_field 'use_reseller_rates' => (
type => 'Text', type => 'Integer',
label => 'Notify Email', label => 'Use reseller rates',
required => 1, required => 1,
element_attr => { element_attr => {
rel => ['tooltip'], rel => ['tooltip'],
title => ['Email used for this notification.'] title => ['Whether the reseller rates were used for interval_cost or not.']
}, },
); );
has_field 'use_reseller_rates' => ( has_field 'interval_notify' => (
type => 'Integer', type => 'Text',
label => 'Use reseller rates', label => 'Notify Email',
required => 1, required => 0,
element_attr => { element_attr => {
rel => ['tooltip'], rel => ['tooltip'],
title => ['Whether the reseller rates were used for interval_cost or not.'] title => ['Email used for this notification.']
}, },
); );
has_field 'notify_status' => ( has_field 'notify_status' => (
type => 'Text', type => 'Select',
label => 'Notify Status', label => 'Notify Status',
required => 1, required => 1,
options => [
{ label => 'new', value => 'new' },
{ label => 'notified', value => 'notified' },
],
element_attr => { element_attr => {
rel => ['tooltip'], rel => ['tooltip'],
title => ['Status of the notification.'] title => ['Status of the notification. \'new\' events are pending to be sent.']
}, },
); );
has_field 'notified_at' => ( has_field 'notified_at' => (
type => 'Text', type => 'Text',
label => 'Notified at', label => 'Notified at',
required => 1, required => 0,
element_attr => { element_attr => {
rel => ['tooltip'], rel => ['tooltip'],
title => ['When the last related notification was sent.'] title => ['When the last email notification was sent.']
}, },
); );
1; 1;
=head1 NAME =head1 NAME

@ -8,27 +8,84 @@ use boolean qw(true);
use Data::HAL qw(); use Data::HAL qw();
use Data::HAL::Link qw(); use Data::HAL::Link qw();
use HTTP::Status qw(:constants); use HTTP::Status qw(:constants);
use NGCP::Panel::Utils::BillingMappings qw();
use NGCP::Panel::Utils::DateTime qw();
use DateTime::Format::Strptime qw();
sub _item_rs { sub _item_rs {
my ($self, $c) = @_; my ($self, $c, $id) = @_;
my $item_rs = $c->model('DB')->resultset('contract_fraud_events')->search({
});
if (my $interval = $c->request->param('interval')) { my %cond = ();
$item_rs = $item_rs->search({ interval => $interval }); if ($c->user->roles eq "admin") {
if (my $reseller_id = $c->request->param('reseller_id')) {
$cond{'contact.reseller_id'} = $reseller_id;
}
} elsif ($c->user->roles eq "reseller") {
$cond{'contact.reseller_id'} = $c->user->reseller_id;
}
if (my $contract_id = $c->request->param('contract_id')) {
$cond{'me.contract_id'} = $contract_id;
} }
if (my $notify_status = $c->request->param('notify_status')) { if (my $notify_status = $c->request->param('notify_status')) {
$item_rs = $item_rs->search({ notify_status => $notify_status }); $cond{'notify_status'} = $notify_status;
} }
if ($id) {
if($c->user->roles eq "admin") { $cond{'me.id'} = $id;
# }
} elsif($c->user->roles eq "reseller") { my $attr = {
$item_rs = $item_rs->search({ reseller_id => $c->user->reseller_id }); join => { 'contract' => 'contact' },
};
my $dtf = $c->model('DB')->storage->datetime_parser;
my $now;
my $datetime_fmt = DateTime::Format::Strptime->new(
pattern => '%Y-%m-%d',
);
unless ($now = $datetime_fmt->parse_datetime($c->request->param('date'))) {
$now = NGCP::Panel::Utils::DateTime::current_local();
}
my $first_of_month = $now->clone;
$first_of_month->set_day(1);
my $day_rs = $c->model('DB')->resultset('cdr_period_costs')->search_rs({
'period' => 'day',
'period_date' => $dtf->format_date($now),
'direction' => 'out',
'fraud_limit_exceeded' => 1,
'contract.status' => 'active',
%cond,
},$attr);
$now->subtract(days => 1);
my $previous_day_rs = $c->model('DB')->resultset('cdr_period_costs')->search_rs({
'period' => 'day',
'period_date' => $dtf->format_date($now),
'direction' => 'out',
'fraud_limit_exceeded' => 1,
'contract.status' => 'active',
%cond,
},$attr);
my $month_rs = $c->model('DB')->resultset('cdr_period_costs')->search_rs({
'period' => 'month',
'period_date' => $dtf->format_date($first_of_month),
'direction' => 'out',
'fraud_limit_exceeded' => 1,
'contract.status' => 'active',
%cond,
},$attr);
my $interval = $c->request->param('interval');
my $rs;
if (defined $interval and $interval eq 'day') {
$rs = $day_rs->union_all($previous_day_rs);
} elsif (defined $interval and $interval eq 'month') {
$rs = $month_rs;
} elsif (not defined $interval) {
$rs = $day_rs->union_all([$previous_day_rs, $month_rs]);
} else {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid interval '$interval'");
return;
} }
return $item_rs; return $rs;
} }
sub get_form { sub get_form {
@ -40,49 +97,91 @@ sub get_form {
} }
} }
sub hal_from_item { sub resource_from_item {
my ($self, $c, $item, $form) = @_; my ($self, $c, $item) = @_; #$form
my %resource = $item->get_inflated_columns; my %cpc = $item->get_inflated_columns;
my %resource;
my $hal = Data::HAL->new( my $billing_mapping = NGCP::Panel::Utils::BillingMappings::get_actual_billing_mapping(c => $c,
links => [ now => NGCP::Panel::Utils::DateTime::epoch_local($item->last_cdr_start_time),
Data::HAL::Link->new( contract => $item->contract,
relation => 'curies',
href => 'http://purl.org/sipwise/ngcp-api/#rel-{rel}',
name => 'ngcp',
templated => true,
),
Data::HAL::Link->new(relation => 'collection', href => sprintf('/api/%s/', $self->resource_name)),
Data::HAL::Link->new(relation => 'profile', href => 'http://purl.org/sipwise/ngcp-api/'),
Data::HAL::Link->new(relation => 'self', href => sprintf("%s%d", $self->dispatch_path, $item->id)),
],
relation => 'ngcp:'.$self->resource_name,
); );
my $billing_profile = $billing_mapping->billing_profile;
my $contract_fraud_preference = $item->contract->contract_fraud_preference;
$resource{'contract_id'} = $item->contract->id;
$resource{'reseller_id'} = $item->contract->contact->reseller_id;
$resource{'interval'} = $cpc{'period'};
$resource{'type'} = $cpc{'fraud_limit_type'};
$resource{'type'} = 'account_limit' if $resource{'type'} eq 'contract';
$resource{'type'} = 'profile_limit' if $resource{'type'} eq 'billing_profile';
if ($billing_profile->fraud_use_reseller_rates) {
$resource{'interval_cost'} = $cpc{'customer_cost'};
} else {
$resource{'interval_cost'} = $cpc{'reseller_cost'};
}
if ('month' eq $cpc{'period'}) {
if ('contract' eq $cpc{'fraud_limit_type'}) {
if ($contract_fraud_preference) {
$resource{'interval_limit'} = $contract_fraud_preference->fraud_interval_limit;
$resource{'interval_lock'} = $contract_fraud_preference->fraud_interval_lock;
$resource{'interval_notify'} = $contract_fraud_preference->fraud_interval_notify;
} else {
$self->debug($c, "no contract fraud preference any more for contract ID $cpc{contract_id}");
$resource{'interval_limit'} = undef;
$resource{'interval_lock'} = undef;
$resource{'interval_notify'} = undef;
}
} elsif ('billing_profile' eq $cpc{'fraud_limit_type'}) {
$resource{'interval_limit'} = $billing_profile->fraud_interval_limit;
$resource{'interval_lock'} = $billing_profile->fraud_interval_lock;
$resource{'interval_notify'} = $billing_profile->fraud_interval_notify;
} else {
$self->debug($c, "unsupported fraud limit type '$cpc{fraud_limit_type}'");
$resource{'interval_limit'} = undef;
$resource{'interval_lock'} = undef;
$resource{'interval_notify'} = undef;
}
} elsif ('day' eq $cpc{'period'}) {
if ('contract' eq $cpc{'fraud_limit_type'}) {
if ($contract_fraud_preference) {
$resource{'interval_limit'} = $contract_fraud_preference->fraud_daily_limit;
$resource{'interval_lock'} = $contract_fraud_preference->fraud_daily_lock;
$resource{'interval_notify'} = $contract_fraud_preference->fraud_daily_notify;
} else {
$form //= $self->get_form($c); }
return unless $self->validate_form( } elsif ('billing_profile' eq $cpc{'fraud_limit_type'}) {
c => $c, $resource{'interval_limit'} = $billing_profile->fraud_daily_limit;
form => $form, $resource{'interval_lock'} = $billing_profile->fraud_daily_lock;
resource => \%resource, $resource{'interval_notify'} = $billing_profile->fraud_daily_notify;
run => 0, } else {
$self->debug($c, "unsupported fraud limit type '$cpc{fraud_limit_type}'");
$resource{'interval_limit'} = undef;
$resource{'interval_lock'} = undef;
$resource{'interval_notify'} = undef;
}
} else {
$self->debug($c, "unsupported fraud interval '$cpc{'period'}'");
$resource{'interval_limit'} = undef;
$resource{'interval_lock'} = undef;
$resource{'interval_notify'} = undef;
}
$resource{'use_reseller_rates'} = $billing_profile->fraud_use_reseller_rates;
$resource{'notify_status'} = $cpc{'notify_status'};
my $datetime_fmt = DateTime::Format::Strptime->new(
pattern => '%F %T',
); );
$resource{'notified_at'} = undef;
$resource{'notified_at'} = $datetime_fmt->format_datetime($cpc{notified_at}) if defined $cpc{notified_at};
return \%resource;
$resource{id} = int($item->id);
$hal->resource({%resource});
return $hal;
} }
sub item_by_id { sub item_by_id {
my ($self, $c, $id) = @_; my ($self, $c, $id) = @_;
my $item_rs = $self->item_rs($c); return $self->item_rs($c,$id)->first;
my ($contract_id, $period, $period_date) = split(/-/, $id, 3);
return $item_rs->search_rs({
id => $contract_id,
interval => $period,
interval_date => $period_date
})->first;
} }
sub update_item { sub update_item {
@ -95,24 +194,18 @@ sub update_item {
resource => $resource, resource => $resource,
); );
my $cpc_rs = $c->model('DB')->resultset('cdr_period_costs')->search({ try {
contract_id => $item->id,
period => $item->interval,
period_date => $item->interval_date
});
my $cpc = $cpc_rs->first;
unless ($cpc) {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Customer fraud event does not exist");
return;
}
# only update r/w fields # only update r/w fields
$cpc->update({ $item->update({
map { $_ => $resource->{$_} } qw(notify_status notified_at) map { $_ => $resource->{$_} } qw(notify_status notified_at)
}); })->discard_changes;
} catch($e) {
$c->log->error("failed to update customer fraud event: $e");
$self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to update customer fraud event.");
return;
};
return $item; return $item;
} }
1; 1;
# vim: set tabstop=4 expandtab:

Loading…
Cancel
Save