X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fcust_main.pm;h=1b663c9ae11a12b615ee0037a60523542646ca64;hb=8fda124d646333848b311c99263813c7d2466592;hp=858ac14ffcdced771a2a9a083c0c853546512cdb;hpb=eddd64eca86ded1a286a229f86312f676adeef54;p=freeside.git diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 858ac14ff..1b663c9ae 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -1955,6 +1955,28 @@ sub cust_location { qsearch('cust_location', { 'custnum' => $self->custnum } ); } +=item location_label_short + +Returns the short label of the service location (see analog in L) for this customer. + +=cut + +# false laziness with FS::cust_location::line_short + +sub location_label_short { + my $self = shift; + my $cydefault = FS::conf->new->config('countrydefault') || 'US'; + + my $line = $self->address1; + #$line .= ', '. $self->address2 if $self->address2; + $line .= ', '. $self->city; + $line .= ', '. $self->state if $self->state; + $line .= ' '. $self->zip if $self->zip; + $line .= ' '. code2country($self->country) if $self->country ne $cydefault; + + $line; +} + =item ncancelled_pkgs [ EXTRA_QSEARCH_PARAMS_HASHREF ] Returns all non-cancelled packages (see L) for this customer. @@ -2016,6 +2038,9 @@ sub _cust_pkg { # This should be generalized to use config options to determine order. sub sort_packages { + my $locationsort = $a->locationnum <=> $b->locationnum; + return $locationsort if $locationsort; + if ( $a->get('cancel') xor $b->get('cancel') ) { return -1 if $b->get('cancel'); return 1 if $a->get('cancel'); @@ -2528,7 +2553,7 @@ plans support this feature (they tend to charge 0). =item invoice_terms -Options terms to be printed on this invocice. Otherwise, customer-specific +Optional terms to be printed on this invoice. Otherwise, customer-specific terms or the default terms are used. =back @@ -4774,6 +4799,9 @@ sub realtime_refund_bop { ) { warn " attempting void\n" if $DEBUG > 1; my $void = new Business::OnlinePayment( $processor, @bop_options ); + $content{'card_number'} = $cust_pay->payinfo + if $cust_pay->payby eq 'CARD' + && $void->can('info') && $void->info('CC_void_requires_card'); $void->content( 'action' => 'void', %content ); $void->submit(); if ( $void->is_success ) { @@ -6112,6 +6140,9 @@ sub _new_realtime_refund_bop { ) { warn " attempting void\n" if $DEBUG > 1; my $void = new Business::OnlinePayment( $processor, @bop_options ); + $content{'card_number'} = $cust_pay->payinfo + if $cust_pay->payby eq 'CARD' + && $void->can('info') && $void->info('CC_void_requires_card'); $void->content( 'action' => 'void', %content ); $void->submit(); if ( $void->is_success ) { @@ -6847,6 +6878,36 @@ sub balance_date { ); } +=item balance_date_range START_TIME [ END_TIME [ OPTION => VALUE ... ] ] + +Returns the balance for this customer, only considering invoices with date +earlier than START_TIME, and optionally not later than END_TIME +(total_owed_date minus total_unapplied_credits minus total_unapplied_payments). + +Times are specified as SQL fragments or numeric +UNIX timestamps; see L). Also see L and +L for conversion functions. The empty string can be passed +to disable that time constraint completely. + +Available options are: + +=over 4 + +=item unapplied_date + +set to true to disregard unapplied credits, payments and refunds outside the specified time period - by default the time period restriction only applies to invoices (useful for reporting, probably a bad idea for event triggering) + +=back + +=cut + +sub balance_date_range { + my $self = shift; + my $sql = 'SELECT SUM('. $self->balance_date_sql(@_). + ') FROM cust_main WHERE custnum='. $self->custnum; + sprintf( "%.2f", $self->scalar_sql($sql) ); +} + =item balance_pkgnum PKGNUM Returns the balance for this customer's specific package when using @@ -8258,7 +8319,7 @@ sub _money_table_where { } -=item search_sql HASHREF +=item search HASHREF (Class method) @@ -8301,7 +8362,7 @@ bool =cut -sub search_sql { +sub search { my ($class, $params) = @_; my $dbh = dbh; @@ -8368,24 +8429,41 @@ sub search_sql { # classnum ### - my @classnum = grep /^(\d*)$/, @{ $params->{'classnum'} }; - if ( @classnum ) { - push @where, '( '. join(' OR ', map { - $_ ? "cust_main.classnum = $_" - : "cust_main.classnum IS NULL" - } - @classnum - ). - ' )'; + if ( $params->{'classnum'} ) { + + my @classnum = ref( $params->{'classnum'} ) + ? @{ $params->{'classnum'} } + : ( $params->{'classnum'} ); + + @classnum = grep /^(\d*)$/, @classnum; + + if ( @classnum ) { + push @where, '( '. join(' OR ', map { + $_ ? "cust_main.classnum = $_" + : "cust_main.classnum IS NULL" + } + @classnum + ). + ' )'; + } + } ### # payby ### - my @payby = grep /^([A-Z]{4})$/, @{ $params->{'payby'} }; - if ( @payby ) { - push @where, '( '. join(' OR ', map "cust_main.payby = '$_'", @payby). ' )'; + if ( $params->{'payby'} ) { + + my @payby = ref( $params->{'payby'} ) + ? @{ $params->{'payby'} } + : ( $params->{'payby'} ); + + @payby = grep /^([A-Z]{4})$/, @{ $params->{'payby'} }; + + push @where, '( '. join(' OR ', map "cust_main.payby = '$_'", @payby). ' )' + if @payby; + } ### @@ -8405,15 +8483,40 @@ sub search_sql { ; } + ### + # invoice terms + ### + + if ( $params->{'invoice_terms'} =~ /^([\w ]+)$/ ) { + my $terms = $1; + if ( $1 eq 'NULL' ) { + push @where, + "( cust_main.invoice_terms IS NULL OR cust_main.invoice_terms = '' )"; + } else { + push @where, + "cust_main.invoice_terms IS NOT NULL", + "cust_main.invoice_terms = '$1'"; + } + } + ## # amounts ## - #my $balance_sql = $class->balance_sql(); - my $balance_sql = FS::cust_main->balance_sql(); + if ( $params->{'current_balance'} ) { + + #my $balance_sql = $class->balance_sql(); + my $balance_sql = FS::cust_main->balance_sql(); + + my @current_balance = + ref( $params->{'current_balance'} ) + ? @{ $params->{'current_balance'} } + : ( $params->{'current_balance'} ); - push @where, map { s/current_balance/$balance_sql/; $_ } - @{ $params->{'current_balance'} }; + push @where, map { s/current_balance/$balance_sql/; $_ } + @current_balance; + + } ## # custbatch @@ -8491,13 +8594,13 @@ sub search_sql { } -=item email_search_sql HASHREF +=item email_search_result HASHREF (Class method) Emails a notice to the specified customers. -Valid parameters are those of the L method, plus the following: +Valid parameters are those of the L method, plus the following: =over 4 @@ -8531,7 +8634,7 @@ retrying everything. =cut -sub email_search_sql { +sub email_search_result { my($class, $params) = @_; my $from = delete $params->{from}; @@ -8544,7 +8647,7 @@ sub email_search_sql { $params->{'payby'} = [ split(/\0/, $params->{'payby'}) ] unless ref($params->{'payby'}); - my $sql_query = $class->search_sql($params); + my $sql_query = $class->search($params); my $count_query = delete($sql_query->{'count_query'}); my $count_sth = dbh->prepare($count_query) @@ -8596,7 +8699,7 @@ sub email_search_sql { use Storable qw(thaw); use Data::Dumper; use MIME::Base64; -sub process_email_search_sql { +sub process_email_search_result { my $job = shift; #warn "$me process_re_X $method for job $job\n" if $DEBUG; @@ -8608,7 +8711,7 @@ sub process_email_search_sql { $param->{'payby'} = [ split(/\0/, $param->{'payby'}) ] unless ref($param->{'payby'}); - my $error = FS::cust_main->email_search_sql( $param ); + my $error = FS::cust_main->email_search_result( $param ); die $error if $error; } @@ -8792,17 +8895,21 @@ sub smart_search { # "Company (Last, First)" #this is probably something a browser remembered, - #so just do an exact (but case-insensitive) search + #so just do an exact search (but case-insensitive, so USPS standardization + #doesn't throw a wrench in the works) foreach my $prefix ( '', 'ship_' ) { push @cust_main, qsearch( { 'table' => 'cust_main', - 'hashref' => { $prefix.'first' => $first, - $prefix.'last' => $last, - $prefix.'company' => $company, - %options, - }, - 'extra_sql' => " AND $agentnums_sql", + 'hashref' => { %options }, + 'extra_sql' => + ( keys(%options) ? ' AND ' : ' WHERE ' ). + join(' AND ', + " LOWER(${prefix}first) = ". dbh->quote(lc($first)), + " LOWER(${prefix}last) = ". dbh->quote(lc($last)), + " LOWER(${prefix}company) = ". dbh->quote(lc($company)), + $agentnums_sql, + ), } ); } @@ -8883,7 +8990,7 @@ sub smart_search { #getting complaints searches are not returning enough unless ( @cust_main && $skip_fuzzy || $conf->exists('disable-fuzzy') ) { - #still some false laziness w/search_sql (was search/cust_main.cgi) + #still some false laziness w/search (was search/cust_main.cgi) #substring