summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Kohler <ivan@freeside.biz>2013-07-08 14:09:40 -0700
committerIvan Kohler <ivan@freeside.biz>2013-07-08 14:09:40 -0700
commit59c29eed0653360378f9c5428c1c3c5833c3b387 (patch)
treee3de55179e19b73a0ee8d6c4281ebe82e876038f
parentd4bd6b057accfd69731168873d57f5d0e652cf43 (diff)
parent3c693abdf3cccf5a716a0ce7075f3f1ed1063786 (diff)
Merge branch 'master' of git.freeside.biz:/home/git/freeside
-rw-r--r--FS/FS/Conf.pm7
-rw-r--r--FS/FS/Schema.pm1
-rw-r--r--FS/FS/cdr/netsapiens.pm17
-rw-r--r--FS/FS/cust_pkg.pm11
-rw-r--r--FS/FS/part_pkg.pm37
-rw-r--r--FS/FS/part_pkg/delayed_Mixin.pm12
-rw-r--r--bin/sqlradius-reexport-group25
-rwxr-xr-xhttemplate/edit/part_pkg.cgi11
-rw-r--r--httemplate/elements/order_pkg.js25
-rw-r--r--httemplate/elements/select-part_pkg.html1
-rw-r--r--httemplate/elements/tr-select-cust-part_pkg.html13
-rw-r--r--httemplate/misc/cust-part_pkg.cgi13
-rw-r--r--httemplate/misc/order_pkg.html10
-rw-r--r--httemplate/search/customer_accounting_summary.html9
14 files changed, 149 insertions, 43 deletions
diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm
index f76c72ff4..ae1fd4be8 100644
--- a/FS/FS/Conf.pm
+++ b/FS/FS/Conf.pm
@@ -4349,6 +4349,13 @@ and customer address. Include units.',
},
{
+ 'key' => 'part_pkg-delay_start',
+ 'section' => '',
+ 'description' => 'Enabled "delayed start" option for packages.',
+ 'type' => 'checkbox',
+ },
+
+ {
'key' => 'mcp_svcpart',
'section' => '',
'description' => 'Master Control Program svcpart. Leave this blank.',
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 6df45e2b1..5e2e2efd5 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -2050,6 +2050,7 @@ sub tables_hashref {
'setup_show_zero', 'char', 'NULL', 1, '', '',
'successor', 'int', 'NULL', '', '', '',
'family_pkgpart','int', 'NULL', '', '', '',
+ 'delay_start', 'int', 'NULL', '', '', '',
],
'primary_key' => 'pkgpart',
'unique' => [],
diff --git a/FS/FS/cdr/netsapiens.pm b/FS/FS/cdr/netsapiens.pm
index bcaa3496d..9d07aef7e 100644
--- a/FS/FS/cdr/netsapiens.pm
+++ b/FS/FS/cdr/netsapiens.pm
@@ -15,11 +15,11 @@ use FS::cdr qw( _cdr_date_parser_maker _cdr_min_parser_maker );
'disabled' => 0, #0 default, set to 1 to disable
'import_fields' => [
-
+
sub { my ($cdr, $direction) = @_;
- if ($direction =~ /^o/) { # 'origination'
+ if ($direction =~ /^t/) { # 'origination'
# leave src and dst as they are
- } elsif ($direction =~ /^t/) {
+ } elsif ($direction =~ /^o/) {
my ($local, $remote) = ($cdr->src, $cdr->dst);
$cdr->set('dst', $local);
$cdr->set('src', $remote);
@@ -28,7 +28,7 @@ use FS::cdr qw( _cdr_date_parser_maker _cdr_min_parser_maker );
'', #Domain
'', #user
'src', #local party (src/dst, based on direction)
- _cdr_date_parser_maker('startddate'),
+ _cdr_date_parser_maker('startdate'),
_cdr_date_parser_maker('answerdate'),
sub { my ($cdr, $duration) = @_;
$cdr->set('duration', $duration);
@@ -37,14 +37,15 @@ use FS::cdr qw( _cdr_date_parser_maker _cdr_min_parser_maker );
if $cdr->answerdate;
},
'dst', #remote party
- '', #dialed number
+ sub { my ($cdr, $dialednum) = @_;
+ $cdr->set('dst',$dialednum) if $dialednum =~ /^(\+?1)?8(8|([02-7])\3)/;
+ }, #dialed number
'uniqueid', #CallID (timestamp + '-' + 32 char hex string)
- 'src_ip_addr',
- 'dst_ip_addr',
+ '',
+ '',
'disposition',
],
);
1;
-
diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm
index 398dce134..dd67d0313 100644
--- a/FS/FS/cust_pkg.pm
+++ b/FS/FS/cust_pkg.pm
@@ -289,6 +289,7 @@ sub insert {
my $part_pkg = $self->part_pkg;
+ # if the package def says to start only on the first of the month:
if ( $part_pkg->option('start_1st', 1) && !$self->start_date ) {
my ($sec,$min,$hour,$mday,$mon,$year) = (localtime(time) )[0,1,2,3,4,5];
$mon += 1 unless $mday == 1;
@@ -296,6 +297,8 @@ sub insert {
$self->start_date( timelocal_nocheck(0,0,0,1,$mon,$year) );
}
+ # set up any automatic expire/adjourn/contract_end timers
+ # based on the start date
foreach my $action ( qw(expire adjourn contract_end) ) {
my $months = $part_pkg->option("${action}_months",1);
if($months and !$self->$action) {
@@ -304,16 +307,16 @@ sub insert {
}
}
+ # if this package has "free days" and delayed setup fee, tehn
+ # set start date that many days in the future.
+ # (this should have been set in the UI, but enforce it here)
if ( ! $options{'change'}
&& ( my $free_days = $part_pkg->option('free_days',1) )
&& $part_pkg->option('delay_setup',1)
#&& ! $self->start_date
)
{
- my ($mday,$mon,$year) = (localtime(time) )[3,4,5];
- #my $start_date = ($self->start_date || timelocal(0,0,0,$mday,$mon,$year)) + 86400 * $free_days;
- my $start_date = timelocal(0,0,0,$mday,$mon,$year) + 86400 * $free_days;
- $self->start_date($start_date);
+ $self->start_date( $part_pkg->default_start_date );
}
$self->order_date(time);
diff --git a/FS/FS/part_pkg.pm b/FS/FS/part_pkg.pm
index 22e8828d6..0722647b4 100644
--- a/FS/FS/part_pkg.pm
+++ b/FS/FS/part_pkg.pm
@@ -5,7 +5,7 @@ use strict;
use vars qw( %plans $DEBUG $setup_hack $skip_pkg_svc_hack );
use Carp qw(carp cluck confess);
use Scalar::Util qw( blessed );
-use Time::Local qw( timelocal_nocheck );
+use Time::Local qw( timelocal timelocal_nocheck );
use Tie::IxHash;
use FS::Conf;
use FS::Record qw( qsearch qsearchs dbh dbdef );
@@ -116,6 +116,8 @@ If this record is not obsolete, will be null.
ancestor of this record. If this record is not a successor to another
part_pkg, will be equal to pkgpart.
+=item delay_start - Number of days to delay package start, by default
+
=back
=head1 METHODS
@@ -682,6 +684,7 @@ sub check {
)
|| $self->ut_numbern('fcc_ds0s')
|| $self->ut_numbern('fcc_voip_class')
+ || $self->ut_numbern('delay_start')
|| $self->ut_foreign_keyn('successor', 'part_pkg', 'pkgpart')
|| $self->ut_foreign_keyn('family_pkgpart', 'part_pkg', 'pkgpart')
|| $self->SUPER::check
@@ -1072,9 +1075,39 @@ sub is_free {
}
}
+# whether the plan allows discounts to be applied to this package
sub can_discount { 0; }
-
+
+# whether the plan allows changing the start date
sub can_start_date { 1; }
+
+# the default start date; takes an FS::cust_main as an argument
+sub default_start_date {
+ my $self = shift;
+ my $cust_main = shift;
+ my $conf = FS::Conf->new;
+
+ if ( $self->delay_start ) {
+ my $delay = $self->delay_start;
+
+ my ($mday,$mon,$year) = (localtime(time))[3,4,5];
+ my $start_date = timelocal(0,0,0,$mday,$mon,$year) + 86400 * $delay;
+ return $start_date;
+
+ } elsif ( $conf->exists('order_pkg-no_start_date') ) {
+
+ return '';
+
+ } elsif ( $cust_main ) {
+
+ return $cust_main->next_bill_date;
+
+ } else {
+
+ return '';
+
+ }
+}
sub can_currency_exchange { 0; }
diff --git a/FS/FS/part_pkg/delayed_Mixin.pm b/FS/FS/part_pkg/delayed_Mixin.pm
index ab53bda06..ae286d351 100644
--- a/FS/FS/part_pkg/delayed_Mixin.pm
+++ b/FS/FS/part_pkg/delayed_Mixin.pm
@@ -2,6 +2,7 @@ package FS::part_pkg::delayed_Mixin;
use strict;
use vars qw(%info);
+use Time::Local qw(timelocal);
use NEXT;
%info = (
@@ -52,4 +53,15 @@ sub calc_remain {
sub can_start_date { ! shift->option('delay_setup', 1) }
+sub default_start_date {
+ my $self = shift;
+ if ( $self->option('delay_setup') and $self->option('free_days') ) {
+ my $delay = $self->option('free_days');
+
+ my ($mday, $mon, $year) = (localtime(time))[3,4,5];
+ return timelocal(0,0,0,$mday,$mon,$year) + 86400 * $self->option('free_days');
+ }
+ return $self->NEXT::default_start_date(@_);
+}
+
1;
diff --git a/bin/sqlradius-reexport-group b/bin/sqlradius-reexport-group
new file mode 100644
index 000000000..a60e47126
--- /dev/null
+++ b/bin/sqlradius-reexport-group
@@ -0,0 +1,25 @@
+#!/usr/bin/perl
+
+use FS::UID 'adminsuidsetup';
+use FS::Record qw( qsearch );
+use FS::part_export;
+use FS::radius_group;
+
+my ($user, $exportnum, $group) = @ARGV;
+my $dbh = adminsuidsetup($user) or die;
+$FS::UID::AutoCommit = 0;
+my $radius_group;
+if ( $group =~ /^\d+$/ ) {
+ $radius_group = FS::radius_group->by_key($group);
+} else {
+ $radius_group = qsearchs('radius_group',{'groupname' => $group});
+}
+die "no radius group $group" unless $radius_group;
+
+my @attrs = qsearch('radius_attr', {groupnum => $radius_group->groupnum});
+foreach my $attr (@attrs) {
+ print $attr->attrname."\n";
+ my $error = $export->export_attr_insert($attr);
+ die $error if $error;
+}
+
diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi
index 89f16158f..c13caf588 100755
--- a/httemplate/edit/part_pkg.cgi
+++ b/httemplate/edit/part_pkg.cgi
@@ -65,6 +65,7 @@
'report_option' => 'Report classes',
'fcc_ds0s' => 'Voice-grade equivalents',
'fcc_voip_class' => 'Category',
+ 'delay_start' => 'Default delay (days)',
},
'fields' => [
@@ -199,6 +200,16 @@
{ field=>'setup_cost', type=>'money', },
{ field=>'recur_cost', type=>'money', },
+ ( $conf->exists('part_pkg-delay_start')
+ ? ( { type => 'tablebreak-tr-title',
+ value => 'Delayed start',
+ },
+ { field => 'delay_start',
+ type => 'text', size => 6 },
+ )
+ : ()
+ ),
+
{ type => 'columnnext' },
{ field => 'agent_type',
diff --git a/httemplate/elements/order_pkg.js b/httemplate/elements/order_pkg.js
index 1069a0ee4..762b2ddde 100644
--- a/httemplate/elements/order_pkg.js
+++ b/httemplate/elements/order_pkg.js
@@ -4,9 +4,15 @@ function pkg_changed () {
if ( form.pkgpart.selectedIndex > 0 ) {
+ var opt = form.pkgpart.options[form.pkgpart.selectedIndex];
+ var date_button = document.getElementById('start_date_button');
+ var date_button_disabled = document.getElementById('start_date_button_disabled');
+ var date_text = document.getElementById('start_date_text');
+
+
form.submitButton.disabled = false;
if ( discountnum ) {
- if ( form.pkgpart.options[form.pkgpart.selectedIndex].getAttribute('data-can_discount') == 1 ) {
+ if ( opt.getAttribute('data-can_discount') == 1 ) {
form.discountnum.disabled = false;
discountnum_changed(form.discountnum);
} else {
@@ -15,14 +21,17 @@ function pkg_changed () {
}
}
- if ( form.pkgpart.options[form.pkgpart.selectedIndex].getAttribute('data-can_start_date') == 1 ) {
- form.start_date_text.disabled = false;
- form.start_date.style.backgroundColor = '#ffffff';
- form.start_date_button.style.display = '';
+ form.start_date_text.value = opt.getAttribute('data-start_date');
+ if ( opt.getAttribute('data-can_start_date') == 1 ) {
+ date_text.style.backgroundColor = '#ffffff';
+ date_text.disabled = false;
+ date_button.style.display = '';
+ date_button_disabled.style.display = 'none';
} else {
- form.start_date_text.disabled = true;
- form.start_date.style.backgroundColor = '#dddddd';
- form.start_date_button.style.display = 'none';
+ date_text.style.backgroundColor = '#dddddd';
+ date_text.disabled = true;
+ date_button.style.display = 'none';
+ date_button_disabled.style.display = '';
}
} else {
diff --git a/httemplate/elements/select-part_pkg.html b/httemplate/elements/select-part_pkg.html
index 439c4b53e..9d41b07dc 100644
--- a/httemplate/elements/select-part_pkg.html
+++ b/httemplate/elements/select-part_pkg.html
@@ -23,7 +23,6 @@ Example:
'empty_label' => 'Select package', #should this be the default?
'label_callback' => sub { shift->pkg_comment },
'hashref' => \%hash,
- 'extra_option_attributes' => [ 'can_discount', 'can_start_date' ],
%opt,
)
%>
diff --git a/httemplate/elements/tr-select-cust-part_pkg.html b/httemplate/elements/tr-select-cust-part_pkg.html
index 848ab0a4b..c9c50d27e 100644
--- a/httemplate/elements/tr-select-cust-part_pkg.html
+++ b/httemplate/elements/tr-select-cust-part_pkg.html
@@ -7,10 +7,11 @@
<SCRIPT TYPE="text/javascript">
- function part_pkg_opt(what, value, text, can_discount, can_start_date) {
+ function part_pkg_opt(what, value, text, can_discount, can_start_date, start_date) {
var optionName = new Option(text, value, false, false);
optionName.setAttribute('data-can_discount', can_discount);
optionName.setAttribute('data-can_start_date', can_start_date);
+ optionName.setAttribute('data-start_date', start_date || '');
var length = what.length;
what.options[length] = optionName;
}
@@ -38,12 +39,14 @@
// add the new packages
opt(what.form.pkgpart, '', 'Select package');
var packagesArray = eval('(' + part_pkg + ')' );
- for ( var s = 0; s < packagesArray.length; s=s+4 ) {
+ for ( var s = 0; s < packagesArray.length; s=s+5 ) {
+ //surely this should be some kind of JSON structure
var packagesLabel = packagesArray[s+1];
var can_discount = packagesArray[s+2];
var can_start_date = packagesArray[s+3];
+ var start_date = packagesArray[s+4];
part_pkg_opt(
- what.form.pkgpart, packagesArray[s], packagesLabel, can_discount, can_start_date
+ what.form.pkgpart, packagesArray[s], packagesLabel, can_discount, can_start_date, start_date
);
}
@@ -58,6 +61,10 @@
);
}
+ window.onload = function() {
+ classnum_changed(document.getElementById('classnum'));
+ }
+
</SCRIPT>
<TR>
diff --git a/httemplate/misc/cust-part_pkg.cgi b/httemplate/misc/cust-part_pkg.cgi
index 43b92297e..7aebda40c 100644
--- a/httemplate/misc/cust-part_pkg.cgi
+++ b/httemplate/misc/cust-part_pkg.cgi
@@ -5,8 +5,9 @@ my( $custnum, $prospectnum, $classnum ) = $cgi->param('arg');
my $agent;
+my $cust_main;
if ( $custnum ) {
- my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
+ $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
or die 'unknown custnum';
$agent = $cust_main->agent;
} else {
@@ -31,12 +32,18 @@ my @part_pkg = qsearch({
'order_by' => 'ORDER BY pkg',
});
-my @return = map { warn $_->can_start_date;
+my $date_format = FS::Conf->new->config('date_format') || '%m/%d/%Y';
+
+my @return = map {
+ my $start_date = $_->default_start_date($cust_main);
+ $start_date = time2str($date_format, $start_date)
+ if $start_date;
( $_->pkgpart,
$_->pkg_comment,
$_->can_discount,
$_->can_start_date,
- );
+ $start_date,
+ )
}
#sort { $a->pkg_comment cmp $b->pkg_comment }
@part_pkg;
diff --git a/httemplate/misc/order_pkg.html b/httemplate/misc/order_pkg.html
index 39734427e..a257e53e3 100644
--- a/httemplate/misc/order_pkg.html
+++ b/httemplate/misc/order_pkg.html
@@ -54,9 +54,12 @@
<& /elements/input-date-field.html,{
'name' => 'start_date',
'format' => $date_format,
- 'value' => $start_date,
+ 'value' => '',
'noinit' => 1,
} &>
+ <IMG SRC = "<%$fsurl%>images/calendar-disabled.png"
+ ID = "start_date_button_disabled"
+ STYLE = "display:none">
<FONT SIZE=-1>(<% mt('leave blank to start immediately') |h %>)</FONT>
</TD>
</TR>
@@ -213,11 +216,6 @@ if ( $cgi->param('quantity') =~ /^\s*(\d+)\s*$/ ) {
}
my $format = $date_format. ' %T %z (%Z)'; #false laziness w/REAL_cust_pkg.cgi?
-my $start_date = '';
-if( ! $conf->exists('order_pkg-no_start_date') && $cust_main ) {
- $start_date = $cust_main->next_bill_date;
- $start_date = $start_date ? time2str($format, $start_date) : '';
-}
my $svcpart = scalar($cgi->param('svcpart'));
diff --git a/httemplate/search/customer_accounting_summary.html b/httemplate/search/customer_accounting_summary.html
index b48ff21e3..c9cfa4088 100644
--- a/httemplate/search/customer_accounting_summary.html
+++ b/httemplate/search/customer_accounting_summary.html
@@ -121,10 +121,7 @@ die "access denied"
unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
my ($agentnum,$sel_agent);
-if ( $cgi->param('agentnum') eq 'all' ) {
- $agentnum = 0;
-}
-elsif ( $cgi->param('agentnum') =~ /^(\d+)$/ ) {
+if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) {
$agentnum = $1;
$sel_agent = qsearchs('agent', { 'agentnum' => $agentnum } );
die "agentnum $agentnum not found!" unless $sel_agent;
@@ -177,10 +174,6 @@ my $query = FS::cust_main::Search->search(\%search_hash);
my @custs = qsearch($query);
foreach my $cust_main ( @custs ) {
- # XXX should do this in the qsearch
- next unless ($status eq '' || $status eq $cust_main->status);
- next unless ($agentnum == 0 || $cust_main->agentnum eq $agentnum);
- next unless ($refnum == 0 || $cust_main->refnum eq $refnum);
push @custnames, $cust_main->name;