package FS::svc_acct;
use strict;
-use vars qw( @ISA $DEBUG $me $conf $skip_fuzzyfiles
+use base qw( FS::svc_Domain_Mixin FS::svc_CGP_Mixin FS::svc_CGPRule_Mixin
+ FS::svc_Common );
+use vars qw( $DEBUG $me $conf $skip_fuzzyfiles
$dir_prefix @shells $usernamemin
$usernamemax $passwordmin $passwordmax
$username_ampersand $username_letter $username_letterfirst
use FS::UI::bytecount;
use FS::UI::Web;
use FS::part_pkg;
-use FS::svc_Common;
-use FS::cust_svc;
use FS::part_svc;
use FS::svc_acct_pop;
use FS::cust_main_invoice;
use FS::svc_domain;
+use FS::svc_pbx;
use FS::raddb;
use FS::queue;
use FS::radius_usergroup;
use FS::svc_forward;
use FS::svc_www;
use FS::cdr;
-
-@ISA = qw( FS::svc_Common );
+use FS::acct_snarf;
$DEBUG = 0;
$me = '[FS::svc_acct]';
);
@saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' );
-@pw_set = ( 'a'..'z', 'A'..'Z', '0'..'9', '(', ')', '#', '!', '.', ',' );
+@pw_set = ( 'a'..'z', 'A'..'Z', '0'..'9', '(', ')', '#', '.', ',' );
sub _cache {
my $self = shift;
=over 4
-=item svcnum - primary key (assigned automatcially for new accounts)
+=item svcnum
+
+Primary key (assigned automatcially for new accounts)
=item username
-=item _password - generated if blank
+=item _password
+
+generated if blank
+
+=item _password_encoding
-=item _password_encoding - plain, crypt, ldap (or empty for autodetection)
+plain, crypt, ldap (or empty for autodetection)
-=item sec_phrase - security phrase
+=item sec_phrase
-=item popnum - Point of presence (see L<FS::svc_acct_pop>)
+security phrase
+
+=item popnum
+
+Point of presence (see L<FS::svc_acct_pop>)
=item uid
=item gid
-=item finger - GECOS
+=item finger
+
+GECOS
+
+=item dir
-=item dir - set automatically if blank (and uid is not)
+set automatically if blank (and uid is not)
=item shell
-=item quota - (unimplementd)
+=item quota
-=item slipip - IP address
+=item slipip
-=item seconds -
+IP address
-=item upbytes -
+=item seconds
-=item downbytes -
+=item upbytes
-=item totalbytes -
+=item downbyte
-=item domsvc - svcnum from svc_domain
+=item totalbytes
-=item radius_I<Radius_Attribute> - I<Radius-Attribute> (reply)
+=item domsvc
+
+svcnum from svc_domain
+
+=item pbxsvc
+
+Optional svcnum from svc_pbx
-=item rc_I<Radius_Attribute> - I<Radius-Attribute> (check)
+=item radius_I<Radius_Attribute>
+
+I<Radius-Attribute> (reply)
+
+=item rc_I<Radius_Attribute>
+
+I<Radius-Attribute> (check)
=back
disable_fixed => 1,
disable_select => 1,
},
+ 'password_selfchange' => { label => 'Password modification',
+ type => 'checkbox',
+ },
+ 'password_recover' => { label => 'Password recovery',
+ type => 'checkbox',
+ },
'quota' => {
- label => 'Quota',
+ 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,
select_key => 'svcnum',
select_label => 'domain',
disable_inventory => 1,
-
+ },
+ 'pbxsvc' => { label => 'PBX',
+ type => 'select-svc_pbx.html',
+ disable_inventory => 1,
+ disable_select => 1, #UI wonky, pry works otherwise
},
'usergroup' => {
label => 'RADIUS groups',
label => 'Last logout',
type => 'disabled',
},
+
+ 'cgp_aliases' => {
+ label => 'Communigate aliases',
+ type => 'text',
+ disable_inventory => 1,
+ disable_select => 1,
+ },
+ #settings
+ 'cgp_type'=> {
+ label => 'Communigate account type',
+ type => 'select',
+ select_list => [qw( MultiMailbox TextMailbox MailDirMailbox AGrade BGrade CGrade )],
+ disable_inventory => 1,
+ disable_select => 1,
+ },
+ 'cgp_accessmodes' => {
+ label => 'Communigate enabled services',
+ type => 'communigate_pro-accessmodes',
+ disable_inventory => 1,
+ disable_select => 1,
+ },
+ 'cgp_rulesallowed' => {
+ label => 'Allowed mail rules',
+ type => 'select',
+ select_list => [ '', 'No', 'Filter Only', 'All But Exec', 'Any' ],
+ disable_inventory => 1,
+ disable_select => 1,
+ },
+ 'cgp_rpopallowed' => { label => 'RPOP modifications',
+ type => 'checkbox',
+ },
+ 'cgp_mailtoall' => { label => 'Accepts mail to "all"',
+ type => 'checkbox',
+ },
+ 'cgp_addmailtrailer' => { label => 'Add trailer to sent mail',
+ type => 'checkbox',
+ },
+ 'cgp_archiveafter' => {
+ label => 'Archive messages after',
+ type => 'select',
+ select_hash => [
+ -2 => 'default(730 days)',
+ 0 => 'Never',
+ 86400 => '24 hours',
+ 172800 => '2 days',
+ 259200 => '3 days',
+ 432000 => '5 days',
+ 604800 => '7 days',
+ 1209600 => '2 weeks',
+ 2592000 => '30 days',
+ 7776000 => '90 days',
+ 15552000 => '180 days',
+ 31536000 => '365 days',
+ 63072000 => '730 days',
+ ],
+ disable_inventory => 1,
+ disable_select => 1,
+ },
+ #XXX mailing lists
+
+ #preferences
+ 'cgp_deletemode' => {
+ label => 'Communigate message delete method',
+ type => 'select',
+ select_list => [ 'Move To Trash', 'Immediately', 'Mark' ],
+ disable_inventory => 1,
+ disable_select => 1,
+ },
+ 'cgp_emptytrash' => {
+ label => 'Communigate on logout remove trash',
+ type => 'select',
+ select_list => __PACKAGE__->cgp_emptytrash_values,
+ disable_inventory => 1,
+ disable_select => 1,
+ },
+ 'cgp_language' => {
+ label => 'Communigate language',
+ type => 'select',
+ select_list => [ '', qw( English Arabic Chinese Dutch French German Hebrew Italian Japanese Portuguese Russian Slovak Spanish Thai ) ],
+ disable_inventory => 1,
+ disable_select => 1,
+ },
+ 'cgp_timezone' => {
+ label => 'Communigate time zone',
+ type => 'select',
+ select_list => __PACKAGE__->cgp_timezone_values,
+ disable_inventory => 1,
+ disable_select => 1,
+ },
+ 'cgp_skinname' => {
+ label => 'Communigate layout',
+ type => 'select',
+ select_list => [ '', '***', 'GoldFleece', 'Skin2' ],
+ disable_inventory => 1,
+ disable_select => 1,
+ },
+ 'cgp_prontoskinname' => {
+ label => 'Communigate Pronto style',
+ type => 'select',
+ select_list => [ '', 'Pronto', 'Pronto-darkflame', 'Pronto-steel', 'Pronto-twilight', ],
+ disable_inventory => 1,
+ disable_select => 1,
+ },
+ 'cgp_sendmdnmode' => {
+ label => 'Communigate send read receipts',
+ type => 'select',
+ select_list => [ '', 'Never', 'Manually', 'Automatically' ],
+ disable_inventory => 1,
+ disable_select => 1,
+ },
+
+ #mail
+ #XXX RPOP settings
+
},
};
}
$class->search_sql_field('username', $string ).
' ) ';
} else {
- ' ( '.
- $class->search_sql_field('username', $string).
- ( $string =~ /^\d+$/
- ? 'OR '. $class->search_sql_field('svcnum', $string)
- : ''
- ).
- ' ) ';
+ $class->search_sql_field('username', $string);
}
}
}
#welcome email
- my ($to,$welcome_template,$welcome_from,$welcome_subject,$welcome_subject_template,$welcome_mimetype)
- = ('','','','','','');
-
- if ( $conf->exists('welcome_email', $agentnum) ) {
- $welcome_template = new Text::Template (
- TYPE => 'ARRAY',
- SOURCE => [ map "$_\n", $conf->config('welcome_email', $agentnum) ]
- ) or warn "can't create welcome email template: $Text::Template::ERROR";
- $welcome_from = $conf->config('welcome_email-from', $agentnum);
- # || 'your-isp-is-dum'
- $welcome_subject = $conf->config('welcome_email-subject', $agentnum)
- || 'Welcome';
- $welcome_subject_template = new Text::Template (
- TYPE => 'STRING',
- SOURCE => $welcome_subject,
- ) or warn "can't create welcome email subject template: $Text::Template::ERROR";
- $welcome_mimetype = $conf->config('welcome_email-mimetype', $agentnum)
- || 'text/plain';
+ my $error = '';
+ my $msgnum = $conf->config('welcome_msgnum', $agentnum);
+ if ( $msgnum ) {
+ my $msg_template = qsearchs('msg_template', { msgnum => $msgnum });
+ $error = $msg_template->send('cust_main' => $cust_main);
}
- if ( $welcome_template && $cust_pkg ) {
- my $to = join(', ', grep { $_ !~ /^(POST|FAX)$/ } $cust_main->invoicing_list );
- if ( $to ) {
-
- my %hash = (
- 'custnum' => $self->custnum,
- 'username' => $self->username,
- 'password' => $self->_password,
- 'first' => $cust_main->first,
- 'last' => $cust_main->getfield('last'),
- 'pkg' => $cust_pkg->part_pkg->pkg,
- );
- my $wqueue = new FS::queue {
- 'svcnum' => $self->svcnum,
- 'job' => 'FS::svc_acct::send_email'
- };
- my $error = $wqueue->insert(
- 'to' => $to,
- 'from' => $welcome_from,
- 'subject' => $welcome_subject_template->fill_in( HASH => \%hash, ),
- 'mimetype' => $welcome_mimetype,
- 'body' => $welcome_template->fill_in( HASH => \%hash, ),
- );
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return "error queuing welcome email: $error";
- }
+ else { #!$msgnum
+ my ($to,$welcome_template,$welcome_from,$welcome_subject,$welcome_subject_template,$welcome_mimetype)
+ = ('','','','','','');
+
+ if ( $conf->exists('welcome_email', $agentnum) ) {
+ $welcome_template = new Text::Template (
+ TYPE => 'ARRAY',
+ SOURCE => [ map "$_\n", $conf->config('welcome_email', $agentnum) ]
+ ) or warn "can't create welcome email template: $Text::Template::ERROR";
+ $welcome_from = $conf->config('welcome_email-from', $agentnum);
+ # || 'your-isp-is-dum'
+ $welcome_subject = $conf->config('welcome_email-subject', $agentnum)
+ || 'Welcome';
+ $welcome_subject_template = new Text::Template (
+ TYPE => 'STRING',
+ SOURCE => $welcome_subject,
+ ) or warn "can't create welcome email subject template: $Text::Template::ERROR";
+ $welcome_mimetype = $conf->config('welcome_email-mimetype', $agentnum)
+ || 'text/plain';
+ }
+ if ( $welcome_template ) {
+ my $to = join(', ', grep { $_ !~ /^(POST|FAX)$/ } $cust_main->invoicing_list );
+ if ( $to ) {
+
+ my %hash = (
+ 'custnum' => $self->custnum,
+ 'username' => $self->username,
+ 'password' => $self->_password,
+ 'first' => $cust_main->first,
+ 'last' => $cust_main->getfield('last'),
+ 'pkg' => $cust_pkg->part_pkg->pkg,
+ );
+ my $wqueue = new FS::queue {
+ 'svcnum' => $self->svcnum,
+ 'job' => 'FS::svc_acct::send_email'
+ };
+ my $error = $wqueue->insert(
+ 'to' => $to,
+ 'from' => $welcome_from,
+ 'subject' => $welcome_subject_template->fill_in( HASH => \%hash, ),
+ 'mimetype' => $welcome_mimetype,
+ 'body' => $welcome_template->fill_in( HASH => \%hash, ),
+ );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error queuing welcome email: $error";
+ }
- if ( $options{'depend_jobnum'} ) {
- warn "$me depend_jobnum found; adding to welcome email dependancies"
- if $DEBUG;
- if ( ref($options{'depend_jobnum'}) ) {
- warn "$me adding jobs ". join(', ', @{$options{'depend_jobnum'}} ).
- "to welcome email dependancies"
- if $DEBUG;
- push @jobnums, @{ $options{'depend_jobnum'} };
- } else {
- warn "$me adding job $options{'depend_jobnum'} ".
- "to welcome email dependancies"
+ if ( $options{'depend_jobnum'} ) {
+ warn "$me depend_jobnum found; adding to welcome email dependancies"
if $DEBUG;
- push @jobnums, $options{'depend_jobnum'};
+ if ( ref($options{'depend_jobnum'}) ) {
+ warn "$me adding jobs ". join(', ', @{$options{'depend_jobnum'}} ).
+ "to welcome email dependancies"
+ if $DEBUG;
+ push @jobnums, @{ $options{'depend_jobnum'} };
+ } else {
+ warn "$me adding job $options{'depend_jobnum'} ".
+ "to welcome email dependancies"
+ if $DEBUG;
+ push @jobnums, $options{'depend_jobnum'};
+ }
}
- }
- foreach my $jobnum ( @jobnums ) {
- my $error = $wqueue->depend_insert($jobnum);
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return "error queuing welcome email job dependancy: $error";
+ foreach my $jobnum ( @jobnums ) {
+ my $error = $wqueue->depend_insert($jobnum);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error queuing welcome email job dependancy: $error";
+ }
}
- }
-
- }
- }
+ }
- } # if ( $cust_pkg )
+ } # if $welcome_template
+ } # if !$msgnum
+ } # if $cust_pkg
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
''; #no error
}
# set usage fields and thresholds if unset but set in a package def
+# AND the package already has a last bill date (otherwise they get double added)
sub preinsert_hook_first {
my $self = shift;
return '' unless $self->pkgnum;
my $cust_pkg = qsearchs( 'cust_pkg', { 'pkgnum' => $self->pkgnum } );
- my $part_pkg = $cust_pkg->part_pkg if $cust_pkg;
+ return '' unless $cust_pkg && $cust_pkg->last_bill;
+
+ my $part_pkg = $cust_pkg->part_pkg;
return '' unless $part_pkg && $part_pkg->can('usage_valuehash');
my %values = $part_pkg->usage_valuehash;
my $error = $self->ut_numbern('svcnum')
#|| $self->ut_number('domsvc')
- || $self->ut_foreign_key('domsvc', 'svc_domain', 'svcnum' )
+ || $self->ut_foreign_key( 'domsvc', 'svc_domain', 'svcnum' )
+ || $self->ut_foreign_keyn('pbxsvc', 'svc_pbx', 'svcnum' )
|| $self->ut_textn('sec_phrase')
|| $self->ut_snumbern('seconds')
|| $self->ut_snumbern('upbytes')
|| $self->ut_snumbern('downbytes')
|| $self->ut_snumbern('totalbytes')
- || $self->ut_enum( '_password_encoding',
- [ '', qw( plain crypt ldap ) ]
- )
+ || $self->ut_snumbern('seconds_threshold')
+ || $self->ut_snumbern('upbytes_threshold')
+ || $self->ut_snumbern('downbytes_threshold')
+ || $self->ut_snumbern('totalbytes_threshold')
+ || $self->ut_enum('_password_encoding', ['',qw(plain crypt ldap)])
+ || $self->ut_enum('password_selfchange', [ '', 'Y' ])
+ || $self->ut_enum('password_recover', [ '', 'Y' ])
+ || $self->ut_textn('cgp_accessmodes')
+ || $self->ut_alphan('cgp_type')
+ || $self->ut_textn('cgp_aliases' ) #well
+ #settings
+ || $self->ut_alphasn('cgp_rulesallowed')
+ || $self->ut_enum('cgp_rpopallowed', [ '', 'Y' ])
+ || $self->ut_enum('cgp_mailtoall', [ '', 'Y' ])
+ || $self->ut_enum('cgp_addmailtrailer', [ '', 'Y' ])
+ || $self->ut_snumbern('cgp_archiveafter')
+ #preferences
+ || $self->ut_alphasn('cgp_deletemode')
+ || $self->ut_enum('cgp_emptytrash', $self->cgp_emptytrash_values)
+ || $self->ut_alphan('cgp_language')
+ || $self->ut_textn('cgp_timezone')
+ || $self->ut_textn('cgp_skinname')
+ || $self->ut_textn('cgp_prontoskinname')
+ || $self->ut_alphan('cgp_sendmdnmode')
+ #XXX RPOP settings
;
return $error if $error;
or return "Illegal finger: ". $self->getfield('finger');
$self->setfield('finger', $1);
- $recref->{quota} =~ /^(\w*)$/ or return "Illegal quota";
- $recref->{quota} = $1;
+ for (qw( quota file_quota file_maxsize )) {
+ $recref->{$_} =~ /^(\w*)$/ or return "Illegal $_";
+ $recref->{$_} = $1;
+ }
+ $recref->{file_maxnum} =~ /^\s*(\d*)\s*$/ or return "Illegal file_maxnum";
+ $recref->{file_maxnum} = $1;
unless ( $part_svc->part_svc_column('slipip')->columnflag eq 'F' ) {
if ( $recref->{slipip} eq '' ) {
# First, if _password is blank, generate one and set default encoding.
if ( ! $recref->{_password} ) {
- $self->set_password('');
+ $error = $self->set_password('');
}
# But if there's a _password but no encoding, assume it's plaintext and
# set it to default encoding.
elsif ( ! $recref->{_password_encoding} ) {
- $self->set_password($recref->{_password});
+ $error = $self->set_password($recref->{_password});
}
+ return $error if $error;
# Next, check _password to ensure compliance with the encoding.
if ( $recref->{_password_encoding} eq 'ldap' ) {
$recref->{_password} =~ /\!/ and return gettext('illegal_password');
}
}
- elsif ( $recref->{_password_encoding} eq 'legacy' ) {
- # this happens when set_password fails
- return gettext('illegal_password'). " $passwordmin-$passwordmax ".
- FS::Msgcat::_gettext('illegal_password_characters').
- ": ". $recref->{_password};
+ else {
+ return "invalid password encoding ('".$recref->{_password_encoding}."'";
}
$self->SUPER::check;
=cut
sub set_password {
- my $self = shift;
- my $pass = shift;
- my ($encoding, $encryption);
+ my( $self, $pass ) = ( shift, shift );
+
+ warn "[$me] set_password (to $pass) called on $self: ". Dumper($self)
+ if $DEBUG;
+ my $failure = gettext('illegal_password'). " $passwordmin-$passwordmax ".
+ FS::Msgcat::_gettext('illegal_password_characters').
+ ": ". $pass;
- if($self->_password_encoding) {
+ my( $encoding, $encryption ) = ('', '');
+
+ if ( $self->_password_encoding ) {
$encoding = $self->_password_encoding;
# identify existing encryption method, try to use it.
$encryption = $self->_password_encryption;
- if(!$encryption) {
+ if (!$encryption) {
# use the system default
undef $encoding;
}
}
- if(!$encoding) {
+ if ( !$encoding ) {
# set encoding to system default
- ($encoding, $encryption) = split(/-/, lc($conf->config('default-password-encoding')));
+ ($encoding, $encryption) =
+ split(/-/, lc($conf->config('default-password-encoding')));
$encoding ||= 'legacy';
$self->_password_encoding($encoding);
}
- if($encoding eq 'legacy') {
+ if ( $encoding eq 'legacy' ) {
+
# The legacy behavior from check():
# If the password is blank, randomize it and set encoding to 'plain'.
if(!defined($pass) or (length($pass) == 0 and $passwordmin)) {
$pass = join('',map($pw_set[ int(rand $#pw_set) ], (0..7) ) );
$self->_password_encoding('plain');
- }
- else {
+ } else {
# Prefix + valid-length password
if ( $pass =~ /^((\*SUSPENDED\* |!!?)?)([^\t\n]{$passwordmin,$passwordmax})$/ ) {
$pass = $1.$3;
$self->_password_encoding('plain');
- }
# Prefix + crypt string
- elsif ( $pass =~ /^((\*SUSPENDED\* |!!?)?)([\w\.\/\$\;\+]{13,64})$/ ) {
+ } elsif ( $pass =~ /^((\*SUSPENDED\* |!!?)?)([\w\.\/\$\;\+]{13,64})$/ ) {
$pass = $1.$3;
$self->_password_encoding('crypt');
- }
# Various disabled crypt passwords
- elsif ( $pass eq '*' or
- $pass eq '!' or
- $pass eq '!!' ) {
+ } elsif ( $pass eq '*' || $pass eq '!' || $pass eq '!!' ) {
$self->_password_encoding('crypt');
+ } else {
+ return $failure;
}
- else {
- # do nothing; check() will recognize this as an error
- }
- }
+ }
+
+ $self->_password($pass);
+ return;
+
}
- elsif($encoding eq 'crypt') {
- if($encryption eq 'md5') {
+
+ return $failure
+ if $passwordmin && length($pass) < $passwordmin
+ or $passwordmax && length($pass) > $passwordmax;
+
+ if ( $encoding eq 'crypt' ) {
+ if ($encryption eq 'md5') {
$pass = unix_md5_crypt($pass);
- }
- elsif($encryption eq 'des') {
+ } elsif ($encryption eq 'des') {
$pass = crypt($pass, $saltset[int(rand(64))].$saltset[int(rand(64))]);
}
- }
- elsif($encoding eq 'ldap') {
- if($encryption eq 'md5') {
+
+ } elsif ( $encoding eq 'ldap' ) {
+ if ($encryption eq 'md5') {
$pass = md5_base64($pass);
- }
- elsif($encryption eq 'sha1') {
+ } elsif ($encryption eq 'sha1') {
$pass = sha1_base64($pass);
- }
- elsif($encryption eq 'crypt') {
+ } elsif ($encryption eq 'crypt') {
$pass = crypt($pass, $saltset[int(rand(64))].$saltset[int(rand(64))]);
}
# else $encryption eq 'plain', do nothing
sub radius_password {
my $self = shift;
- my($pw_attrib, $password);
+ my $pw_attrib;
if ( $self->_password_encoding eq 'ldap' ) {
-
$pw_attrib = 'Password-With-Header';
- $password = $self->_password;
-
} elsif ( $self->_password_encoding eq 'crypt' ) {
-
$pw_attrib = 'Crypt-Password';
- $password = $self->_password;
-
} elsif ( $self->_password_encoding eq 'plain' ) {
-
- $pw_attrib = $radius_password; #Cleartext-Password? man rlm_pap
- $password = $self->_password;
-
+ $pw_attrib = $radius_password;
} else {
-
- $pw_attrib = length($password) <= 12 ? $radius_password : 'Crypt-Password';
- $password = $self->_password;
-
+ $pw_attrib = length($self->_password) <= 12
+ ? $radius_password
+ : 'Crypt-Password';
}
- ($pw_attrib, $password);
+ ($pw_attrib, $self->_password);
}
$svc_domain->domain;
}
-=item svc_domain
-
-Returns the FS::svc_domain record for this account's domain (see
-L<FS::svc_domain>).
-
-=cut
-
-# FS::h_svc_acct has a history-aware svc_domain override
-
-sub svc_domain {
- my $self = shift;
- $self->{'_domsvc'}
- ? $self->{'_domsvc'}
- : qsearchs( 'svc_domain', { 'svcnum' => $self->domsvc } );
-}
-
=item cust_svc
Returns the FS::cust_svc record for this account (see L<FS::cust_svc>).
=item acct_snarf
Returns an array of FS::acct_snarf records associated with the account.
-If the acct_snarf table does not exist or there are no associated records,
-an empty list is returned
=cut
sub acct_snarf {
my $self = shift;
- return () unless dbdef->table('acct_snarf');
- eval "use FS::acct_snarf;";
- die $@ if $@;
- qsearch('acct_snarf', { 'svcnum' => $self->svcnum } );
+ qsearch({
+ 'table' => 'acct_snarf',
+ 'hashref' => { 'svcnum' => $self->svcnum },
+ #'order_by' => 'ORDER BY priority ASC',
+ });
+}
+
+=item cgp_rpop_hashref
+
+Returns an arrayref of RPOP data suitable for Communigate Pro API commands.
+
+=cut
+
+sub cgp_rpop_hashref {
+ my $self = shift;
+ { map { $_->snarfname => $_->cgp_hashref } $self->acct_snarf };
}
=item decrement_upbytes OCTETS
my $reset = 0;
my %handyhash = ();
if ( $options{null} ) {
- %handyhash = ( map { ( $_ => 'NULL', $_."_threshold" => 'NULL' ) }
+ %handyhash = ( map { ( $_ => undef, $_."_threshold" => undef ) }
qw( seconds upbytes downbytes totalbytes )
);
}
#die $error if $error; #services not explicity changed via the UI
my $sql = "UPDATE svc_acct SET " .
- join (',', map { "$_ = $handyhash{$_}" } (keys %handyhash) ).
+ join (',', map { "$_ = ?" } (keys %handyhash) ).
" WHERE svcnum = ". $self->svcnum;
warn "$me $sql\n"
if (scalar(keys %handyhash)) {
my $sth = $dbh->prepare( $sql )
or die "Error preparing $sql: ". $dbh->errstr;
- my $rv = $sth->execute();
+ my $rv = $sth->execute(values %handyhash);
die "Error executing $sql: ". $sth->errstr
unless defined($rv);
die "Can't update usage for svcnum ". $self->svcnum
#$self->snapshot; #not necessary, we retain the old values
#create an object with the updated usage values
my $new = qsearchs('svc_acct', { 'svcnum' => $self->svcnum });
- #call exports
- my $error = $new->replace($self);
+ local($FS::Record::nowarn_identical) = 1;
+ my $error = $new->replace($self); #call exports
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
return "Error replacing: $error";
=cut
-=item domain_select_hash %OPTIONS
-
-Returns a hash SVCNUM => DOMAIN ... representing the domains this customer
-may at present purchase.
-
-Currently available options are: I<pkgnum> I<svcpart>
-
-=cut
-
-sub domain_select_hash {
- my ($self, %options) = @_;
- my %domains = ();
- my $part_svc;
- my $cust_pkg;
-
- if (ref($self)) {
- $part_svc = $self->part_svc;
- $cust_pkg = $self->cust_svc->cust_pkg
- if $self->cust_svc;
- }
-
- $part_svc = qsearchs('part_svc', { 'svcpart' => $options{svcpart} })
- if $options{'svcpart'};
-
- $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $options{pkgnum} })
- if $options{'pkgnum'};
-
- if ($part_svc && ( $part_svc->part_svc_column('domsvc')->columnflag eq 'S'
- || $part_svc->part_svc_column('domsvc')->columnflag eq 'F')) {
- %domains = map { $_->svcnum => $_->domain }
- map { qsearchs('svc_domain', { 'svcnum' => $_ }) }
- split(',', $part_svc->part_svc_column('domsvc')->columnvalue);
- }elsif ($cust_pkg && !$conf->exists('svc_acct-alldomains') ) {
- %domains = map { $_->svcnum => $_->domain }
- map { qsearchs('svc_domain', { 'svcnum' => $_->svcnum }) }
- map { qsearch('cust_svc', { 'pkgnum' => $_->pkgnum } ) }
- qsearch('cust_pkg', { 'custnum' => $cust_pkg->custnum });
- }else{
- %domains = map { $_->svcnum => $_->domain } qsearch('svc_domain', {} );
- }
-
- if ($part_svc && $part_svc->part_svc_column('domsvc')->columnflag eq 'D') {
- my $svc_domain = qsearchs('svc_domain',
- { 'svcnum' => $part_svc->part_svc_column('domsvc')->columnvalue } );
- if ( $svc_domain ) {
- $domains{$svc_domain->svcnum} = $svc_domain->domain;
- }else{
- warn "unknown svc_domain.svcnum for part_svc_column domsvc: ".
- $part_svc->part_svc_column('domsvc')->columnvalue;
-
- }
- }
-
- (%domains);
-}
-
1;
-