From e2505a120a7d182d86d589a7b0cb881840021ddc Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Tue, 2 Feb 2016 16:33:32 -0800 Subject: [PATCH] fix reasonnum upgrade, fallout from #39398 --- FS/FS/reason_Mixin.pm | 187 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 131 insertions(+), 56 deletions(-) diff --git a/FS/FS/reason_Mixin.pm b/FS/FS/reason_Mixin.pm index a3975419c..9c436ab1e 100644 --- a/FS/FS/reason_Mixin.pm +++ b/FS/FS/reason_Mixin.pm @@ -6,18 +6,22 @@ use FS::Record qw( qsearch qsearchs dbdef ); use FS::access_user; use FS::UID qw( dbh ); use FS::reason; +use FS::reason_type; our $DEBUG = 0; our $me = '[FS::reason_Mixin]'; =item reason -Returns the text of the associated reason (see L) for this credit. +Returns the text of the associated reason (see L) for this credit / +voided payment / voided invoice. This can no longer be used to set the +(deprecated) free-text "reason" field; see L. =cut sub reason { - my ($self, $value, %options) = @_; + my $self = shift; + my $reason_text; if ( $self->reasonnum ) { my $reason = FS::reason->by_key($self->reasonnum); @@ -32,65 +36,136 @@ sub reason { return $reason_text; } -# it was a mistake to allow setting the reason this way; use -# FS::reason->new_or_existing - # Used by FS::Upgrade to migrate reason text fields to reasonnum. -sub _upgrade_reasonnum { # class method - my $class = shift; - my $table = $class->table; - - if (defined dbdef->table($table)->column('reason')) { - - warn "$me Checking for unmigrated reasons\n" if $DEBUG; - - my @cust_refunds = qsearch({ 'table' => $table, - 'hashref' => {}, - 'extra_sql' => 'WHERE reason IS NOT NULL', - }); - - if (scalar(grep { $_->getfield('reason') =~ /\S/ } @cust_refunds)) { - warn "$me Found unmigrated reasons\n" if $DEBUG; - my $hashref = { 'class' => 'F', 'type' => 'Legacy' }; - my $reason_type = qsearchs( 'reason_type', $hashref ); - unless ($reason_type) { - $reason_type = new FS::reason_type( $hashref ); - my $error = $reason_type->insert(); - die "$class had error inserting FS::reason_type into database: $error\n" - if $error; - } - - $hashref = { 'reason_type' => $reason_type->typenum, - 'reason' => '(none)' - }; - my $noreason = qsearchs( 'reason', $hashref ); - unless ($noreason) { - $hashref->{'disabled'} = 'Y'; - $noreason = new FS::reason( $hashref ); - my $error = $noreason->insert(); - die "can't insert legacy reason '(none)' into database: $error\n" - if $error; - } - - foreach my $cust_refund ( @cust_refunds ) { - my $reason = $cust_refund->getfield('reason'); - warn "Contemplating reason $reason\n" if $DEBUG > 1; - if ($reason =~ /\S/) { - $cust_refund->reason($reason, 'reason_type' => $reason_type->typenum) - or die "can't insert legacy reason $reason into database\n"; - }else{ - $cust_refund->reasonnum($noreason->reasonnum); +# Note that any new tables that get reasonnum fields do NOT need to be +# added here unless they have previously had a free-text "reason" field. + +sub _upgrade_reasonnum { # class method + my $class = shift; + my $table = $class->table; + + my $reason_class; + if ( $table =~ /^cust_bill/ ) { # also includes cust_bill_pkg + $reason_class = 'I'; + } elsif ( $table =~ /^cust_pay/ ) { + $reason_class = 'P'; + } elsif ( $table eq 'cust_refund' ) { + $reason_class = 'F'; + } elsif ( $table =~ /^cust_credit/ ) { + $reason_class = 'R'; + } else { + die "don't know the reason class to use for upgrading $table"; + } + + for my $fieldname (qw(reason void_reason)) { + + if ( $table =~ /^cust_credit/ and $fieldname eq 'void_reason' ) { + $reason_class = 'X'; + } + + if ( defined dbdef->table($table)->column($fieldname) + && defined dbdef->table($table)->column( $fieldname . 'num' ) ) + { + + warn "$me Checking for unmigrated reasons\n" if $DEBUG; + + my @legacy_reason_records = qsearch( + { + 'table' => $table, + 'hashref' => {}, + 'extra_sql' => 'WHERE ' . $fieldname . ' IS NOT NULL', + } + ); + + if ( @legacy_reason_records ) { + + warn "$me Found unmigrated reasons\n" if $DEBUG; + + my $reason_type = + $class->_upgrade_get_legacy_reason_type( $reason_class ); + # XXX "noreason" does not actually work, because we limited to + # "reason is not null" above. Records where the reason string + # is null will end up with a reasonnum of null also. + my $noreason = $class->_upgrade_get_no_reason( $reason_type ); + + foreach my $record_to_upgrade (@legacy_reason_records) { + my $reason = $record_to_upgrade->getfield($fieldname); + warn "Contemplating reason $reason\n" if $DEBUG > 1; + if ( $reason =~ /\S/ ) { + my $reason = + $class->_upgrade_get_reason( $reason, $reason_type ); + $record_to_upgrade->set( $fieldname . 'num', + $reason->reasonnum ); + } + else { + $record_to_upgrade->set( $fieldname . 'num', + $noreason->reasonnum ); + } + + $record_to_upgrade->setfield( $fieldname, '' ); + my $error = $record_to_upgrade->replace; + + my $primary_key = $record_to_upgrade->primary_key; + warn "*** WARNING: error replacing $fieldname in $class " + . $record_to_upgrade->get($primary_key) + . ": $error ***\n" + if $error; + } + } } + } +} - $cust_refund->setfield('reason', ''); - my $error = $cust_refund->replace; +# internal methods for upgrade - warn "*** WARNING: error replacing reason in $class ". - $cust_refund->refundnum. ": $error ***\n" - if $error; - } +# _upgrade_get_legacy_reason_type is class method supposed to be used only +# within the reason_Mixin class which will either find or create a reason_type +sub _upgrade_get_legacy_reason_type { + + my $class = shift; + my $reason_class = shift; + my $reason_type_params = { 'class' => $reason_class, 'type' => 'Legacy' }; + my $reason_type = qsearchs( 'reason_type', $reason_type_params ); + unless ($reason_type) { + $reason_type = new FS::reason_type($reason_type_params); + my $error = $reason_type->insert(); + die "$class had error inserting FS::reason_type into database: $error\n" + if $error; } - } + return $reason_type; +} + +# _upgrade_get_no_reason is class method supposed to be used only within the +# reason_Mixin class which will either find or create a default (no reason) +# reason +sub _upgrade_get_no_reason { + + my $class = shift; + my $reason_type = shift; + return $class->_upgrade_get_reason( '(none)', $reason_type ); +} + +# _upgrade_get_reason is class method supposed to be used only within the +# reason_Mixin class which will either find or create a reason +sub _upgrade_get_reason { + + my $class = shift; + my $reason_text = shift; + my $reason_type = shift; + + my $reason_params = { + 'reason_type' => $reason_type->typenum, + 'reason' => $reason_text + }; + my $reason = qsearchs( 'reason', $reason_params ); + unless ($reason) { + $reason_params->{'disabled'} = 'Y'; + $reason = new FS::reason($reason_params); + my $error = $reason->insert(); + die "can't insert legacy reason '$reason_text' into database: $error\n" + if $error; + } + return $reason; } 1; -- 2.11.0