diff options
-rw-r--r-- | FS/FS/Conf.pm | 7 | ||||
-rw-r--r-- | FS/FS/Schema.pm | 1 | ||||
-rw-r--r-- | FS/FS/cust_location.pm | 69 | ||||
-rwxr-xr-x | httemplate/edit/cust_location.cgi | 54 | ||||
-rw-r--r-- | httemplate/edit/process/cust_location.cgi | 38 | ||||
-rw-r--r-- | httemplate/elements/tr-select-cust_location.html | 1 | ||||
-rwxr-xr-x | httemplate/misc/disable-cust_location.cgi | 35 | ||||
-rwxr-xr-x | httemplate/view/cust_main/locations.html | 87 | ||||
-rwxr-xr-x | httemplate/view/cust_main/packages.html | 96 | ||||
-rw-r--r-- | httemplate/view/cust_main/packages/location.html | 13 | ||||
-rw-r--r-- | httemplate/view/cust_main/packages/package.html | 27 | ||||
-rwxr-xr-x | httemplate/view/cust_main/packages/section.html | 95 |
12 files changed, 445 insertions, 78 deletions
diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index a05ad0358..072982ab4 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -2689,6 +2689,13 @@ and customer address. Include units.', }, { + 'key' => 'cust_pkg-group_by_location', + 'section' => 'UI', + 'description' => "Group packages by location.", + 'type' => 'checkbox', + }, + + { 'key' => 'cust_pkg-show_fcc_voice_grade_equivalent', 'section' => 'UI', 'description' => "Show a field on package definitions for assigning a DSO equivalency number suitable for use on FCC form 477.", diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index b48e5af8a..253eb6602 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -909,6 +909,7 @@ sub tables_hashref { 'location_type', 'varchar', 'NULL', 20, '', '', 'location_number', 'varchar', 'NULL', 20, '', '', 'location_kind', 'char', 'NULL', 1, '', '', + 'disabled', 'char', 'NULL', 1, '', '', ], 'primary_key' => 'locationnum', 'unique' => [], diff --git a/FS/FS/cust_location.pm b/FS/FS/cust_location.pm index ab80941f9..60c0181a3 100644 --- a/FS/FS/cust_location.pm +++ b/FS/FS/cust_location.pm @@ -3,6 +3,7 @@ package FS::cust_location; use strict; use base qw( FS::geocode_Mixin FS::Record ); use Locale::Country; +use FS::UID qw( dbh ); use FS::Record qw( qsearch ); #qsearchs ); use FS::prospect_main; use FS::cust_main; @@ -74,6 +75,10 @@ Country (see L<FS::cust_main_county>) Geocode +=item disabled + +Disabled flag; set to 'Y' to disable the location. + =back =head1 METHODS @@ -192,6 +197,70 @@ city, county, state, zip, country, geocode. =cut +=item move_to HASHREF + +Takes a hashref with one or more cust_location fields. Creates a duplicate +of the existing location with all fields set to the values in the hashref. +Moves all packages that use the existing location to the new one, then sets +the "disabled" flag on the old location. Returns nothing on success, an +error message on error. + +=cut + +sub move_to { + my $old = shift; + my $hashref = shift; + + local $SIG{HUP} = 'IGNORE'; + local $SIG{INT} = 'IGNORE'; + local $SIG{QUIT} = 'IGNORE'; + local $SIG{TERM} = 'IGNORE'; + local $SIG{TSTP} = 'IGNORE'; + local $SIG{PIPE} = 'IGNORE'; + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + my $error = ''; + + my $new = FS::cust_location->new({ + $old->location_hash, + 'custnum' => $old->custnum, + 'prospectnum' => $old->prospectnum, + %$hashref + }); + $error = $new->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "Error creating location: $error"; + } + + my @pkgs = qsearch('cust_pkg', { + 'locationnum' => $old->locationnum, + 'cancel' => '' + }); + foreach my $cust_pkg (@pkgs) { + $error = $cust_pkg->change( + 'locationnum' => $new->locationnum, + 'keep_dates' => 1 + ); + if ( $error and not ref($error) ) { + $dbh->rollback if $oldAutoCommit; + return "Error moving pkgnum ".$cust_pkg->pkgnum.": $error"; + } + } + + $old->disabled('Y'); + $error = $old->replace; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "Error disabling old location: $error"; + } + + $dbh->commit if $oldAutoCommit; + return; +} + =back =head1 BUGS diff --git a/httemplate/edit/cust_location.cgi b/httemplate/edit/cust_location.cgi new file mode 100755 index 000000000..80b27c2b3 --- /dev/null +++ b/httemplate/edit/cust_location.cgi @@ -0,0 +1,54 @@ +<% include('/elements/header-popup.html', "Edit Location") %> + +<% include('/elements/error.html') %> + +<FORM NAME="EditLocationForm" +ACTION="<% $p %>edit/process/cust_location.cgi" METHOD=POST> +<INPUT TYPE="hidden" NAME="locationnum" VALUE="<% $locationnum %>"> + +<% ntable('#cccccc') %> +<% include('/elements/location.html', + 'object' => $cust_location, + 'no_asterisks' => 1, + ) %> +</TABLE> + +<BR> +<SCRIPT TYPE="text/javascript"> +function areyousure() { + return confirm('Modify this service location?'); +} +</SCRIPT> +<INPUT TYPE="submit" VALUE="Submit" onclick="return areyousure()"> + +</FORM> +</BODY> +</HTML> + +<%init> + +my $conf = new FS::Conf; + +my $curuser = $FS::CurrentUser::CurrentUser; + +# it's the same access right you'd need to do this by editing packages +die "access denied" + unless $curuser->access_right('Change customer package'); + +my $locationnum = scalar($cgi->param('locationnum')); +my $cust_location = qsearchs({ + 'select' => 'cust_location.*', + 'table' => 'cust_location', + 'addl_from' => 'LEFT JOIN cust_main USING ( custnum )', + 'hashref' => { 'locationnum' => $locationnum }, + 'extra_sql' => ' AND '. $curuser->agentnums_sql, + }) or die "unknown locationnum $locationnum"; + +die "can't edit disabled locationnum $locationnum" if $cust_location->disabled; + +my $cust_main = qsearchs('cust_main', { 'custnum' => $cust_location->custnum }) + or die "can't get cust_main record for custnum ". $cust_location->custnum; + +my @cust_pkgs = qsearch('cust_pkg', { 'locationnum' => $locationnum }); + +</%init> diff --git a/httemplate/edit/process/cust_location.cgi b/httemplate/edit/process/cust_location.cgi new file mode 100644 index 000000000..790fc8ea4 --- /dev/null +++ b/httemplate/edit/process/cust_location.cgi @@ -0,0 +1,38 @@ +% if ($error) { +% $cgi->param('error', Dumper($error)); +% $cgi->redirect(popurl(3). 'edit/cust_location.cgi?'. $cgi->query_string ); +% } else { + + <% header("Location changed") %> + <SCRIPT TYPE="text/javascript"> + window.top.location.reload(); + </SCRIPT> + </BODY> + </HTML> + +% } +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right('Change customer package'); + +my $locationnum = $cgi->param('locationnum'); +my $cust_location = qsearchs({ + 'select' => 'cust_location.*', + 'table' => 'cust_location', + 'addl_from' => 'LEFT JOIN cust_main USING ( custnum )', + 'hashref' => { 'locationnum' => $locationnum }, + 'extra_sql' => ' AND '. $curuser->agentnums_sql, +}); +die "unknown locationnum $locationnum" unless $cust_location; + +my $new = { + map { $_ => scalar($cgi->param($_)) } + qw( address1 address2 city county state zip country ) +}; + +my $error = $cust_location->move_to($new); + +</%init> diff --git a/httemplate/elements/tr-select-cust_location.html b/httemplate/elements/tr-select-cust_location.html index 78252ba1d..fa19405b2 100644 --- a/httemplate/elements/tr-select-cust_location.html +++ b/httemplate/elements/tr-select-cust_location.html @@ -162,6 +162,7 @@ Example: % push @locations, $cust_location % if !$cust_main && $cust_location && $cust_location->locationnum>0; % foreach my $loc ( sort $location_sort @locations ) { +% next if $loc->disabled; <OPTION VALUE="<% $loc->locationnum %>" <% $locationnum == $loc->locationnum ? 'SELECTED' : '' %> ><% $loc->line |h %> diff --git a/httemplate/misc/disable-cust_location.cgi b/httemplate/misc/disable-cust_location.cgi new file mode 100755 index 000000000..ee7ba1dbc --- /dev/null +++ b/httemplate/misc/disable-cust_location.cgi @@ -0,0 +1,35 @@ +<% header("Location disabled") %> + <SCRIPT TYPE="text/javascript"> + window.top.location.reload(); + </SCRIPT> +</BODY> +</HTML> +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; +my $error; + +die "access denied" + unless $curuser->access_right('Change customer package'); + +my $locationnum = $cgi->param('locationnum'); +my $cust_location = qsearchs({ + 'select' => 'cust_location.*', + 'table' => 'cust_location', + 'addl_from' => 'LEFT JOIN cust_main USING ( custnum )', + 'hashref' => { 'locationnum' => $locationnum }, + 'extra_sql' => ' AND '. $curuser->agentnums_sql, +}); +die "unknown locationnum $locationnum" unless $cust_location; + +my @pkgs = qsearch('cust_pkg', { 'locationnum' => $locationnum, + 'cancel' => '' }); +if ( @pkgs ) { + $error = "Location $locationnum has active packages" +} +else { + $cust_location->disabled('Y'); + $error = $cust_location->replace; +} +die $error if $error; +</%init> diff --git a/httemplate/view/cust_main/locations.html b/httemplate/view/cust_main/locations.html new file mode 100755 index 000000000..319a92747 --- /dev/null +++ b/httemplate/view/cust_main/locations.html @@ -0,0 +1,87 @@ +<STYLE> +span.loclabel { + padding-left: 4px; + padding-right: 4px; + background-color: #cccccc; + border: 1px solid black +} +</STYLE> +% foreach my $locationnum (@sorted) { +% my $packages = $packages_in{$locationnum}; +% my $loc = $locations{$locationnum}; +% next if $loc->disabled and scalar(@$packages) == 0; +<% include('/elements/table-grid.html') %> +<TR><TH COLSPAN=3 ALIGN="left" VALIGN="bottom" +STYLE="padding-bottom: 0px; + padding-left: 0px; + border-bottom-style: solid; + border-bottom-color: black; + border-bottom-width: 1px;"> +<SPAN CLASS="loclabel"> +% if (! $locationnum) { +Default service location: +% } +% elsif ( $loc->disabled ) { +<FONT COLOR="#808080"><I> +% } +<% $loc->location_label %></SPAN> +<SPAN STYLE="float:right;"> +% if ( $locationnum and !$loc->disabled ) { +<% edit_location_link($locationnum) %> +% } +% if ( !$loc->disabled and !$active{$locationnum} ) { + <% disable_location_link($locationnum) %> +% } +</SPAN></TH></TR> +% if (@$packages) { +<% include('packages/section.html', 'packages' => $packages ) %> +% } +</TABLE><BR> +% } #foreach $locationnum +<%init> +my %opt = @_; +my $cust_main = $opt{'cust_main'}; +my $all_packages = $opt{'packages'}; + +my %locations = map { $_->locationnum => $_ } qsearch({ + 'table' => 'cust_location', + 'hashref' => { 'custnum' => $cust_main->custnum }, + 'order_by' => 'ORDER BY country, state, city, address1, locationnum', + }); +my @sections = keys %locations; +$locations{''} = $cust_main; +my %packages_in = map { $_ => [] } @sections; + +my %active = (); # groups with non-canceled packages +foreach my $cust_pkg ( @$all_packages ) { + my $key = $cust_pkg->locationnum; + push @{ $packages_in{$key} }, $cust_pkg; + $active{$key} = 1 if !$cust_pkg->getfield('cancel'); +} + +my @sorted = ( + '', + grep ( { $active{$_} } @sections), + grep ( { !$active{$_} } @sections), +); + +sub edit_location_link { + my $locationnum = shift; + include( '/elements/popup_link.html', + 'action' => $p. "edit/cust_location.cgi?locationnum=$locationnum", + 'label' => '(Edit location)', + 'actionlabel' => 'Edit', + ); +} + +sub disable_location_link { + my $locationnum = shift; + include( '/elements/popup_link.html', + 'action' => $p. "misc/disable-cust_location.cgi?locationnum=$locationnum", + 'label' => '(Disable location)', + 'actionlabel' => 'Disable', + ); +} + + +</%init> diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index ce34158d8..383c2a75e 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -75,61 +75,23 @@ Current packages <TR> <TD COLSPAN=2> - -% if ( @$packages ) { - -<% include('/elements/table-grid.html') %> -% my $bgcolor1 = '#eeeeee'; -% my $bgcolor2 = '#ffffff'; -% my $bgcolor = ''; - -<TR> - <TH CLASS="grid" BGCOLOR="#cccccc">Package</TH> - <TH CLASS="grid" BGCOLOR="#cccccc">Status</TH> -% if ( $show_location ) { - <TH CLASS="grid" BGCOLOR="#cccccc">Location</TH> -% } - <TH CLASS="grid" BGCOLOR="#cccccc">Services</TH> -</TR> - -% #$FS::cust_pkg::DEBUG = 2; -% foreach my $cust_pkg (@$packages) { -% -% if ( $bgcolor eq $bgcolor1 ) { -% $bgcolor = $bgcolor2; -% } else { -% $bgcolor = $bgcolor1; -% } -% -% my %iopt = ( -% 'bgcolor' => $bgcolor, -% 'cust_pkg' => $cust_pkg, -% 'part_pkg' => $cust_pkg->part_pkg, -% %conf_opt, -% ); -% - - <!--pkgnum: <% $cust_pkg->pkgnum %>--> - <TR> - <% include('packages/package.html', %iopt) %> - <% include('packages/status.html', %iopt) %> -% if ( $show_location ) { - <% include('packages/location.html', %iopt) %> +% if ( $conf->exists('cust_pkg-group_by_location') and $show_location ) { +<% include('locations.html', + 'cust_main' => $cust_main, + 'packages' => $packages, +) %> % } - <% include('packages/services.html', %iopt) %> - </TR> - -% } - +% else { +% # in this format, put all packages in one section +<% include('/elements/table-grid.html') %> +<% include('packages/section.html', + 'packages' => $packages, + 'show_location' => $show_location, +) %> </TABLE> - -% } else { -<BR> -% } - +% } </TD> </TR> -</TABLE> % if ( $cgi->param('fragment') =~ /^cust_pkg(\d+)$/ ) { <SCRIPT> @@ -140,42 +102,22 @@ Current packages if ( el ) el.scrollIntoView(true); </SCRIPT> % } - +</TABLE> <%init> -my( $cust_main ) = @_; +my $cust_main = shift; +my %opt = @_; my $conf = new FS::Conf; my $curuser = $FS::CurrentUser::CurrentUser; my( $packages, $num_old_packages ) = get_packages($cust_main, $conf); -my $show_location = $conf->exists('cust_pkg-always_show_location') - || ( grep $_->locationnum, @$packages ); # ? '1' : '0'; -my $countrydefault = scalar($conf->config('countrydefault')) || 'US'; -my %conf_opt = ( - #for services.html and status.html - 'cust_pkg-display_times' => ($conf->exists('cust_pkg-display_times') - || $curuser->option('cust_pkg-display_times')), - #for status.html - 'cust_pkg-show_autosuspend' => $conf->exists('cust_pkg-show_autosuspend'), - #for status.html pkg-balances - 'pkg-balances' => $conf->exists('pkg-balances'), - 'money_char' => ( $conf->config('money_char') || '$' ), - - #for location.html - 'countrydefault' => $countrydefault, - 'statedefault' => ( scalar($conf->config('statedefault')) - || ($countrydefault eq 'US' ? 'CA' : '') ), - #for services.html - 'svc_external-skip_manual' => $conf->exists('svc_external-skip_manual'), - 'legacy_link' => $conf->exists('legacy_link'), - 'svc_broadband-manage_link' => scalar($conf->config('svc_broadband-manage_link')), - 'maestro-status_test' => $conf->exists('maestro-status_test'), - 'cust_pkg-large_pkg_size' => $conf->config('cust_pkg-large_pkg_size'), -); +my $show_location = $conf->exists('cust_pkg-always_show_location') + || (grep $_->locationnum, @$packages); # ? '1' : '0'; +my $countrydefault = scalar($conf->config('countrydefault')) || 'US'; #subroutines sub get_packages { diff --git a/httemplate/view/cust_main/packages/location.html b/httemplate/view/cust_main/packages/location.html index 41155cbae..40a7de59f 100644 --- a/httemplate/view/cust_main/packages/location.html +++ b/httemplate/view/cust_main/packages/location.html @@ -21,12 +21,16 @@ % { <FONT SIZE=-1> ( <%pkg_change_location_link($cust_pkg)%> ) +% if ( $cust_pkg->locationnum ) { + ( <%edit_location_link($cust_pkg->locationnum)%> ) +% } </FONT> % } </TD> <%init> +my $conf = new FS::Conf; my %opt = @_; my $bgcolor = $opt{'bgcolor'}; @@ -50,4 +54,13 @@ sub pkg_change_location_link { ); } +sub edit_location_link { + my $locationnum = shift; + include( '/elements/popup_link.html', + 'action' => $p. "edit/cust_location.cgi?locationnum=$locationnum", + 'label' => 'Edit location', + 'actionlabel' => 'Edit', + ); +} + </%init> diff --git a/httemplate/view/cust_main/packages/package.html b/httemplate/view/cust_main/packages/package.html index 3b58f9ec0..8cae5fdba 100644 --- a/httemplate/view/cust_main/packages/package.html +++ b/httemplate/view/cust_main/packages/package.html @@ -168,8 +168,16 @@ % } </TR> +% if ( $curuser->access_right('Change customer package') and +% !$cust_pkg->get('cancel') and +% !$opt{'show_location'}) { + <TR> + <TD><FONT SIZE="-1"> + ( <% pkg_change_location_link($cust_pkg) %> ) + </FONT></TD> + </TR> +% } % } - </TABLE> </TD> @@ -184,6 +192,10 @@ my $part_pkg = $opt{'part_pkg'}; my $curuser = $FS::CurrentUser::CurrentUser; +my $countrydefault = $opt{'countrydefault'} || 'US'; +my $statedefault = $opt{'statedefault'} + || ($countrydefault eq 'US' ? 'CA' : ''); + #subroutines #false laziness w/status.html @@ -204,6 +216,19 @@ sub pkg_change_link { ); } +sub pkg_change_location_link { + my $cust_pkg = shift; + my $pkgpart = $cust_pkg->pkgpart; + include( '/elements/popup_link-cust_pkg.html', + 'action' => $p. "misc/change_pkg.cgi?locationnum=-1;pkgpart=$pkgpart;". + "address1=;address2=;city=;county=;state=$statedefault;". + "zip=;country=$countrydefault", + 'label' => 'Change location', + 'actionlabel' => 'Change', + 'cust_pkg' => $cust_pkg, + ); +} + sub pkg_dates_link { pkg_link('edit/REAL_cust_pkg', 'Edit dates', @_ ); } sub pkg_discount_link { diff --git a/httemplate/view/cust_main/packages/section.html b/httemplate/view/cust_main/packages/section.html new file mode 100755 index 000000000..0795d4e59 --- /dev/null +++ b/httemplate/view/cust_main/packages/section.html @@ -0,0 +1,95 @@ +% if ( @$packages ) { +% my $bgcolor1 = '#eeeeee'; +% my $bgcolor2 = '#ffffff'; +% my $bgcolor = ''; + +<TR> +% #my $width = $show_location ? 'WIDTH="25%"' : 'WIDTH="33%"'; + <TH CLASS="grid" BGCOLOR="#cccccc">Package</TH> + <TH CLASS="grid" BGCOLOR="#cccccc">Status</TH> +% if ( $show_location ) { + <TH CLASS="grid" BGCOLOR="#cccccc">Location</TH> +% } + <TH CLASS="grid" BGCOLOR="#cccccc">Services</TH> +</TR> + +% #$FS::cust_pkg::DEBUG = 2; +% foreach my $cust_pkg (@$packages) { +% +% if ( $bgcolor eq $bgcolor1 ) { +% $bgcolor = $bgcolor2; +% } else { +% $bgcolor = $bgcolor1; +% } +% +% my %iopt = ( +% 'bgcolor' => $bgcolor, +% 'cust_pkg' => $cust_pkg, +% 'part_pkg' => $cust_pkg->part_pkg, +% %conf_opt, +% ); +% + + <!--pkgnum: <% $cust_pkg->pkgnum %>--> + <TR> + <% include('package.html', %iopt) %> + <% include('status.html', %iopt) %> +% if ( $show_location ) { + <% include('location.html', %iopt) %> +% } + <% include('services.html', %iopt) %> + </TR> + +% } #foreach $cust_pkg +%# </TABLE> +% } #if @$packages +% else { +<BR> +% } + +<%init> + +my %opt = @_; +my $conf = new FS::Conf; + +my $curuser = $FS::CurrentUser::CurrentUser; + +my $packages = $opt{'packages'}; +my $show_location = $opt{'show_location'}; + +# Sort order is hardcoded for now, can change this if needed. +@$packages = sort { + ( $a->getfield('cancel') <=> $b->getfield('cancel') ) or + ( $a->getfield('setup') <=> $b->getfield('setup') ) or + ( $a->getfield('pkgnum') <=> $b->getfield('pkgnum') ) +} @$packages; + +my $countrydefault = scalar($conf->config('countrydefault')) || 'US'; + +my %conf_opt = ( + #for services.html and status.html + 'cust_pkg-display_times' => $conf->exists('cust_pkg-display_times') + || $curuser->option('cust_pkg-display_times')), + #for status.html + 'cust_pkg-show_autosuspend' => $conf->exists('cust_pkg-show_autosuspend'), + #for status.html pkg-balances + 'pkg-balances' => $conf->exists('pkg-balances'), + 'money_char' => ( $conf->config('money_char') || '$' ), + + #for location.html + 'countrydefault' => $countrydefault, + 'statedefault' => ( scalar($conf->config('statedefault')) + || ($countrydefault eq 'US' ? 'CA' : '') ), + #for services.html + 'svc_external-skip_manual' => $conf->exists('svc_external-skip_manual'), + 'legacy_link' => $conf->exists('legacy_link'), + 'svc_broadband-manage_link' => scalar($conf->config('svc_broadband-manage_link')), + 'maestro-status_test' => $conf->exists('maestro-status_test'), + 'cust_pkg-large_pkg_size' => $conf->config('cust_pkg-large_pkg_size'), + + # for packages.html Change location link + 'show_location' => $show_location, +); + + +</%init> |