- web interface for hourly account charges!
[freeside.git] / FS / FS / cust_pkg.pm
index 1bcf74f..b241eca 100644 (file)
@@ -17,9 +17,31 @@ use FS::svc_acct;
 use FS::svc_acct_sm;
 use FS::svc_domain;
 use FS::svc_www;
+use FS::svc_forward;
 
 @ISA = qw( FS::Record );
 
+sub _cache {
+  my $self = shift;
+  my ( $hashref, $cache ) = @_;
+  #if ( $hashref->{'pkgpart'} ) {
+  if ( $hashref->{'pkg'} ) {
+    # #@{ $self->{'_pkgnum'} } = ();
+    # my $subcache = $cache->subcache('pkgpart', 'part_pkg');
+    # $self->{'_pkgpart'} = $subcache;
+    # #push @{ $self->{'_pkgnum'} },
+    #   FS::part_pkg->new_or_cached($hashref, $subcache);
+    $self->{'_pkgpart'} = FS::part_pkg->new($hashref);
+  }
+  if ( exists $hashref->{'svcnum'} ) {
+    #@{ $self->{'_pkgnum'} } = ();
+    my $subcache = $cache->subcache('svcnum', 'cust_svc', $hashref->{pkgnum});
+    $self->{'_svcnum'} = $subcache;
+    #push @{ $self->{'_pkgnum'} },
+    FS::cust_svc->new_or_cached($hashref, $subcache) if $hashref->{svcnum};
+  }
+}
+
 =head1 NAME
 
 FS::cust_pkg - Object methods for cust_pkg objects
@@ -49,6 +71,8 @@ FS::cust_pkg - Object methods for cust_pkg objects
 
   @labels = $record->labels;
 
+  $seconds = $record->seconds_since($timestamp);
+
   $error = FS::cust_pkg::order( $custnum, \@pkgparts );
   $error = FS::cust_pkg::order( $custnum, \@pkgparts, \@remove_pkgnums ] );
 
@@ -78,7 +102,7 @@ inherits from FS::Record.  The following fields are currently supported:
 =item otaker - order taker (assigned automatically if null, see L<FS::UID>)
 
 =item manual_flag - If this field is set to 1, disables the automatic
-unsuspensiond of this package when using the B<unsuspendauto> config file.
+unsuspension of this package when using the B<unsuspendauto> config file.
 
 =back
 
@@ -115,8 +139,7 @@ sub insert {
   my $error = $self->ut_number('custnum');
   return $error if $error;
 
-  return "Unknown customer ". $self->custnum
-    unless qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
+  return "Unknown customer ". $self->custnum unless $self->cust_main;
 
   $self->SUPER::insert;
 
@@ -124,15 +147,16 @@ sub insert {
 
 =item delete
 
-Currently unimplemented.  You don't want to delete billing items, because there
-would then be no record the customer ever purchased the item.  Instead, see
-the cancel method.
+This method now works but you probably shouldn't use it.
+
+You don't want to delete billing items, because there would then be no record
+the customer ever purchased the item.  Instead, see the cancel method.
 
 =cut
 
-sub delete {
-  return "Can't delete cust_pkg records!";
-}
+#sub delete {
+#  return "Can't delete cust_pkg records!";
+#}
 
 =item replace OLD_RECORD
 
@@ -158,9 +182,12 @@ sub replace {
 
   #return "Can't (yet?) change pkgpart!" if $old->pkgpart != $new->pkgpart;
   return "Can't change otaker!" if $old->otaker ne $new->otaker;
-  return "Can't change setup once it exists!"
-    if $old->getfield('setup') &&
-       $old->getfield('setup') != $new->getfield('setup');
+
+  #allow this *sigh*
+  #return "Can't change setup once it exists!"
+  #  if $old->getfield('setup') &&
+  #     $old->getfield('setup') != $new->getfield('setup');
+
   #some logic for bill, susp, cancel?
 
   $new->SUPER::replace($old);
@@ -189,8 +216,7 @@ sub check {
   return $error if $error;
 
   if ( $self->custnum ) { 
-    return "Unknown customer"
-      unless qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
+    return "Unknown customer ". $self->custnum unless $self->cust_main;
   }
 
   return "Unknown pkgpart"
@@ -418,7 +444,26 @@ L<FS::part_pkg>).
 
 sub part_pkg {
   my $self = shift;
-  qsearchs( 'part_pkg', { 'pkgpart' => $self->pkgpart } );
+  #exists( $self->{'_pkgpart'} )
+  $self->{'_pkgpart'}
+    ? $self->{'_pkgpart'}
+    : qsearchs( 'part_pkg', { 'pkgpart' => $self->pkgpart } );
+}
+
+=item cust_svc
+
+Returns the services for this package, as FS::cust_svc objects (see
+L<FS::cust_svc>)
+
+=cut
+
+sub cust_svc {
+  my $self = shift;
+  if ( $self->{'_svcnum'} ) {
+    values %{ $self->{'_svcnum'}->cache };
+  } else {
+    qsearch ( 'cust_svc', { 'pkgnum' => $self->pkgnum } );
+  }
 }
 
 =item labels
@@ -430,7 +475,42 @@ Returns a list of lists, calling the label method for all services
 
 sub labels {
   my $self = shift;
-  map { [ $_->label ] } qsearch ( 'cust_svc', { 'pkgnum' => $self->pkgnum } );
+  map { [ $_->label ] } $self->cust_svc;
+}
+
+=item cust_main
+
+Returns the parent customer object (see L<FS::cust_main>).
+
+=cut
+
+sub cust_main {
+  my $self = shift;
+  qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
+}
+
+=item seconds_since TIMESTAMP
+
+Returns the number of seconds all accounts (see L<FS::svc_acct>) in this
+package have been online since TIMESTAMP.
+
+TIMESTAMP is specified as a UNIX timestamp; see L<perlfunc/"time">.  Also see
+L<Time::Local> and L<Date::Parse> for conversion functions.
+
+=cut
+
+sub seconds_since {
+  my($self, $since) = @_;
+  my $seconds = 0;
+
+  foreach my $cust_svc (
+    grep { $_->part_svc->svcdb eq 'svc_acct' } $self->cust_svc
+  ) {
+    $seconds += $cust_svc->seconds_since($since);
+  }
+
+  $seconds;
+
 }
 
 =back
@@ -576,7 +656,7 @@ sub order {
 
 =head1 VERSION
 
-$Id: cust_pkg.pm,v 1.9 2001-10-09 23:10:16 ivan Exp $
+$Id: cust_pkg.pm,v 1.16 2002-01-29 16:33:15 ivan Exp $
 
 =head1 BUGS
 
@@ -598,8 +678,8 @@ moved to check ?
 
 =head1 SEE ALSO
 
-L<FS::Record>, L<FS::cust_main>, L<FS::part_pkg>, L<FS::cust_svc>
-L<FS::pkg_svc>, schema.html from the base documentation
+L<FS::Record>, L<FS::cust_main>, L<FS::part_pkg>, L<FS::cust_svc>,
+L<FS::pkg_svc>, schema.html from the base documentation
 
 =cut