From da355fb20a69bbe5710ce7dca16e2c84a207a084 Mon Sep 17 00:00:00 2001 From: Christopher Burger Date: Tue, 27 Mar 2018 09:20:05 -0400 Subject: [PATCH] RT# 78356 - added ability to create and modify rateplans and access point when changed on freeside. cleanded up documentation. Conflicts: FS/FS/tower_sector.pm httemplate/edit/process/tower.html httemplate/edit/tower.html --- FS/FS/Schema.pm | 8 +- FS/FS/part_export/saisei.pm | 454 ++++++++++++++++++++------ FS/FS/part_svc.pm | 17 + FS/FS/tower.pm | 12 +- FS/FS/tower_sector.pm | 33 +- httemplate/edit/part_export.cgi | 14 + httemplate/edit/process/elements/process.html | 8 + httemplate/edit/process/tower.html | 2 +- httemplate/edit/tower.html | 10 +- httemplate/elements/tr-tower_sectors.html | 14 +- 10 files changed, 442 insertions(+), 130 deletions(-) diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index cc7470302..431f125f8 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -4891,8 +4891,8 @@ sub tables_hashref { 'height', 'decimal', 'NULL', '', '', '', 'veg_height', 'decimal', 'NULL', '', '', '', 'color', 'varchar', 'NULL', 6, '', '', - 'up_rate', 'int', 'NULL', '', '', '', - 'down_rate', 'int', 'NULL', '', '', '', + 'up_rate_limit', 'int', 'NULL', '', '', '', + 'down_rate_limit', 'int', 'NULL', '', '', '', ], 'primary_key' => 'towernum', 'unique' => [ [ 'towername' ] ], # , 'agentnum' ] ], @@ -4919,8 +4919,8 @@ sub tables_hashref { 'south', 'decimal', 'NULL', '10,7', '', '', 'north', 'decimal', 'NULL', '10,7', '', '', 'title', 'varchar', 'NULL', $char_d,'', '', - 'up_rate', 'int', 'NULL', '', '', '', - 'down_rate', 'int', 'NULL', '', '', '', + 'up_rate_limit', 'int', 'NULL', '', '', '', + 'down_rate_limit', 'int', 'NULL', '', '', '', ], 'primary_key' => 'sectornum', 'unique' => [ [ 'towernum', 'sectorname' ], [ 'ip_addr' ], ], diff --git a/FS/FS/part_export/saisei.pm b/FS/FS/part_export/saisei.pm index f76051ea3..1c95081bd 100644 --- a/FS/FS/part_export/saisei.pm +++ b/FS/FS/part_export/saisei.pm @@ -28,30 +28,47 @@ This is a customer integration with Saisei. This will setup a rate plan and tie the rate plan to a host and access point via the Saisei API when the broadband service is provisioned. It will also untie the rate plan via the API upon unprovisioning of the broadband service. +This will create and modify the rate plans at Saisei as soon as the broadband service attached to this export is created or modified. +This will also create and modify a access point at Saisei as soon as the tower is created or modified. + +To use this export, follow the below instructions: + Add a new export and fill out required fields: - + +Hostname or IP - Host name to Saisei API +User Name - Saisei API user name +Password - Saisei API password + Create a broadband service. The broadband service name will become the Saisei rate plan name. -Set the upload and download speed, and set the modifier to fixed. -Set IP Address to required. -Attach Saisei export to service +Set the upload and download speed for the service. This is required to be able to export the service to Saisei. +Attach above created Saisei export to this broadband service. Create a tower and add a sector to that tower. The sector name will be the name of the access point, -Make sure you have set an up and down rate for the Tower and Sector. +Make sure you have set the up and down rate limit for the Tower and Sector. This is required to be able to export the access point. -When you provision the service, enter the ip address associated to this service. -Select the Tower and Sector for it's access point. +Create a package for the above created broadband service, and order this package for a customer. -When the service is provisioned it will auto setup the rate plan. +When you provision the service, enter the ip address associated to this service and select the Tower and Sector for it's access point. +This provisioned service will then be exported as a host to Saisei. + +when you un provision this service, the host entry at Saisei will be deleted. + +When setting this up, if you wish to export your allready provisioned services, make sure the broadband service has this export attached and +on export edit screen there will be a link to export Provisioned Services attached to this export. Clicking on that will export all services +not currently exported to Saisei. This module also provides generic methods for working through the L. =cut +tie my %scripts, 'Tie::IxHash', + 'export_provisioned_services' => { component => '/elements/popup_link.html', + label => 'Export provisioned services', + description => 'will export provisioned services of part service with Saisei export attached.', + html_label => 'Export Provisioned Services attached to this export.', + }, +; + tie my %options, 'Tie::IxHash', 'port' => { label => 'Port', default => 5000 }, @@ -67,11 +84,19 @@ tie my %options, 'Tie::IxHash', 'svc' => 'svc_broadband', 'desc' => 'Export broadband service/account to Saisei', 'options' => \%options, + 'scripts' => \%scripts, 'notes' => <<'END', This is a customer integration with Saisei. This will setup a rate plan and tie the rate plan to a host and access point via the Saisei API when the broadband service is provisioned. It will also untie the rate plan via the API upon unprovisioning of the broadband service.

+This will create and modify the rate plans at Saisei as soon as the broadband service attached to this export is created or modified. +This will also create and modify a access point at Saisei as soon as the tower is created or modified. +

+To use this export, follow the below instructions: +

+

    +
  1. Add a new export and fill out required fields:
    • Hostname or IP - Host name to Saisei API
    • @@ -79,18 +104,34 @@ Add a new export and fill out required fields:
    • User Name - Saisei API user name
    • Password - Saisei API password
    +
  2. +

    +

  3. Create a broadband service. The broadband service name will become the Saisei rate plan name. -Set the upload and download speed, and set the modifier to fixed. -Set IP Address to required. -Attach Saisei export to service +Set the upload and download speed for the service. This is required to be able to export the service to Saisei. +Attach above created Saisei export to this broadband service. +
  4. +

  5. Create a tower and add a sector to that tower. The sector name will be the name of the access point, -Make sure you have set an up and down rate for the Tower and Sector. +Make sure you have set the up and down rate limit for the Tower and Sector. This is required to be able to export the access point. +
  6. +

    +

  7. +Create a package for the above created broadband service, and order this package for a customer. +
  8. +

    +

  9. +When you provision the service, enter the ip address associated to this service and select the Tower and Sector for it's access point. +This provisioned service will then be exported as a host to Saisei.

    -When you provision the service, enter the ip address associated to this service. -Select the Tower and Sector for it's access point. +when you un provision this service, the host entry at Saisei will be deleted. +

  10. +

-When the service is provisioned it will auto setup the rate plan. +When setting this up, if you wish to export your allready provisioned services, make sure the broadband service has this export attached and +on export edit screen there will be a link to export Provisioned Services attached to this export. Clicking on that will export all services +not currently exported to Saisei. END ); @@ -101,21 +142,14 @@ sub _export_insert { my $rateplan_name = $service_part->{Hash}->{svc}; $rateplan_name =~ s/\s/_/g; - # load needed info from our end - my $cust_main = $svc_broadband->cust_main; - return "Could not load service customer" unless $cust_main; - my $conf = new FS::Conf; - - # get policy list - my $policies = $self->api_get_policies(); - # check for existing rate plan my $existing_rateplan; $existing_rateplan = $self->api_get_rateplan($rateplan_name) unless $self->{'__saisei_error'}; # if no existing rate plan create one and modify it. $self->api_create_rateplan($svc_broadband, $rateplan_name) unless $existing_rateplan; - $self->api_modify_rateplan($policies->{collection}, $svc_broadband, $rateplan_name) unless ($self->{'__saisei_error'} || $existing_rateplan); + $self->api_modify_rateplan($svc_broadband, $rateplan_name) unless ($self->{'__saisei_error'} || $existing_rateplan); + return $self->api_error if $self->{'__saisei_error'}; # set rateplan to existing one or newly created one. my $rateplan = $existing_rateplan ? $existing_rateplan : $self->api_get_rateplan($rateplan_name); @@ -125,7 +159,6 @@ sub _export_insert { if (!$username) { $self->{'__saisei_error'} = 'no username - can not export'; - warn "No user $username\n" if $self->option('debug'); return $self->api_error; } else { @@ -135,59 +168,49 @@ sub _export_insert { # if no existing user create one. $self->api_create_user($username, $description) unless $existing_user; + return $self->api_error if $self->{'__saisei_error'}; # set user to existing one or newly created one. my $user = $existing_user ? $existing_user : $self->api_get_user($username); - ## add access point ? + ## add access point my $tower_sector = FS::Record::qsearchs({ 'table' => 'tower_sector', 'select' => 'tower.towername, - tower.up_rate as toweruprate, - tower.down_rate as towerdownrate, + tower.up_rate_limit as tower_upratelimit, + tower.down_rate_limit as tower_downratelimit, tower_sector.sectorname, - tower_sector.up_rate as sectoruprate, - tower_sector.down_rate as sectordownrate ', + tower_sector.up_rate_limit as sector_upratelimit, + tower_sector.down_rate_limit as sector_downratelimit ', 'addl_from' => 'LEFT JOIN tower USING ( towernum )', 'hashref' => { 'sectornum' => $svc_broadband->{Hash}->{sectornum}, }, }); - my $existing_tower_ap; my $tower_name = $tower_sector->{Hash}->{towername}; $tower_name =~ s/\s/_/g; - #check if tower has been set up as an access point. - $existing_tower_ap = $self->api_get_accesspoint($tower_name) unless $self->{'__saisei_error'};; + my $tower_opt = { + 'tower_name' => $tower_name, + 'tower_uprate_limit' => $tower_sector->{Hash}->{tower_upratelimit}, + 'tower_downrate_limit' => $tower_sector->{Hash}->{tower_downratelimit}, + }; - #if tower does not exist as an access point create it. - $self->api_create_accesspoint( - $tower_name, - $tower_sector->{Hash}->{toweruprate}, - $tower_sector->{Hash}->{towerdownrate} - ) unless $existing_tower_ap; + my $tower_ap = process_tower($self, $tower_opt); + return $self->api_error if $self->{'__saisei_error'}; - my $existing_sector_ap; my $sector_name = $tower_sector->{Hash}->{sectorname}; $sector_name =~ s/\s/_/g; - #check if sector has been set up as an access point. - $existing_sector_ap = $self->api_get_accesspoint($sector_name); - - #if sector does not exist as an access point create it. - $self->api_create_accesspoint( - $sector_name, - $tower_sector->{Hash}->{sectoruprate}, - $tower_sector->{Hash}->{sectordownrate}, - $tower_name, - ) unless $existing_sector_ap; - - # Attach newly created sector to it's tower. - $self->api_modify_accesspoint($sector_name, $tower_name) unless ($self->{'__saisei_error'} || $existing_sector_ap); - - # set access point to existing one or newly created one. - my $accesspoint = $existing_sector_ap ? $existing_sector_ap : $self->api_get_accesspoint($sector_name); + my $sector_opt = { + 'tower_name' => $tower_name, + 'sector_name' => $sector_name, + 'sector_uprate_limit' => $tower_sector->{Hash}->{sector_upratelimit}, + 'sector_downrate_limit' => $tower_sector->{Hash}->{sector_downratelimit}, + }; + my $accesspoint = process_sector($self, $sector_opt); + return $self->api_error if $self->{'__saisei_error'}; ## tie host to user add sector name as access point. $self->api_add_host_to_user( @@ -203,27 +226,17 @@ sub _export_insert { } sub _export_replace { - my ($self, $svc_phone) = @_; + my ($self, $svc_broadband) = @_; return ''; } sub _export_delete { my ($self, $svc_broadband) = @_; - my $cust_main = $svc_broadband->cust_main; - return "Could not load service customer" unless $cust_main; - my $conf = new FS::Conf; - - my $rateplan_name = $svc_broadband->{Hash}->{description}; + my $service_part = FS::Record::qsearchs( 'part_svc', { 'svcpart' => $svc_broadband->{Hash}->{svcpart} } ); + my $rateplan_name = $service_part->{Hash}->{svc}; $rateplan_name =~ s/\s/_/g; - - my @email = map { $_->emailaddress } FS::Record::qsearch({ - 'table' => 'cust_contact', - 'select' => 'emailaddress', - 'addl_from' => ' JOIN contact_email USING (contactnum)', - 'hashref' => { 'custnum' => $cust_main->{Hash}->{custnum}, }, - }); - my $username = $email[0]; + my $username = $svc_broadband->{Hash}->{svcnum}; ## tie host to user $self->api_delete_host_to_user($username, $rateplan_name, $svc_broadband->{Hash}->{ip_addr}) unless $self->{'__saisei_error'}; @@ -232,15 +245,81 @@ sub _export_delete { } sub _export_suspend { - my ($self, $svc_phone) = @_; + my ($self, $svc_broadband) = @_; return ''; } sub _export_unsuspend { - my ($self, $svc_phone) = @_; + my ($self, $svc_broadband) = @_; return ''; } +sub export_partsvc { + my ($self, $svc_part) = @_; + + my $rateplan_name = $svc_part->{Hash}->{svc}; + $rateplan_name =~ s/\s/_/g; + my $speeddown = $svc_part->{Hash}->{svc_broadband__speed_down}; + my $speedup = $svc_part->{Hash}->{svc_broadband__speed_up}; + + my $temp_svc = $svc_part->{Hash}; + my $svc_broadband = {}; + map { if ($_ =~ /^svc_broadband__(.*)$/) { $svc_broadband->{Hash}->{$1} = $temp_svc->{$_}; } } keys %$temp_svc; + + # check for existing rate plan + my $existing_rateplan; + $existing_rateplan = $self->api_get_rateplan($rateplan_name) unless $self->{'__saisei_error'}; + + # Modify the existing rate plan with new service data. + $self->api_modify_existing_rateplan($svc_broadband, $rateplan_name) unless ($self->{'__saisei_error'} || !$existing_rateplan); + + # if no existing rate plan create one and modify it. + $self->api_create_rateplan($svc_broadband, $rateplan_name) unless $existing_rateplan; + $self->api_modify_rateplan($svc_part, $rateplan_name) unless ($self->{'__saisei_error'} || $existing_rateplan); + + return $self->api_error; + +} + +sub export_tower_sector { + my ($self, $tower) = @_; + + #modify tower or create it. + my $tower_name = $tower->{Hash}->{towername}; + $tower_name =~ s/\s/_/g; + my $tower_opt = { + 'tower_name' => $tower_name, + 'tower_uprate_limit' => $tower->{Hash}->{up_rate_limit}, + 'tower_downrate_limit' => $tower->{Hash}->{down_rate_limit}, + 'modify_existing' => '1', # modify an existing access point with this info + }; + + my $tower_access_point = process_tower($self, $tower_opt); + + #get list of all access points + my $hash_opt = { + 'table' => 'tower_sector', + 'select' => '*', + 'hashref' => { 'towernum' => $tower->{Hash}->{towernum}, }, + }; + + #for each one modify or create it. + foreach my $tower_sector ( FS::Record::qsearch($hash_opt) ) { + my $sector_name = $tower_sector->{Hash}->{sectorname}; + $sector_name =~ s/\s/_/g; + my $sector_opt = { + 'tower_name' => $tower_name, + 'sector_name' => $sector_name, + 'sector_uprate_limit' => $tower_sector->{Hash}->{up_rate_limit}, + 'sector_downrate_limit' => $tower_sector->{Hash}->{down_rate_limit}, + 'modify_existing' => '1', # modify an existing access point with this info + }; + my $sector_access_point = process_sector($self, $sector_opt); + } + + return $self->api_error; +} + =head1 Saisei API These methods allow access to the Saisei API using the credentials @@ -259,6 +338,7 @@ Returns empty on failure; retrieve error messages using L. sub api_call { my ($self,$method,$path,$params) = @_; + $self->{'__saisei_error'} = ''; my $auth_info = $self->option('username') . ':' . $self->option('password'); $params ||= {}; @@ -286,7 +366,8 @@ sub api_call { } } else { - $self->{'__saisei_error'} = "Bad response from server during $method: " . $client->responseContent(); + $self->{'__saisei_error'} = "Bad response from server during $method: " . $client->responseContent() + unless ($method eq "GET"); warn "Response Content is\n".$client->responseContent."\n" if $self->option('debug'); return; } @@ -321,7 +402,7 @@ sub api_get_policies { $self->{'__saisei_error'} = "Did not receive any global policies" unless $get_policies; - return $get_policies; + return $get_policies->{collection}; } =head2 api_get_rateplan @@ -336,8 +417,6 @@ sub api_get_rateplan { my $get_rateplan = $self->api_call("GET", "/rate_plans/$rateplan"); return if $self->api_error; - $self->{'__saisei_error'} = "Did not receive any rateplan info" - unless $get_rateplan; return $get_rateplan; } @@ -354,8 +433,6 @@ sub api_get_user { my $get_user = $self->api_call("GET", "/users/$user"); return if $self->api_error; - $self->{'__saisei_error'} = "Did not receive any user info" - unless $get_user; return $get_user; } @@ -372,12 +449,27 @@ sub api_get_accesspoint { my $get_accesspoint = $self->api_call("GET", "/access_points/$accesspoint"); return if $self->api_error; - $self->{'__saisei_error'} = "Did not receive any access point info" - unless $get_accesspoint; return $get_accesspoint; } +=head2 api_get_host + +Gets user info for specific host. + +=cut + +sub api_get_host { + my $self = shift; + my $ip = shift; + + my $get_host = $self->api_call("GET", "/hosts/$ip"); + + return if $self->api_error; + + return $get_host; +} + =head2 api_create_rateplan Creates a rateplan. @@ -387,6 +479,9 @@ Creates a rateplan. sub api_create_rateplan { my ($self, $svc, $rateplan) = @_; + $self->{'__saisei_error'} = "No downrate listed for service $rateplan" if !$svc->{Hash}->{speed_down}; + $self->{'__saisei_error'} = "No uprate listed for service $rateplan" if !$svc->{Hash}->{speed_up}; + my $new_rateplan = $self->api_call( "PUT", "/rate_plans/$rateplan", @@ -394,22 +489,26 @@ sub api_create_rateplan { 'downstream_rate' => $svc->{Hash}->{speed_down}, 'upstream_rate' => $svc->{Hash}->{speed_up}, }, - ); + ) unless $self->{'__saisei_error'}; $self->{'__saisei_error'} = "Rate Plan not created" - unless $new_rateplan; # should never happen + unless ($new_rateplan || $self->{'__saisei_error'}); + return $new_rateplan; } =head2 api_modify_rateplan -Modify a rateplan. +Modify a new rateplan. =cut sub api_modify_rateplan { - my ($self,$policies,$svc,$rateplan_name) = @_; + my ($self,$svc,$rateplan_name) = @_; + + # get policy list + my $policies = $self->api_get_policies(); foreach my $policy (@$policies) { my $policyname = $policy->{name}; @@ -425,8 +524,8 @@ sub api_modify_rateplan { }, ); - $self->{'__saisei_error'} = "Rate Plan not modified" - unless $modified_rateplan; # should never happen + $self->{'__saisei_error'} = "Rate Plan not modified after create" + unless ($modified_rateplan || $self->{'__saisei_error'}); # should never happen } @@ -434,6 +533,31 @@ sub api_modify_rateplan { } +=head2 api_modify_existing_rateplan + +Modify a existing rateplan. + +=cut + +sub api_modify_existing_rateplan { + my ($self,$svc,$rateplan_name) = @_; + + my $modified_rateplan = $self->api_call( + "PUT", + "/rate_plans/$rateplan_name", + { + 'downstream_rate' => $svc->{Hash}->{speed_down}, + 'upstream_rate' => $svc->{Hash}->{speed_up}, + }, + ); + + $self->{'__saisei_error'} = "Rate Plan not modified" + unless ($modified_rateplan || $self->{'__saisei_error'}); # should never happen + + return; + +} + =head2 api_create_user Creates a user. @@ -452,7 +576,7 @@ sub api_create_user { ); $self->{'__saisei_error'} = "User not created" - unless $new_user; # should never happen + unless ($new_user || $self->{'__saisei_error'}); # should never happen return $new_user; @@ -465,34 +589,34 @@ Creates a access point. =cut sub api_create_accesspoint { - my ($self,$accesspoint, $uprate, $downrate) = @_; + my ($self,$accesspoint, $upratelimit, $downratelimit) = @_; # this has not been tested, but should work, if needed. my $new_accesspoint = $self->api_call( "PUT", "/access_points/$accesspoint", { - 'downstream_rate_limit' => $downrate, - 'upstream_rate_limit' => $uprate, + 'downstream_rate_limit' => $downratelimit, + 'upstream_rate_limit' => $upratelimit, }, ); $self->{'__saisei_error'} = "Access point not created" - unless $new_accesspoint; # should never happen + unless ($new_accesspoint || $self->{'__saisei_error'}); # should never happen return; } =head2 api_modify_accesspoint -Modify a access point. +Modify a new access point. =cut sub api_modify_accesspoint { my ($self, $accesspoint, $uplink) = @_; - my $modified_rateplan = $self->api_call( + my $modified_accesspoint = $self->api_call( "PUT", "/access_points/$accesspoint", { @@ -501,7 +625,33 @@ sub api_modify_accesspoint { ); $self->{'__saisei_error'} = "Rate Plan not modified" - unless $modified_rateplan; # should never happen + unless ($modified_accesspoint || $self->{'__saisei_error'}); # should never happen + + return; + +} + +=head2 api_modify_existing_accesspoint + +Modify a existing accesspoint. + +=cut + +sub api_modify_existing_accesspoint { + my ($self, $accesspoint, $uplink, $upratelimit, $downratelimit) = @_; + + my $modified_accesspoint = $self->api_call( + "PUT", + "/access_points/$accesspoint", + { + 'downstream_rate_limit' => $downratelimit, + 'upstream_rate_limit' => $upratelimit, +# 'uplink' => $uplink, # name of attached access point + }, + ); + + $self->{'__saisei_error'} = "Access point not modified" + unless ($modified_accesspoint || $self->{'__saisei_error'}); # should never happen return; @@ -527,7 +677,7 @@ sub api_add_host_to_user { ); $self->{'__saisei_error'} = "Host not created" - unless $new_host; # should never happen + unless ($new_host || $self->{'__saisei_error'}); # should never happen return $new_host; @@ -560,12 +710,114 @@ sub api_delete_host_to_user { ); $self->{'__saisei_error'} = "Host not created" - unless $delete_host; # should never happen + unless ($delete_host || $self->{'__saisei_error'}); # should never happen return $delete_host; } +sub process_tower { + my ($self, $opt) = @_; + + my $existing_tower_ap; + my $tower_name = $opt->{tower_name}; + + #check if tower has been set up as an access point. + $existing_tower_ap = $self->api_get_accesspoint($tower_name) unless $self->{'__saisei_error'}; + + # modify the existing accesspoint if changing tower . + $self->api_modify_existing_accesspoint ( + $tower_name, + '', # tower does not have a uplink on sectors. + $opt->{tower_uprate_limit}, + $opt->{tower_downrate_limit}, + ) if $existing_tower_ap && $opt->{modify_existing}; + + #if tower does not exist as an access point create it. + $self->api_create_accesspoint( + $tower_name, + $opt->{tower_uprate_limit}, + $opt->{tower_downrate_limit} + ) unless $existing_tower_ap; + + my $accesspoint = $self->api_get_accesspoint($tower_name); + + return $accesspoint; +} + +sub process_sector { + my ($self, $opt) = @_; + + my $existing_sector_ap; + my $sector_name = $opt->{sector_name}; + + #check if sector has been set up as an access point. + $existing_sector_ap = $self->api_get_accesspoint($sector_name); + + # modify the existing accesspoint if changing sector . + $self->api_modify_existing_accesspoint ( + $sector_name, + $opt->{tower_name}, + $opt->{sector_uprate_limit}, + $opt->{sector_downrate_limit}, + ) if $existing_sector_ap && $opt->{modify_existing}; + + #if sector does not exist as an access point create it. + $self->api_create_accesspoint( + $sector_name, + $opt->{sector_uprate_limit}, + $opt->{sector_downrate_limit}, + ) unless $existing_sector_ap; + + # Attach newly created sector to it's tower. + $self->api_modify_accesspoint($sector_name, $opt->{tower_name}) unless ($self->{'__saisei_error'} || $existing_sector_ap); + + # set access point to existing one or newly created one. + my $accesspoint = $existing_sector_ap ? $existing_sector_ap : $self->api_get_accesspoint($sector_name); + + return $accesspoint; +} + +sub export_provisioned_services { + my $job = shift; + my $param = shift; + + my $part_export = FS::Record::qsearchs('part_export', { 'exportnum' => $param->{export_provisioned_services_exportnum}, } ) + or die "unknown exportnum $param->{export_provisioned_services_exportnum}"; + bless $part_export; + + my @svcparts = FS::Record::qsearch({ + 'table' => 'export_svc', + 'addl_from' => 'LEFT JOIN part_svc USING ( svcpart ) ', + 'hashref' => { 'exportnum' => $param->{export_provisioned_services_exportnum}, }, + }); + my $part_count = scalar @svcparts; + + my $parts = join "', '", map { $_->{Hash}->{svcpart} } @svcparts; + + my @svcs = FS::Record::qsearch({ + 'table' => 'cust_svc', + 'addl_from' => 'LEFT JOIN svc_broadband USING ( svcnum ) ', + 'extra_sql' => " WHERE svcpart in ('".$parts."')", + }); + + my $svc_count = scalar @svcs; + + my %status = {}; + for (my $c=10; $c <=100; $c=$c+10) { $status{int($svc_count * ($c/100))} = $c; } + + my $process_count=0; + foreach my $svc (@svcs) { + if ($status{$process_count}) { my $s = $status{$process_count}; $job->update_statustext($s); } + ## check if service exists as host if not export it. + _export_insert($part_export,$svc) unless api_get_host($part_export, $svc->{Hash}->{ip_addr}); + $process_count++; + } + + return; + +} + =head1 SEE ALSO L diff --git a/FS/FS/part_svc.pm b/FS/FS/part_svc.pm index dcc78435b..341559594 100644 --- a/FS/FS/part_svc.pm +++ b/FS/FS/part_svc.pm @@ -519,6 +519,18 @@ sub part_export_dsl_pull { grep $_->can('dsl_pull'), $self->part_export; } +=item part_export_partsvc + +Returns a list of any exports (see L) for this service that +are capable of pushing a change after part svc is changed. + +=cut + +sub part_export_partsvc { + my $self = shift; + grep $_->can('export_partsvc'), $self->part_export; +} + =item cust_svc [ PKGPART ] Returns a list of associated customer services (FS::cust_svc records). @@ -909,6 +921,11 @@ sub process { ); die "$error\n" if $error; + + foreach my $part_svc_export ( $new->part_export_partsvc ) { + $error = $part_svc_export->export_partsvc($new); + } + return $error if $error; } =item process_bulk_cust_svc diff --git a/FS/FS/tower.pm b/FS/FS/tower.pm index 5dcf1f843..13453f1d8 100644 --- a/FS/FS/tower.pm +++ b/FS/FS/tower.pm @@ -44,13 +44,13 @@ Tower name Disabled flag, empty or 'Y' -=item up_rate +=item up_rate_limit -Up Rate for towner +Up Rate limit for towner -=item down_rate +=item down_rate_limit -Down Rate for tower +Down Rate limit for tower =back @@ -105,8 +105,8 @@ sub check { || $self->ut_floatn('height') || $self->ut_floatn('veg_height') || $self->ut_alphan('color') - || $self->ut_numbern('up_rate') - || $self->ut_numbern('down_rate') + || $self->ut_numbern('up_rate_limit') + || $self->ut_numbern('down_rate_limit') ; return $error if $error; diff --git a/FS/FS/tower_sector.pm b/FS/FS/tower_sector.pm index b58cacf46..90d6a9cb5 100644 --- a/FS/FS/tower_sector.pm +++ b/FS/FS/tower_sector.pm @@ -92,13 +92,13 @@ The coordinate boundaries of the coverage map. The sector title. -=item up_rate +=item up_rate_limit -Up rate for sector. +Up rate limit for sector. -=item down_rate +=item down_rate_limit -down rate for sector. +down rate limit for sector. =back @@ -162,8 +162,8 @@ sub check { || $self->ut_numbern('downtilt') || $self->ut_floatn('sector_range') || $self->ut_numbern('margin') - || $self->ut_numbern('up_rate') - || $self->ut_numbern('down_rate') + || $self->ut_numbern('up_rate_limit') + || $self->ut_numbern('down_rate_limit') || $self->ut_anything('image') || $self->ut_sfloatn('west') || $self->ut_sfloatn('east') @@ -251,6 +251,27 @@ sub queue_generate_coverage { =back +=head1 CLASS METHODS + +=over 4 + +=item part_export_svc_broadband + +Returns all svc_broadband exports. + +=cut + +sub part_export_svc_broadband { + my $info = $FS::part_export::exports{'svc_broadband'} or return; + my @exporttypes = map { dbh->quote($_) } keys %$info or return; + qsearch({ + 'table' => 'part_export', + 'extra_sql' => 'WHERE exporttype IN(' . join(',', @exporttypes) . ')' + }); +} + +=back + =head1 SUBROUTINES =over 4 diff --git a/httemplate/edit/part_export.cgi b/httemplate/edit/part_export.cgi index 5411feb5f..381fbcaf8 100644 --- a/httemplate/edit/part_export.cgi +++ b/httemplate/edit/part_export.cgi @@ -290,6 +290,20 @@ my $widget = new HTML::Widgets::SelectLayers( $html .= ' CHECKED' if $part_export->no_suspend eq 'Y'; $html .= '>'; + foreach my $script ( keys %{$exports->{$layer}{scripts}} ) { + $html .= '' . + include('/elements/progress-init.html', + $part_export->exportname, + [ $script.'_exportnum', $script.'_script' ], + rooturl().'view/svc_export/run_script.cgi', + rooturl().'edit/part_export.cgi?'.$part_export->{Hash}->{exportnum}, + $script, + ) . + ' + + '.$exports->{$layer}{scripts}{$script}->{html_label}.''; + } + $html .= ''; # false laziness with config_element above diff --git a/httemplate/edit/process/elements/process.html b/httemplate/edit/process/elements/process.html index 76722c960..8c307f0b6 100644 --- a/httemplate/edit/process/elements/process.html +++ b/httemplate/edit/process/elements/process.html @@ -459,6 +459,14 @@ foreach my $value ( @values ) { } +if ($class eq "FS::tower") { + foreach my $part_svc_broadband_export ( FS::tower_sector->part_export_svc_broadband ) { + if ($part_svc_broadband_export and $part_svc_broadband_export->can('export_tower_sector')) { + $error = $part_svc_broadband_export->export_tower_sector($new); + } + } +} + # set up redirect URLs my $redirect; diff --git a/httemplate/edit/process/tower.html b/httemplate/edit/process/tower.html index e17cd55ae..ba7309c99 100644 --- a/httemplate/edit/process/tower.html +++ b/httemplate/edit/process/tower.html @@ -5,7 +5,7 @@ 'fields' => [qw( sectorname ip_addr height freq_mhz direction width downtilt v_width margin - sector_range up_rate down_rate + sector_range up_rate_limit down_rate_limit )], }, &> diff --git a/httemplate/edit/tower.html b/httemplate/edit/tower.html index 660788849..b9fea779f 100644 --- a/httemplate/edit/tower.html +++ b/httemplate/edit/tower.html @@ -12,8 +12,8 @@ 'altitude', 'height', 'veg_height', - 'up_rate', - 'down_rate', + 'up_rate_limit', + 'down_rate_limit', { field => 'sectornum', type => 'tower_sector', o2m_table => 'tower_sector', @@ -32,8 +32,8 @@ 'height' => 'Height (feet)', 'veg_height' => 'Vegetation height (feet)', 'color' => 'Color', - 'up_rate' => 'Up Rate (Kbps)', - 'down_rate' => 'Down Rate (Kbps)', + 'up_rate_limit' => 'Up Rate Limit(Kbps)', + 'down_rate_limit' => 'Down Rate Limit(Kbps)', }, &> <%init> @@ -43,7 +43,7 @@ my $m2_error_callback = sub { # reconstruct the list my @fields = qw( sectorname ip_addr height freq_mhz direction width tilt v_width margin - sector_range up_rate down_rate + sector_range up_rate_limit down_rate_limit ); map { diff --git a/httemplate/elements/tr-tower_sectors.html b/httemplate/elements/tr-tower_sectors.html index 6843f4fdc..8acedb84b 100644 --- a/httemplate/elements/tr-tower_sectors.html +++ b/httemplate/elements/tr-tower_sectors.html @@ -17,7 +17,7 @@ my $tabcounter = 0; my @fields = qw( sectorname ip_addr height freq_mhz direction width downtilt v_width db_high db_low sector_range - power line_loss antenna_gain hardware_typenum up_rate down_rate + power line_loss antenna_gain hardware_typenum up_rate_limit down_rate_limit ); my @sectors; @@ -294,16 +294,16 @@ $(function() {

+ id="<% $id %>_up_rate_limit" + name="<% $id %>_up_rate_limit" + value="<% $sector->up_rate_limit |h %>">

+ id="<% $id %>_down_rate_limit" + name="<% $id %>_down_rate_limit" + value="<% $sector->down_rate_limit |h %>">

-- 2.11.0