diff options
-rw-r--r-- | FS/FS/AccessRight.pm | 1 | ||||
-rw-r--r-- | FS/FS/access_right.pm | 1 | ||||
-rw-r--r-- | FS/FS/cust_main/Packages.pm | 106 | ||||
-rw-r--r-- | FS/FS/cust_pkg.pm | 4 | ||||
-rwxr-xr-x | httemplate/misc/cust_main-merge.html | 12 | ||||
-rw-r--r-- | httemplate/misc/merge_cust.html | 42 | ||||
-rwxr-xr-x | httemplate/view/cust_main.cgi | 11 | ||||
-rw-r--r-- | httemplate/view/cust_main/packages/contact.html | 28 | ||||
-rwxr-xr-x | httemplate/view/cust_main/packages/section.html | 12 | ||||
-rw-r--r-- | httemplate/view/cust_main/packages/status.html | 7 |
10 files changed, 200 insertions, 24 deletions
diff --git a/FS/FS/AccessRight.pm b/FS/FS/AccessRight.pm index bfb39b4ad..373617e36 100644 --- a/FS/FS/AccessRight.pm +++ b/FS/FS/AccessRight.pm @@ -132,6 +132,7 @@ tie my %rights, 'Tie::IxHash', 'Order customer package', 'One-time charge', 'Change customer package', + 'Detach customer package', 'Bulk change customer packages', 'Edit customer package dates', 'Discount customer package', #NEW diff --git a/FS/FS/access_right.pm b/FS/FS/access_right.pm index d370ba5d1..5bcf92214 100644 --- a/FS/FS/access_right.pm +++ b/FS/FS/access_right.pm @@ -232,6 +232,7 @@ sub _upgrade_data { # class method 'Financial reports' => [ 'Employees: Commission Report', 'Employees: Audit Report', ], + 'Change customer package' => 'Detach customer package', ; foreach my $old_acl ( keys %onetime ) { diff --git a/FS/FS/cust_main/Packages.pm b/FS/FS/cust_main/Packages.pm index f83bce915..41ef22894 100644 --- a/FS/FS/cust_main/Packages.pm +++ b/FS/FS/cust_main/Packages.pm @@ -4,9 +4,11 @@ use strict; use vars qw( $DEBUG $me ); use List::Util qw( min ); use FS::UID qw( dbh ); -use FS::Record qw( qsearch ); +use FS::Record qw( qsearch qsearchs ); use FS::cust_pkg; use FS::cust_svc; +use FS::contact; # for attach_pkgs +use FS::cust_location; # $DEBUG = 0; $me = '[FS::cust_main::Packages]'; @@ -291,6 +293,108 @@ sub order_pkgs { ''; #no error } +=item attach_pkgs + +Merges this customer's package's into the target customer and then cancels them. + +=cut + +sub attach_pkgs { + my( $self, $new_custnum ) = @_; + + #mostly false laziness w/ merge + + return "Can't attach packages to self" if $self->custnum == $new_custnum; + + my $new_cust_main = qsearchs( 'cust_main', { 'custnum' => $new_custnum } ) + or return "Invalid new customer number: $new_custnum"; + + return 'Access denied: "Merge customer across agents" access right required to merge into a customer of a different agent' + if $self->agentnum != $new_cust_main->agentnum + && ! $FS::CurrentUser::CurrentUser->access_right('Merge customer across agents'); + + 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; + + if ( qsearch('agent', { 'agent_custnum' => $self->custnum } ) ) { + $dbh->rollback if $oldAutoCommit; + return "Can't merge a master agent customer"; + } + + #use FS::access_user + if ( qsearch('access_user', { 'user_custnum' => $self->custnum } ) ) { + $dbh->rollback if $oldAutoCommit; + return "Can't merge a master employee customer"; + } + + if ( qsearch('cust_pay_pending', { 'custnum' => $self->custnum, + 'status' => { op=>'!=', value=>'done' }, + } + ) + ) { + $dbh->rollback if $oldAutoCommit; + return "Can't merge a customer with pending payments"; + } + + #end of false laziness + + #pull in contact + + my %contact_hash = ( 'first' => $self->first, + 'last' => $self->get('last'), + 'custnum' => $new_custnum, + 'disabled' => '', + ); + + my $contact = qsearchs( 'contact', \%contact_hash) + || new FS::contact \%contact_hash; + unless ( $contact->contactnum ) { + my $error = $contact->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + + foreach my $cust_pkg ( $self->ncancelled_pkgs ) { + + my $cust_location = $cust_pkg->cust_location || $self->ship_location; + my %loc_hash = $cust_location->hash; + $loc_hash{'locationnum'} = ''; + $loc_hash{'custnum'} = $new_custnum; + $loc_hash{'disabled'} = ''; + my $new_cust_location = qsearchs( 'cust_location', \%loc_hash) + || new FS::cust_location \%loc_hash; + + my $pkg_or_error = $cust_pkg->change( { + 'keep_dates' => 1, + 'cust_main' => $new_cust_main, + 'contactnum' => $contact->contactnum, + 'cust_location' => $new_cust_location, + } ); + + my $error = ref($pkg_or_error) ? '' : $pkg_or_error; + + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + ''; #no error + +} + =item all_pkgs [ OPTION => VALUE... | EXTRA_QSEARCH_PARAMS_HASHREF ] Returns all packages (see L<FS::cust_pkg>) for this customer. diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index d8b6e699e..4464aa5a2 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -1827,7 +1827,7 @@ sub change { my $custnum = $self->custnum; if ( $opt->{cust_main} ) { my $cust_main = $opt->{cust_main}; - unless ( $cust_main->custnum) { + unless ( $cust_main->custnum ) { my $error = $cust_main->insert; if ( $error ) { $dbh->rollback if $oldAutoCommit; @@ -1837,6 +1837,8 @@ sub change { $custnum = $cust_main->custnum; } + $hash{'contactnum'} = $opt->{'contactnum'} if $opt->{'contactnum'}; + # Create the new package. my $cust_pkg = new FS::cust_pkg { custnum => $custnum, diff --git a/httemplate/misc/cust_main-merge.html b/httemplate/misc/cust_main-merge.html index 4decbef7a..3b4425fc8 100755 --- a/httemplate/misc/cust_main-merge.html +++ b/httemplate/misc/cust_main-merge.html @@ -31,7 +31,17 @@ if ( $cgi->param('new_custnum') =~ /^(\d+)$/ ) { } ); die "No customer # $custnum" unless $cust_main; - $error = $cust_main->merge($new_custnum); + if ( $cgi->param('merge') eq 'Y' ) { + + #old-style merge: everything + delete old customer + $error = $cust_main->merge($new_custnum); + + } else { + + #new-style attach: move packages 3.0 style, that's it + $error = $cust_main->attach_pkgs($new_custnum); + + } } else { $error = 'Select a customer to merge into'; diff --git a/httemplate/misc/merge_cust.html b/httemplate/misc/merge_cust.html index ad075be2f..9c869fa21 100644 --- a/httemplate/misc/merge_cust.html +++ b/httemplate/misc/merge_cust.html @@ -1,6 +1,6 @@ -<% include('/elements/header-popup.html', 'Merge customer' ) %> +<& /elements/header-popup.html, 'Merge customer' &> -<% include('/elements/error.html') %> +<& /elements/error.html &> <FORM NAME="cust_merge_popup" ID="cust_merge_popup" ACTION="<% popurl(1) %>cust_main-merge.html" METHOD=POST onSubmit="submit_merge(); return false;"> @@ -35,13 +35,43 @@ function do_submit_merge() { <INPUT TYPE="hidden" NAME="custnum" VALUE="<% $custnum %>"> <TABLE BORDER="0" CELLSPACING="2" STYLE="margin-left:auto; margin-right:auto"> - <% include('/elements/tr-search-cust_main.html', + + <& /elements/tr-search-cust_main.html, 'label' => 'Merge into: ', 'field' => 'new_custnum', 'find_button' => 1, 'curr_value' => scalar($cgi->param('new_custnum')), - ) - %> + &> + +% if ( $conf->exists('deletecustomers') ) { + +% if ( scalar($cust_main->ncancelled_pkgs) ) { + <TR> + <TD COLSPAN=2> + <& /elements/radio.html, + 'field' => 'merge', + 'value' => '', + 'curr_value' => scalar($cgi->param('merge')), + &> + Merge packages only. + </TD> + </TR> +% } else { +% $cgi->param('merge', 'Y'); +% } + + <TR> + <TD COLSPAN=2> + <& /elements/radio.html, + 'field' => 'merge', + 'value' => 'Y', + 'curr_value' => scalar($cgi->param('merge')), + &> + Merge invoices, payments/credits, notes, tickets and delete this customer. + </TD> + </TR> +% } + </TABLE> <P ALIGN="CENTER"> @@ -54,6 +84,8 @@ function do_submit_merge() { <%init> +my $conf = new FS::Conf; + $cgi->param('custnum') =~ /^(\d+)$/ or die 'illegal custnum'; my $custnum = $1; diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi index ec3191971..be0100fb3 100755 --- a/httemplate/view/cust_main.cgi +++ b/httemplate/view/cust_main.cgi @@ -91,14 +91,19 @@ function areyousure(href, message) { &> | % } -% if ( $curuser->access_right('Merge customer') ) { +% if ( $curuser->access_right('Merge customer') +% and ( scalar($cust_main->ncancelled_pkgs) +% || $conf->exists('deletecustomers') +% ) +% ) +% { <& /elements/popup_link-cust_main.html, { 'action' => $p. 'misc/merge_cust.html', 'label' => emt('Merge this customer'), 'actionlabel' => emt('Merge customer'), 'cust_main' => $cust_main, - 'width' => 480, - 'height' => 192, + 'width' => 569, + 'height' => 210, } &> | % } diff --git a/httemplate/view/cust_main/packages/contact.html b/httemplate/view/cust_main/packages/contact.html index 4e0551b31..fe8b71534 100644 --- a/httemplate/view/cust_main/packages/contact.html +++ b/httemplate/view/cust_main/packages/contact.html @@ -1,15 +1,19 @@ % if ( $contact ) { <% $contact->line |h %> -% if ( $show_link ) { +% if ( $show_change_link ) { <FONT SIZE=-1> ( <%pkg_change_contact_link($cust_pkg)%> ) - ( <%pkg_detach_link($cust_pkg)%> ) </FONT> -% } -% } elsif ( $show_link ) { +% } +% if ( $show_detach_link ) { <FONT SIZE=-1> - ( <%pkg_add_contact_link($cust_pkg)%> ) + ( <%pkg_detach_link($cust_pkg)%> ) </FONT> +% } +% } elsif ( $show_contact_link ) { + <FONT SIZE=-1> + ( <%pkg_add_contact_link($cust_pkg)%> ) + </FONT> % } <%init> @@ -18,10 +22,18 @@ my %opt = @_; my $cust_pkg = $opt{'cust_pkg'}; -my $show_link = +my $show_change_link = ! $cust_pkg->get('cancel') && $FS::CurrentUser::CurrentUser->access_right('Change customer package'); +my $show_detach_link = + ! $cust_pkg->get('cancel') + && $FS::CurrentUser::CurrentUser->access_right('Detach customer package'); + +my $show_contact_link = + ! $cust_pkg->get('cancel') + ; #&& $FS::CurrentUser::CurrentUser->access_right('Add package contact'); #or something like that + my $contact = $cust_pkg->contact_obj; sub pkg_change_contact_link { @@ -43,7 +55,7 @@ sub pkg_add_contact_link { include( '/elements/popup_link-cust_pkg.html', 'action' => $p. "misc/change_pkg_contact.html", 'label' => emt('Add contact'), - 'actionlabel' => emt('Change'), + 'actionlabel' => emt('Add contact'), 'cust_pkg' => $cust_pkg, 'width' => 616, 'height' => 192, @@ -59,7 +71,7 @@ sub pkg_detach_link { 'actionlabel' => emt('Detach'), 'cust_pkg' => $cust_pkg, 'width' => 616, - 'height' => 676, + 'height' => 684, ); } diff --git a/httemplate/view/cust_main/packages/section.html b/httemplate/view/cust_main/packages/section.html index 5f54c0a36..391a13b5f 100755 --- a/httemplate/view/cust_main/packages/section.html +++ b/httemplate/view/cust_main/packages/section.html @@ -28,7 +28,7 @@ <& package.html, %iopt &> <& status.html, %iopt &> <TD CLASS="inv" BGCOLOR="<% $iopt{bgcolor} %>" WIDTH="20%" VALIGN="top"> - <& contact.html, %iopt &> + <& contact.html, %iopt &><BR> <& location.html, %iopt &> </TD> <& services.html, %iopt &> @@ -59,6 +59,15 @@ my $packages = $opt{'packages'}; ( $a->getfield('pkgnum') <=> $b->getfield('pkgnum') ) } @$packages; +my %change_custnum = map { $_->change_custnum => 1 } + grep { $_->change_custnum } + grep { $_->getfield('cancel') } + @$packages; + +my $pkg_attached = ( scalar(keys %change_custnum) == 1 + && ! grep { ! $_->getfield('cancel') } @$packages + ); + my $countrydefault = scalar($conf->config('countrydefault')) || 'US'; my %conf_opt = ( @@ -67,6 +76,7 @@ my %conf_opt = ( || $curuser->option('cust_pkg-display_times')), #for status.html 'cust_pkg-show_autosuspend' => $conf->exists('cust_pkg-show_autosuspend'), + 'pkg_attached' => $pkg_attached, #for status.html pkg-balances 'pkg-balances' => $conf->exists('pkg-balances'), 'money_char' => ( $conf->config('money_char') || '$' ), diff --git a/httemplate/view/cust_main/packages/status.html b/httemplate/view/cust_main/packages/status.html index 24a4dfcd0..c0213e90b 100644 --- a/httemplate/view/cust_main/packages/status.html +++ b/httemplate/view/cust_main/packages/status.html @@ -365,9 +365,6 @@ sub pkg_status_row_changed { sub pkg_status_row_detached { my( $cust_pkg, %opt ) = @_; -warn $cust_pkg->pkgnum; -warn $cust_pkg->change_custnum; - return '' unless $cust_pkg->change_custnum; my $html = ''; @@ -379,8 +376,10 @@ warn $cust_pkg->change_custnum; encode_entities( $cust_main->name ). '</A>'; + my $what = $opt{'pkg_attached'} ? 'Attached' : 'Detached'; + $html .= pkg_status_row_colspan( $cust_pkg, - emt("Detached to customer #[_1]: ", + emt("$what to customer #[_1]: ", $cust_pkg->change_custnum ). $cust_link, |