qsearch('cust_location', { 'custnum' => $self->custnum } );
}
-=item location_label_short
+=item location_label [ OPTION => VALUE ... ]
-Returns the short label of the service location (see analog in L<FS::cust_location>) for this customer.
+Returns the label of the service location (see analog in L<FS::cust_location>) for this customer.
+
+Options are
+
+=over 4
+
+=item join_string
+
+used to separate the address elements (defaults to ', ')
+
+=item escape_function
+
+a callback used for escaping the text of the address elements
+
+=back
=cut
-# false laziness with FS::cust_location::line_short
+# false laziness with FS::cust_location::line
-sub location_label_short {
+sub location_label {
my $self = shift;
+ my %opt = @_;
+
+ my $separator = $opt{join_string} || ', ';
+ my $escape = $opt{escape_function} || sub{ shift };
+ my $line = '';
my $cydefault = FS::conf->new->config('countrydefault') || 'US';
+ my $prefix = length($self->ship_last) ? 'ship_' : '';
- 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;
+ my $notfirst = 0;
+ foreach (qw ( address1 address2 ) ) {
+ my $method = "$prefix$_";
+ $line .= ($notfirst ? $separator : ''). &$escape($self->$method)
+ if $self->$method;
+ $notfirst++;
+ }
+ $notfirst = 0;
+ foreach (qw ( city county state zip ) ) {
+ my $method = "$prefix$_";
+ if ( $self->$method ) {
+ $line .= ' (' if $method eq 'county';
+ $line .= ($notfirst ? ' ' : $separator). &$escape($self->$method);
+ $line .= ' )' if $method eq 'county';
+ $notfirst++;
+ }
+ }
+ $line .= $separator. &$escape(code2country($self->country))
+ if $self->country ne $cydefault;
$line;
}
# This should be generalized to use config options to determine order.
sub sort_packages {
- my $locationsort = $a->locationnum <=> $b->locationnum;
+ my $locationsort = ( $a->locationnum || 0 ) <=> ( $b->locationnum || 0 );
return $locationsort if $locationsort;
if ( $a->get('cancel') xor $b->get('cancel') ) {
=item bill_and_collect
Cancels and suspends any packages due, generates bills, applies payments and
-cred
+credits, and applies collection events to run cards, send bills and notices,
+etc.
-Warns on errors (Does not currently: If there is an error, returns the error, otherwise returns false.)
+By default, warns on errors and continues with the next operation (but see the
+"fatal" flag below).
Options are passed as name-value pairs. Currently available options are:
If set true, re-charges setup fees.
+=item fatal
+
+If set any errors prevent subsequent operations from continusing. If set
+specifically to "return", returns the error (or false, if there is no error).
+Any other true value causes errors to die.
+
=item debug
Debugging level. Default is 0 (no debugging), or can be set to 1 (passed-in options), 2 (traces progress), 3 (more information), or 4 (include full search queries)
sub bill_and_collect {
my( $self, %options ) = @_;
+ my $error;
+
#$options{actual_time} not $options{time} because freeside-daily -d is for
#pre-printing invoices
- $self->cancel_expired_pkgs( $options{actual_time} );
- $self->suspend_adjourned_pkgs( $options{actual_time} );
- my $error = $self->bill( %options );
- warn "Error billing, custnum ". $self->custnum. ": $error" if $error;
+ $options{'actual_time'} ||= time;
- $self->apply_payments_and_credits;
+ $error = $self->cancel_expired_pkgs( $options{actual_time} );
+ if ( $error ) {
+ $error = "Error expiring custnum ". $self->custnum. ": $error";
+ if ( $options{fatal} && $options{fatal} eq 'return' ) { return $error; }
+ elsif ( $options{fatal} ) { die $error; }
+ else { warn $error; }
+ }
+
+ $error = $self->suspend_adjourned_pkgs( $options{actual_time} );
+ if ( $error ) {
+ $error = "Error adjourning custnum ". $self->custnum. ": $error";
+ if ( $options{fatal} && $options{fatal} eq 'return' ) { return $error; }
+ elsif ( $options{fatal} ) { die $error; }
+ else { warn $error; }
+ }
+
+ $error = $self->bill( %options );
+ if ( $error ) {
+ $error = "Error billing custnum ". $self->custnum. ": $error";
+ if ( $options{fatal} && $options{fatal} eq 'return' ) { return $error; }
+ elsif ( $options{fatal} ) { die $error; }
+ else { warn $error; }
+ }
+
+ $error = $self->apply_payments_and_credits;
+ if ( $error ) {
+ $error = "Error applying custnum ". $self->custnum. ": $error";
+ if ( $options{fatal} && $options{fatal} eq 'return' ) { return $error; }
+ elsif ( $options{fatal} ) { die $error; }
+ else { warn $error; }
+ }
unless ( $conf->exists('cancelled_cust-noevents')
&& ! $self->num_ncancelled_pkgs
) {
-
$error = $self->collect( %options );
- warn "Error collecting, custnum". $self->custnum. ": $error" if $error;
-
+ if ( $error ) {
+ $error = "Error collecting custnum ". $self->custnum. ": $error";
+ if ($options{fatal} && $options{fatal} eq 'return') { return $error; }
+ elsif ($options{fatal} ) { die $error; }
+ else { warn $error; }
+ }
}
+ '';
+
}
sub cancel_expired_pkgs {
- my ( $self, $time ) = @_;
+ my ( $self, $time, %options ) = @_;
my @cancel_pkgs = $self->ncancelled_pkgs( {
'extra_sql' => " AND expire IS NOT NULL AND expire > 0 AND expire <= $time "
} );
+ my @errors = ();
+
foreach my $cust_pkg ( @cancel_pkgs ) {
my $cpr = $cust_pkg->last_cust_pkg_reason('expire');
my $error = $cust_pkg->cancel($cpr ? ( 'reason' => $cpr->reasonnum,
)
: ()
);
- warn "Error cancelling expired pkg ". $cust_pkg->pkgnum.
- " for custnum ". $self->custnum. ": $error"
- if $error;
+ push @errors, 'pkgnum '.$cust_pkg->pkgnum.": $error" if $error;
}
+ scalar(@errors) ? join(' / ', @errors) : '';
+
}
sub suspend_adjourned_pkgs {
- my ( $self, $time ) = @_;
+ my ( $self, $time, %options ) = @_;
my @susp_pkgs = $self->ncancelled_pkgs( {
'extra_sql' =>
}
@susp_pkgs;
+ my @errors = ();
+
foreach my $cust_pkg ( @susp_pkgs ) {
my $cpr = $cust_pkg->last_cust_pkg_reason('adjourn')
if ($cust_pkg->adjourn && $cust_pkg->adjourn < $^T);
)
: ()
);
-
- warn "Error suspending package ". $cust_pkg->pkgnum.
- " for custnum ". $self->custnum. ": $error"
- if $error;
+ push @errors, 'pkgnum '.$cust_pkg->pkgnum.": $error" if $error;
}
+ scalar(@errors) ? join(' / ', @errors) : '';
+
}
=item bill OPTIONS
my $old_cust_pkg = new FS::cust_pkg \%hash;
my @details = ();
-
+ my @discounts = ();
my $lineitems = 0;
$cust_pkg->pkgpart($part_pkg->pkgpart);
);
my %param = ( 'precommit_hooks' => $precommit_hooks,
'increment_next_bill' => $increment_next_bill,
+ 'discounts' => \@discounts,
);
my $method = $options{cancel} ? 'calc_cancel' : 'calc_recur';
'unitrecur' => $unitrecur,
'quantity' => $cust_pkg->quantity,
'details' => \@details,
+ 'discounts' => \@discounts,
'hidden' => $part_pkg->hidden,
};
warn " invalid conditions not eliminated with condition_sql:\n".
join('', map " $_: ".$unsat{$_}."\n", keys %unsat )
- if $DEBUG; # > 1;
+ if keys %unsat && $DEBUG; # > 1;
##
# insert
warn " $_ => $options{$_}\n" foreach keys %options;
}
+ return "Amount must be greater than 0" unless $amount > 0;
+
unless ( $options{'description'} ) {
if ( $conf->exists('business-onlinepayment-description') ) {
my $dtempl = $conf->config('business-onlinepayment-description');
my $botpp = 'Business::OnlineThirdPartyPayment';
return 1
- if ( $conf->config('business-onlinepayment-namespace') eq $botpp ||
- scalar( grep { $_->gateway_namespace eq $botpp }
- qsearch( 'payment_gateway', { 'disabled' => '' } )
- )
+ if ( ( $conf->exists('business-onlinepayment-namespace')
+ && $conf->config('business-onlinepayment-namespace') eq $botpp
+ )
+ or scalar( grep { $_->gateway_namespace eq $botpp }
+ qsearch( 'payment_gateway', { 'disabled' => '' } )
+ )
)
;
? 'ship_'
: '';
- my ($zip,$plus4) = split /-/, $self->get("${prefix}zip")
+ my($zip,$plus4) = split /-/, $self->get("${prefix}zip")
if $self->country eq 'US';
+ $zip ||= '';
+ $plus4 ||= '';
#CCH specific location stuff
my $extra_sql = "AND plus4lo <= '$plus4' AND plus4hi >= '$plus4'";
(Class method)
-Returns a qsearch hash expression to search for parameters specified in HREF.
-Valid parameters are
+Returns a qsearch hash expression to search for parameters specified in
+HASHREF. Valid parameters are
=over 4