okay. counts are needed for the package sort, so push the embedded counting into...
[freeside.git] / FS / FS / cust_pkg.pm
index c671163..902b1d3 100644 (file)
@@ -2,6 +2,7 @@ package FS::cust_pkg;
 
 use strict;
 use vars qw(@ISA $disable_agentcheck $DEBUG);
+use Carp qw(cluck);
 use Scalar::Util qw( blessed );
 use List::Util qw(max);
 use Tie::IxHash;
@@ -439,9 +440,7 @@ replace methods.
 sub check {
   my $self = shift;
 
-  $self->locationnum('')
-    if defined($self->locationnum) && length($self->locationnum)
-    && ( $self->locationnum == 0 || $self->locationnum == -1 );
+  $self->locationnum('') if !$self->locationnum || $self->locationnum == -1;
 
   my $error = 
     $self->ut_numbern('pkgnum')
@@ -1137,6 +1136,21 @@ sub change {
     return "Unable to transfer all services from package ". $self->pkgnum;
   }
 
+  #reset usage if changing pkgpart
+  if ($self->pkgpart != $cust_pkg->pkgpart) {
+    my $part_pkg = $cust_pkg->part_pkg;
+    $error = $part_pkg->reset_usage($cust_pkg, $part_pkg->is_prepaid
+                                                 ? ()
+                                                 : ( 'null' => 1 )
+                                   )
+      if $part_pkg->can('reset_usage');
+
+    if ($error) {
+      $dbh->rollback if $oldAutoCommit;
+      return "Error setting usage values: $error";
+    }
+  }
+
   #Good to go, cancel old package.
   $error = $self->cancel( quiet=>1 );
   if ($error) {
@@ -1209,10 +1223,9 @@ L<FS::part_pkg>).
 
 sub part_pkg {
   my $self = shift;
-  #exists( $self->{'_pkgpart'} )
-  $self->{'_pkgpart'}
-    ? $self->{'_pkgpart'}
-    : qsearchs( 'part_pkg', { 'pkgpart' => $self->pkgpart } );
+  return $self->{'_pkgpart'} if $self->{'_pkgpart'};
+  cluck "cust_pkg->part_pkg called" if $DEBUG > 1;
+  qsearchs( 'part_pkg', { 'pkgpart' => $self->pkgpart } );
 }
 
 =item old_cust_pkg
@@ -1402,11 +1415,15 @@ services.
 sub cust_svc {
   my $self = shift;
 
+  return () unless $self->num_cust_svc(@_);
+
   if ( @_ ) {
     return qsearch( 'cust_svc', { 'pkgnum'  => $self->pkgnum,
                                   'svcpart' => shift,          } );
   }
 
+  cluck "cust_pkg->cust_svc called" if $DEBUG > 2;
+
   #if ( $self->{'_svcnum'} ) {
   #  values %{ $self->{'_svcnum'}->cache };
   #} else {
@@ -1427,7 +1444,8 @@ is specified, return only the matching services.
 
 sub overlimit {
   my $self = shift;
-  grep { $_->overlimit } $self->cust_svc;
+  return () unless $self->num_cust_svc(@_);
+  grep { $_->overlimit } $self->cust_svc(@_);
 }
 
 =item h_cust_svc END_TIMESTAMP [ START_TIMESTAMP ] 
@@ -1476,9 +1494,19 @@ specified, counts only the matching services.
 
 sub num_cust_svc {
   my $self = shift;
+
+  return $self->{'_num_cust_svc'}
+    if !scalar(@_)
+       && exists($self->{'_num_cust_svc'})
+       && $self->{'_num_cust_svc'} =~ /\d/;
+
+  cluck "cust_pkg->num_cust_svc called, _num_cust_svc:".$self->{'_num_cust_svc'}
+    if $DEBUG > 2;
+
   my $sql = 'SELECT COUNT(*) FROM cust_svc WHERE pkgnum = ?';
   $sql .= ' AND svcpart = ?' if @_;
-  my $sth = dbh->prepare($sql) or die dbh->errstr;
+
+  my $sth = dbh->prepare($sql)     or die  dbh->errstr;
   $sth->execute($self->pkgnum, @_) or die $sth->errstr;
   $sth->fetchrow_arrayref->[0];
 }
@@ -1535,7 +1563,8 @@ sub part_svc {
     $part_svc->{'Hash'}{'num_cust_svc'} = $num_cust_svc; #more evil
     $part_svc->{'Hash'}{'num_avail'}    =
       max( 0, $pkg_svc->quantity - $num_cust_svc );
-    $part_svc->{'Hash'}{'cust_pkg_svc'} = [ $self->cust_svc($part_svc->svcpart) ];
+    $part_svc->{'Hash'}{'cust_pkg_svc'} =
+      $num_cust_svc ? [ $self->cust_svc($part_svc->svcpart) ] : [];
     $part_svc;
   } $self->part_pkg->pkg_svc;
 
@@ -1545,7 +1574,8 @@ sub part_svc {
     my $num_cust_svc = $self->num_cust_svc($part_svc->svcpart);
     $part_svc->{'Hash'}{'num_cust_svc'} = $num_cust_svc; #speak no evail
     $part_svc->{'Hash'}{'num_avail'}    = 0; #0-$num_cust_svc ?
-    $part_svc->{'Hash'}{'cust_pkg_svc'} = [ $self->cust_svc($part_svc->svcpart) ];
+    $part_svc->{'Hash'}{'cust_pkg_svc'} =
+      $num_cust_svc ? [ $self->cust_svc($part_svc->svcpart) ] : [];
     $part_svc;
   } $self->extra_part_svc;
 
@@ -1567,20 +1597,38 @@ sub extra_part_svc {
   my $pkgnum  = $self->pkgnum;
   my $pkgpart = $self->pkgpart;
 
+#  qsearch( {
+#    'table'     => 'part_svc',
+#    'hashref'   => {},
+#    'extra_sql' =>
+#      "WHERE 0 = ( SELECT COUNT(*) FROM pkg_svc 
+#                     WHERE pkg_svc.svcpart = part_svc.svcpart 
+#                       AND pkg_svc.pkgpart = ?
+#                       AND quantity > 0 
+#                 )
+#       AND 0 < ( SELECT COUNT(*) FROM cust_svc
+#                       LEFT JOIN cust_pkg USING ( pkgnum )
+#                     WHERE cust_svc.svcpart = part_svc.svcpart
+#                       AND pkgnum = ?
+#                 )",
+#    'extra_param' => [ [$self->pkgpart=>'int'], [$self->pkgnum=>'int'] ],
+#  } );
+
+#seems to benchmark slightly faster...
   qsearch( {
-    'table'     => 'part_svc',
-    'hashref'   => {},
-    'extra_sql' => "WHERE 0 = ( SELECT COUNT(*) FROM pkg_svc 
-                                  WHERE pkg_svc.svcpart = part_svc.svcpart 
-                                   AND pkg_svc.pkgpart = $pkgpart
-                                   AND quantity > 0 
-                             )
-                     AND 0 < ( SELECT count(*)
-                                 FROM cust_svc
-                                   LEFT JOIN cust_pkg using ( pkgnum )
-                                 WHERE cust_svc.svcpart = part_svc.svcpart
-                                   AND pkgnum = $pkgnum
-                             )",
+    'select'      => 'DISTINCT ON (svcpart) part_svc.*',
+    'table'       => 'part_svc',
+    'addl_from'   =>
+      'LEFT JOIN pkg_svc  ON (     pkg_svc.svcpart   = part_svc.svcpart 
+                               AND pkg_svc.pkgpart   = ?
+                               AND quantity > 0
+                             )
+       LEFT JOIN cust_svc ON (     cust_svc.svcpart = part_svc.svcpart )
+       LEFT JOIN cust_pkg USING ( pkgnum )
+      ',
+    'hashref'     => {},
+    'extra_sql'   => "WHERE pkgsvcnum IS NULL AND cust_pkg.pkgnum = ? ",
+    'extra_param' => [ [$self->pkgpart=>'int'], [$self->pkgnum=>'int'] ],
   } );
 }
 
@@ -2424,6 +2472,8 @@ sub _location_sql_where {
   my $prefix = @_ ? shift : '';
   my $ornull = @_ ? shift : '';
 
+#  $ornull             = $ornull          ? " OR ( ? IS NULL AND $table.${prefix}county IS NULL ) " : '';
+
   $ornull = $ornull ? ' OR ? IS NULL ' : '';
 
   my $or_empty_county = " OR ( ? = '' AND $table.${prefix}county IS NULL ) ";
@@ -2712,11 +2762,11 @@ All svc_accts which are part of this package have their values reset.
 =cut
 
 sub set_usage {
-  my ($self, $valueref) = @_;
+  my ($self, $valueref, %opt) = @_;
 
   foreach my $cust_svc ($self->cust_svc){
     my $svc_x = $cust_svc->svc_x;
-    $svc_x->set_usage($valueref)
+    $svc_x->set_usage($valueref, %opt)
       if $svc_x->can("set_usage");
   }
 }