detach a package into a new customer, RT#22185
authorIvan Kohler <ivan@freeside.biz>
Thu, 2 May 2013 08:10:45 +0000 (01:10 -0700)
committerIvan Kohler <ivan@freeside.biz>
Thu, 2 May 2013 08:10:45 +0000 (01:10 -0700)
FS/FS/Schema.pm
FS/FS/cust_pkg.pm
httemplate/edit/process/detach-cust_pkg.html [new file with mode: 0644]
httemplate/misc/change_pkg_contact.html
httemplate/misc/detach_pkg.html [new file with mode: 0755]
httemplate/view/cust_main/packages/contact.html
httemplate/view/cust_main/packages/status.html

index 4f395f2..bbc4f1d 100644 (file)
@@ -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, '', '', 
index be3acb9..d8b6e69 100644 (file)
@@ -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<FS::part_pkg>).
@@ -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<calc_setup> 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 (file)
index 0000000..ab87eb5
--- /dev/null
@@ -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")) %>
+      <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 $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;
+
+</%init>
index d9da5be..c88140e 100755 (executable)
@@ -9,7 +9,7 @@
 
   <TR>
     <TH ALIGN="right"><% mt('Package') |h %></TH>
-    <TD COLSPAN=7>
+    <TD COLSPAN=7 BGCOLOR="#dddddd">
       <% $curuser->option('show_pkgnum') ? $cust_pkg->pkgnum.': ' : '' %><B><% $part_pkg->pkg |h %></B> - <% $part_pkg->comment |h %>
     </TD>
   </TR>
@@ -17,7 +17,7 @@
 % if ( $cust_pkg->contactnum ) {
     <TR>
       <TH ALIGN="right"><% mt('Current Contact') %></TH>
-      <TD COLSPAN=7>
+      <TD COLSPAN=7 BGCOLOR="#dddddd">
         <% $cust_pkg->contact_obj->line |h %>
       </TD>
     </TR>
diff --git a/httemplate/misc/detach_pkg.html b/httemplate/misc/detach_pkg.html
new file mode 100755 (executable)
index 0000000..64b3e6e
--- /dev/null
@@ -0,0 +1,104 @@
+<& /elements/header-popup.html, mt("Detach Package to New Customer") &>
+
+<SCRIPT TYPE="text/javascript" SRC="../elements/order_pkg.js"></SCRIPT>
+
+<& /elements/error.html &>
+
+<FORM NAME="OrderPkgForm" ACTION="<% $p %>edit/process/detach-cust_pkg.html" METHOD=POST>
+<INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum %>">
+% foreach my $f (qw( agentnum refnum )) {
+  <INPUT TYPE="hidden" NAME="<% $f %>" VALUE="<% $cust_main->$f() %>">
+% }
+<INPUT TYPE="hidden" NAME="referral_custnum" VALUE="<% $cust_main->custnum %>">
+% foreach my $f (FS::cust_main->location_fields) {
+  <INPUT TYPE="hidden" NAME="<% $f %>" VALUE="<% $loc->$f() |h %>">
+% }
+
+<% ntable('#cccccc') %>
+
+  <TR>
+    <TH ALIGN="right"><% mt('Package') |h %></TH>
+    <TD COLSPAN=7 BGCOLOR="#dddddd">
+      <% $curuser->option('show_pkgnum') ? $cust_pkg->pkgnum.': ' : '' %><B><% $part_pkg->pkg |h %></B> - <% $part_pkg->comment |h %>
+    </TD>
+  </TR>
+
+% #always should be present for detaching, yes? #if ( $cust_pkg->contactnum ) {
+%   my $cust_contact = $cust_pkg->contact_obj;
+
+    <INPUT TYPE="hidden" NAME="first" VALUE="<% $cust_contact->get('first') |h %>">
+    <INPUT TYPE="hidden" NAME="last"  VALUE="<% $cust_contact->get('last')  |h %>">
+
+    <TR>
+      <TH ALIGN="right"><% mt('Name') %></TH>
+      <TD COLSPAN=7 BGCOLOR="#dddddd">
+        <% $cust_pkg->contact_obj->line |h %>
+      </TD>
+    </TR>
+% #}
+
+  <TR>
+    <TH ALIGN="right" VALIGN="top"><% mt('Address') %></TH>
+    <TD COLSPAN=7 BGCOLOR="#dddddd">
+
+      <% $loc->location_label( 'join_string'     => '<BR>',
+                               'double_space'    => ' &nbsp; ',
+                               'escape_function' => \&encode_entities,
+                               'countrydefault'  => $countrydefault,
+                             )
+      %>
+    </TD>
+  </TR>
+
+</TABLE>
+
+%#XXX payment info
+%#XXX should be sticky on errors...
+<& /edit/cust_main/billing.html, FS::cust_main->new({}),
+                                 invoicing_list => [],
+
+&>
+
+<BR>
+<BR>
+<INPUT NAME    = "submitButton"
+       TYPE    = "submit"
+       VALUE   = "<% mt("Detach package") |h %>"
+>
+
+%#and a cancel button?  or is the popup close sufficient?
+
+</FORM>
+</BODY>
+</HTML>
+
+<%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;
+
+</%init>
index 9312991..4e0551b 100644 (file)
@@ -3,6 +3,7 @@
 % if ( $show_link ) {
         <FONT SIZE=-1>
           (&nbsp;<%pkg_change_contact_link($cust_pkg)%>&nbsp;)
+          (&nbsp;<%pkg_detach_link($cust_pkg)%>&nbsp;)
         </FONT>
 %    }
 % } 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',
index 9d5a88e..24a4dfc 100644 (file)
@@ -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 ) { #?
 
       <TR>
         <TD COLSPAN=<%$opt{colspan}%>>
@@ -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 = '<A HREF="cust_main.cgi?'.  $cust_pkg->change_custnum. '">'.
+                      encode_entities( $cust_main->name ).
+                    '</A>';
+
+    $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'};