diff --git a/lib/NGCP/Panel/Form/Event/Reseller.pm b/lib/NGCP/Panel/Form/Event/Reseller.pm index af5bde96fc..8e58079bf1 100644 --- a/lib/NGCP/Panel/Form/Event/Reseller.pm +++ b/lib/NGCP/Panel/Form/Event/Reseller.pm @@ -47,4 +47,95 @@ has_field 'timestamp' => ( required => 1, ); + +has_field 'primary_number_id' => ( + type => 'PosInteger', + label => 'The subscriber\'s primary number.', + required => 0, +); +has_field 'primary_number_ac' => ( + type => 'Text', + label => 'The subscriber\'s primary number area code.', + required => 0, +); +has_field 'primary_number_cc' => ( + type => 'Text', + label => 'The subscriber\'s primary number country code.', + required => 0, +); +has_field 'primary_number_sn' => ( + type => 'Text', + label => 'The subscriber\'s primary number subscriber number.', + required => 0, +); +has_field 'subscriber_profile_id' => ( + type => 'PosInteger', + label => 'The subscriber\'s profile.', + required => 0, +); +has_field 'subscriber_profile_name' => ( + type => 'Text', + label => 'The subscriber\'s profile name.', + required => 0, +); +has_field 'subscriber_profile_set_id' => ( + type => 'PosInteger', + label => 'The subscriber\'s profile set.', + required => 0, +); +has_field 'subscriber_profile_set_name' => ( + type => 'Text', + label => 'The subscriber\'s profile set name.', + required => 0, +); + + +has_field 'pilot_subscriber_id' => ( + type => 'PosInteger', + label => 'The pilot subscriber of the subscriber the event is related to.', + required => 0, +); + + +has_field 'pilot_primary_number_id' => ( + type => 'PosInteger', + label => 'The primary number of the subscriber\'s pilot subscriber.', + required => 0, +); +has_field 'pilot_primary_number_ac' => ( + type => 'Text', + label => 'The primary number area code of the subscriber\'s pilot subscriber.', + required => 0, +); +has_field 'pilot_primary_number_cc' => ( + type => 'Text', + label => 'The primary number country code of the subscriber\'s pilot subscriber.', + required => 0, +); +has_field 'pilot_primary_number_sn' => ( + type => 'Text', + label => 'The primary number subscriber number of the subscriber\'s pilot subscriber.', + required => 0, +); +has_field 'pilot_subscriber_profile_id' => ( + type => 'PosInteger', + label => 'The profile of the subscriber\'s pilot subscriber.', + required => 0, +); +has_field 'pilot_subscriber_profile_name' => ( + type => 'Text', + label => 'The profile name of the subscriber\'s pilot subscriber.', + required => 0, +); +has_field 'pilot_subscriber_profile_set_id' => ( + type => 'PosInteger', + label => 'The profile set of the subscriber\'s pilot subscriber.', + required => 0, +); +has_field 'pilot_subscriber_profile_set_name' => ( + type => 'Text', + label => 'The profile set name of the subscriber\'s pilot subscriber.', + required => 0, +); + 1; diff --git a/lib/NGCP/Panel/Role/API/Events.pm b/lib/NGCP/Panel/Role/API/Events.pm index 48fb68608f..e2f0ecf3fc 100644 --- a/lib/NGCP/Panel/Role/API/Events.pm +++ b/lib/NGCP/Panel/Role/API/Events.pm @@ -12,7 +12,8 @@ use Data::HAL::Link qw(); use HTTP::Status qw(:constants); use NGCP::Panel::Form::Event::Reseller; use NGCP::Panel::Form::Event::Admin; -use Data::Dumper; +use NGCP::Panel::Utils::Events qw(); +#use Data::Dumper; sub _item_rs { my ($self, $c) = @_; @@ -45,6 +46,27 @@ sub hal_from_item { ); $resource{timestamp} = $datetime_fmt->format_datetime($resource{timestamp}) if defined $resource{timestamp}; + $resource{primary_number_id} = NGCP::Panel::Utils::Events::get_relation_value(c => $c, event => $item, type => 'primary_number_id'); + $resource{primary_number_ac} = NGCP::Panel::Utils::Events::get_tag_value(c => $c, event => $item, type => 'primary_number_ac'); + $resource{primary_number_cc} = NGCP::Panel::Utils::Events::get_tag_value(c => $c, event => $item, type => 'primary_number_cc'); + $resource{primary_number_sn} = NGCP::Panel::Utils::Events::get_tag_value(c => $c, event => $item, type => 'primary_number_sn'); + $resource{subscriber_profile_id} = NGCP::Panel::Utils::Events::get_relation_value(c => $c, event => $item, type => 'subscriber_profile_id'); + $resource{subscriber_profile_name} = NGCP::Panel::Utils::Events::get_tag_value(c => $c, event => $item, type => 'subscriber_profile_name'); + $resource{subscriber_profile_set_id} = NGCP::Panel::Utils::Events::get_relation_value(c => $c, event => $item, type => 'subscriber_profile_set_id'); + $resource{subscriber_profile_set_name} = NGCP::Panel::Utils::Events::get_tag_value(c => $c, event => $item, type => 'subscriber_profile_set_name'); + + $resource{pilot_subscriber_id} = NGCP::Panel::Utils::Events::get_relation_value(c => $c, event => $item, type => 'pilot_subscriber_id'); + + $resource{pilot_primary_number_id} = NGCP::Panel::Utils::Events::get_relation_value(c => $c, event => $item, type => 'pilot_primary_number_id'); + $resource{pilot_primary_number_ac} = NGCP::Panel::Utils::Events::get_tag_value(c => $c, event => $item, type => 'pilot_primary_number_ac'); + $resource{pilot_primary_number_cc} = NGCP::Panel::Utils::Events::get_tag_value(c => $c, event => $item, type => 'pilot_primary_number_cc'); + $resource{pilot_primary_number_sn} = NGCP::Panel::Utils::Events::get_tag_value(c => $c, event => $item, type => 'pilot_primary_number_sn'); + $resource{pilot_subscriber_profile_id} = NGCP::Panel::Utils::Events::get_relation_value(c => $c, event => $item, type => 'pilot_subscriber_profile_id'); + $resource{pilot_subscriber_profile_name} = NGCP::Panel::Utils::Events::get_tag_value(c => $c, event => $item, type => 'pilot_subscriber_profile_name'); + $resource{pilot_subscriber_profile_set_id} = NGCP::Panel::Utils::Events::get_relation_value(c => $c, event => $item, type => 'pilot_subscriber_profile_set_id'); + $resource{pilot_subscriber_profile_set_name} = NGCP::Panel::Utils::Events::get_tag_value(c => $c, event => $item, type => 'pilot_subscriber_profile_set_name'); + + my $hal = Data::HAL->new( links => [ Data::HAL::Link->new( @@ -58,6 +80,9 @@ sub hal_from_item { Data::HAL::Link->new(relation => 'self', href => sprintf("%s%d", $self->dispatch_path, $item->id)), (defined $item->subscriber_id ? Data::HAL::Link->new(relation => 'ngcp:subscribers', href => sprintf("/api/subscribers/%d", $item->subscriber_id)) : ()), (defined $item->reseller_id ? Data::HAL::Link->new(relation => 'ngcp:resellers', href => sprintf("/api/resellers/%d", $item->reseller_id)) : ()), + #(defined $resource{pilot_subscriber_id} ? Data::HAL::Link->new(relation => 'ngcp:subscribers', href => sprintf("/api/subscribers/%d", $resource{pilot_subscriber_id})) : ()), + #(defined $resource{subscriber_profile_set_id} ? Data::HAL::Link->new(relation => 'ngcp:subscriberprofilesets', href => sprintf("/api/subscriberprofilesets/%d", $resource{subscriber_profile_set_id})) : ()), + #(defined $resource{subscriber_profile_id} ? Data::HAL::Link->new(relation => 'ngcp:subscriberprofiles', href => sprintf("/api/subscriberprofiles/%d", $resource{subscriber_profile_id})) : ()), ], relation => 'ngcp:'.$self->resource_name, ); @@ -69,7 +94,10 @@ sub hal_from_item { resource => \%resource, form => $form, run => 0, - exceptions => [qw/id subscriber_id reseller_id/], + exceptions => [qw/id subscriber_id reseller_id + primary_number_id subscriber_profile_id subscriber_profile_set_id + pilot_subscriber_id + pilot_primary_number_id pilot_subscriber_profile_id pilot_subscriber_profile_set_id/], ); $resource{id} = int($item->id); diff --git a/lib/NGCP/Panel/Utils/Events.pm b/lib/NGCP/Panel/Utils/Events.pm index a6e7985811..aa0ecbd27a 100644 --- a/lib/NGCP/Panel/Utils/Events.pm +++ b/lib/NGCP/Panel/Utils/Events.pm @@ -2,6 +2,8 @@ package NGCP::Panel::Utils::Events; use Sipwise::Base; +use NGCP::Panel::Utils::DateTime qw(); + sub insert { my %params = @_; my $c = $params{c}; @@ -11,19 +13,271 @@ sub insert { my $old = $params{old}; my $new = $params{new}; + #reload it: + $subscriber = $schema->resultset('voip_subscribers')->find({ + id => $subscriber->id, + }); + + my $now_hires = NGCP::Panel::Utils::DateTime::current_local_hires; + my $customer = $subscriber->contract; + my $prov_subscriber = $subscriber->provisioning_voip_subscriber; + + my $tags_rs = $schema->resultset('events_tag'); + my $relations_rs = $schema->resultset('events_relation'); - $schema->resultset('events')->create({ + my $event = $schema->resultset('events')->create({ type => $type, subscriber_id => $subscriber->id, - reseller_id => $subscriber->contract->contact->reseller_id, + reseller_id => $customer->contact->reseller_id, old_status => $old // '', new_status => $new // '', - timestamp => NGCP::Panel::Utils::DateTime::current_local_hires, + timestamp => $now_hires, export_status => 'unexported', exported_at => undef, }); + + save_e164( + schema => $schema, + event => $event, + number => $subscriber->primary_number, + types_prefix => 'primary_number_', + now_hires => $now_hires, + tags_rs => $tags_rs, + relations_rs => $relations_rs, + ); + + save_subscriber_profile( + schema => $schema, + event => $event, + subscriber_profile => ($prov_subscriber ? $prov_subscriber->voip_subscriber_profile : undef), + types_prefix => 'subscriber_profile_', + now_hires => $now_hires, + tags_rs => $tags_rs, + relations_rs => $relations_rs, + ); + + save_subscriber_profile_set( + schema => $schema, + event => $event, + subscriber_profile_set => ($prov_subscriber ? $prov_subscriber->voip_subscriber_profile_set : undef), + types_prefix => 'subscriber_profile_set_', + now_hires => $now_hires, + tags_rs => $tags_rs, + relations_rs => $relations_rs, + ); + + my $bm_actual = get_actual_billing_mapping(c => $c,schema => $schema, contract => $customer, now => $now_hires); + if ($bm_actual->billing_mappings->first->product->class eq 'pbxaccount') { + my $pilot_subscriber; + if ($prov_subscriber and $prov_subscriber->is_pbx_pilot) { + $pilot_subscriber = $subscriber; + } else { + $pilot_subscriber = $customer->voip_subscribers->search({ + 'provisioning_voip_subscriber.is_pbx_pilot' => 1, + },{ + join => 'provisioning_voip_subscriber', + })->first; + } + + if ($pilot_subscriber) { + $event->create_related("relation_data", { + relation_id => $relations_rs->find({ type => 'pilot_subscriber_id' })->id, + val => $pilot_subscriber->id, + event_timestamp => $now_hires, + }); + my $pilot_prov_subscriber = $pilot_subscriber->provisioning_voip_subscriber; + save_e164( + schema => $schema, + event => $event, + number => $pilot_subscriber->primary_number, + types_prefix => 'pilot_primary_number_', + now_hires => $now_hires, + tags_rs => $tags_rs, + relations_rs => $relations_rs, + ); + save_subscriber_profile( + schema => $schema, + event => $event, + subscriber_profile => ($pilot_prov_subscriber ? $pilot_prov_subscriber->voip_subscriber_profile : undef), + types_prefix => 'pilot_subscriber_profile_', + now_hires => $now_hires, + tags_rs => $tags_rs, + relations_rs => $relations_rs, + ); + + save_subscriber_profile_set( + schema => $schema, + event => $event, + subscriber_profile_set => ($pilot_prov_subscriber ? $pilot_prov_subscriber->voip_subscriber_profile_set : undef), + types_prefix => 'pilot_subscriber_profile_set_', + now_hires => $now_hires, + tags_rs => $tags_rs, + relations_rs => $relations_rs, + ); + } + } + +} + +sub save_e164 { + my %params = @_; + my ($schema, + $event, + $number, + $types_prefix, + $now_hires, + $tags_rs, + $relations_rs) = @params{qw/ + schema + event + number + types_prefix + now_hires + tags_rs + relations_rs + /}; + if ($number) { + $tags_rs //= $schema->resultset('events_tag'); + $relations_rs //= $schema->resultset('events_relation'); + $event->create_related("relation_data", { + relation_id => $relations_rs->find({ type => $types_prefix.'id' })->id, + val => $number->id, + event_timestamp => $now_hires, + }); + if (length(my $cc = $number->cc) > 0) { + $event->create_related("tag_data", { + tag_id => $tags_rs->find({ type => $types_prefix.'cc' })->id, + val => $cc, + event_timestamp => $now_hires, + }); + } + if (length(my $ac = $number->ac) > 0) { + $event->create_related("tag_data", { + tag_id => $tags_rs->find({ type => $types_prefix.'ac' })->id, + val => $ac, + event_timestamp => $now_hires, + }); + } + if (length(my $sn = $number->sn) > 0) { + $event->create_related("tag_data", { + tag_id => $tags_rs->find({ type => $types_prefix.'sn' })->id, + val => $sn, + event_timestamp => $now_hires, + }); + } + } +} + +sub save_subscriber_profile { + my %params = @_; + my ($schema, + $event, + $subscriber_profile, + $types_prefix, + $now_hires, + $tags_rs, + $relations_rs) = @params{qw/ + schema + event + subscriber_profile + types_prefix + now_hires + tags_rs + relations_rs + /}; + + if ($subscriber_profile) { + $tags_rs //= $schema->resultset('events_tag'); + $relations_rs //= $schema->resultset('events_relation'); + $event->create_related("relation_data", { + relation_id => $relations_rs->find({ type => $types_prefix.'id' })->id, + val => $subscriber_profile->id, + event_timestamp => $now_hires, + }); + $event->create_related("tag_data", { + tag_id => $tags_rs->find({ type => $types_prefix.'name' })->id, + val => $subscriber_profile->name, + event_timestamp => $now_hires, + }); + } +} + +sub save_subscriber_profile_set { + my %params = @_; + my ($schema, + $event, + $subscriber_profile_set, + $types_prefix, + $now_hires, + $tags_rs, + $relations_rs) = @params{qw/ + schema + event + subscriber_profile_set + types_prefix + now_hires + tags_rs + relations_rs + /}; + + if ($subscriber_profile_set) { + $tags_rs //= $schema->resultset('events_tag'); + $relations_rs //= $schema->resultset('events_relation'); + $event->create_related("relation_data", { + relation_id => $relations_rs->find({ type => $types_prefix.'id' })->id, + val => $subscriber_profile_set->id, + event_timestamp => $now_hires, + }); + $event->create_related("tag_data", { + tag_id => $tags_rs->find({ type => $types_prefix.'name' })->id, + val => $subscriber_profile_set->name, + event_timestamp => $now_hires, + }); + } } +sub get_actual_billing_mapping { + my %params = @_; + my ($c,$schema,$contract,$now) = @params{qw/c schema contract now/}; + $schema //= $c->model('DB'); + $now //= NGCP::Panel::Utils::DateTime::current_local; + my $contract_create = NGCP::Panel::Utils::DateTime::set_local_tz($contract->create_timestamp // $contract->modify_timestamp); + my $dtf = $schema->storage->datetime_parser; + $now = $contract_create if $now < $contract_create; #if there is no mapping starting with or before $now, it would returns the mapping with max(id): + return $schema->resultset('billing_mappings_actual')->search({ contract_id => $contract->id },{bind => [ ( $dtf->format_datetime($now) ) x 2, ($contract->id) x 2 ],})->first; +} + +sub get_relation_value { + my %params = @_; + my ($c,$schema,$event,$type) = @params{qw/c schema event type/}; + $schema //= $c->model('DB'); + if ($event) { + my $relations_rs = $schema->resultset('events_relation'); + my $relation_data = $event->relation_data->find({ + relation_id => $relations_rs->find({ type => $type })->id, + }); + if ($relation_data) { + return $relation_data->val; + } + } + return undef; +} + +sub get_tag_value { + my %params = @_; + my ($c,$schema,$event,$type) = @params{qw/c schema event type/}; + $schema //= $c->model('DB'); + if ($event) { + my $tags_rs = $schema->resultset('events_tag'); + my $tag_data = $event->tag_data->find({ + tag_id => $tags_rs->find({ type => $type })->id, + }); + if ($tag_data) { + return $tag_data->val; + } + } + return undef; +} 1; diff --git a/t/api-rest/api-events.t b/t/api-rest/api-events.t index 53b7408eb4..3d906c625b 100644 --- a/t/api-rest/api-events.t +++ b/t/api-rest/api-events.t @@ -3,6 +3,7 @@ use Net::Domain qw(hostfqdn); use LWP::UserAgent; use JSON qw(); use Test::More; +use Data::Dumper; my $is_local_env = 0; @@ -60,6 +61,45 @@ is($res->code, 201, "create test billing profile"); my $billing_profile_id = $res->header('Location'); $billing_profile_id =~ s/^.+\/(\d+)$/$1/; +$req = HTTP::Request->new('POST', $uri.'/api/subscriberprofilesets/'); +$req->header('Content-Type' => 'application/json'); +$req->content(JSON::to_json({ + name => "subscriber_profile_set_".$t, + reseller_id => $reseller_id, + description => "subscriber_profile_set_description_".$t, +})); +$res = $ua->request($req); +is($res->code, 201, "POST test subscriberprofileset"); +$req = HTTP::Request->new('GET', $uri.'/'.$res->header('Location')); +$res = $ua->request($req); +is($res->code, 200, "fetch POSTed test subscriberprofileset"); +my $subscriberprofileset = JSON::from_json($res->decoded_content); + +$req = HTTP::Request->new('GET', $uri.'/api/subscriberpreferencedefs/'); +$res = $ua->request($req); +is($res->code, 200, "fetch profilepreferencedefs"); +my $subscriberpreferencedefs = JSON::from_json($res->decoded_content); + +my @subscriber_profile_attributes = (); +foreach my $attr (keys %$subscriberpreferencedefs) { + push(@subscriber_profile_attributes,$attr); +} + +$req = HTTP::Request->new('POST', $uri.'/api/subscriberprofiles/'); +$req->header('Content-Type' => 'application/json'); +$req->content(JSON::to_json({ + name => "subscriber_profile_".$t, + profile_set_id => $subscriberprofileset->{id}, + attributes => \@subscriber_profile_attributes, + description => "subscriber_profile_description_".$t, +})); +$res = $ua->request($req); +is($res->code, 201, "POST test subscriberprofile"); +$req = HTTP::Request->new('GET', $uri.'/'.$res->header('Location')); +$res = $ua->request($req); +is($res->code, 200, "fetch POSTed test subscriberprofile"); +my $subscriberprofile = JSON::from_json($res->decoded_content); + $req = HTTP::Request->new('POST', $uri.'/api/customercontacts/'); $req->header('Content-Type' => 'application/json'); $req->content(JSON::to_json({ @@ -106,7 +146,7 @@ my %customer_map = (); #$t = time; -SKIP: +#SKIP: { my $customer = _create_customer( @@ -153,6 +193,7 @@ SKIP: timeset => $timeset->{name}}], cfu => [{ destinationset => $destinationset_2->{name}, timeset => $timeset->{name}}], + cfs => [], }); #1. update destination set: @@ -177,6 +218,54 @@ SKIP: } +#SKIP: +{ + + my $customer = _create_customer( + type => "pbxaccount", + ); + my $cc = "888"; + my $pilot_ac = undef; #'3'.(scalar keys %subscriber_map); + my $pilot_sn = $t.(scalar keys %subscriber_map); + my $pilot_subscriber = _create_subscriber($customer, + primary_number => { cc => $cc, ac => $pilot_ac, sn => $pilot_sn }, + is_pbx_pilot => JSON::true, + profile_id => $subscriberprofile->{id}, + profile_set_id => $subscriberprofileset->{id}, + ); + my $ac = undef; #'3'.(scalar keys %subscriber_map); + my $sn = ($t+1).(scalar keys %subscriber_map); + my $subscriber = _create_subscriber($customer, + primary_number => { cc => $cc, ac => $ac, sn => $sn }, + profile_id => $subscriberprofile->{id}, + profile_set_id => $subscriberprofileset->{id}, + ); + #_update_subscriber($subscriber, + _check_event_history("events when creating a pbx pilot subscriber: ",$pilot_subscriber->{id},"start_profile",[ + { subscriber_id => $pilot_subscriber->{id}, type => "start_profile", + subscriber_profile_id => $subscriberprofile->{id}, subscriber_profile_name => $subscriberprofile->{name}, + subscriber_profile_set_id => $subscriberprofileset->{id}, subscriber_profile_set_name => $subscriberprofileset->{name}, + primary_number_cc => $cc, primary_number_ac => $pilot_ac, primary_number_sn => $pilot_sn, + pilot_subscriber_id => $pilot_subscriber->{id}, + pilot_subscriber_profile_id => $subscriberprofile->{id}, pilot_subscriber_profile_name => $subscriberprofile->{name}, + pilot_subscriber_profile_set_id => $subscriberprofileset->{id}, pilot_subscriber_profile_set_name => $subscriberprofileset->{name}, + pilot_primary_number_cc => $cc, pilot_primary_number_ac => $pilot_ac, pilot_primary_number_sn => $pilot_sn, + }, + ]); + _check_event_history("events when creating a pbx subscriber: ",$subscriber->{id},"start_profile",[ + { subscriber_id => $subscriber->{id}, type => "start_profile", + subscriber_profile_id => $subscriberprofile->{id}, subscriber_profile_name => $subscriberprofile->{name}, + subscriber_profile_set_id => $subscriberprofileset->{id}, subscriber_profile_set_name => $subscriberprofileset->{name}, + primary_number_cc => $cc, primary_number_ac => $ac, primary_number_sn => $sn, + pilot_subscriber_id => $pilot_subscriber->{id}, + pilot_subscriber_profile_id => $subscriberprofile->{id}, pilot_subscriber_profile_name => $subscriberprofile->{name}, + pilot_subscriber_profile_set_id => $subscriberprofileset->{id}, pilot_subscriber_profile_set_name => $subscriberprofileset->{name}, + pilot_primary_number_cc => $cc, pilot_primary_number_ac => $pilot_ac, pilot_primary_number_sn => $pilot_sn, + }, + ]); + +} + sub _create_cfmapping { my ($subscriber,$mappings) = @_; @@ -431,16 +520,8 @@ sub _compare_event { my $ok = 1; - if ($expected->{id}) { - $ok = is($got->{id},$expected->{id},$label . "check event " . $got->{id} . " id") && $ok; - } - - if ($expected->{subscriber_id}) { - $ok = is($got->{subscriber_id},$expected->{subscriber_id},$label . "check event " . $got->{id} . " subscriber_id") && $ok; - } - - if ($expected->{type}) { - $ok = is($got->{type},$expected->{type},$label . "check event " . $got->{id} . " type '".$expected->{type}."'") && $ok; + foreach my $field (keys %$expected) { + $ok = is($got->{$field},$expected->{$field},$label . "check event " . $got->{$field} . " $field") && $ok; } return $ok;