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 {
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 {
@ -22,18 +22,19 @@ sub query_params {
{
param => 'reseller_id',
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',
description => 'Interval filter. values: ["day", "month"].',
},
{
param => 'date',
description => 'Date of the period (YYYY-MM-DD), defaults to current date.',
},
{
param => 'notify_status',
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/;
sub resource_name{
@ -60,48 +74,4 @@ __PACKAGE__->set_config({
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;
# vim: set tabstop=4 expandtab:
1;

@ -27,90 +27,8 @@ sub relation{
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({
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;
# vim: set tabstop=4 expandtab:

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

@ -8,27 +8,84 @@ use boolean qw(true);
use Data::HAL qw();
use Data::HAL::Link qw();
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 {
my ($self, $c) = @_;
my $item_rs = $c->model('DB')->resultset('contract_fraud_events')->search({
});
my ($self, $c, $id) = @_;
if (my $interval = $c->request->param('interval')) {
$item_rs = $item_rs->search({ interval => $interval });
my %cond = ();
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')) {
$item_rs = $item_rs->search({ notify_status => $notify_status });
$cond{'notify_status'} = $notify_status;
}
if($c->user->roles eq "admin") {
#
} elsif($c->user->roles eq "reseller") {
$item_rs = $item_rs->search({ reseller_id => $c->user->reseller_id });
if ($id) {
$cond{'me.id'} = $id;
}
my $attr = {
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 {
@ -40,49 +97,91 @@ sub get_form {
}
}
sub hal_from_item {
my ($self, $c, $item, $form) = @_;
my %resource = $item->get_inflated_columns;
my $hal = Data::HAL->new(
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 => '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,
);
sub resource_from_item {
my ($self, $c, $item) = @_; #$form
$form //= $self->get_form($c);
return unless $self->validate_form(
c => $c,
form => $form,
resource => \%resource,
run => 0,
my %cpc = $item->get_inflated_columns;
my %resource;
my $billing_mapping = NGCP::Panel::Utils::BillingMappings::get_actual_billing_mapping(c => $c,
now => NGCP::Panel::Utils::DateTime::epoch_local($item->last_cdr_start_time),
contract => $item->contract,
);
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 {
}
} elsif ('billing_profile' eq $cpc{'fraud_limit_type'}) {
$resource{'interval_limit'} = $billing_profile->fraud_daily_limit;
$resource{'interval_lock'} = $billing_profile->fraud_daily_lock;
$resource{'interval_notify'} = $billing_profile->fraud_daily_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;
}
} 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 {
my ($self, $c, $id) = @_;
my $item_rs = $self->item_rs($c);
my ($contract_id, $period, $period_date) = split(/-/, $id, 3);
return $item_rs->search_rs({
id => $contract_id,
interval => $period,
interval_date => $period_date
})->first;
return $self->item_rs($c,$id)->first;
}
sub update_item {
@ -95,24 +194,18 @@ sub update_item {
resource => $resource,
);
my $cpc_rs = $c->model('DB')->resultset('cdr_period_costs')->search({
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");
try {
# only update r/w fields
$item->update({
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;
}
# only update r/w fields
$cpc->update({
map { $_ => $resource->{$_} } qw(notify_status notified_at)
});
};
return $item;
}
1;
# vim: set tabstop=4 expandtab:

Loading…
Cancel
Save