non-blocking upgrade for part_pkg, #29155
[freeside.git] / FS / FS / detail_format.pm
index af97f36..c90d313 100644 (file)
@@ -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,19 @@ 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<finish> 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<finish> 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<FS::cdr_termination> object will be fetched and its values used for
-  rated_price, rated_seconds, rated_minutes, and svcnum.  This can be 
-  changed with the C<inbound> 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<FS::cdr_termination> object will be fetched and its values used for
+rated_price, rated_seconds, rated_minutes, and svcnum.  This can be changed
+with the C<inbound> method.
+
+- locale: a locale string to use for static text and date formats.  This is
+optional.
 
 =cut
 
@@ -58,11 +62,21 @@ 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),
                buffer   => ($opt{'buffer'} || []),
-             }; 
+               _lh      => FS::L10N->get_handle($locale),
+               _dh      => eval { Date::Language->new($language_name) } ||
+                           Date::Language->new()
+             };
   bless $self, $class;
 }
 
@@ -70,6 +84,8 @@ sub new {
 
 =head1 METHODS
 
+=over 4
+
 =item inbound VALUE
 
 Set/get the 'inbound' flag.
@@ -139,7 +155,7 @@ sub header {
   my $self = shift;
 
   FS::cust_bill_pkg_detail->new(
-    { 'format' => 'C', 'detail' => $self->header_detail }
+    { 'format' => 'C', 'detail' => $self->mt($self->header_detail) }
   )
 }
 
@@ -149,12 +165,21 @@ Takes a single CDR and returns an invoice detail to describe it.
 
 By default, this maps the following fields from the CDR:
 
-rated_price       => amount
-rated_classnum    => classnum
-rated_seconds     => duration
-rated_regionname  => regionname
-accountcode       => accountcode
-startdate         => startdate
+=over 4
+
+=item rated_price       => amount
+
+=item rated_classnum    => classnum
+
+=item rated_seconds     => duration
+
+=item rated_regionname  => regionname
+
+=item accountcode       => accountcode
+
+=item startdate         => startdate
+
+=back
 
 It then calls C<columns> on the CDR to obtain a list of detail
 columns, formats them as a CSV string, and stores that in the 
@@ -171,11 +196,12 @@ sub single_detail {
   die "$me error combining ".$self->csv->error_input."\n"
     if !$status;
 
-  my $rated_price = $cdr->rated_price;
-  $rated_price = 0 if $cdr->freesidestatus eq 'no-charge';
+  my $object = $self->{inbound} ? $cdr->cdr_termination(1) : $cdr;
+  my $price = $object->rated_price if $object;
+  $price = 0 if $cdr->freesidestatus eq 'no-charge';
 
   FS::cust_bill_pkg_detail->new( {
-      'amount'      => $rated_price,
+      'amount'      => $price,
       'classnum'    => $cdr->rated_classnum,
       'duration'    => $cdr->rated_seconds,
       'regionname'  => $cdr->rated_regionname,
@@ -227,6 +253,18 @@ sub money_char {
   $self->{money_char} ||= ($self->conf->config('money_char') || '$');
 }
 
+# localization methods
+
+sub time2str_local {
+  my $self = shift;
+  $self->{_dh}->time2str(@_);
+}
+
+sub mt {
+  my $self = shift;
+  $self->{_lh}->maketext(@_);
+}
+
 #imitate previous behavior for now
 
 sub duration {
@@ -234,6 +272,7 @@ sub duration {
   my $cdr = shift;
   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.