From 9f3d1466f4dd917aeb07d7e85222d97e131062f1 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 11 Aug 2010 06:35:20 +0000 Subject: [PATCH] a better customer delete, RT#9564 --- FS/FS/cust_main.pm | 87 +++++++++++++++++++++-------- bin/wipe-customers | 30 ++++++++++ httemplate/misc/process/delete-customer.cgi | 2 +- 3 files changed, 96 insertions(+), 23 deletions(-) create mode 100644 bin/wipe-customers diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 3bfccfc66..83cb25b3e 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -1301,7 +1301,7 @@ sub reexport { } -=item delete NEW_CUSTNUM +=item delete [ OPTION => VALUE ... ] This deletes the customer. If there is an error, returns the error, otherwise returns false. @@ -1311,18 +1311,20 @@ what you want when a customer cancels service; for that, cancel all of the customer's packages (see L). If the customer has any uncancelled packages, you need to pass a new (valid) -customer number for those packages to be transferred to. Cancelled packages -will be deleted. Did I mention that this is NOT what you want when a customer -cancels service and that you really should be looking see L? +customer number for those packages to be transferred to, as the "new_customer" +option. Cancelled packages will be deleted. Did I mention that this is NOT +what you want when a customer cancels service and that you really should be +looking at L? You can't delete a customer with invoices (see L), -or credits (see L), payments (see L) or -refunds (see L). +statements (see L), credits (see L), +payments (see L) or refunds (see L), unless you +set the "delete_financials" option to a true value. =cut sub delete { - my $self = shift; + my( $self, %opt ) = @_; local $SIG{HUP} = 'IGNORE'; local $SIG{INT} = 'IGNORE'; @@ -1335,26 +1337,47 @@ sub delete { local $FS::UID::AutoCommit = 0; my $dbh = dbh; - if ( $self->cust_bill ) { - $dbh->rollback if $oldAutoCommit; - return "Can't delete a customer with invoices"; + if ( qsearch('agent', { 'agent_custnum' => $self->custnum } ) ) { + $dbh->rollback if $oldAutoCommit; + return "Can't delete a master agent customer"; } - if ( $self->cust_credit ) { - $dbh->rollback if $oldAutoCommit; - return "Can't delete a customer with credits"; - } - if ( $self->cust_pay ) { - $dbh->rollback if $oldAutoCommit; - return "Can't delete a customer with payments"; + + #use FS::access_user + if ( qsearch('access_user', { 'user_custnum' => $self->custnum } ) ) { + $dbh->rollback if $oldAutoCommit; + return "Can't delete a master employee customer"; } - if ( $self->cust_refund ) { - $dbh->rollback if $oldAutoCommit; - return "Can't delete a customer with refunds"; + + tie my %financial_tables, 'Tie::IxHash', + 'cust_bill' => 'invoices', + 'cust_statement' => 'statements', + 'cust_credit' => 'credits', + 'cust_pay' => 'payments', + 'cust_refund' => 'refunds', + ; + + foreach my $table ( keys %financial_tables ) { + + my @records = $self->$table(); + + if ( @records && ! $opt{'delete_financials'} ) { + $dbh->rollback if $oldAutoCommit; + return "Can't delete a customer with ". $financial_tables{$table}; + } + + foreach my $record ( @records ) { + my $error = $record->delete; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "Error deleting ". $financial_tables{$table}. ": $error\n"; + } + } + } my @cust_pkg = $self->ncancelled_pkgs; if ( @cust_pkg ) { - my $new_custnum = shift; + my $new_custnum = $opt{'new_custnum'}; unless ( qsearchs( 'cust_main', { 'custnum' => $new_custnum } ) ) { $dbh->rollback if $oldAutoCommit; return "Invalid new customer number: $new_custnum"; @@ -1381,7 +1404,14 @@ sub delete { } } - foreach my $table (qw( cust_main_invoice cust_main_exemption cust_tag )) { + #cust_tax_adjustment in financials? + #cust_pay_pending? ouch + foreach my $table (qw( + cust_main_invoice cust_main_exemption cust_tag cust_attachment contact + cust_location cust_main_note cust_tax_adjustment + cust_pay_void cust_pay_batch queue cust_tax_exempt + cust_recon + )) { foreach my $record ( qsearch( $table, { 'custnum' => $self->custnum } ) ) { my $error = $record->delete; if ( $error ) { @@ -1391,6 +1421,19 @@ sub delete { } } + my $sth = $dbh->prepare( + 'UPDATE cust_main SET referral_custnum = NULL WHERE referral_custnum = ?' + ) or do { + my $errstr = $dbh->errstr; + $dbh->rollback if $oldAutoCommit; + return $errstr; + }; + $sth->execute($self->custnum) or do { + my $errstr = $sth->errstr; + $dbh->rollback if $oldAutoCommit; + return $errstr; + }; + my $error = $self->SUPER::delete; if ( $error ) { $dbh->rollback if $oldAutoCommit; diff --git a/bin/wipe-customers b/bin/wipe-customers new file mode 100644 index 000000000..e65ed61be --- /dev/null +++ b/bin/wipe-customers @@ -0,0 +1,30 @@ +#!/usr/bin/perl + +use strict; +use FS::UID qw(adminsuidsetup); +use FS::Record qw(qsearch); +use FS::cust_main; + +die "this removes all customers in your database except for customer 1 - remove this line to enable"; + +my $user = shift or die "usage: wipe-customers username\n"; +adminsuidsetup $user; + +#this isn't terribly efficient, but the idea was clearing out a test database, +#not actually destroying a large amount of data + +foreach my $cust_main ( + + qsearch('cust_main', { 'custnum' => { op=>'!=', value=>'1' } } ) + +) { + + my @cerrors = $cust_main->cancel( quiet=>1, nobill=>1 ); + if ( @cerrors ) { + die join(' / ', @cerrors); + } + + my $error = $cust_main->delete( 'delete_financials' => 1); + die $error if $error; + +} diff --git a/httemplate/misc/process/delete-customer.cgi b/httemplate/misc/process/delete-customer.cgi index d509a5e0e..12011311a 100755 --- a/httemplate/misc/process/delete-customer.cgi +++ b/httemplate/misc/process/delete-customer.cgi @@ -28,6 +28,6 @@ if ( $cgi->param('new_custnum') ) { my $cust_main = qsearchs( 'cust_main', { 'custnum' => $custnum } ) or die "Customer not found: $custnum"; -my $error = $cust_main->delete($new_custnum); +my $error = $cust_main->delete('new_custnum' => $new_custnum); -- 2.11.0