package FS::usage_class; 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 NAME FS::usage_class - Object methods for usage_class records =head1 SYNOPSIS use FS::usage_class; $record = new FS::usage_class \%hash; $record = new FS::usage_class { 'column' => 'value' }; $error = $record->insert; $error = $new_record->replace($old_record); $error = $record->delete; $error = $record->check; =head1 DESCRIPTION An FS::usage_class object represents a usage class. Every rate detail (see L) has, optionally, a usage class. FS::usage_class inherits from FS::Record. The following fields are currently supported: =over 4 =item classnum Primary key (assigned automatically for new usage classes) =item classname Text name of this usage class =item disabled Disabled flag, empty or 'Y' =back =head1 METHODS =over 4 =item new HASHREF Creates a new usage class. To add the usage class to the database, see L<"insert">. Note that this stores the hash reference, not a distinct copy of the hash it points to. You can ask the object for a copy with the I method. =cut sub table { 'usage_class'; } =item insert Adds this record to the database. If there is an error, returns the error, otherwise returns false. =cut =item delete Delete this record from the database. =cut =item replace OLD_RECORD Replaces the OLD_RECORD with this one in the database. If there is an error, returns the error, otherwise returns false. =cut =item check Checks all fields to make sure this is a valid usage class. If there is an error, returns the error, otherwise returns false. Called by the insert and replace methods. =cut sub check { my $self = shift; 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_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 = ''; $suffix = ''; $separator = ''; $column = sub { my ($d,$a,$s,$w) = @_; return qq!$d!; }; } 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 = '">'; $suffix = ''; $separator = ''; $column = sub { my ($d,$a,$s,$w) = @_; return qq!$d!; }; $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!$d!; }; } 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!$d!; }; } 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; }; } sub _populate_initial_data { my ($class, %opts) = @_; foreach ("Intrastate", "Interstate", "International") { my $object = $class->new( { 'classname' => $_ } ); my $error = $object->insert; die "error inserting $class into database: $error\n" if $error; } ''; } sub _upgrade_data { my $class = shift; return $class->_populate_initial_data(@_) unless scalar( qsearch( 'usage_class', {} ) ); ''; } =back =head1 BUGS =head1 SEE ALSO L, schema.html from the base documentation. =cut 1;