'Usage: Unrateable CDRs',
'Usage: Time worked',
#gone in 4.x as a distinct ACL (for now?) { rightname=>'Employees: Commission Report', global=>1 },
- { rightname=>'Employees: Audit Report', global=>1 },
+ { rightname=>'Employee Reports', global=>1 },
#{ rightname => 'List customers of all agents', global=>1 },
],
{
'key' => 'logout-timeout',
- 'section' => 'UI',
- 'description' => 'If set, automatically log users out of the backoffice after this many minutes.',
+ 'section' => 'deprecated',
+ 'description' => 'Deprecated. Used to automatically log users out of the backoffice after this many minutes. Set session timeouts in employee groups instead.',
'type' => 'text',
},
my $ext;
if ( driver_name eq 'Pg' ) {
- system("pg_dump -Fc $database >/var/tmp/$database.Pg");
+ system("pg_dump -Fc -T h_cdr -T h_queue -T h_queue_arg $database >/var/tmp/$database.Pg");
$ext = 'Pg';
} elsif ( driver_name eq 'mysql' ) {
system("mysqldump $database >/var/tmp/$database.sql");
my $system = $FS::TicketSystem::system;
return if !defined($system) || $system ne 'RT_Internal';
+ system('/opt/rt3/sbin/rt-fulltext-indexer --quiet --limit 5400 &');
+
# if -d or -y is in use, bail out. There's no reliable way to tell RT
# to use an alternate system time.
if ( $opt{'d'} or $opt{'y'} ) {
=item ut_text COLUMN
Check/untaint text. Alphanumerics, spaces, and the following punctuation
-symbols are currently permitted: ! @ # $ % & ( ) - + ; : ' " , . ? / = [ ] < >
+symbols are currently permitted: ! @ # $ % & ( ) - + ; : ' " , . ? / = [ ] < > ~
May not be null. If there is an error, returns the error, otherwise returns
false.
# \p{Word} = alphanumerics, marks (diacritics), and connectors
# see perldoc perluniprops
$self->getfield($field)
- =~ /^([\p{Word} \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=\[\]\<\>$money_char]+)$/
+ =~ /^([\p{Word} \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=\[\]\<\>\~$money_char]+)$/
or return gettext('illegal_or_empty_text'). " $field: ".
$self->getfield($field);
$self->setfield($field,$1);
# $DEBUG = 2; # prints decoded request and response (noisy, be careful)
# $DEBUG = 3; # prints raw response from the API, ridiculously unreadable
-our $json = Cpanel::JSON::XS->new->pretty(1);
+our $json = Cpanel::JSON::XS->new->pretty(0)->shrink(1);
our %taxproduct_cache;
return;
}
- warn "sending SureTax request\n" if $DEBUG;
+ warn "encoding SureTax request\n" if $DEBUG;
my $request_json = $json->encode($request);
warn $request_json if $DEBUG > 1;
my $host = $conf->config('suretax-hostname');
$host ||= 'testapi.taxrating.net';
+ warn "sending SureTax request\n" if $DEBUG;
# We are targeting the "V05" interface:
# - accepts both telecom and general sales transactions
# - produces results broken down by "invoice" (Freeside line item)
'Accept' => 'application/json',
);
+ warn "received SureTax response\n" if $DEBUG;
my $raw_response = $http_response->content;
- warn "received response\n" if $DEBUG;
warn $raw_response if $DEBUG > 2;
my $response;
if ( $raw_response =~ /^<\?xml/ ) {
$response = XMLin( $raw_response );
$raw_response = $response->{content};
}
+
+ warn "decoding SureTax response\n" if $DEBUG;
$response = eval { $json->decode($raw_response) }
or die "$raw_response\n";
}
return if !$response->{GroupList};
+ warn "creating FS objects from SureTax data\n" if $DEBUG;
foreach my $taxable ( @{ $response->{GroupList} } ) {
# each member of this array here corresponds to what SureTax calls an
# "invoice" and we call a "line item". The invoice number is
});
}
}
+ warn "TaxEngine/suretax.pm make_taxlines done; returning FS objects\n" if $DEBUG;
return @elements;
}
'Refund payment' => [ 'Refund credit card payment', 'Refund Echeck payment' ],
'Regular void' => [ 'Void payments' ],
'Unvoid' => [ 'Unvoid payments', 'Unvoid invoices' ],
+ 'Employees: Audit Report' => [ 'Employee Reports' ],
);
foreach my $oldright (keys %migrate) {
'Usage: Unrateable CDRs',
],
'Provision customer service' => [ 'Edit password' ],
- 'Financial reports' => [ 'Employees: Commission Report',
- 'Employees: Audit Report',
- ],
+ 'Financial reports' => 'Employee Reports',
'Change customer package' => 'Detach customer package',
'Services: Accounts' => 'Services: Cable Subscribers',
'Bulk change customer packages' => 'Bulk move customer services',
--- /dev/null
+package FS::access_user_session_log;
+use base qw( FS::Record );
+
+use strict;
+#use FS::Record qw( qsearch qsearchs );
+
+=head1 NAME
+
+FS::access_user_session_log - Object methods for access_user_session_log records
+
+=head1 SYNOPSIS
+
+ use FS::access_user_session_log;
+
+ $record = new FS::access_user_session_log \%hash;
+ $record = new FS::access_user_session_log { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::access_user_session_log object represents an log of an employee session.
+FS::access_user_session_log inherits from FS::Record. The following fields
+are currently supported:
+
+=over 4
+
+=item sessionlognum
+
+primary key
+
+=item usernum
+
+usernum
+
+=item start_date
+
+start_date
+
+=item last_date
+
+last_date
+
+=item logout_date
+
+logout_date
+
+=item logout_type
+
+logout_type
+
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new log entry. To add the entry to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+sub table { 'access_user_session_log'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Delete this record from the database.
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid log entry. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_number('usernum')
+ || $self->ut_numbern('start_date')
+ || $self->ut_numbern('last_date')
+ || $self->ut_numbern('logout_date')
+ || $self->ut_text('logout_type')
+ ;
+ return $error if $error;
+
+ $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>
+
+=cut
+
+1;
+
use Carp;
use Data::Dumper;
use Business::CreditCard 0.35;
+use Business::OnlinePayment;
use FS::UID qw( dbh myconnect );
use FS::Record qw( qsearch qsearchs );
use FS::payby;
my %svc_x = ();
my %bill_location = ();
my %ship_location = ();
+ my $cust_payby = '';
foreach my $field ( @fields ) {
if ( $field =~ /^cust_pkg\.(pkgpart|setup|bill|susp|adjourn|expire|cancel)$/ ) {
if ( $cust_main{'payinfo'} =~ /^\s*(\d+\@[\d\.]+)\s*$/ ) {
- $cust_main{'payby'} = 'CHEK';
- $cust_main{'payinfo'} = $1;
+ delete $cust_main{'payinfo'};
- } else {
+ $cust_payby = new FS::cust_payby {
+ 'payby' => 'CHEK',
+ 'payinfo' => $1,
+ };
- $cust_main{'payby'} = 'CARD';
+ } elsif ($cust_main{'payinfo'} =~ /^\s*([AD]?)(.*)\s*$/) {
- if ($cust_main{'payinfo'} =~ /^\s*([AD]?)(.*)\s*$/) {
- $cust_main{'payby'} = 'DCRD' if $1 eq 'D';
- $cust_main{'payinfo'} = $2;
- }
+ delete $cust_main{'payinfo'};
+
+ $cust_payby = new FS::cust_payby {
+ 'payby' => ($1 eq 'D') ? 'DCRD' : 'CARD',
+ 'payinfo' => $2,
+ 'paycvv' => delete $cust_main{'paycvv'},
+ 'paydate' => delete $cust_main{'paydate'},
+ 'payname' => $cust_main{'first'}. ' '. $cust_main{'last'},
+ };
}
$hash{$cust_pkg} = \@svc_x;
}
- my $error = $cust_main->insert( \%hash, $invoicing_list );
+ my %options = ('invoicing_list' => $invoicing_list);
+ $options{'cust_payby'} = [ $cust_payby ] if $cust_payby;
+
+ my $error = $cust_main->insert( \%hash, %options );
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
: '000000';
}
+=item agent_name
+
+=cut
+
+sub agent_name {
+ my $self = shift;
+ $self->cust_linked
+ ? $self->cust_main->agent_name
+ : $self->cust_unlinked_msg;
+}
+
=item prospect_sql
=item active_sql
my $command = $self->option($action);
return '' if $command =~ /^\s*$/;
- #set variables for the command
+ my $command_string = $self->_export_subvars( $svc_broadband, $command );
+
+ $self->shellcommands_queue( $svc_broadband->svcnum,
+ user => $self->option('user')||'root',
+ host => $self->machine,
+ command => $command_string,
+ );
+}
+
+sub _export_subvars {
+ my( $self, $svc_broadband, $command ) = @_;
+
no strict 'vars';
{
no strict 'refs';
$locationnum = $cust_pkg ? $cust_pkg->locationnum : '';
$custnum = $cust_pkg ? $cust_pkg->custnum : '';
- #done setting variables for the command
+ eval(qq("$command"));
+}
- $self->shellcommands_queue( $svc_broadband->svcnum,
+sub _export_replace {
+ my($self, $new, $old ) = (shift, shift, shift);
+ my $command = $self->option('replace');
+
+ my $command_string = $self->_export_subvars_replace( $new, $old, $command );
+
+ $self->shellcommands_queue( $new->svcnum,
user => $self->option('user')||'root',
host => $self->machine,
- command => eval(qq("$command")),
+ command => $command_string,
);
}
-sub _export_replace {
- my($self, $new, $old ) = (shift, shift, shift);
- my $command = $self->option('replace');
+sub _export_subvars_replace {
+ my( $self, $new, $old, $command ) = @_;
- #set variable for the command
no strict 'vars';
{
no strict 'refs';
$new_locationnum = $new_cust_pkg ? $new_cust_pkg->locationnum : '';
$new_custnum = $new_cust_pkg ? $new_cust_pkg->custnum : '';
- #done setting variables for the command
-
- $self->shellcommands_queue( $new->svcnum,
- user => $self->option('user')||'root',
- host => $self->machine,
- command => eval(qq("$command")),
- );
+ eval(qq("$command"));
}
+
#a good idea to queue anything that could fail or take any time
sub shellcommands_queue {
my( $self, $svcnum ) = (shift, shift);
--- /dev/null
+package FS::part_export::broadband_shellcommands_expect;
+use base qw( FS::part_export::shellcommands_expect );
+
+use strict;
+use FS::part_export::broadband_shellcommands;
+
+our %info = %FS::part_export::shellcommands_expect::info;
+$info{'svc'} = 'svc_broadband';
+$info{'desc'} = 'Real time export via remote SSH, with interactive ("Expect"-like) scripting, for svc_broadband services';
+
+sub _export_subvars {
+ FS::part_export::broadband_shellcommands::_export_subvars(@_)
+}
+
+sub _export_subvars_replace {
+ FS::part_export::broadband_shellcommands::_export_subvars_replace(@_)
+}
+
+1;
# page's IDs or something.
my $uniqueid = md5_hex(join(',',@$row));
if ( FS::cdr->row_exists('uniqueid = ?', $uniqueid) ) {
- warn "skipped duplicate row in page $page\n" if $DEBUG > 1;
+ warn "skipped duplicate row in page $page\n" if $DEBUG;
next CDR;
}
]
);
warn "$me $method\n" if $DEBUG;
- warn $request->as_string."\n" if $DEBUG > 1;
+ warn $request->as_string."\n" if $DEBUG;
my $ua = LWP::UserAgent->new;
my $response = $ua->request($request);
use Tie::IxHash;
use Date::Format;
use String::ShellQuote;
+use Net::OpenSSH;
use FS::part_export;
use FS::Record qw( qsearch qsearchs );
} else {
$self->_export_command($action, @_);
}
-};
+}
sub _export_command {
my ( $self, $action, $svc_acct) = (shift, shift, shift);
return '' if $command =~ /^\s*$/;
my $stdin = $self->option($action."_stdin");
+ my( $command_string, $stdin_string ) =
+ $self->_export_subvars( $svc_acct, $command, $stdin );
+
+ $self->ssh_or_queue( $svc_acct, $command_string, $stdin_string );
+}
+
+sub ssh_or_queue {
+ my( $self, $svc_acct, $command_string, $stdin_string ) = @_;
+
+ my @ssh_cmd_args = (
+ user => $self->option('user') || 'root',
+ host => $self->svc_machine($svc_acct),
+ command => $command_string,
+ stdin_string => $stdin_string,
+ ignored_errors => $self->option('ignored_errors') || '',
+ ignore_all_errors => $self->option('ignore_all_errors'),
+ fail_on_output => $self->option('fail_on_output'),
+ );
+
+ if ( $self->option($action. '_no_queue') ) {
+ # discard return value just like freeside-queued.
+ eval { ssh_cmd(@ssh_cmd_args) };
+ $error = $@;
+ $error = $error->full_message if ref $error; # Exception::Class::Base
+ return $error.
+ ' ('. $self->exporttype. ' to '. $self->svc_machine($svc_acct). ')'
+ if $error;
+ } else {
+ $self->shellcommands_queue( $svc_acct->svcnum, @ssh_cmd_args );
+ }
+}
+
+sub _export_subvars {
+ my( $self, $svc_acct, $command, $stdin ) = @_;
+
no strict 'vars';
{
no strict 'refs';
my $command_string = eval(qq("$command"));
return "error filling in command: $@" if $@;
- my @ssh_cmd_args = (
- user => $self->option('user') || 'root',
- host => $self->svc_machine($svc_acct),
- command => $command_string,
- stdin_string => $stdin_string,
- ignored_errors => $self->option('ignored_errors') || '',
- ignore_all_errors => $self->option('ignore_all_errors'),
- fail_on_output => $self->option('fail_on_output'),
- );
-
- if ( $self->option($action. '_no_queue') ) {
- # discard return value just like freeside-queued.
- eval { ssh_cmd(@ssh_cmd_args) };
- $error = $@;
- $error = $error->full_message if ref $error; # Exception::Class::Base
- return $error.
- ' ('. $self->exporttype. ' to '. $self->svc_machine($svc_acct). ')'
- if $error;
- } else {
- $self->shellcommands_queue( $svc_acct->svcnum, @ssh_cmd_args );
- }
+ ( $command_string, $stdin_string );
}
sub _export_replace {
my $command = $self->option('usermod');
return '' if $command =~ /^\s*$/;
my $stdin = $self->option('usermod_stdin');
+
+ my( $command_string, $stdin_string ) =
+ $self->_export_subvars_replace( $new, $old, $command, $stdin );
+
+ $self->ssh_or_queue( $new, $command_string, $stdin_string );
+}
+
+sub _export_subvars_replace {
+ my( $self, $new, $old, $command, $stdin ) = @_;
+
no strict 'vars';
{
no strict 'refs';
my $command_string = eval(qq("$command"));
- my @ssh_cmd_args = (
- user => $self->option('user') || 'root',
- host => $self->svc_machine($new),
- command => $command_string,
- stdin_string => $stdin_string,
- ignored_errors => $self->option('ignored_errors') || '',
- ignore_all_errors => $self->option('ignore_all_errors'),
- fail_on_output => $self->option('fail_on_output'),
- );
-
- if($self->option('usermod_no_queue')) {
- # discard return value just like freeside-queued.
- eval { ssh_cmd(@ssh_cmd_args) };
- $error = $@;
- $error = $error->full_message if ref $error; # Exception::Class::Base
- return $error. ' ('. $self->exporttype. ' to '. $self->svc_machine($new). ')'
- if $error;
- }
- else {
- $self->shellcommands_queue( $new->svcnum, @ssh_cmd_args );
- }
+ ( $command_string, $stdin_string );
}
#a good idea to queue anything that could fail or take any time
}
sub ssh_cmd { #subroutine, not method
- use Net::OpenSSH;
my $opt = { @_ };
open my $def_in, '<', '/dev/null' or die "unable to open /dev/null\n";
my $ssh = Net::OpenSSH->new(
--- /dev/null
+package FS::part_export::shellcommands_expect;
+use base qw( FS::part_export::shellcommands );
+
+use strict;
+use Tie::IxHash;
+use Net::OpenSSH;
+use Expect;
+#use FS::Record qw( qsearch qsearchs );
+
+tie my %options, 'Tie::IxHash',
+ 'user' => { label =>'Remote username', default=>'root' },
+ 'useradd' => { label => 'Insert commands', type => 'textarea', },
+ 'userdel' => { label => 'Delete commands', type => 'textarea', },
+ 'usermod' => { label => 'Modify commands', type => 'textarea', },
+ 'suspend' => { label => 'Suspend commands', type => 'textarea', },
+ 'unsuspend' => { label => 'Unsuspend commands', type => 'textarea', },
+ 'debug' => { label => 'Enable debugging',
+ type => 'checkbox',
+ value => 1,
+ },
+;
+
+our %info = (
+ 'svc' => 'svc_acct',
+ 'desc' => 'Real time export via remote SSH, with interactive ("Expect"-like) scripting, for svc_acct services',
+ 'options' => \%options,
+ 'notes' => q[
+Interactively run commands via SSH in a remote terminal, like "Expect". In
+most cases, you probably want a regular shellcommands (or broadband_shellcommands, etc.) export instead, unless
+you have a specific need to interact with a terminal-based interface in an
+"Expect"-like fashion.
+<BR><BR>
+
+Each line specifies a string to match and a command to
+run after that string is found, separated by the first space. For example, to
+run "exit" after a prompt ending in "#" is sent, "# exit". You will need to
+<a href="http://www.freeside.biz/mediawiki/index.php/Freeside:1.9:Documentation:Administration:SSH_Keys">setup SSH for unattended operation</a>.
+<BR><BR>
+
+In commands, all variable substitutions of the regular shellcommands (or
+broadband_shellcommands, etc.) export are available (use a backslash to escape
+a literal $).
+]
+);
+
+sub _export_command {
+ my ( $self, $action, $svc_acct) = (shift, shift, shift);
+ my @lines = split("\n", $self->option($action) );
+
+ return '' unless @lines;
+
+ my @commands = ();
+ foreach my $line (@lines) {
+ my($match, $command) = split(' ', $line, 2);
+ my( $command_string ) = $self->_export_subvars( $svc_acct, $command, '' );
+ push @commands, [ $match, $command_string ];
+ }
+
+ $self->shellcommands_expect_queue( $svc_acct->svcnum, @commands );
+}
+
+sub _export_replace {
+ my( $self, $new, $old ) = (shift, shift, shift);
+ my @lines = split("\n", $self->option('replace') );
+
+ return '' unless @lines;
+
+ my @commands = ();
+ foreach my $line (@lines) {
+ my($match, $command) = split(' ', $line, 2);
+ my( $command_string ) = $self->_export_subvars_replace( $new, $old, $command, '' );
+ push @commands, [ $match, $command_string ];
+ }
+
+ $self->shellcommands_expect_queue( $new->svcnum, @commands );
+}
+
+sub shellcommands_expect_queue {
+ my( $self, $svcnum, @commands ) = @_;
+
+ my $queue = new FS::queue {
+ 'svcnum' => $svcnum,
+ 'job' => "FS::part_export::shellcommands_expect::ssh_expect",
+ };
+ $queue->insert(
+ user => $self->option('user') || 'root',
+ host => $self->machine,
+ debug => $self->option('debug'),
+ commands => \@commands,
+ );
+}
+
+sub ssh_expect { #subroutine, not method
+ my $opt = { @_ };
+
+ my $dest = $opt->{'user'}.'@'.$opt->{'host'};
+
+ open my $def_in, '<', '/dev/null' or die "unable to open /dev/null\n";
+ my $ssh = Net::OpenSSH->new( $dest, 'default_stdin_fh' => $def_in );
+ # ignore_all_errors doesn't override SSH connection/auth errors--
+ # probably correct
+ die "Couldn't establish SSH connection to $dest: ". $ssh->error
+ if $ssh->error;
+
+ my ($pty, $pid) = $ssh->open2pty
+ or die "Couldn't start a remote terminal session";
+ my $expect = Expect->init($pty);
+ #not useful #$expect->debug($opt->{debug} ? 3 : 0);
+
+ foreach my $line ( @{ $opt->{commands} } ) {
+ my( $match, $command ) = @$line;
+
+ warn "Waiting for '$match'\n" if $opt->{debug};
+
+ my $matched = $expect->expect(30, $match);
+ unless ( $matched ) {
+ my $err = "Never saw '$match'\n";
+ warn $err;
+ die $err;
+ }
+ warn "Running '$command'\n" if $opt->{debug};
+ $expect->send("$command\n");
+ }
+
+ '';
+}
+
+1;
my $e911_result = $self->vitelity_command('e911send', %e911send);
- unless ( $e911_result =~ /^(missingdata|invalid)/i ) {
+ unless ( $e911_result =~ /status=(missingdata|invalid)/i ) {
warn "Vitelity response: $e911_result" if $self->option('debug');
return '';
}
use Getopt::Std;
use Date::Format;
use File::Temp 'tempdir';
-use Net::FTP;
+use Net::SSLGlue::FTP; #at least until the Deb 9 transition is done, then
+ # regular Net::FTP has SSL support
use FS::UID qw(adminsuidsetup datasrc dbh);
use FS::cdr;
use FS::cdr_batch;
my $format = 'voip_innovations';
my $hostname = 'customercdr.voipinnovations.com';
-my $ftp = Net::FTP->new($hostname, Debug => $opt_d)
+my $ftp = Net::FTP->new($hostname, Passive => 1, Debug => $opt_d)
or die "Can't connect to $hostname: $@\n";
+$ftp->starttls()
+ or die "TLS initialization failed: ". $ftp->message. "\n";
+
$ftp->login($login, $password)
- or die "Login failed: ".$ftp->message."\n";
+ or die "Login failed: ". $ftp->message. "\n";
###
# get the file list
warn "Retrieving directory listing\n" if $opt_v;
-$ftp->cwd('/');
+#$ftp->cwd('/');
my @dirs = $ftp->ls();
warn scalar(@dirs)." directories found.\n" if $opt_v;
# apply date range
--- /dev/null
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::access_user_session_log;
+$loaded=1;
+print "ok 1\n";
Architecture: all
Pre-Depends: freeside-lib
# dbconfig-common
-Depends: ${perl:Depends}, ${shlibs:Depends}, ${misc:Depends}, freeside-webui,
- debconf, cron, openbsd-inetd, tcpd, undersmtpd, ssmtp, freeside-lib (>= 4.0~git-20160211)
+Depends: ${perl:Depends}, ${shlibs:Depends}, ${misc:Depends},
+ freeside-webui (= ${binary:Version}), freeside-lib (= ${binary:Version}),
+ debconf, cron, openbsd-inetd, tcpd, undersmtpd, ssmtp
Description: Billing and trouble ticketing for service providers
Freeside is a web-based billing, trouble ticketing and network monitoring
application. It includes features for ISPs and WISPs, hosting providers and
libxml-writer-perl, libio-socket-ssl-perl,
libmap-splat-perl, libdatetime-format-ical-perl, librest-client-perl,
libgeo-streetaddress-us-perl, libbusiness-onlinepayment-perl,
- libnet-vitelity-perl (>= 0.05)
+ libnet-vitelity-perl (>= 0.05), libnet-sslglue-perl, libexpect-perl
Conflicts: libparams-classify-perl (>= 0.013-6)
Replaces: freeside (<<4)
Breaks: freeside (<<4)
$custnum='';
$cust_main = new FS::cust_main ( {} );
+
+ my @agentnums = $curuser->agentnums;
+ $cust_main->agentnum( $agentnums[0] )
+ if scalar(@agentnums) == 1;
$cust_main->agentnum( $conf->config('default_agentnum') )
if $conf->exists('default_agentnum');
+
$cust_main->referral_custnum( $cgi->param('referral_custnum') );
$cust_main->set('postal_invoice', 'Y')
unless $conf->exists('disablepostalinvoicedefault');
if $curuser->access_right('Billing event reports');
$report_logs{'Credit limit incidents'} = [ $fsurl.'search/report_cust_main_credit_limit.html', '' ]
if $curuser->access_right('List rating data');
-$report_logs{'Employee activity'} = [ $fsurl.'search/report_employee_audit.html', '' ]
- if $curuser->access_right('Employees: Audit Report');
$report_logs{'System log'} = [ $fsurl.'search/log.html', 'View system events and debugging information.' ],
if $curuser->access_right('View system logs')
|| $curuser->access_right('Configuration');
if $curuser->access_right('View email logs')
|| $curuser->access_right('Configuration');
+tie my %report_employee, 'Tie::IxHash',
+ 'Employee activity' => [ $fsurl.'search/report_employee_audit.html', '' ],
+ 'Employee sessions' => [ $fsurl.'search/report_access_user_session_log.html', '' ],
+ 'Access log statistics' => [ $fsurl.'search/report_access_user_log.html?group_by=path', '' ],
+;
+
tie my %report_menu, 'Tie::IxHash';
$report_menu{'Saved searches'} = [ \%report_saved_searches, 'My saved searches' ]
if keys(%report_saved_searches);
$report_menu{'Financial (Payables)'} = [ \%report_payable, 'Financial reports (Payables)' ]
if $curuser->access_right('Financial reports');
+$report_menu{'Employees'} = [ \%report_employee, 'Employee reports' ]
+ if $curuser->access_right('Employee Reports');
$report_menu{'Logs'} = [ \%report_logs, 'System and email logs' ]
if (keys %report_logs); # empty if the user has no rights to it
$report_menu{'SQL Query'} = [ $fsurl.'search/report_sql.html', 'SQL Query']
if $curuser->access_right('Configuration'); # 'View system status');
$tools_system{'Job Queue'} = [ $fsurl.'search/queue.html', 'View pending job queue' ]
if $curuser->access_right('Job queue');
-$tools_system{'Access log statistics'} = [ $fsurl.'search/report_access_user_log.html?group_by=path', '' ]
- if $curuser->access_right('Configuration'); # 'View profiling data');
tie my %tools_menu, 'Tie::IxHash', ();
$tools_menu{'Customers'} = [ \%tools_customers, 'Customer tools' ]
my $part_pkg = $cust_pkg->part_pkg;
-my @unprovision_warning;
-{
- my @services_w_export;
- for ( $cust_pkg->cust_svc ) {
- push( @services_w_export, ($_->label)[0] . ': ' . ($_->label)[1], )
- if $_->part_svc->export_svc;
- }
- if ( @services_w_export ) {
- push( @unprovision_warning, 'NOTE: This package has '
- . @services_w_export . ' ' . PL( "service", @services_w_export )
- . ' that will be unprovisioned', );
- if ( @services_w_export < 10 ) {
- $unprovision_warning[0] .= ':';
- push( @unprovision_warning, @services_w_export, );
- }
- else {
- $unprovision_warning[0] .= '.';
- }
+my @unprovision_warning = ();
+unless ( $method =~ /^(resume|uncancel)$/ ) {
+ my @services_w_export = map { my @l = $_->label; $l[0]. ': '. $l[1]; }
+ grep $_->part_svc->export_svc,
+ $cust_pkg->cust_svc;
+ if ( @services_w_export ) {
+
+ my $actioned = ($method =~ /^(suspend|adjourn)$/) ? 'suspended'
+ : 'unprovisioned';
+ push @unprovision_warning,
+ 'NOTE: This package has '. @services_w_export. ' '.
+ PL( 'service', @services_w_export ). " that will be $actioned";
+
+ if ( @services_w_export < 10 ) {
+ $unprovision_warning[0] .= ':';
+ push @unprovision_warning, @services_w_export;
+ } else {
+ $unprovision_warning[0] .= '.';
}
+
+ }
}
$date ||= $cust_pkg->get($method);
<%init>
die "access denied"
- unless $FS::CurrentUser::CurrentUser->access_right('Employees: Audit Report');
+ unless $FS::CurrentUser::CurrentUser->access_right('Employee Reports');
my %tables = (
cust_pay => 'Payments',
<%init>
die "access denied"
- unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+ unless $FS::CurrentUser::CurrentUser->access_right('Employee Reports');
my $group_by = '';
if ( $cgi->param('group_by') =~ /^(\w+)$/ ) {
<%init>
die "access denied"
- unless $FS::CurrentUser::CurrentUser->access_right('Employees: Audit Report');
+ unless $FS::CurrentUser::CurrentUser->access_right('Employee Reports');
my %tables = (
cust_pay => 'Payments',
--- /dev/null
+<& /elements/header-popup.html, {
+ 'title' => 'Database size details',
+ }
+&>
+
+<& /search/elements/search.html,
+ 'name_singular' => 'table',
+ 'header' => [ 'Table', 'Size' ],
+ 'query' => $query,
+ 'count_query' => $count_query,
+ 'nohtmlheader' => 1,
+&>
+
+<& /elements/footer-popup.html &>
+<%init>
+
+my $query = q{
+
+ SELECT table_name, pg_size_pretty(total_bytes) AS total
+ FROM (
+ SELECT * FROM (
+ SELECT relname AS TABLE_NAME,
+ pg_total_relation_size(c.oid) AS total_bytes
+ FROM pg_class c
+ LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
+ WHERE relkind = 'r'
+ AND nspname = 'public'
+ ) a
+ ) a order by total_bytes desc
+};
+
+my $count_query = q{
+ SELECT count(*) FROM pg_class c
+ LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
+ WHERE relkind = 'r'
+ AND nspname = 'public'
+};
+
+</%init>
<& /elements/header.html, 'System Status' &>
+
+<& /elements/init_overlib.html &>
+
% foreach my $section ( keys %status ) {
<FONT CLASS="fsinnerbox-title"><% mt($section) |h %></FONT>
<TABLE CLASS="fsinnerbox">
</TABLE>
<BR><BR>
% }
+
<& /elements/footer.html &>
<%init>
my $db_size = 'Unknown';
if ( $db eq 'PostgreSQL' ) {
$db_size = FS::Record->scalar_sql(qq(
- SELECT pg_size_pretty(pg_database_size('freeside'))
- ));
+ SELECT pg_size_pretty(pg_database_size('freeside'))
+ )). ' '.
+ include('/elements/popup_link.html',
+ 'action' => 'Status-db_size_detail.html',
+ 'label' => '(details)',
+ 'actionlabel' => 'Database size details',
+ );
}
tie my %status, 'Tie::IxHash',
}
my $void = '';
-# note: "TOKN" is not yet supported in stock freeside
-my $voidmsg = $cust_pay->payby =~ /^(CARD|CHEK|TOKN)$/
+my $voidmsg = $cust_pay->payby =~ /^(CARD|CHEK)$/
? ' (' . emt('do not send anything to the payment gateway').')'
: '';
$void = ' ('.
- include( '/elements/popup_link.html',
- 'label' => emt('void'),
- 'action' => "${p}misc/void-cust_pay.html?".$cust_pay->paynum,
- 'actionlabel' => emt('Void payment'),
- ).
- ')'
+ include( '/elements/popup_link.html',
+ 'label' => emt('void'),
+ 'action' => "${p}misc/void-cust_pay.html?".$cust_pay->paynum,
+ 'actionlabel' => emt('Void payment'),
+ 'title' => emt('Void this payment from the database').
+ $voidmsg,
+ ).
+ ')'
if $cust_pay->closed !~ /^Y/i
&& ( ( $cust_pay->payby eq 'CARD' && $opt{'Credit card void'} )
|| ( $cust_pay->payby eq 'CHEK' && $opt{'Echeck void'} )