X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2Fdetail_format.pm;h=46c6300ad951b358e21fb01c853767c0549f9561;hp=88cc02f83deca63a491ed3ba8980d4f67ba66424;hb=57bb423fe457ba4e13726877f53bcdf944f828f8;hpb=5665d202b0b91bb9ad685c209265b7a3405de768 diff --git a/FS/FS/detail_format.pm b/FS/FS/detail_format.pm index 88cc02f83..46c6300ad 100644 --- a/FS/FS/detail_format.pm +++ b/FS/FS/detail_format.pm @@ -5,7 +5,8 @@ use vars qw( $DEBUG ); use FS::Conf; use FS::cdr; use FS::cust_bill_pkg_detail; -use Date::Format qw(time2str); +use FS::L10N; +use Date::Language; use Text::CSV_XS; my $me = '[FS::detail_format]'; @@ -33,16 +34,22 @@ a subclass. OPTIONS may contain: -- buffer: an arrayref to store details into. This may avoid the need for - a large copy operation at the end of processing. However, since - summary formats will produce nothing until the end of processing, - C must be called after all CDRs have been appended. +- buffer: an arrayref to store details into. This may avoid the need for a +large copy operation at the end of processing. However, since summary +formats will produce nothing until the end of processing, C must be +called after all CDRs have been appended. -- inbound: a flag telling the formatter to format CDRs for display to - the receiving party, rather than the originator. In this case, the - L object will be fetched and its values used for - rated_price, rated_seconds, rated_minutes, and svcnum. This can be - changed with the C method. +- inbound: a flag telling the formatter to format CDRs for display to the +receiving party, rather than the originator. In this case, the +L object will be fetched and its values used for +rated_price, rated_seconds, rated_minutes, and svcnum. This can be changed +with the C method. + +- locale: a locale string to use for static text and date formats. This is +optional. + +- rounding: the number of decimal places to show in the amount column. This +is optional, and defaults to whatever's in the schema (which is 4). =cut @@ -58,11 +65,22 @@ sub new { die "$me error loading $class: $@" if $@; my %opt = @_; - my $self = { conf => FS::Conf->new, - csv => Text::CSV_XS->new, + my $locale = $opt{'locale'} || ''; + my $conf = FS::Conf->new({ locale => $locale }); + $locale ||= $conf->config('locale') || 'en_US'; + + my %locale_info = FS::Locales->locale_info($locale); + my $language_name = $locale_info{'name'}; + + my $self = { conf => FS::Conf->new({ locale => $locale }), + csv => Text::CSV_XS->new({ binary => 1 }), inbound => ($opt{'inbound'} ? 1 : 0), + rounding => $opt{'rounding'}, buffer => ($opt{'buffer'} || []), - }; + _lh => FS::L10N->get_handle($locale), + _dh => eval { Date::Language->new($language_name) } || + Date::Language->new() + }; bless $self, $class; } @@ -70,6 +88,8 @@ sub new { =head1 METHODS +=over 4 + =item inbound VALUE Set/get the 'inbound' flag. @@ -82,6 +102,19 @@ sub inbound { $self->{inbound}; } +=item phonenum VALUE + +Set/get the locally meaningful phone number. This is used to tag call details +for presentation on certain kinds of invoices. + +=cut + +sub phonenum { + my $self = shift; + $self->{phonenum} = shift if @_; + $self->{phonenum}; +} + =item append CDRS Takes any number of call detail records (as L objects), @@ -149,6 +182,7 @@ Takes a single CDR and returns an invoice detail to describe it. By default, this maps the following fields from the CDR: +acctid => acctid rated_price => amount rated_classnum => classnum rated_seconds => duration @@ -156,6 +190,14 @@ rated_regionname => regionname accountcode => accountcode startdate => startdate +If the formatter is in inbound mode, it will look up a C +record and use rated_price and rated_seconds from that, and acctid will be +set to null to avoid linking the CDR to the detail record for the inbound +leg of the call. + +'phonenum' is set to the internal C value set on the formatter +object. + It then calls C on the CDR to obtain a list of detail columns, formats them as a CSV string, and stores that in the 'detail' field. @@ -174,16 +216,20 @@ sub single_detail { my $object = $self->{inbound} ? $cdr->cdr_termination(1) : $cdr; my $price = $object->rated_price if $object; $price = 0 if $cdr->freesidestatus eq 'no-charge'; + $price = sprintf('%.*f', $self->{'rounding'}, $price) + if $self->{'rounding'} and length($price); FS::cust_bill_pkg_detail->new( { + 'acctid' => ($self->{inbound} ? '' : $cdr->acctid), 'amount' => $price, 'classnum' => $cdr->rated_classnum, - 'duration' => $cdr->rated_seconds, + 'duration' => $object->rated_seconds, 'regionname' => $cdr->rated_regionname, 'accountcode' => $cdr->accountcode, 'startdate' => $cdr->startdate, 'format' => 'C', 'detail' => $self->csv->string, + 'phonenum' => $self->phonenum, }); } @@ -228,6 +274,15 @@ sub money_char { $self->{money_char} ||= ($self->conf->config('money_char') || '$'); } +# localization methods + +sub time2str_local { + my $self = shift; + $self->{_dh}->time2str(@_); +} + +# header strings are now localized in FS::TemplateItem_Mixin::detail + #imitate previous behavior for now sub duration { @@ -236,13 +291,11 @@ sub duration { my $object = $self->{inbound} ? $cdr->cdr_termination(1) : $cdr; my $sec = $object->rated_seconds if $object; $sec ||= 0; - # XXX termination objects don't have rated_granularity so this may - # result in inbound CDRs being displayed as min/sec when they shouldn't. - # Should probably fix this. - if ( $cdr->rated_granularity eq '0' ) { + # termination objects now have rated_granularity. + if ( $object->rated_granularity eq '0' ) { '1 call'; } - elsif ( $cdr->rated_granularity eq '60' ) { + elsif ( $object->rated_granularity eq '60' ) { sprintf('%dm', ($sec + 59)/60); } else { @@ -256,7 +309,15 @@ sub price { my $object = $self->{inbound} ? $cdr->cdr_termination(1) : $cdr; my $price = $object->rated_price if $object; $price = '0.00' if $object->freesidestatus eq 'no-charge'; - length($price) ? $self->money_char . $price : ''; + $price = sprintf('%.*f', $self->{'rounding'}, $price) + if $self->{'rounding'}; + if (length($price)) { + $price = sprintf('%.*f', $self->{'rounding'}, $price) + if $self->{'rounding'}; + return $self->money_char . $price; + } else { + return ''; + } } 1;