use strict;
use vars qw( @ISA );
use FS::Record qw( qsearch qsearchs );
+use FS::Conf;
+
+my $conf = new FS::Conf;
@ISA = qw(FS::Record);
=head1 DESCRIPTION
An FS::usage_class object represents a usage class. Every rate detail
-(see L<FS::rate_detail) has, optionally, a usage class. FS::usage_class
+(see L<FS::rate_detail>) has, optionally, a usage class. FS::usage_class
inherits from FS::Record. The following fields are currently supported:
=over 4
my $error =
$self->ut_numbern('classnum')
+ || $self->ut_numbern('weight')
|| $self->ut_text('classname')
+ || $self->ut_textn('format')
|| $self->ut_enum('disabled', [ '', 'Y' ])
;
return $error if $error;
$self->SUPER::check;
}
+=item summary_formats_labelhash
+
+Returns a list of line item format descriptions suitable for assigning to
+a hash.
+
+=cut
+
+# transform hashes of arrays to arrays of hashes for false laziness removal?
+my %summary_formats = (
+ 'simple' => {
+ 'label' => [ qw( Description Calls Minutes Amount ) ],
+ 'fields' => [
+ sub { shift->{description} },
+ sub { shift->{calls} },
+ sub { sprintf( '%.1f', shift->{duration}/60 ) },
+ sub { my($href, %opt) = @_;
+ ($opt{dollar} || ''). $href->{amount};
+ },
+ ],
+ 'align' => [ qw( l r r r ) ],
+ 'span' => [ qw( 4 1 1 1 ) ], # unitprices?
+ 'width' => [ qw( 8.2cm 2.5cm 1.4cm 1.6cm ) ], # don't like this
+ 'show' => 1,
+ },
+ 'simpler' => {
+ 'label' => [ qw( Description Calls Amount ) ],
+ 'fields' => [
+ sub { shift->{description} },
+ sub { shift->{calls} },
+ sub { my($href, %opt) = @_;
+ ($opt{dollar} || ''). $href->{amount};
+ },
+ ],
+ 'align' => [ qw( l r r ) ],
+ 'span' => [ qw( 5 1 1 ) ],
+ 'width' => [ qw( 10.7cm 1.4cm 1.6cm ) ], # don't like this
+ 'show' => 1,
+ },
+ 'usage_simple' => {
+ 'label' => [ qw( Date Time Number Destination Duration Amount ) ],
+ 'fields' => [
+ sub { ' ' },
+ sub { ' ' },
+ sub { ' ' },
+ sub { ' ' },
+ sub { ' ' },
+ sub { my $href = shift; #ugh! making bunk of 'normalization'
+ $href->{subtotal} ? $href->{subtotal} : ' '
+ },
+ ],
+ 'align' => [ qw( l l l l r r ) ],
+ 'span' => [ qw( 1 1 1 1 1 2 ) ], # unitprices?
+ 'width' => [ qw( 4.3cm 1.4cm 2.5cm 2.5cm 1.4cm 1.6cm ) ],# don't like this
+ 'show' => 0,
+ },
+ 'usage_6col' => {
+ 'label' => [ qw( col1 col2 col3 col4 col5 col6 ) ],
+ 'fields' => [
+ sub { ' ' },
+ sub { ' ' },
+ sub { ' ' },
+ sub { ' ' },
+ sub { ' ' },
+ sub { my $href = shift; #ugh! making bunk of 'normalization'
+ $href->{subtotal} ? $href->{subtotal} : ' '
+ },
+ ],
+ 'align' => [ qw( l l l l r r ) ],
+ 'span' => [ qw( 1 1 1 1 1 2 ) ], # unitprices?
+ 'width' => [ qw( 4.3cm 1.4cm 2.5cm 2.5cm 1.4cm 1.6cm ) ],# don't like this
+ 'show' => 0,
+ },
+ 'usage_4col' => {
+ 'label' => [ qw( col1 col2 col3 col4 ) ],
+ 'fields' => [
+ sub { ' ' },
+ sub { ' ' },
+ sub { ' ' },
+ sub { ' ' },
+ ],
+ 'align' => [ qw( l l l l r r ) ],
+ 'span' => [ qw( 1 1 1 1 1 2 ) ],
+ 'width' => [ qw( 4.3cm 1.4cm 2.5cm 2.5cm ) ],
+ 'show' => 0,
+ },
+ 'usage_7col' => {
+ 'label' => [ qw( col1 col2 col3 col4 col5 col6 col7 ) ],
+ 'fields' => [
+ sub { ' ' },
+ sub { ' ' },
+ sub { ' ' },
+ sub { ' ' },
+ sub { ' ' },
+ sub { ' ' },
+ sub { my $href = shift; #ugh! making bunk of 'normalization'
+ $href->{subtotal} ? $href->{subtotal} : ' '
+ },
+ ],
+ 'align' => [ qw( l l l l l r r ) ],
+ 'span' => [ qw( 1 1 1 1 1 1 1 ) ], # unitprices?
+ 'width' => [ qw( 2.9cm 1.4cm 1.4cm 2.5cm 2.5cm 1.4cm 1.6cm ) ],# don't like this
+ 'show' => 0,
+ },
+);
+
+sub summary_formats_labelhash {
+ map { $_ => join(',', @{$summary_formats{$_}{label}}) }
+ grep { $summary_formats{$_}{show} }
+ keys %summary_formats;
+}
+
+=item header_generator FORMAT
+
+Returns a coderef used for generation of an invoice line item header for this
+usage_class. FORMAT is either html or latex
+
+=cut
+
+my %html_align = (
+ 'c' => 'center',
+ 'l' => 'left',
+ 'r' => 'right',
+);
+
+sub _generator_defaults {
+ my ( $self, $format, %opt ) = @_;
+ my %format = ( %{ $summary_formats{$self->format} }, %opt );
+ return ( \%format, ' ', ' ', ' ', sub { shift } );
+}
+
+sub header_generator {
+ my ( $self, $format, %opt ) = @_;
+
+ my ( $f, $prefix, $suffix, $separator, $column ) =
+ $self->_generator_defaults($format, %opt);
+
+ if ($format eq 'latex') {
+ $prefix = "\\hline\n\\rule{0pt}{2.5ex}\n\\makebox[1.4cm]{}&\n";
+ $suffix = "\\\\\n\\hline";
+ $separator = "&\n";
+ $column =
+ sub { my ($d,$a,$s,$w) = @_;
+ return "\\multicolumn{$s}{$a}{\\makebox[$w][$a]{\\textbf{$d}}}";
+ };
+ } elsif ( $format eq 'html' ) {
+ $prefix = '<th></th>';
+ $suffix = '';
+ $separator = '';
+ $column =
+ sub { my ($d,$a,$s,$w) = @_;
+ return qq!<th align="$html_align{$a}">$d</th>!;
+ };
+ }
+
+ sub {
+ my @args = @_;
+ my @result = ();
+
+ foreach (my $i = 0; exists($f->{label}->[$i]); $i++) {
+ push @result,
+ &{$column}( map { $f->{$_}->[$i] } qw(label align span width) );
+ }
+
+ $prefix. join($separator, @result). $suffix;
+ };
+
+}
+
+=item description_generator FORMAT
+
+Returns a coderef used for generation of invoice line items for this
+usage_class. FORMAT is either html or latex
+
+=cut
+
+sub description_generator {
+ my ( $self, $format, %opt ) = @_;
+
+ my ( $f, $prefix, $suffix, $separator, $column ) =
+ $self->_generator_defaults($format, %opt);
+
+ my $money_char = '$';
+ if ($format eq 'latex') {
+ $prefix = "\\hline\n\\multicolumn{1}{c}{\\rule{0pt}{2.5ex}~} &\n";
+ $suffix = '\\\\';
+ $separator = " & \n";
+ $column =
+ sub { my ($d,$a,$s,$w) = @_;
+ return "\\multicolumn{$s}{$a}{\\makebox[$w][$a]{\\textbf{$d}}}";
+ };
+ $money_char = '\\dollar';
+ }elsif ( $format eq 'html' ) {
+ $prefix = '"><td align="center"></td>';
+ $suffix = '';
+ $separator = '';
+ $column =
+ sub { my ($d,$a,$s,$w) = @_;
+ return qq!<td align="$html_align{$a}">$d</td>!;
+ };
+ $money_char = $conf->config('money_char') || '$';
+ }
+
+ sub {
+ #my @args = @_;
+ my ($href) = shift;
+ my @result = ();
+
+ foreach (my $i = 0; $f->{label}->[$i]; $i++) {
+ my $dollar = '';
+ $dollar = $money_char if $i == scalar(@{$f->{label}})-1;
+ push @result,
+ &{$column}( &{$f->{fields}->[$i]}($href, 'dollar' => $dollar),
+ map { $f->{$_}->[$i] } qw(align span width)
+ );
+ }
+
+ $prefix. join( $separator, @result ). $suffix;
+ };
+
+}
+
+=item total_generator FORMAT
+
+Returns a coderef used for generation of invoice total lines for this
+usage_class. FORMAT is either html or latex
+
+=cut
+
+sub total_generator {
+ my ( $self, $format, %opt ) = @_;
+
+# $OUT .= '\FStotaldesc{' . $section->{'description'} . ' Total}' .
+# '{' . $section->{'subtotal'} . '}' . "\n";
+
+ my ( $f, $prefix, $suffix, $separator, $column ) =
+ $self->_generator_defaults($format, %opt);
+ my $style = '';
+
+ if ($format eq 'latex') {
+ $prefix = "& ";
+ $suffix = "\\\\\n";
+ $separator = " & \n";
+ $column =
+ sub { my ($d,$a,$s,$w) = @_;
+ return "\\multicolumn{$s}{$a}{\\makebox[$w][$a]{$d}}";
+ };
+ }elsif ( $format eq 'html' ) {
+ $prefix = '';
+ $suffix = '';
+ $separator = '';
+ $style = 'border-top: 3px solid #000000;border-bottom: 3px solid #000000;';
+ $column =
+ sub { my ($d,$a,$s,$w) = @_;
+ return qq!<td align="$html_align{$a}" style="$style">$d</td>!;
+ };
+ }
+
+
+ sub {
+ my @args = @_;
+ my @result = ();
+
+ # my $r = &{$f->{fields}->[$i]}(@args);
+ # $r .= ' Total' unless $i;
+
+ foreach (my $i = 0; $f->{label}->[$i]; $i++) {
+ push @result,
+ &{$column}( &{$f->{fields}->[$i]}(@args). ($i ? '' : ' Total'),
+ map { $f->{$_}->[$i] } qw(align span width)
+ );
+ }
+
+ $prefix. join( $separator, @result ). $suffix;
+ };
+
+}
+
+=item total_line_generator FORMAT
+
+Returns a coderef used for generation of invoice total line items for this
+usage_class. FORMAT is either html or latex
+
+=cut
+
+# not used: will have issues with hash element names (description vs
+# total_item and amount vs total_amount -- another array of functions?
+
+sub total_line_generator {
+ my ( $self, $format, %opt ) = @_;
+
+# $OUT .= '\FStotaldesc{' . $line->{'total_item'} . '}' .
+# '{' . $line->{'total_amount'} . '}' . "\n";
+
+ my ( $f, $prefix, $suffix, $separator, $column ) =
+ $self->_generator_defaults($format, %opt);
+ my $style = '';
+
+ if ($format eq 'latex') {
+ $prefix = "& ";
+ $suffix = "\\\\\n";
+ $separator = " & \n";
+ $column =
+ sub { my ($d,$a,$s,$w) = @_;
+ return "\\multicolumn{$s}{$a}{\\makebox[$w][$a]{$d}}";
+ };
+ }elsif ( $format eq 'html' ) {
+ $prefix = '';
+ $suffix = '';
+ $separator = '';
+ $style = 'border-top: 3px solid #000000;border-bottom: 3px solid #000000;';
+ $column =
+ sub { my ($d,$a,$s,$w) = @_;
+ return qq!<td align="$html_align{$a}" style="$style">$d</td>!;
+ };
+ }
+
+
+ sub {
+ my @args = @_;
+ my @result = ();
+
+ foreach (my $i = 0; $f->{label}->[$i]; $i++) {
+ push @result,
+ &{$column}( &{$f->{fields}->[$i]}(@args),
+ map { $f->{$_}->[$i] } qw(align span width)
+ );
+ }
+
+ $prefix. join( $separator, @result ). $suffix;
+ };
+
+}
+
+# Used by FS::Setup to initialize a new database.
sub _populate_initial_data {
my ($class, %opts) = @_;
}
+# Used by FS::Upgrade to migrate to a new database.
sub _upgrade_data {
my $class = shift;