1 helps alot
[freeside.git] / FS / FS / part_pkg.pm
index e53d7b8..8cfd614 100644 (file)
@@ -1,7 +1,7 @@
 package FS::part_pkg;
 
 use strict;
-use vars qw( @ISA %plans $DEBUG );
+use vars qw( @ISA %plans $DEBUG $setup_hack );
 use Carp qw(carp cluck confess);
 use Scalar::Util qw( blessed );
 use Time::Local qw( timelocal_nocheck );
@@ -22,6 +22,7 @@ use FS::part_pkg_link;
 
 @ISA = qw( FS::m2m_Common FS::option_Common );
 $DEBUG = 0;
+$setup_hack = 0;
 
 =head1 NAME
 
@@ -454,7 +455,10 @@ sub check {
                               'part_pkg_taxproduct',
                               'taxproductnum'
                              )
-    || $self->ut_agentnum_acl('agentnum', \@null_agentnum_right)
+    || ( $setup_hack
+           ? $self->ut_foreign_keyn('agentnum', 'agent', 'agentnum' )
+           : $self->ut_agentnum_acl('agentnum', \@null_agentnum_right)
+       )
     || $self->SUPER::check
   ;
   return $error if $error;
@@ -560,6 +564,18 @@ packages.
 
 =cut
 
+=item type_pkgs
+
+Returns all FS::type_pkgs objects (see L<FS::type_pkgs>) for this package
+definition.
+
+=cut
+
+sub type_pkgs {
+  my $self = shift;
+  qsearch('type_pkgs', { 'pkgpart' => $self->pkgpart } );
+}
+
 sub pkg_svc {
   my $self = shift;
 
@@ -597,25 +613,49 @@ Returns the svcpart of the primary service definition (see L<FS::part_svc>)
 associated with this package definition (see L<FS::pkg_svc>).  Returns
 false if there not a primary service definition or exactly one service
 definition with quantity 1, or if SVCDB is specified and does not match the
-svcdb of the service definition, 
+svcdb of the service definition.  SVCDB can be specified as a scalar table
+name, such as 'svc_acct', or as an arrayref of possible table names.
 
 =cut
 
 sub svcpart {
+  my $pkg_svc = shift->_primary_pkg_svc(@_);
+  $pkg_svc ? $pkg_svc->svcpart : '';
+}
+
+=item part_svc [ SVCDB ]
+
+Like the B<svcpart> method, but returns the FS::part_svc object (see
+L<FS::part_svc>).
+
+=cut
+
+sub part_svc {
+  my $pkg_svc = shift->_primary_pkg_svc(@_);
+  $pkg_svc ? $pkg_svc->part_svc : '';
+}
+
+sub _primary_pkg_svc {
   my $self = shift;
-  my $svcdb = scalar(@_) ? shift : '';
+
+  my $svcdb = scalar(@_) ? shift : [];
+  $svcdb = ref($svcdb) ? $svcdb : [ $svcdb ];
+  my %svcdb = map { $_=>1 } @$svcdb;
+
   my @svcdb_pkg_svc =
-    grep { ( $svcdb eq $_->part_svc->svcdb || !$svcdb ) } $self->pkg_svc;
+    grep { !scalar(@$svcdb) || $svcdb{ $_->part_svc->svcdb } }
+         $self->pkg_svc;
+
   my @pkg_svc = grep { $_->primary_svc =~ /^Y/i } @svcdb_pkg_svc;
   @pkg_svc = grep {$_->quantity == 1 } @svcdb_pkg_svc
     unless @pkg_svc;
   return '' if scalar(@pkg_svc) != 1;
-  $pkg_svc[0]->svcpart;
+  $pkg_svc[0];
 }
 
 =item svcpart_unique_svcdb SVCDB
 
-Returns the svcpart of the a service definition (see L<FS::part_svc>) matching
+Returns the svcpart of a service definition (see L<FS::part_svc>) matching
 SVCDB associated with this package definition (see L<FS::pkg_svc>).  Returns
 false if there not a primary service definition for SVCDB or there are multiple
 service definitions for SVCDB.
@@ -1100,10 +1140,51 @@ sub calc_remain { 0; }
 sub calc_cancel { 0; }
 sub calc_units  { 0; }
 
+#fallback for everything except bulk.pm
+sub hide_svc_detail { 0; }
+
+=item format OPTION DATA
+
+Returns data formatted according to the function 'format' described
+in the plan info.  Returns DATA if no such function exists.
+
+=cut
+
+sub format {
+  my ($self, $option, $data) = (shift, shift, shift);
+  if (exists($plans{$self->plan}->{fields}->{$option}{format})) {
+    &{$plans{$self->plan}->{fields}->{$option}{format}}($data);
+  }else{
+    $data;
+  }
+}
+
+=item parse OPTION DATA
+
+Returns data parsed according to the function 'parse' described
+in the plan info.  Returns DATA if no such function exists.
+
+=cut
+
+sub parse {
+  my ($self, $option, $data) = (shift, shift, shift);
+  if (exists($plans{$self->plan}->{fields}->{$option}{parse})) {
+    &{$plans{$self->plan}->{fields}->{$option}{parse}}($data);
+  }else{
+    $data;
+  }
+}
+
 =back
 
 =cut
 
+=head1 CLASS METHODS
+
+=over 4
+
+=cut
+
 # _upgrade_data
 #
 # Used by FS::Upgrade to migrate to a new database.
@@ -1170,6 +1251,59 @@ sub _upgrade_data { # class method
 
 }
 
+=item curuser_pkgs_sql
+
+Returns an SQL fragment for searching for packages the current user can
+use, either via part_pkg.agentnum directly, or via agent type (see
+L<FS::type_pkgs>).
+
+=cut
+
+sub curuser_pkgs_sql {
+  my $class = shift;
+
+  $class->_pkgs_sql( $FS::CurrentUser::CurrentUser->agentnums );
+
+}
+
+=item agent_pkgs_sql AGENT | AGENTNUM, ...
+
+Returns an SQL fragment for searching for packages the provided agent or agents
+can use, either via part_pkg.agentnum directly, or via agent type (see
+L<FS::type_pkgs>).
+
+=cut
+
+sub agent_pkgs_sql {
+  my $class = shift;  #i'm a class method, not a sub (the question is... why??)
+  my @agentnums = map { ref($_) ? $_->agentnum : $_ } @_;
+
+  $class->_pkgs_sql(@agentnums); #is this why
+
+}
+
+sub _pkgs_sql {
+  my( $class, @agentnums ) = @_;
+  my $agentnums = join(',', @agentnums);
+
+  "
+    (
+      agentnum IS NOT NULL
+      OR
+      0 < ( SELECT COUNT(*)
+              FROM type_pkgs
+                LEFT JOIN agent_type USING ( typenum )
+                LEFT JOIN agent AS typeagent USING ( typenum )
+              WHERE type_pkgs.pkgpart = part_pkg.pkgpart
+                AND typeagent.agentnum IN ($agentnums)
+          )
+    )
+  ";
+
+}
+
+=back
+
 =head1 SUBROUTINES
 
 =over 4
@@ -1217,38 +1351,6 @@ sub plan_info {
   \%plans;
 }
 
-=item format OPTION DATA
-
-Returns data formatted according to the function 'format' described
-in the plan info.  Returns DATA if no such function exists.
-
-=cut
-
-sub format {
-  my ($self, $option, $data) = (shift, shift, shift);
-  if (exists($plans{$self->plan}->{fields}->{$option}{format})) {
-    &{$plans{$self->plan}->{fields}->{$option}{format}}($data);
-  }else{
-    $data;
-  }
-}
-
-=item parse OPTION DATA
-
-Returns data parsed according to the function 'parse' described
-in the plan info.  Returns DATA if no such function exists.
-
-=cut
-
-sub parse {
-  my ($self, $option, $data) = (shift, shift, shift);
-  if (exists($plans{$self->plan}->{fields}->{$option}{parse})) {
-    &{$plans{$self->plan}->{fields}->{$option}{parse}}($data);
-  }else{
-    $data;
-  }
-}
-
 
 =back