From 1be9f06bc75c2e06c937979c4ed0dba08a06f8da Mon Sep 17 00:00:00 2001 From: Rene Krenn Date: Thu, 5 Mar 2026 11:58:09 +0100 Subject: [PATCH] MT#64594 prov templates: fraud preferences support this change introduces support to set contract fraud preferences via provisioning template, ie: fraud_preferences: fraud_interval_limit: "function { current_fraud_interval_source == 'profile' ? current_fraud_interval_limit : 10000; }" fraud_interval_lock: "function { current_fraud_interval_source == 'profile' ? current_fraud_interval_lock : 2; }" fraud_interval_notify: "function { current_fraud_interval_source == 'profile' ? current_fraud_interval_notify : 'jdoe@sipwise.com'; }" fraud_daily_limit: 500 fraud_daily_lock: 2 fraud_daily_notify: "jdoe@sipwise.com" Change-Id: Id7e67fd71e0b1d291ee5e2ea9e2ea9b6bae64781 (cherry picked from commit 47b5cc7b7ba628a502e8c9999f134b9405c27398) --- .../Controller/API/BillingNetworksItem.pm | 2 +- .../Controller/API/BillingProfilesItem.pm | 2 +- .../Role/API/CustomerFraudPreferences.pm | 55 ++------------ lib/NGCP/Panel/Utils/Contract.pm | 76 +++++++++++++++++++ lib/NGCP/Panel/Utils/ProvisioningTemplates.pm | 66 +++++++++++++++- 5 files changed, 148 insertions(+), 53 deletions(-) diff --git a/lib/NGCP/Panel/Controller/API/BillingNetworksItem.pm b/lib/NGCP/Panel/Controller/API/BillingNetworksItem.pm index 7da9b6b1a8..96b5790f85 100644 --- a/lib/NGCP/Panel/Controller/API/BillingNetworksItem.pm +++ b/lib/NGCP/Panel/Controller/API/BillingNetworksItem.pm @@ -11,7 +11,7 @@ use HTTP::Status qw(:constants); use NGCP::Panel::Utils::ValidateJSON qw(); use NGCP::Panel::Utils::Reseller qw(); -use NGCP::Panel::Utils::BillingNetworks qw /check_network_update_item/; +use NGCP::Panel::Utils::BillingNetworks qw(); require Catalyst::ActionRole::ACL; require NGCP::Panel::Role::HTTPMethods; require Catalyst::ActionRole::RequireSSL; diff --git a/lib/NGCP/Panel/Controller/API/BillingProfilesItem.pm b/lib/NGCP/Panel/Controller/API/BillingProfilesItem.pm index 2d79088cd8..8e70f12371 100644 --- a/lib/NGCP/Panel/Controller/API/BillingProfilesItem.pm +++ b/lib/NGCP/Panel/Controller/API/BillingProfilesItem.pm @@ -8,7 +8,7 @@ use HTTP::Status qw(:constants); use Clone qw/clone/; use NGCP::Panel::Utils::ValidateJSON qw(); -use NGCP::Panel::Utils::Billing qw /check_profile_update_item/; +use NGCP::Panel::Utils::Billing qw(); require Catalyst::ActionRole::ACL; require NGCP::Panel::Role::HTTPMethods; require Catalyst::ActionRole::RequireSSL; diff --git a/lib/NGCP/Panel/Role/API/CustomerFraudPreferences.pm b/lib/NGCP/Panel/Role/API/CustomerFraudPreferences.pm index 1606323397..43392b550f 100644 --- a/lib/NGCP/Panel/Role/API/CustomerFraudPreferences.pm +++ b/lib/NGCP/Panel/Role/API/CustomerFraudPreferences.pm @@ -56,44 +56,8 @@ sub hal_from_item { sub resource_from_item { my ($self, $c, $customer, $form) = @_; - my $item = $customer->contract_fraud_preference; - my $bp_item = $customer->actual_billing_profile->billing_profile; - my $resource; - - my ($prefs, $bp_prefs); - $bp_prefs = { $bp_item->get_inflated_columns }; - $prefs = $item ? { $item->get_inflated_columns } : undef; - - if ($prefs) { - $resource = $prefs; - delete $resource->{contract_id}; - delete $resource->{id}; - } else { - $resource = { - fraud_interval_limit => undef, - fraud_interval_lock => undef, - fraud_interval_notify => undef, - fraud_daily_limit => undef, - fraud_daily_lock => undef, - fraud_daily_notify => undef, - } - } - foreach my $type (qw(interval daily)) { - my $prefix = 'fraud_'.$type.'_'; - my $c_prefix = 'current_fraud_'.$type.'_'; - $resource->{$c_prefix.'source'} = - $prefs && $prefs->{$prefix.'limit'} - ? 'customer' - : 'billing_profile'; - my $sel_prefs = - $resource->{$c_prefix.'source'} eq 'customer' - ? $prefs - : $bp_prefs; - map { - $resource->{$c_prefix.$_} = $sel_prefs->{$prefix.$_} - } qw(limit lock notify); - } + my $resource = NGCP::Panel::Utils::Contract::prepare_fraud_preferences_resource($c, $customer); return $resource; @@ -146,18 +110,11 @@ sub update_item { $resource->{contract_id} = $customer->id; - foreach my $type (qw(interval daily)) { - if (not defined $resource->{'fraud_'.$type.'_limit'}) { - if (defined $resource->{'fraud_'.$type.'_lock'}) { - $self->error($c, HTTP_UNPROCESSABLE_ENTITY, 'for cleared fraud_'.$type.'_limit, fraud_'.$type.'_lock must be cleared too.'); - return; - } - if (defined $resource->{'fraud_'.$type.'_notify'}) { - $self->error($c, HTTP_UNPROCESSABLE_ENTITY, 'for cleared fraud_'.$type.'_limit, fraud_'.$type.'_notify must be cleared too.'); - return; - } - } - } + return unless NGCP::Panel::Utils::Contract::check_fraud_preferences_resource($resource,sub { + my ($code, $msg, @errors) = @_; + $self->error($c, $code, $msg, @errors); + return 0; + }); try { my $item = $c->model('DB')->resultset('contract_fraud_preferences')->update_or_create($resource,{ diff --git a/lib/NGCP/Panel/Utils/Contract.pm b/lib/NGCP/Panel/Utils/Contract.pm index 4863208d0d..f00dae44a9 100644 --- a/lib/NGCP/Panel/Utils/Contract.pm +++ b/lib/NGCP/Panel/Utils/Contract.pm @@ -6,6 +6,7 @@ use Sipwise::Base; use DBIx::Class::Exception; use NGCP::Panel::Utils::DateTime; use NGCP::Panel::Utils::CallList qw(); +use HTTP::Status qw(:constants); my $lock_timeout = 5; @@ -585,6 +586,81 @@ sub acquire_contract_rowlocks { return []; } +sub prepare_fraud_preferences_resource { + + my ($c, $customer) = @_; + my $item = $customer->contract_fraud_preference; + my $bp_item = $customer->actual_billing_profile->billing_profile; + my $resource; + + my ($prefs, $bp_prefs); + $bp_prefs = { $bp_item->get_inflated_columns }; + $prefs = $item ? { $item->get_inflated_columns } : undef; + + if ($prefs) { + $resource = $prefs; + delete $resource->{contract_id}; + delete $resource->{id}; + } else { + $resource = { + fraud_interval_limit => undef, + fraud_interval_lock => undef, + fraud_interval_notify => undef, + fraud_daily_limit => undef, + fraud_daily_lock => undef, + fraud_daily_notify => undef, + } + } + + foreach my $type (qw(interval daily)) { + my $prefix = 'fraud_'.$type.'_'; + my $c_prefix = 'current_fraud_'.$type.'_'; + $resource->{$c_prefix.'source'} = + $prefs && $prefs->{$prefix.'limit'} + ? 'customer' + : 'billing_profile'; + my $sel_prefs = + $resource->{$c_prefix.'source'} eq 'customer' + ? $prefs + : $bp_prefs; + map { + $resource->{$c_prefix.$_} = $sel_prefs->{$prefix.$_} + } qw(limit lock notify); + } + + return $resource; + +} + +sub check_fraud_preferences_resource { + + my ($resource, $err_code) = @_; + + if (!defined $err_code || ref $err_code ne 'CODE') { + $err_code = sub { return 1; }; + } + + #foreach my $type (qw(interval daily)) { + # if (defined $resource->{'fraud_'.$type.'_limit'} && $resource->{'fraud_'.$type.'_limit'} <= 0) { + # die "Fraud ${type} limit must be greater than 0"; + # } + #} + + foreach my $type (qw(interval daily)) { + if (not defined $resource->{'fraud_'.$type.'_limit'}) { + if (defined $resource->{'fraud_'.$type.'_lock'}) { + return unless &$err_code(HTTP_UNPROCESSABLE_ENTITY, 'for cleared fraud_'.$type.'_limit, fraud_'.$type.'_lock must be cleared too.'); + } + if (defined $resource->{'fraud_'.$type.'_notify'}) { + return unless &$err_code(HTTP_UNPROCESSABLE_ENTITY, 'for cleared fraud_'.$type.'_limit, fraud_'.$type.'_notify must be cleared too.'); + } + } + } + + return 1; + +} + 1; __END__ diff --git a/lib/NGCP/Panel/Utils/ProvisioningTemplates.pm b/lib/NGCP/Panel/Utils/ProvisioningTemplates.pm index 33ae28212c..7b3cfab2c0 100644 --- a/lib/NGCP/Panel/Utils/ProvisioningTemplates.pm +++ b/lib/NGCP/Panel/Utils/ProvisioningTemplates.pm @@ -538,6 +538,17 @@ sub provision_commit_row { $context, $schema, ); + _init_fraud_preferences_context( + $c, + $context, + $schema, + $c->stash->{provisioning_templates}->{$template}, + ); + _set_fraud_preferences( + $c, + $context, + $schema, + ); _init_contract_preferences_context( $c, $context, @@ -1030,7 +1041,6 @@ sub _init_subscriber_preferences_context { } - sub _init_contract_balance_context { my ($c, $context, $schema, $template) = @_; @@ -1041,13 +1051,14 @@ sub _init_contract_balance_context { contract => $schema->resultset('contracts')->find({ id => $context->{contract}->{id}, }), - now => $context->{now},); + now => $context->{now}, ); my %contract_balance = ( cash_balance => $context->{_cb}->cash_balance, free_time_balance => $context->{_cb}->free_time_balance, ); + $context->{contract_balance} = { %contract_balance }; #expose current balance fields for calculations foreach my $col (keys %{$template->{contract_balance}}) { my ($k,$v) = _calculate($context,$col, $template->{contract_balance}->{$col}); $contract_balance{$k} = $v; @@ -1060,6 +1071,32 @@ sub _init_contract_balance_context { } +sub _init_fraud_preferences_context { + + my ($c, $context, $schema, $template) = @_; + + if (exists $template->{fraud_preferences}) { + + my $customer = $schema->resultset('contracts')->find({ + id => $context->{contract}->{id}, + }); + my $resource = NGCP::Panel::Utils::Contract::prepare_fraud_preferences_resource($c, $customer); + + my %fraud_preferences = %$resource; + $context->{fraud_preferences} = { %fraud_preferences }; #expose current_* and *_source fields for calculations + foreach my $col (keys %{$template->{fraud_preferences}}) { + my ($k,$v) = _calculate($context,$col, $template->{fraud_preferences}->{$col}); + $fraud_preferences{$k} = $v; + } + $fraud_preferences{contract_id} = $customer->id; + $context->{fraud_preferences} = \%fraud_preferences; + + $c->log->debug("provisioning template - fraud preferences: " . Dumper($context->{fraud_preferences})); + + } + +} + sub _init_contract_preferences_context { my ($c, $context, $schema, $template) = @_; @@ -1230,6 +1267,31 @@ sub _set_contract_balance { } +sub _set_fraud_preferences { + + my ($c, $context, $schema) = @_; + + if (exists $context->{fraud_preferences}) { + + my $resource = { + map { ($_ =~ /^current|source$/) ? () : ($_ => $context->{fraud_preferences}->{$_}); } + keys %{$context->{fraud_preferences}} }; + + NGCP::Panel::Utils::Contract::check_fraud_preferences_resource($resource,sub { + my ($code, $msg) = @_; + die($msg); + }); + + my $item = $schema->resultset('contract_fraud_preferences')->update_or_create($resource,{ + key => 'contract_id' + }); + + $c->log->debug("provisioning template - contract id $context->{contract}->{id} fraud preferences set"); + + } + +} + sub _create_subscriber { my ($c, $context, $schema) = @_;