X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fcust_pkg.pm;h=771d3ec75e8de69f320770bdd6ed66272d64e4df;hb=a180208786cccb72ab017e39fff0cb128aa6ba01;hp=0cb1b50a20d142ed75c98a98bd22e5eaaf766b15;hpb=fe4515eb37d76849dd08c62782d86bc7ba311dcd;p=freeside.git diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 0cb1b50a2..771d3ec75 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -4,7 +4,7 @@ use base qw( FS::otaker_Mixin FS::cust_main_Mixin FS::Sales_Mixin FS::m2m_Common FS::option_Common ); use strict; -use vars qw($disable_agentcheck $DEBUG $me); +use vars qw( $disable_agentcheck $DEBUG $me $upgrade ); use Carp qw(cluck); use Scalar::Util qw( blessed ); use List::Util qw(min max); @@ -35,6 +35,8 @@ use FS::cust_pkg_discount; use FS::discount; use FS::UI::Web; use FS::sales; +# for modify_charge +use FS::cust_credit; # need to 'use' these instead of 'require' in sub { cancel, suspend, unsuspend, # setup } @@ -52,6 +54,8 @@ $me = '[FS::cust_pkg]'; $disable_agentcheck = 0; +$upgrade = 0; #go away after setup+start dates cleaned up for old customers + sub _cache { my $self = shift; my ( $hashref, $cache ) = @_; @@ -654,7 +658,7 @@ sub check { return $error if $error; return "A package with both start date (future start) and setup date (already started) will never bill" - if $self->start_date && $self->setup; + if $self->start_date && $self->setup && ! $upgrade; return "A future unsuspend date can only be set for a package with a suspend date" if $self->resume and !$self->susp and !$self->adjourn; @@ -2256,8 +2260,128 @@ sub set_salesnum { $self = $self->replace_old; # just to make sure $self->salesnum(shift); $self->replace; + # XXX this should probably reassign any credit that's already been given } +=item modify_charge OPTIONS + +Change the properties of a one-time charge. Currently the only properties +that can be changed this way are those that have no impact on billing +calculations: +- pkg: the package description +- classnum: the package class +- additional: arrayref of additional invoice details to add to this package + +If you pass 'adjust_commission' => 1, and the classnum changes, and there are +commission credits linked to this charge, they will be recalculated. + +=cut + +sub modify_charge { + my $self = shift; + my %opt = @_; + my $part_pkg = $self->part_pkg; + my $pkgnum = $self->pkgnum; + + my $dbh = dbh; + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + + return "Can't use modify_charge except on one-time charges" + unless $part_pkg->freq eq '0'; + + if ( length($opt{'pkg'}) and $part_pkg->pkg ne $opt{'pkg'} ) { + $part_pkg->set('pkg', $opt{'pkg'}); + } + + my %pkg_opt = $part_pkg->options; + if ( ref($opt{'additional'}) ) { + delete $pkg_opt{$_} foreach grep /^additional/, keys %pkg_opt; + my $i; + for ( $i = 0; exists($opt{'additional'}->[$i]); $i++ ) { + $pkg_opt{ "additional_info$i" } = $opt{'additional'}->[$i]; + } + $pkg_opt{'additional_count'} = $i if $i > 0; + } + + my $old_classnum; + if ( exists($opt{'classnum'}) and $part_pkg->classnum ne $opt{'classnum'} ) { + # remember it + $old_classnum = $part_pkg->classnum; + $part_pkg->set('classnum', $opt{'classnum'}); + } + + my $error = $part_pkg->replace( options => \%pkg_opt ); + return $error if $error; + + if (defined $old_classnum) { + # fix invoice grouping records + my $old_catname = $old_classnum + ? FS::pkg_class->by_key($old_classnum)->categoryname + : ''; + my $new_catname = $opt{'classnum'} + ? $part_pkg->pkg_class->categoryname + : ''; + if ( $old_catname ne $new_catname ) { + foreach my $cust_bill_pkg ($self->cust_bill_pkg) { + # (there should only be one...) + my @display = qsearch( 'cust_bill_pkg_display', { + 'billpkgnum' => $cust_bill_pkg->billpkgnum, + 'section' => $old_catname, + }); + foreach (@display) { + $_->set('section', $new_catname); + $error = $_->replace; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + } # foreach $cust_bill_pkg + } + + if ( $opt{'adjust_commission'} ) { + # fix commission credits...tricky. + foreach my $cust_event ($self->cust_event) { + my $part_event = $cust_event->part_event; + foreach my $table (qw(sales agent)) { + my $class = + "FS::part_event::Action::Mixin::credit_${table}_pkg_class"; + my $credit = qsearchs('cust_credit', { + 'eventnum' => $cust_event->eventnum, + }); + if ( $part_event->isa($class) ) { + # Yes, this results in current commission rates being applied + # retroactively to a one-time charge. For accounting purposes + # there ought to be some kind of time limit on doing this. + my $amount = $part_event->_calc_credit($self); + if ( $credit and $credit->amount ne $amount ) { + # Void the old credit. + $error = $credit->void('Package class changed'); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "$error (adjusting commission credit)"; + } + } + # redo the event action to recreate the credit. + local $@ = ''; + eval { $part_event->do_action( $self, $cust_event ) }; + if ( $@ ) { + $dbh->rollback if $oldAutoCommit; + return $@; + } + } # if $part_event->isa($class) + } # foreach $table + } # foreach $cust_event + } # if $opt{'adjust_commission'} + } # if defined $old_classnum + + $dbh->commit if $oldAutoCommit; + ''; +} + + + use Storable 'thaw'; use MIME::Base64; use Data::Dumper; @@ -4161,6 +4285,32 @@ boolean; if true, returns only packages with more than 0 FCC phone lines. Limit to packages with a service location in the specified state and country. For FCC 477 reporting, mostly. +=item location_cust + +Limit to packages whose service locations are the same as the customer's +default service location. + +=item location_nocust + +Limit to packages whose service locations are not the customer's default +service location. + +=item location_census + +Limit to packages whose service locations have census tracts. + +=item location_nocensus + +Limit to packages whose service locations do not have a census tract. + +=item location_geocode + +Limit to packages whose locations have geocodes. + +=item location_geocode + +Limit to packages whose locations do not have geocodes. + =back =cut @@ -4179,6 +4329,14 @@ sub search { } ## + # parse cust_status + ## + + if ( $params->{'cust_status'} =~ /^([a-z]+)$/ ) { + push @where, FS::cust_main->cust_status_sql . " = '$1' "; + } + + ## # parse customer sales person ## @@ -4385,6 +4543,22 @@ sub search { } ### + # location_* flags + ### + if ( $params->{location_cust} xor $params->{location_nocust} ) { + my $op = $params->{location_cust} ? '=' : '!='; + push @where, "cust_location.locationnum $op cust_main.ship_locationnum"; + } + if ( $params->{location_census} xor $params->{location_nocensus} ) { + my $op = $params->{location_census} ? "IS NOT NULL" : "IS NULL"; + push @where, "cust_location.censustract $op"; + } + if ( $params->{location_geocode} xor $params->{location_nogeocode} ) { + my $op = $params->{location_geocode} ? "IS NOT NULL" : "IS NULL"; + push @where, "cust_location.geocode $op"; + } + + ### # parse part_pkg ###