package FS::svc_acct;
use strict;
-use base qw( FS::svc_Domain_Mixin FS::svc_CGP_Mixin FS::svc_CGPRule_Mixin
- FS::svc_Common );
+use base qw( FS::svc_Domain_Mixin
+ FS::svc_CGP_Mixin
+ FS::svc_CGPRule_Mixin
+ FS::svc_Radius_Mixin
+ FS::svc_Tower_Mixin
+ FS::svc_IP_Mixin
+ FS::Password_Mixin
+ FS::svc_Common
+ );
+
+use strict;
use vars qw( $DEBUG $me $conf $skip_fuzzyfiles
$dir_prefix @shells $usernamemin
$usernamemax $passwordmin $passwordmax
$username_noperiod $username_nounderscore $username_nodash
$username_uppercase $username_percent $username_colon
$username_slash $username_equals $username_pound
+ $username_exclamation
$password_noampersand $password_noexclamation
$warning_template $warning_from $warning_subject $warning_mimetype
$warning_cc
use Fcntl qw(:flock);
use Date::Format;
use Crypt::PasswdMD5 1.2;
-use Digest::SHA1 'sha1_base64';
+use Digest::SHA 'sha1_base64';
use Digest::MD5 'md5_base64';
use Data::Dumper;
use Text::Template;
use FS::Msgcat qw(gettext);
use FS::UI::bytecount;
use FS::UI::Web;
+use FS::PagedSearch qw( psearch ); # XXX in v4, replace with FS::Cursor
use FS::part_pkg;
use FS::part_svc;
use FS::svc_acct_pop;
use FS::svc_www;
use FS::cdr;
use FS::acct_snarf;
+use FS::tower_sector;
$DEBUG = 0;
$me = '[FS::svc_acct]';
$username_slash = $conf->exists('username-slash');
$username_equals = $conf->exists('username-equals');
$username_pound = $conf->exists('username-pound');
+ $username_exclamation = $conf->exists('username-exclamation');
$password_noampersand = $conf->exists('password-noexclamation');
$password_noexclamation = $conf->exists('password-noexclamation');
$dirhash = $conf->config('dirhash') || 0;
$smtpmachine = $conf->config('smtpmachine');
$radius_password = $conf->config('radius-password') || 'Password';
$radius_ip = $conf->config('radius-ip') || 'Framed-IP-Address';
- @pw_set = ( 'A'..'Z' ) if $conf->exists('password-generated-allcaps');
+ @pw_set = FS::svc_acct->pw_set;
}
);
@saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' );
-@pw_set = ( 'a'..'z', 'A'..'Z', '0'..'9', '(', ')', '#', '.', ',' );
sub _cache {
my $self = shift;
'sorts' => [ 'username', 'uid', 'seconds', 'last_login' ],
'display_weight' => 10,
'cancel_weight' => 50,
+ 'ip_field' => 'slipip',
+ 'manual_require' => 1,
'fields' => {
'dir' => 'Home directory',
'uid' => {
disable_default => 1,
disable_fixed => 1,
disable_select => 1,
+ required => 1,
},
'password_selfchange' => { label => 'Password modification',
type => 'checkbox',
label => 'Quota', #Mail storage limit
type => 'text',
disable_inventory => 1,
- disable_select => 1,
},
'file_quota'=> {
label => 'File storage limit',
type => 'text',
disable_inventory => 1,
- disable_select => 1,
},
'file_maxnum'=> {
label => 'Number of files limit',
type => 'text',
disable_inventory => 1,
- disable_select => 1,
},
'file_maxsize'=> {
label => 'File size limit',
type => 'text',
disable_inventory => 1,
- disable_select => 1,
},
- '_password' => 'Password',
+ '_password' => { label => 'Password',
+ #required => 1
+ },
'gid' => {
label => 'GID',
def_info => 'when blank, defaults to UID',
'domsvc' => {
label => 'Domain',
type => 'select',
+ select_svc => 1,
select_table => 'svc_domain',
select_key => 'svcnum',
select_label => 'domain',
disable_inventory => 1,
+ required => 1,
},
'pbxsvc' => { label => 'PBX',
type => 'select-svc_pbx.html',
disable_inventory => 1,
disable_select => 1, #UI wonky, pry works otherwise
},
+ 'sectornum' => 'Tower sector',
'usergroup' => {
label => 'RADIUS groups',
type => 'select-radius_group.html',
disable_inventory => 1,
disable_select => 1,
+ multiple => 1,
},
'seconds' => { label => 'Seconds',
label_sort => 'with Time Remaining',
sub table_dupcheck_fields { ( 'username', 'domsvc' ); }
-sub _fieldhandlers {
- {
- #false laziness with edit/svc_acct.cgi
- 'usergroup' => sub {
- my( $self, $groups ) = @_;
- if ( ref($groups) eq 'ARRAY' ) {
- $groups;
- } elsif ( length($groups) ) {
- [ split(/\s*,\s*/, $groups) ];
- } else {
- [];
- }
- },
- };
-}
-
sub last_login {
shift->_lastlog('in', @_);
}
my $dbh = dbh;
my @jobnums;
- my $error = $self->SUPER::insert(
+ my $error = $self->SUPER::insert( # usergroup is here
'jobnums' => \@jobnums,
'child_objects' => $self->child_objects,
%options,
);
+
+ $error ||= $self->insert_password_history;
+
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
return $error;
}
- if ( $self->usergroup ) {
- foreach my $groupnum ( @{$self->usergroup} ) {
- my $radius_usergroup = new FS::radius_usergroup ( {
- svcnum => $self->svcnum,
- groupnum => $groupnum,
- } );
- my $error = $radius_usergroup->insert;
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return $error;
- }
- }
- }
-
unless ( $skip_fuzzyfiles ) {
$error = $self->queue_fuzzyfiles_update;
if ( $error ) {
}
}
- my $error = $self->SUPER::delete;
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return $error;
- }
-
- foreach my $radius_usergroup (
- qsearch('radius_usergroup', { 'svcnum' => $self->svcnum } )
+ foreach my $svc_phone (
+ qsearch( 'svc_phone', { 'forward_svcnum' => $self->svcnum })
) {
- my $error = $radius_usergroup->delete;
+ $svc_phone->set('forward_svcnum', '');
+ my $error = $svc_phone->replace;
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
return $error;
}
}
+ my $error = $self->delete_password_history
+ || $self->SUPER::delete; # usergroup here
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
'';
}
local $FS::UID::AutoCommit = 0;
my $dbh = dbh;
- # redundant, but so $new->usergroup gets set
- $error = $new->check;
- return $error if $error;
-
- $old->usergroup( [ $old->radius_groups('NUMBERS') ] );
- if ( $DEBUG ) {
- warn $old->email. " old groups: ". join(' ',@{$old->usergroup}). "\n";
- warn $new->email. " new groups: ". join(' ',@{$new->usergroup}). "\n";
- }
- if ( $new->usergroup ) {
- #(sorta) false laziness with FS::part_export::sqlradius::_export_replace
- my @newgroups = @{$new->usergroup};
- foreach my $oldgroup ( @{$old->usergroup} ) {
- if ( grep { $oldgroup eq $_ } @newgroups ) {
- @newgroups = grep { $oldgroup ne $_ } @newgroups;
- next;
- }
- my $radius_usergroup = qsearchs('radius_usergroup', {
- svcnum => $old->svcnum,
- groupnum => $oldgroup,
- } );
- my $error = $radius_usergroup->delete;
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return "error deleting radius_usergroup $oldgroup: $error";
- }
- }
-
- foreach my $newgroup ( @newgroups ) {
- my $radius_usergroup = new FS::radius_usergroup ( {
- svcnum => $new->svcnum,
- groupnum => $newgroup,
- } );
- my $error = $radius_usergroup->insert;
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return "error adding radius_usergroup $newgroup: $error";
- }
- }
+ $error = $new->SUPER::replace($old, @_); # usergroup here
+ # don't need to record this unless the password was changed
+ if ( $old->_password ne $new->_password ) {
+ $error ||= $new->insert_password_history;
}
- $error = $new->SUPER::replace($old, @_);
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
return $error if $error;
my($recref) = $self->hashref;
- my $x = $self->setfixed( $self->_fieldhandlers );
+ my $x = $self->setfixed;
return $x unless ref($x);
my $part_svc = $x;
- if ( $part_svc->part_svc_column('usergroup')->columnflag eq "F" ) {
- $self->usergroup(
- [ split(',', $part_svc->part_svc_column('usergroup')->columnvalue) ] );
- }
-
my $error = $self->ut_numbern('svcnum')
#|| $self->ut_number('domsvc')
|| $self->ut_foreign_key( 'domsvc', 'svc_domain', 'svcnum' )
|| $self->ut_foreign_keyn('pbxsvc', 'svc_pbx', 'svcnum' )
+ || $self->ut_foreign_keyn('sectornum','tower_sector','sectornum')
+ || $self->ut_foreign_keyn('routernum','router','routernum')
+ || $self->ut_foreign_keyn('blocknum','addr_block','blocknum')
|| $self->ut_textn('sec_phrase')
|| $self->ut_snumbern('seconds')
|| $self->ut_snumbern('upbytes')
;
return $error if $error;
+ # assign IP address, etc.
+ if ( $conf->exists('svc_acct-ip_addr') ) {
+ my $error = $self->svc_ip_check;
+ return $error if $error;
+ } else { # I think this is correct
+ $self->routernum('');
+ $self->blocknum('');
+ }
+
my $cust_pkg;
local $username_letter = $username_letter;
+ local $username_uppercase = $username_uppercase;
if ($self->svcnum) {
my $cust_svc = $self->cust_svc
or return "no cust_svc record found for svcnum ". $self->svcnum;
if ($cust_pkg) {
$username_letter =
$conf->exists('username-letter', $cust_pkg->cust_main->agentnum);
+ $username_uppercase =
+ $conf->exists('username-uppercase', $cust_pkg->cust_main->agentnum);
}
my $ulen = $usernamemax || $self->dbdef_table->column('username')->length;
- $recref->{username} =~ /^([a-z0-9_\-\.\&\%\:\/\=\#]{$usernamemin,$ulen})$/i
+ $recref->{username} =~ /^([a-z0-9_\-\.\&\%\:\/\=\#\!]{$usernamemin,$ulen})$/i
or return gettext('illegal_username'). " ($usernamemin-$ulen): ". $recref->{username};
$recref->{username} = $1;
+ my $uerror = gettext('illegal_username'). ': '. $recref->{username};
+
unless ( $username_uppercase ) {
- $recref->{username} =~ /[A-Z]/ and return gettext('illegal_username');
+ $recref->{username} =~ /[A-Z]/ and return $uerror;
}
if ( $username_letterfirst ) {
- $recref->{username} =~ /^[a-z]/ or return gettext('illegal_username');
+ $recref->{username} =~ /^[a-z]/ or return $uerror;
} elsif ( $username_letter ) {
- $recref->{username} =~ /[a-z]/ or return gettext('illegal_username');
+ $recref->{username} =~ /[a-z]/ or return $uerror;
}
if ( $username_noperiod ) {
- $recref->{username} =~ /\./ and return gettext('illegal_username');
+ $recref->{username} =~ /\./ and return $uerror;
}
if ( $username_nounderscore ) {
- $recref->{username} =~ /_/ and return gettext('illegal_username');
+ $recref->{username} =~ /_/ and return $uerror;
}
if ( $username_nodash ) {
- $recref->{username} =~ /\-/ and return gettext('illegal_username');
+ $recref->{username} =~ /\-/ and return $uerror;
}
unless ( $username_ampersand ) {
- $recref->{username} =~ /\&/ and return gettext('illegal_username');
+ $recref->{username} =~ /\&/ and return $uerror;
}
unless ( $username_percent ) {
- $recref->{username} =~ /\%/ and return gettext('illegal_username');
+ $recref->{username} =~ /\%/ and return $uerror;
}
unless ( $username_colon ) {
- $recref->{username} =~ /\:/ and return gettext('illegal_username');
+ $recref->{username} =~ /\:/ and return $uerror;
}
unless ( $username_slash ) {
- $recref->{username} =~ /\// and return gettext('illegal_username');
+ $recref->{username} =~ /\// and return $uerror;
}
unless ( $username_equals ) {
- $recref->{username} =~ /\=/ and return gettext('illegal_username');
+ $recref->{username} =~ /\=/ and return $uerror;
}
unless ( $username_pound ) {
- $recref->{username} =~ /\#/ and return gettext('illegal_username');
+ $recref->{username} =~ /\#/ and return $uerror;
+ }
+ unless ( $username_exclamation ) {
+ $recref->{username} =~ /\!/ and return $uerror;
}
}
- # $error = $self->ut_textn('finger');
- # return $error if $error;
if ( $self->getfield('finger') eq '' ) {
my $cust_pkg = $self->svcnum
? $self->cust_svc->cust_pkg
$self->setfield('finger', $cust_main->first.' '.$cust_main->get('last') );
}
}
- $self->getfield('finger') =~ /^([\w \,\.\-\'\&\t\!\@\#\$\%\(\)\+\;\"\?\/\*\<\>]+)$/
+ # $error = $self->ut_textn('finger');
+ # return $error if $error;
+ $self->getfield('finger') =~ /^([\w \,\.\-\'\&\t\!\@\#\$\%\(\)\+\;\"\?\/\*\<\>]*)$/
or return "Illegal finger: ". $self->getfield('finger');
$self->setfield('finger', $1);
unless ( $part_svc->part_svc_column('slipip')->columnflag eq 'F' ) {
if ( $recref->{slipip} eq '' ) {
- $recref->{slipip} = '';
+ $recref->{slipip} = ''; # eh?
} elsif ( $recref->{slipip} eq '0e0' ) {
$recref->{slipip} = '0e0';
} else {
or return "Illegal slipip: ". $self->slipip;
$recref->{slipip} = $1;
}
-
}
#arbitrary RADIUS stuff; allow ut_textn for now
else {
return "invalid password encoding ('".$recref->{_password_encoding}."'";
}
+
$self->SUPER::check;
}
if ( !$encoding ) {
# set encoding to system default
($encoding, $encryption) =
- split(/-/, lc($conf->config('default-password-encoding')));
+ split(/-/, lc($conf->config('default-password-encoding') || ''));
$encoding ||= 'legacy';
$self->_password_encoding($encoding);
}
$self->username. '@'. $self->domain(@_);
}
+
=item acct_snarf
Returns an array of FS::acct_snarf records associated with the account.
=cut
+# unused as originally intended, but now by Communigate Pro "RPOP"
sub acct_snarf {
my $self = shift;
qsearch({
$self->cust_svc->seconds_since(@_);
}
-=item seconds_since_sqlradacct TIMESTAMP_START TIMESTAMP_END
-
-Returns the numbers of seconds this account has been online between
-TIMESTAMP_START (inclusive) and TIMESTAMP_END (exclusive), according to an
-external SQL radacct table, specified via sqlradius export. Sessions which
-started in the specified range but are still open are counted from session
-start to the end of the range (unless they are over 1 day old, in which case
-they are presumed missing their stop record and not counted). Also, sessions
-which end in the range but started earlier are counted from the start of the
-range to session end. Finally, sessions which start before the range but end
-after are counted for the entire range.
-
-TIMESTAMP_START and TIMESTAMP_END are specified as UNIX timestamps; see
-L<perlfunc/"time">. Also see L<Time::Local> and L<Date::Parse> for conversion
-functions.
-
-=cut
-
-#note: POD here, implementation in FS::cust_svc
-sub seconds_since_sqlradacct {
- my $self = shift;
- $self->cust_svc->seconds_since_sqlradacct(@_);
-}
-
-=item attribute_since_sqlradacct TIMESTAMP_START TIMESTAMP_END ATTRIBUTE
-
-Returns the sum of the given attribute for all accounts (see L<FS::svc_acct>)
-in this package for sessions ending between TIMESTAMP_START (inclusive) and
-TIMESTAMP_END (exclusive).
-
-TIMESTAMP_START and TIMESTAMP_END are specified as UNIX timestamps; see
-L<perlfunc/"time">. Also see L<Time::Local> and L<Date::Parse> for conversion
-functions.
-
-=cut
-
-#note: POD here, implementation in FS::cust_svc
-sub attribute_since_sqlradacct {
- my $self = shift;
- $self->cust_svc->attribute_since_sqlradacct(@_);
-}
-
-=item get_session_history TIMESTAMP_START TIMESTAMP_END
-
-Returns an array of hash references of this customers login history for the
-given time range. (document this better)
-
-=cut
-
-sub get_session_history {
- my $self = shift;
- $self->cust_svc->get_session_history(@_);
-}
-
=item last_login_text
Returns text describing the time of last login.
$self->last_login ? ctime($self->last_login) : 'unknown';
}
-=item get_cdrs TIMESTAMP_START TIMESTAMP_END [ 'OPTION' => 'VALUE ... ]
+=item psearch_cdrs OPTIONS
-=cut
+Returns a paged search (L<FS::PagedSearch>) for Call Detail Records
+associated with this service. For svc_acct, "associated with" means that
+either the "src" or the "charged_party" field of the CDR matches either
+the "username" field of the service or the username@domain label.
-sub get_cdrs {
- my($self, $start, $end, %opt ) = @_;
-
- my $did = $self->username; #yup
-
- my $prefix = $opt{'default_prefix'}; #convergent.au '+61'
-
- my $for_update = $opt{'for_update'} ? 'FOR UPDATE' : '';
-
- #SELECT $for_update * FROM cdr
- # WHERE calldate >= $start #need a conversion
- # AND calldate < $end #ditto
- # AND ( charged_party = "$did"
- # OR charged_party = "$prefix$did" #if length($prefix);
- # OR ( ( charged_party IS NULL OR charged_party = '' )
- # AND
- # ( src = "$did" OR src = "$prefix$did" ) # if length($prefix)
- # )
- # )
- # AND ( freesidestatus IS NULL OR freesidestatus = '' )
-
- my $charged_or_src;
- if ( length($prefix) ) {
- $charged_or_src =
- " AND ( charged_party = '$did'
- OR charged_party = '$prefix$did'
- OR ( ( charged_party IS NULL OR charged_party = '' )
- AND
- ( src = '$did' OR src = '$prefix$did' )
- )
- )
- ";
- } else {
- $charged_or_src =
- " AND ( charged_party = '$did'
- OR ( ( charged_party IS NULL OR charged_party = '' )
- AND
- src = '$did'
- )
- )
- ";
+=cut
+sub psearch_cdrs {
+ my($self, %options) = @_;
+ my @fields;
+ my %hash;
+ my @where;
+
+ my $did = dbh->quote($self->username);
+ my $diddomain = dbh->quote($self->label);
+
+ my $prefix = $options{'default_prefix'} || ''; #convergent.au '+61'
+ my $prefixdid = dbh->quote($prefix . $self->username);
+
+ my $for_update = $options{'for_update'} ? 'FOR UPDATE' : '';
+
+ if ( $options{inbound} ) {
+ # these will be selected under their DIDs
+ push @where, "FALSE";
+ }
+
+ my @orwhere;
+ if (!$options{'disable_charged_party'}) {
+ push @orwhere,
+ "charged_party = $did",
+ "charged_party = $prefixdid",
+ "charged_party = $diddomain"
+ ;
+ }
+ if (!$options{'disable_src'}) {
+ push @orwhere,
+ "src = $did AND charged_party IS NULL",
+ "src = $prefixdid AND charged_party IS NULL",
+ "src = $diddomain AND charged_party IS NULL"
+ ;
+ }
+ push @where, '(' . join(' OR ', @orwhere) . ')';
+
+ # $options{'status'} = '' is meaningful; for the rest of them it's not
+ if ( exists $options{'status'} ) {
+ $hash{'freesidestatus'} = $options{'status'};
+ }
+ if ( $options{'cdrtypenum'} ) {
+ $hash{'cdrtypenum'} = $options{'cdrtypenum'};
+ }
+ if ( $options{'calltypenum'} ) {
+ $hash{'calltypenum'} = $options{'calltypenum'};
+ }
+ if ( $options{'begin'} ) {
+ push @where, 'startdate >= '. $options{'begin'};
+ }
+ if ( $options{'end'} ) {
+ push @where, 'startdate < '. $options{'end'};
+ }
+ if ( $options{'nonzero'} ) {
+ push @where, 'duration > 0';
+ }
+
+ my $extra_sql = join(' AND ', @where);
+ if ($extra_sql) {
+ if (keys %hash) {
+ $extra_sql = " AND ".$extra_sql;
+ } else {
+ $extra_sql = " WHERE ".$extra_sql;
+ }
}
-
- qsearch(
- 'select' => "$for_update *",
+ return psearch({
+ 'select' => '*',
'table' => 'cdr',
- 'hashref' => {
- #( freesidestatus IS NULL OR freesidestatus = '' )
- 'freesidestatus' => '',
- },
- 'extra_sql' => $charged_or_src,
-
- );
-
+ 'hashref' => \%hash,
+ 'extra_sql' => $extra_sql,
+ 'order_by' => "ORDER BY startdate $for_update",
+ });
}
-=item radius_groups
+=item get_cdrs (DEPRECATED)
-Returns all RADIUS groups for this account (see L<FS::radius_usergroup>).
+Like psearch_cdrs, but returns all the L<FS::cdr> objects at once, in a
+single list. Arguments are the same as for psearch_cdrs.
=cut
-sub radius_groups {
+sub get_cdrs {
my $self = shift;
- if ( $self->usergroup ) {
- confess "explicitly specified usergroup not an arrayref: ". $self->usergroup
- unless ref($self->usergroup) eq 'ARRAY';
- #when provisioning records, export callback runs in svc_Common.pm before
- #radius_usergroup records can be inserted...
- my $groups = join(',',@{$self->usergroup});
- my @groups;
- return @groups unless length($groups);
- @groups = qsearch({ 'table' => 'radius_group',
- 'extra_sql' => "where groupnum in ($groups)",
- });
- map { $_->groupname } @groups;
- } else {
- my $format = shift || '';
- my @groups = qsearch({ 'table' => 'radius_usergroup',
- 'addl_from' => 'left join radius_group using (groupnum)',
- 'select' => 'radius_group.*',
- 'hashref' => { 'svcnum' => $self->svcnum },
- });
-
- # this is to preserve various legacy behaviour / avoid re-writing other code
- return map { $_->groupnum } @groups if $format eq 'NUMBERS';
- return map { $_->description . " (" . $_->groupname . ")" } @groups
- if $format eq 'COMBINED';
- map { $_->groupname } @groups;
- }
+ my $psearch = $self->psearch_cdrs(@_);
+ qsearch ( $psearch->{query} )
}
+# sub radius_groups has moved to svc_Radius_Mixin
+
=item clone_suspended
Constructor used by FS::part_export::_export_suspend fallback. Document
if ( $self->_password_encoding eq 'ldap' ) {
- my $auth = from_rfc2307 Authen::Passphrase $self->_password;
+ $password =~ s/^{PLAIN}/{CLEARTEXT}/;
+ my $auth = from_rfc2307 Authen::Passphrase $password;
return $auth->match($check_password);
} elsif ( $self->_password_encoding eq 'crypt' ) {
$self->domain. '/maildirs/'. $self->username. '/';
}
+=item password_svc_check
+
+Override, for L<FS::Password_Mixin>. Not really intended for other use.
+
+=cut
+
+sub password_svc_check {
+ my ($self, $password) = @_;
+ foreach my $field ( qw(username finger) ) {
+ foreach my $word (split(/\W+/,$self->get($field))) {
+ next unless length($word) > 2;
+ if ($password =~ /$word/i) {
+ return qq(Password contains account information '$word');
+ }
+ }
+ }
+ return '';
+}
+
=back
=head1 CLASS METHODS
=cut
-sub search {
- my ($class, $params) = @_;
+sub _search_svc {
+ my( $class, $params, $from, $where ) = @_;
- my @where = ();
+ #these two should probably move to svc_Domain_Mixin ?
# domain
if ( $params->{'domain'} ) {
my $svc_domain = qsearchs('svc_domain', { 'domain'=>$params->{'domain'} } );
#preserve previous behavior & bubble up an error if $svc_domain not found?
- push @where, 'domsvc = '. $svc_domain->svcnum if $svc_domain;
+ push @$where, 'domsvc = '. $svc_domain->svcnum if $svc_domain;
}
# domsvc
if ( $params->{'domsvc'} =~ /^(\d+)$/ ) {
- push @where, "domsvc = $1";
- }
-
- #unlinked
- push @where, 'pkgnum IS NULL' if $params->{'unlinked'};
-
- #agentnum
- if ( $params->{'agentnum'} =~ /^(\d+)$/ and $1 ) {
- push @where, "cust_main.agentnum = $1";
+ push @$where, "domsvc = $1";
}
- #custnum
- if ( $params->{'custnum'} =~ /^(\d+)$/ and $1 ) {
- push @where, "custnum = $1";
- }
-
- #pkgpart
- if ( $params->{'pkgpart'} && scalar(@{ $params->{'pkgpart'} }) ) {
- #XXX untaint or sql quote
- push @where,
- 'cust_pkg.pkgpart IN ('. join(',', @{ $params->{'pkgpart'} } ). ')';
- }
# popnum
if ( $params->{'popnum'} =~ /^(\d+)$/ ) {
- push @where, "popnum = $1";
+ push @$where, "popnum = $1";
}
- # svcpart
- if ( $params->{'svcpart'} =~ /^(\d+)$/ ) {
- push @where, "svcpart = $1";
- }
+ #and these in svc_Tower_Mixin, or maybe we never should have done svc_acct
+ # towers (or, as mark thought, never should have done svc_broadband)
- # here is the agent virtualization
- #if ($params->{CurrentUser}) {
- # my $access_user =
- # qsearchs('access_user', { username => $params->{CurrentUser} });
- #
- # if ($access_user) {
- # push @where, $access_user->agentnums_sql('table'=>'cust_main');
- # }else{
- # push @where, "1=0";
- # }
- #} else {
- push @where, $FS::CurrentUser::CurrentUser->agentnums_sql(
- 'table' => 'cust_main',
- 'null_right' => 'View/link unlinked services',
- );
- #}
-
- push @where, @{ $params->{'where'} } if $params->{'where'};
-
- my $extra_sql = scalar(@where) ? ' WHERE '. join(' AND ', @where) : '';
-
- my $addl_from = ' LEFT JOIN cust_svc USING ( svcnum ) '.
- ' LEFT JOIN part_svc USING ( svcpart ) '.
- ' LEFT JOIN cust_pkg USING ( pkgnum ) '.
- ' LEFT JOIN cust_main USING ( custnum ) ';
-
- my $count_query = "SELECT COUNT(*) FROM svc_acct $addl_from $extra_sql";
- #if ( keys %svc_acct ) {
- # $count_query .= ' WHERE '.
- # join(' AND ', map "$_ = ". dbh->quote($svc_acct{$_}),
- # keys %svc_acct
- # );
- #}
-
- my $sql_query = {
- 'table' => 'svc_acct',
- 'hashref' => {}, # \%svc_acct,
- 'select' => join(', ',
- 'svc_acct.*',
- 'part_svc.svc',
- 'cust_main.custnum',
- FS::UI::Web::cust_sql_fields($params->{'cust_fields'}),
- ),
- 'addl_from' => $addl_from,
- 'extra_sql' => $extra_sql,
- 'order_by' => $params->{'order_by'},
- 'count_query' => $count_query,
- };
+ # sector and tower
+ my @where_sector = $class->tower_sector_sql($params);
+ if ( @where_sector ) {
+ push @$where, @where_sector;
+ push @$from, ' LEFT JOIN tower_sector USING ( sectornum )';
+ }
}