[freeside-commits] freeside/FS/FS cust_main.pm, 1.564, 1.565 Conf.pm, 1.389, 1.390 cust_bill.pm, 1.295, 1.296 cust_pay.pm, 1.87, 1.88 cust_pay_void.pm, 1.10, 1.11 cust_credit.pm, 1.45, 1.46 cust_refund.pm, 1.37, 1.38 AccessRight.pm, 1.54, 1.55 option_Common.pm, 1.9, 1.10

Ivan,,, ivan at wavetail.420.am
Tue Oct 19 19:07:04 PDT 2010


Update of /home/cvs/cvsroot/freeside/FS/FS
In directory wavetail.420.am:/tmp/cvs-serv8653/FS/FS

Modified Files:
	cust_main.pm Conf.pm cust_bill.pm cust_pay.pm cust_pay_void.pm 
	cust_credit.pm cust_refund.pm AccessRight.pm option_Common.pm 
Log Message:
customer merging, RT#10247

Index: cust_pay.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cust_pay.pm,v
retrieving revision 1.87
retrieving revision 1.88
diff -u -w -d -r1.87 -r1.88
--- cust_pay.pm	22 Sep 2010 19:16:17 -0000	1.87
+++ cust_pay.pm	20 Oct 2010 02:07:01 -0000	1.88
@@ -401,14 +401,17 @@
 
 }
 
-=item replace OLD_RECORD
+=item replace [ OLD_RECORD ]
 
 You can, but probably shouldn't modify payments...
 
+Replaces the OLD_RECORD with this one in the database, or, if OLD_RECORD is not
+supplied, replaces this record.  If there is an error, returns the error,
+otherwise returns false.
+
 =cut
 
 sub replace {
-  #return "Can't modify payment!"
   my $self = shift;
   return "Can't modify closed payment" if $self->closed =~ /^Y/i;
   $self->SUPER::replace(@_);

Index: cust_refund.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cust_refund.pm,v
retrieving revision 1.37
retrieving revision 1.38
diff -u -w -d -r1.37 -r1.38
--- cust_refund.pm	24 Aug 2010 02:27:46 -0000	1.37
+++ cust_refund.pm	20 Oct 2010 02:07:01 -0000	1.38
@@ -238,12 +238,17 @@
 
 =item replace OLD_RECORD
 
-Modifying a refund?  Well, don't say I didn't warn you.
+You can, but probably shouldn't modify refunds... 
+
+Replaces the OLD_RECORD with this one in the database, or, if OLD_RECORD is not
+supplied, replaces this record.  If there is an error, returns the error,
+otherwise returns false.
 
 =cut
 
 sub replace {
   my $self = shift;
+  return "Can't modify closed refund" if $self->closed =~ /^Y/i;
   $self->SUPER::replace(@_);
 }
 

Index: cust_credit.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cust_credit.pm,v
retrieving revision 1.45
retrieving revision 1.46
diff -u -w -d -r1.45 -r1.46
--- cust_credit.pm	18 Sep 2010 07:53:11 -0000	1.45
+++ cust_credit.pm	20 Oct 2010 02:07:01 -0000	1.46
@@ -270,14 +270,17 @@
 
 }
 
-=item replace OLD_RECORD
+=item replace [ OLD_RECORD ]
 
 You can, but probably shouldn't modify credits... 
 
+Replaces the OLD_RECORD with this one in the database, or, if OLD_RECORD is not
+supplied, replaces this record.  If there is an error, returns the error,
+otherwise returns false.
+
 =cut
 
 sub replace {
-  #return "Can't modify credit!"
   my $self = shift;
   return "Can't modify closed credit" if $self->closed =~ /^Y/i;
   $self->SUPER::replace(@_);

Index: cust_main.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cust_main.pm,v
retrieving revision 1.564
retrieving revision 1.565
diff -u -w -d -r1.564 -r1.565
--- cust_main.pm	18 Oct 2010 03:36:39 -0000	1.564
+++ cust_main.pm	20 Oct 2010 02:07:00 -0000	1.565
@@ -1159,6 +1159,209 @@
 
 }
 
+=item merge NEW_CUSTNUM [ , OPTION => VALUE ... ]
+
+This merges this customer into the provided new custnum, and then deletes the
+customer.  If there is an error, returns the error, otherwise returns false.
+
+The source customer's name, company name, phone numbers, agent,
+referring customer, customer class, advertising source, order taker, and
+billing information (except balance) are discarded.
+
+All packages are moved to the target customer.  Packages with package locations
+are preserved.  Packages without package locations are moved to a new package
+location with the source customer's service/shipping address.
+
+All invoices, statements, payments, credits and refunds are moved to the target
+customer.  The source customer's balance is added to the target customer.
+
+All notes, attachments, tickets and customer tags are moved to the target
+customer.
+
+Change history is not currently moved.
+
+=cut
+
+sub merge {
+  my( $self, $new_custnum, %opt ) = @_;
+
+  return "Can't merge a customer into self" if $self->custnum == $new_custnum;
+
+  unless ( qsearchs( 'cust_main', { 'custnum' => $new_custnum } ) ) {
+    return "Invalid new customer number: $new_custnum";
+  }
+
+  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";
+  }
+
+  tie my %financial_tables, 'Tie::IxHash',
+    'cust_bill'      => 'invoices',
+    'cust_statement' => 'statements',
+    'cust_credit'    => 'credits',
+    'cust_pay'       => 'payments',
+    'cust_pay_void'  => 'voided payments',
+    'cust_refund'    => 'refunds',
+  ;
+   
+  foreach my $table ( keys %financial_tables ) {
+
+    my @records = $self->$table();
+
+    foreach my $record ( @records ) {
+      $record->custnum($new_custnum);
+      my $error = $record->replace;
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return "Error merging ". $financial_tables{$table}. ": $error\n";
+      }
+    }
+
+  }
+
+  my $locationnum = '';
+  foreach my $cust_pkg ( $self->all_pkgs ) {
+    $cust_pkg->custnum($new_custnum);
+
+    unless ( $cust_pkg->locationnum ) {
+      unless ( $locationnum ) {
+        my $cust_location = new FS::cust_location {
+          $self->location_hash,
+          'custnum' => $new_custnum,
+        };
+        my $error = $cust_location->insert;
+        if ( $error ) {
+          $dbh->rollback if $oldAutoCommit;
+          return $error;
+        }
+        $locationnum = $cust_location->locationnum;
+      }
+      $cust_pkg->locationnum($locationnum);
+    }
+
+    my $error = $cust_pkg->replace;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
+  #not considered:
+  # cust_tax_exempt (texas tax exemptions)
+  # cust_recon (some sort of not-well understood thing for OnPac)
+
+  #these are moved over
+  foreach my $table (qw(
+    cust_tag cust_location contact cust_attachment cust_main_note
+    cust_tax_adjustment cust_pay_batch queue
+  )) {
+    foreach my $record ( qsearch( $table, { 'custnum' => $self->custnum } ) ) {
+      $record->custnum($new_custnum);
+      my $error = $record->replace;
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return $error;
+      }
+    }
+  }
+
+  #these aren't preserved
+  foreach my $table (qw(
+    cust_main_exemption cust_main_invoice
+  )) {
+    foreach my $record ( qsearch( $table, { 'custnum' => $self->custnum } ) ) {
+      my $error = $record->delete;
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return $error;
+      }
+    }
+  }
+
+
+  my $sth = $dbh->prepare(
+    'UPDATE cust_main SET referral_custnum = ? WHERE referral_custnum = ?'
+  ) or do {
+    my $errstr = $dbh->errstr;
+    $dbh->rollback if $oldAutoCommit;
+    return $errstr;
+  };
+  $sth->execute($new_custnum, $self->custnum) or do {
+    my $errstr = $sth->errstr;
+    $dbh->rollback if $oldAutoCommit;
+    return $errstr;
+  };
+
+  #tickets
+
+  my $ticket_dbh = '';
+  if ($conf->config('ticket_system') eq 'RT_Internal') {
+    $ticket_dbh = $dbh;
+  } elsif ($conf->config('ticket_system') eq 'RT_External') {
+    my ($datasrc, $user, $pass) = $conf->config('ticket_system-rt_external_datasrc');
+    $ticket_dbh = DBI->connect($datasrc, $user, $pass, { 'ChopBlanks' => 1 });
+      #or die "RT_External DBI->connect error: $DBI::errstr\n";
+  }
+
+  if ( $ticket_dbh ) {
+
+    my $ticket_sth = $ticket_dbh->prepare(
+      'UPDATE Links SET Target = ? WHERE Target = ?'
+    ) or do {
+      my $errstr = $ticket_dbh->errstr;
+      $dbh->rollback if $oldAutoCommit;
+      return $errstr;
+    };
+    $ticket_sth->execute('freeside://freeside/cust_main/'.$new_custnum,
+                         'freeside://freeside/cust_main/'.$self->custnum)
+      or do {
+        my $errstr = $ticket_sth->errstr;
+        $dbh->rollback if $oldAutoCommit;
+        return $errstr;
+      };
+
+  }
+
+  #delete the customer record
+
+  my $error = $self->delete;
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
+
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+  '';
+
+}
+
 =item replace [ OLD_RECORD ] [ INVOICING_LIST_ARYREF ] [ , OPTION => VALUE ... ] ]
 
 

Index: cust_pay_void.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cust_pay_void.pm,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -w -d -r1.10 -r1.11
--- cust_pay_void.pm	24 Aug 2010 02:27:46 -0000	1.10
+++ cust_pay_void.pm	20 Oct 2010 02:07:01 -0000	1.11
@@ -155,16 +155,13 @@
 Deletes this voided payment.  You probably don't want to use this directly; see
 the B<unvoid> method to add the original payment back.
 
-=item replace OLD_RECORD
-
-Currently unimplemented.
+=item replace [ OLD_RECORD ]
 
-=cut
+You can, but probably shouldn't modify voided payments...
 
-sub replace {
-   return "Can't modify voided payments!" unless $otaker_upgrade_kludge;
-   shift->SUPER::replace(@_);
-}
+Replaces the OLD_RECORD with this one in the database, or, if OLD_RECORD is not
+supplied, replaces this record.  If there is an error, returns the error,
+otherwise returns false.
 
 =item check
 

Index: Conf.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/Conf.pm,v
retrieving revision 1.389
retrieving revision 1.390
diff -u -w -d -r1.389 -r1.390
--- Conf.pm	19 Oct 2010 00:06:48 -0000	1.389
+++ Conf.pm	20 Oct 2010 02:07:00 -0000	1.390
@@ -2718,7 +2718,7 @@
   {
     'key'         => 'tax-pkg_address',
     'section'     => 'billing',
-    'description' => 'By default, tax calculations are done based on the billing address.  Enable this switch to calculate tax based on the package address instead (when present).  Note that this option is currently incompatible with vendor data taxation enabled by enable_taxproducts.',
+    'description' => 'By default, tax calculations are done based on the billing address.  Enable this switch to calculate tax based on the package address instead (when present).',
     'type'        => 'checkbox',
   },
 

Index: option_Common.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/option_Common.pm,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -w -d -r1.9 -r1.10
--- option_Common.pm	15 Apr 2008 13:41:01 -0000	1.9
+++ option_Common.pm	20 Oct 2010 02:07:01 -0000	1.10
@@ -173,10 +173,15 @@
               ? shift
               : $self->replace_old;
 
-  my $options = 
-    ( ref($_[0]) eq 'HASH' )
-      ? shift
-      : { @_ };
+  my $options;
+  my $options_supplied = 0;
+  if ( ref($_[0]) eq 'HASH' ) {
+    $options = shift;
+    $options_supplied = 1;
+  } else {
+    $options = { @_ };
+    $options_supplied = scalar(@_) ? 1 : 0;
+  }
 
   warn "FS::option_Common::replace called on $self with options ".
        join(', ', map "$_ => ". $options->{$_}, keys %$options)
@@ -252,6 +257,7 @@
   }
 
   #remove extraneous old options
+  if ( $options_supplied ) {
   foreach my $opt (
     grep { !exists $options->{$_->$namecol()} } $old->option_objects
   ) {
@@ -261,6 +267,7 @@
       return $error;
     }
   }
+  }
 
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
 

Index: cust_bill.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cust_bill.pm,v
retrieving revision 1.295
retrieving revision 1.296
diff -u -w -d -r1.295 -r1.296
--- cust_bill.pm	10 Oct 2010 23:41:32 -0000	1.295
+++ cust_bill.pm	20 Oct 2010 02:07:00 -0000	1.296
@@ -263,13 +263,13 @@
 
 }
 
-=item replace OLD_RECORD
+=item replace [ OLD_RECORD ]
 
-Replaces the OLD_RECORD with this one in the database.  If there is an error,
-returns the error, otherwise returns false.
+You can, but probably shouldn't modify invoices...
 
-Only printed may be changed.  printed is normally updated by calling the
-collect method of a customer object (see L<FS::cust_main>).
+Replaces the OLD_RECORD with this one in the database, or, if OLD_RECORD is not
+supplied, replaces this record.  If there is an error, returns the error,
+otherwise returns false.
 
 =cut
 
@@ -280,10 +280,10 @@
 
 sub replace_check {
   my( $new, $old ) = ( shift, shift );
-  return "Can't change custnum!" unless $old->custnum == $new->custnum;
+  return "Can't modify closed invoice" if $old->closed =~ /^Y/i;
   #return "Can't change _date!" unless $old->_date eq $new->_date;
-  return "Can't change _date!" unless $old->_date == $new->_date;
-  return "Can't change charged!" unless $old->charged == $new->charged
+  return "Can't change _date" unless $old->_date == $new->_date;
+  return "Can't change charged" unless $old->charged == $new->charged
                                      || $old->charged == 0;
 
   '';

Index: AccessRight.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/AccessRight.pm,v
retrieving revision 1.54
retrieving revision 1.55
diff -u -w -d -r1.54 -r1.55
--- AccessRight.pm	16 Jul 2010 23:45:23 -0000	1.54
+++ AccessRight.pm	20 Oct 2010 02:07:01 -0000	1.55
@@ -113,6 +113,7 @@
     'View customer history',
     'Cancel customer',
     'Complimentary customer', #aka users-allow_comp 
+    'Merge customer',
     { rightname=>'Delete customer', desc=>"Enable customer deletions. Be very careful! Deleting a customer will remove all traces that this customer ever existed! It should probably only be used when auditing a legacy database. Normally, you cancel all of a customer's packages if they cancel service." }, #aka. deletecustomers
     'Bill customer now', #NEW
     'Bulk send customer notices', #NEW
@@ -346,6 +347,7 @@
     'Redownload resolved batches',
     'Raw SQL',
     'Configuration download',
+    'View customers of all agents',
   );
 
   no warnings 'uninitialized';



More information about the freeside-commits mailing list