From 51d26d73eb99d9f7f45591fa6a4b99c3a3429565 Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Thu, 2 May 2013 01:10:45 -0700 Subject: [PATCH] detach a package into a new customer, RT#22185 --- FS/FS/Schema.pm | 1 + FS/FS/cust_pkg.pm | 48 +++++++++-- httemplate/edit/process/detach-cust_pkg.html | 47 +++++++++++ httemplate/misc/change_pkg_contact.html | 4 +- httemplate/misc/detach_pkg.html | 104 ++++++++++++++++++++++++ httemplate/view/cust_main/packages/contact.html | 14 ++++ httemplate/view/cust_main/packages/status.html | 36 +++++++- 7 files changed, 243 insertions(+), 11 deletions(-) create mode 100644 httemplate/edit/process/detach-cust_pkg.html create mode 100755 httemplate/misc/detach_pkg.html diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 4f395f285..bbc4f1d21 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -1743,6 +1743,7 @@ sub tables_hashref { 'change_pkgnum', 'int', 'NULL', '', '', '', 'change_pkgpart', 'int', 'NULL', '', '', '', 'change_locationnum', 'int', 'NULL', '', '', '', + 'change_custnum', 'int', 'NULL', '', '', '', 'main_pkgnum', 'int', 'NULL', '', '', '', 'pkglinknum', 'int', 'NULL', '', '', '', 'manual_flag', 'char', 'NULL', 1, '', '', diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index be3acb9ee..d8b6e699e 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -862,6 +862,7 @@ sub cancel { my %hash = $self->hash; $date ? ($hash{'expire'} = $date) : ($hash{'cancel'} = $cancel_time); + $hash{'change_custnum'} = $options{'change_custnum'}; my $new = new FS::cust_pkg ( \%hash ); $error = $new->replace( $self, options => { $self->options } ); if ( $error ) { @@ -1703,6 +1704,11 @@ New locationnum, to change the location for this package. New FS::cust_location object, to create a new location and assign it to this package. +=item cust_main + +New FS::cust_main object, to create a new customer and assign the new package +to it. + =item pkgpart New pkgpart (see L). @@ -1818,12 +1824,25 @@ sub change { # 2. (more importantly) changing a package before it's billed $hash{'waive_setup'} = $self->waive_setup; + my $custnum = $self->custnum; + if ( $opt->{cust_main} ) { + my $cust_main = $opt->{cust_main}; + unless ( $cust_main->custnum) { + my $error = $cust_main->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "inserting cust_main (transaction rolled back): $error"; + } + } + $custnum = $cust_main->custnum; + } + # Create the new package. my $cust_pkg = new FS::cust_pkg { - custnum => $self->custnum, - pkgpart => ( $opt->{'pkgpart'} || $self->pkgpart ), - refnum => ( $opt->{'refnum'} || $self->refnum ), - locationnum => ( $opt->{'locationnum'} ), + custnum => $custnum, + pkgpart => ( $opt->{'pkgpart'} || $self->pkgpart ), + refnum => ( $opt->{'refnum'} || $self->refnum ), + locationnum => ( $opt->{'locationnum'} ), %hash, }; $error = $cust_pkg->insert( 'change' => 1, @@ -1919,7 +1938,7 @@ sub change { my $new = FS::cust_pkg->new({ pkgpart => $link->dst_pkgpart, pkglinknum => $link->pkglinknum, - custnum => $self->custnum, + custnum => $custnum, main_pkgnum => $cust_pkg->pkgnum, locationnum => $cust_pkg->locationnum, start_date => $cust_pkg->start_date, @@ -1960,9 +1979,10 @@ sub change { #because the new package will be billed for the same date range. #Supplemental packages are also canceled here. $error = $self->cancel( - quiet => 1, - unused_credit => $unused_credit, - nobill => $keep_dates + quiet => 1, + unused_credit => $unused_credit, + nobill => $keep_dates, + change_custnum => ( $self->custnum != $custnum ? $custnum : '' ), ); if ($error) { $dbh->rollback if $oldAutoCommit; @@ -2134,6 +2154,18 @@ sub old_cust_pkg { qsearchs('cust_pkg', { 'pkgnum' => $self->change_pkgnum } ); } +=item change_cust_main + +Returns the customter this package was detached to, if any. + +=cut + +sub change_cust_main { + my $self = shift; + return '' unless $self->change_custnum; + qsearchs('cust_main', { 'custnum' => $self->change_custnum } ); +} + =item calc_setup Calls the I of the FS::part_pkg object associated with this billing diff --git a/httemplate/edit/process/detach-cust_pkg.html b/httemplate/edit/process/detach-cust_pkg.html new file mode 100644 index 000000000..ab87eb536 --- /dev/null +++ b/httemplate/edit/process/detach-cust_pkg.html @@ -0,0 +1,47 @@ +% if ($error) { +% $cgi->param('error', $error); +% $cgi->redirect(popurl(3). 'misc/detach_pkg.html?'. $cgi->query_string ); +% } else { + + <% header(emt("Package detached")) %> + + + + +% } +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right('Change customer package'); + +my $cust_pkg = qsearchs({ + 'table' => 'cust_pkg', + 'addl_from' => 'LEFT JOIN cust_main USING ( custnum )', + 'hashref' => { 'pkgnum' => scalar($cgi->param('pkgnum')), }, + 'extra_sql' => ' AND '. $curuser->agentnums_sql, +}); +die 'unknown pkgnum' unless $cust_pkg; + +my $cust_location = new FS::cust_location { + map { $_ => scalar($cgi->param($_)) } FS::cust_main->location_fields +}; + +my $cust_main = new FS::cust_main { + ( map { ( $_, scalar($cgi->param($_)) ) } fields('cust_main') ), + ( map { ( "ship_$_", '' ) } FS::cust_main->location_fields ), + 'bill_location' => $cust_location, + 'ship_location' => $cust_location, +}; + +my $pkg_or_error = $cust_pkg->change( { + 'keep_dates' => 1, + 'cust_main' => $cust_main, +} ); + +my $error = ref($pkg_or_error) ? '' : $pkg_or_error; + + diff --git a/httemplate/misc/change_pkg_contact.html b/httemplate/misc/change_pkg_contact.html index d9da5beec..c88140ebf 100755 --- a/httemplate/misc/change_pkg_contact.html +++ b/httemplate/misc/change_pkg_contact.html @@ -9,7 +9,7 @@ <% mt('Package') |h %> - + <% $curuser->option('show_pkgnum') ? $cust_pkg->pkgnum.': ' : '' %><% $part_pkg->pkg |h %> - <% $part_pkg->comment |h %> @@ -17,7 +17,7 @@ % if ( $cust_pkg->contactnum ) { <% mt('Current Contact') %> - + <% $cust_pkg->contact_obj->line |h %> diff --git a/httemplate/misc/detach_pkg.html b/httemplate/misc/detach_pkg.html new file mode 100755 index 000000000..64b3e6e3f --- /dev/null +++ b/httemplate/misc/detach_pkg.html @@ -0,0 +1,104 @@ +<& /elements/header-popup.html, mt("Detach Package to New Customer") &> + + + +<& /elements/error.html &> + +
+ +% foreach my $f (qw( agentnum refnum )) { + +% } + +% foreach my $f (FS::cust_main->location_fields) { + +% } + +<% ntable('#cccccc') %> + + + <% mt('Package') |h %> + + <% $curuser->option('show_pkgnum') ? $cust_pkg->pkgnum.': ' : '' %><% $part_pkg->pkg |h %> - <% $part_pkg->comment |h %> + + + +% #always should be present for detaching, yes? #if ( $cust_pkg->contactnum ) { +% my $cust_contact = $cust_pkg->contact_obj; + + + + + + <% mt('Name') %> + + <% $cust_pkg->contact_obj->line |h %> + + +% #} + + + <% mt('Address') %> + + + <% $loc->location_label( 'join_string' => '
', + 'double_space' => '   ', + 'escape_function' => \&encode_entities, + 'countrydefault' => $countrydefault, + ) + %> + + + + + +%#XXX payment info +%#XXX should be sticky on errors... +<& /edit/cust_main/billing.html, FS::cust_main->new({}), + invoicing_list => [], + +&> + +
+
+" +> + +%#and a cancel button? or is the popup close sufficient? + +
+ + + +<%init> + +my $conf = new FS::Conf; +my $countrydefault = $conf->config('countrydefault') || 'US'; + +my $curuser = $FS::CurrentUser::CurrentUser; +die "access denied" + unless $curuser->access_right('Change customer package'); + +my $pkgnum = scalar($cgi->param('pkgnum')); +$pkgnum =~ /^(\d+)$/ or die "illegal pkgnum $pkgnum"; +$pkgnum = $1; + +my $cust_pkg = + qsearchs({ + 'table' => 'cust_pkg', + 'addl_from' => 'LEFT JOIN cust_main USING ( custnum )', + 'hashref' => { 'pkgnum' => $pkgnum }, + 'extra_sql' => ' AND '. $curuser->agentnums_sql, + }) or die "unknown pkgnum $pkgnum"; + +my $loc = $cust_pkg->cust_location_or_main; + +my $cust_main = $cust_pkg->cust_main + or die "can't get cust_main record for custnum ". $cust_pkg->custnum. + " ( pkgnum ". cust_pkg->pkgnum. ")"; + +my $part_pkg = $cust_pkg->part_pkg; + + diff --git a/httemplate/view/cust_main/packages/contact.html b/httemplate/view/cust_main/packages/contact.html index 93129915f..4e0551b31 100644 --- a/httemplate/view/cust_main/packages/contact.html +++ b/httemplate/view/cust_main/packages/contact.html @@ -3,6 +3,7 @@ % if ( $show_link ) { ( <%pkg_change_contact_link($cust_pkg)%> ) + ( <%pkg_detach_link($cust_pkg)%> ) % } % } elsif ( $show_link ) { @@ -49,6 +50,19 @@ sub pkg_add_contact_link { ); } +sub pkg_detach_link { + my $cust_pkg = shift; + #my $pkgpart = $cust_pkg->pkgpart; + include( '/elements/popup_link-cust_pkg.html', + 'action' => $p. "misc/detach_pkg.html", + 'label' => emt('Detach'), + 'actionlabel' => emt('Detach'), + 'cust_pkg' => $cust_pkg, + 'width' => 616, + 'height' => 676, + ); +} + #sub edit_contact_link { # my $contactnum = shift; # include( '/elements/popup_link.html', diff --git a/httemplate/view/cust_main/packages/status.html b/httemplate/view/cust_main/packages/status.html index 9d5a88e0f..24a4dfcd0 100644 --- a/httemplate/view/cust_main/packages/status.html +++ b/httemplate/view/cust_main/packages/status.html @@ -14,6 +14,8 @@ <% pkg_status_row($cust_pkg, emt('Cancelled'), 'cancel', 'color'=>'FF0000', %opt ) %> + <% pkg_status_row_detached($cust_pkg, %opt) %> + <% pkg_reason_row($cust_pkg, $cpr, color => 'ff0000', %opt) %> % unless ( $cust_pkg->get('setup') ) { @@ -29,7 +31,7 @@ % } % -% if ( $part_pkg->freq and !$supplemental ) { #? +% if ( $part_pkg->freq && !$supplemental && !$cust_pkg->change_custnum ) { #? > @@ -360,6 +362,38 @@ sub pkg_status_row_changed { $html; } +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 = ''; + + my $cust_main = $cust_pkg->change_cust_main; + if ( $cust_main ) { + + my $cust_link = ''. + encode_entities( $cust_main->name ). + ''; + + $html .= pkg_status_row_colspan( $cust_pkg, + emt("Detached to customer #[_1]: ", + $cust_pkg->change_custnum + ). + $cust_link, + '', + 'size' => '-1', + 'align' => 'right', + 'colspan' => 4, + ); + } + + $html; +} + sub pkg_status_row_noauto { my( $cust_pkg, %opt ) = @_; my $part_pkg = $opt{'part_pkg'}; -- 2.11.0