X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fcust_main.pm;h=4973f690da2ffa50e018f45a5787a268dc0a4648;hb=cf49d3c860a2000cfc23a0e0db472a7d6fc58935;hp=700e15a794387ee51d3f1ee3f024ebb93f806c36;hpb=2cb70470a8e5c3287146008e4ce2c4eb9f242373;p=freeside.git diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 700e15a79..4973f690d 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -45,6 +45,7 @@ use FS::cust_refund; use FS::part_referral; use FS::cust_main_county; use FS::cust_location; +use FS::cust_class; use FS::cust_main_exemption; use FS::cust_tax_adjustment; use FS::tax_rate; @@ -1537,6 +1538,7 @@ sub check { || $self->ut_number('agentnum') || $self->ut_textn('agent_custid') || $self->ut_number('refnum') + || $self->ut_foreign_keyn('classnum', 'cust_class', 'classnum') || $self->ut_textn('custbatch') || $self->ut_name('last') || $self->ut_name('first') @@ -2305,6 +2307,53 @@ sub agent { qsearchs( 'agent', { 'agentnum' => $self->agentnum } ); } +=item cust_class + +Returns the customer class, as an FS::cust_class object, or the empty string +if there is no customer class. + +=cut + +sub cust_class { + my $self = shift; + if ( $self->classnum ) { + qsearchs('cust_class', { 'classnum' => $self->classnum } ); + } else { + return ''; + } +} + +=item categoryname + +Returns the customer category name, or the empty string if there is no customer +category. + +=cut + +sub categoryname { + my $self = shift; + my $cust_class = $self->cust_class; + $cust_class + ? $cust_class->categoryname + : ''; +} + +=item classname + +Returns the customer class name, or the empty string if there is no customer +class. + +=cut + +sub classname { + my $self = shift; + my $cust_class = $self->cust_class; + $cust_class + ? $cust_class->classname + : ''; +} + + =item bill_and_collect Cancels and suspends any packages due, generates bills, applies payments and @@ -2479,7 +2528,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 @@ -3175,15 +3224,24 @@ sub _handle_taxes { $taxhash{'taxclass'} = $part_pkg->taxclass; - my @taxes = qsearch( 'cust_main_county', \%taxhash ); - + my @taxes = (); my %taxhash_elim = %taxhash; + my @elim = qw( city county state ); + do { - my @elim = qw( taxclass city county state ); - while ( !scalar(@taxes) && scalar(@elim) ) { - $taxhash_elim{ shift(@elim) } = ''; + #first try a match with taxclass @taxes = qsearch( 'cust_main_county', \%taxhash_elim ); - } + + if ( !scalar(@taxes) && $taxhash_elim{'taxclass'} ) { + #then try a match without taxclass + my %no_taxclass = %taxhash_elim; + $no_taxclass{ 'taxclass' } = ''; + @taxes = qsearch( 'cust_main_county', \%no_taxclass ); + } + + $taxhash_elim{ shift(@elim) } = ''; + + } while ( !scalar(@taxes) && scalar(@elim) ); @taxes = grep { ! $_->taxname or ! $self->tax_exemption($_->taxname) } @taxes @@ -3905,7 +3963,8 @@ I, I and I are also available. Any of these options, if set, will override the value from the customer record. I is a free-text field passed to the gateway. It defaults to -"Internet services". +the value defined by the business-onlinepayment-description configuration +option, or "Internet services" if that is unset. If an I is specified, this payment (if successful) is applied to the specified invoice. If you don't specify an I you might want to @@ -3945,7 +4004,17 @@ sub realtime_bop { warn " $_ => $options{$_}\n" foreach keys %options; } - $options{'description'} ||= 'Internet services'; + unless ( $options{'description'} ) { + if ( $conf->exists('business-onlinepayment-description') ) { + my $dtempl = $conf->config('business-onlinepayment-description'); + + my $agent = $self->agent->agent; + #$pkgs... not here + $options{'description'} = eval qq("$dtempl"); + } else { + $options{'description'} = 'Internet services'; + } + } return $self->fake_bop($method, $amount, %options) if $options{'fake'}; @@ -4705,6 +4774,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 ) { @@ -4901,7 +4973,8 @@ I, I and I are also available. Any of these options, if set, will override the value from the customer record. I is a free-text field passed to the gateway. It defaults to -"Internet services". +the value defined by the business-onlinepayment-description configuration +option, or "Internet services" if that is unset. If an I is specified, this payment (if successful) is applied to the specified invoice. If you don't specify an I you might want to @@ -4955,7 +5028,8 @@ I, I and I are also available. Any of these options, if set, will override the value from the customer record. I is a free-text field passed to the gateway. It defaults to -"Internet services". +the value defined by the business-onlinepayment-description configuration +option, or "Internet services" if that is unset. If an I is specified, this payment (if successful) is applied to the specified invoice. If you don't specify an I you might want to @@ -5006,7 +5080,18 @@ sub _bop_options { sub _bop_defaults { my ($self, $options) = @_; - $options->{description} ||= 'Internet services'; + unless ( $options->{'description'} ) { + if ( $conf->exists('business-onlinepayment-description') ) { + my $dtempl = $conf->config('business-onlinepayment-description'); + + my $agent = $self->agent->agent; + #$pkgs... not here + $options->{'description'} = eval qq("$dtempl"); + } else { + $options->{'description'} = 'Internet services'; + } + } + $options->{payinfo} = $self->payinfo unless exists( $options->{payinfo} ); $options->{invnum} ||= ''; $options->{payname} = $self->payname unless exists( $options->{payname} ); @@ -6030,6 +6115,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 ) { @@ -8176,7 +8264,7 @@ sub _money_table_where { } -=item search_sql HASHREF +=item search HASHREF (Class method) @@ -8201,6 +8289,10 @@ listref of start date, end date listref +=item paydate_year + +=item paydate_month + =item current_balance listref (list returned by FS::UI::Web::parse_lt_gt($cgi, 'current_balance')) @@ -8215,7 +8307,7 @@ bool =cut -sub search_sql { +sub search { my ($class, $params) = @_; my $dbh = dbh; @@ -8279,6 +8371,21 @@ 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 + ). + ' )'; + } + + ### # payby ### @@ -8287,15 +8394,57 @@ sub search_sql { push @where, '( '. join(' OR ', map "cust_main.payby = '$_'", @payby). ' )'; } + ### + # paydate_year / paydate_month + ### + + if ( $params->{'paydate_year'} =~ /^(\d{4})$/ ) { + my $year = $1; + $params->{'paydate_month'} =~ /^(\d\d?)$/ + or die "paydate_year without paydate_month?"; + my $month = $1; + + push @where, + 'paydate IS NOT NULL', + "paydate != ''", + "CAST(paydate AS timestamp) < CAST('$year-$month-01' AS timestamp )" +; + } + + ### + # 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(); - push @where, map { s/current_balance/$balance_sql/; $_ } - @{ $params->{'current_balance'} }; + my @current_balance = + ref( $params->{'current_balance'} ) + ? @{ $params->{'current_balance'} } + : ( $params->{'current_balance'} ); + + push @where, map { s/current_balance/$balance_sql/; $_ } + @current_balance; + + } ## # custbatch @@ -8373,13 +8522,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 @@ -8413,7 +8562,7 @@ retrying everything. =cut -sub email_search_sql { +sub email_search_result { my($class, $params) = @_; my $from = delete $params->{from}; @@ -8426,7 +8575,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) @@ -8478,7 +8627,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; @@ -8490,7 +8639,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; } @@ -8674,17 +8823,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, + ), } ); } @@ -8765,7 +8918,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