diff options
Diffstat (limited to 'FS')
-rw-r--r-- | FS/FS/API.pm | 17 | ||||
-rw-r--r-- | FS/FS/Conf.pm | 10 | ||||
-rw-r--r-- | FS/FS/cdr/cia.pm | 54 | ||||
-rw-r--r-- | FS/FS/cdr/cia_callblast.pm | 54 | ||||
-rw-r--r-- | FS/FS/cust_main.pm | 21 | ||||
-rw-r--r-- | FS/FS/cust_pkg.pm | 46 | ||||
-rw-r--r-- | FS/FS/part_pkg/global_Mixin.pm | 5 | ||||
-rw-r--r-- | FS/FS/reason.pm | 2 |
8 files changed, 171 insertions, 38 deletions
diff --git a/FS/FS/API.pm b/FS/FS/API.pm index dd172c143..c49fb205a 100644 --- a/FS/FS/API.pm +++ b/FS/FS/API.pm @@ -603,8 +603,21 @@ sub location_info { Bills a single customer now, in the same fashion as the "Bill now" link in the UI. -Returns a hash reference with a single key, 'error'. If there is an error, -the value contains the error, otherwise it is empty. +Returns a hash reference with a single key, 'error'. If there is an error, +the value contains the error, otherwise it is empty. Takes a list of keys and +values as parameters with the following keys: + +=over 4 + +=item secret + +API Secret (required) + +=item custnum + +Customer number (required) + +=back =cut diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index a4e26f7c8..091070ec5 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -4627,6 +4627,16 @@ and customer address. Include units.', }, { + 'key' => 'part_pkg-delay_cancel-days', + 'section' => '', + 'description' => 'Expire packages in this many days when using delay_cancel (default is 1)', + 'type' => 'text', + 'validate' => sub { (($_[0] =~ /^\d*$/) && (($_[0] eq '') || $_[0])) + ? 'Must specify an integer number of days' + : '' } + }, + + { 'key' => 'mcp_svcpart', 'section' => '', 'description' => 'Master Control Program svcpart. Leave this blank.', diff --git a/FS/FS/cdr/cia.pm b/FS/FS/cdr/cia.pm index 0471e9bb4..ca44c0fdf 100644 --- a/FS/FS/cdr/cia.pm +++ b/FS/FS/cdr/cia.pm @@ -1,9 +1,8 @@ package FS::cdr::cia; use strict; -use vars qw( @ISA %info $date $tmp_mday $tmp_mon $tmp_year); +use vars qw( @ISA %info ); use FS::cdr qw(_cdr_date_parser_maker); -use Time::Local; @ISA = qw(FS::cdr); @@ -12,39 +11,26 @@ use Time::Local; 'weight' => 510, 'header' => 1, 'type' => 'csv', - 'sep_char' => "|", + 'sep_char' => "\t", 'import_fields' => [ - 'accountcode', - skip(2), # First and last name - - sub { my($cdr, $date) = @_; - $date =~ /^(\d{1,2})\/(\d{1,2})\/(\d\d(\d\d)?)$/ - or die "unparsable date: $date"; #maybe we shouldn't die... - ($tmp_mday, $tmp_mon, $tmp_year) = ( $2, $1-1, $3 ); - }, #Date - - sub { my($cdr, $time) = @_; - #my($sec, $min, $hour, $mday, $mon, $year)= localtime($cdr->startdate); - $time =~ /^(\d{1,2}):(\d{1,2}):(\d{1,2})$/ - or die "unparsable time: $time"; #maybe we shouldn't die... - $cdr->startdate( timelocal($3, $2, $1 ,$tmp_mday, $tmp_mon, $tmp_year)); - $cdr->answerdate( timelocal($3, $2, $1 ,$tmp_mday, $tmp_mon, $tmp_year)); - - }, # Start time - - sub { my($cdr, $time) = @_; - #my($sec, $min, $hour, $mday, $mon, $year)= localtime($cdr->startdate); - $time =~ /^(\d{1,2}):(\d{1,2}):(\d{1,2})$/ - or die "unparsable time: $time"; #maybe we shouldn't die... - #$cdr->startdate( timelocal($3, $2, $1 ,$mday, $mon, $year) ); - $cdr->enddate( - timelocal($3, $2, $1 ,$tmp_mday, $tmp_mon, $tmp_year) ); - }, # End time - - 'disposition', # Disposition - 'dst', # PhoneNumber - skip(3), # Extension, Service Type, Filler - 'src', # ClientContactID + skip(2), # Reseller Account Number, Confirmation Number + 'description', # Conference Name + skip(3), # Organization Name, Bill Code, Q&A Active + 'userfield', # Chairperson Name + skip(2), # Conference Start Time, Conference End Time + _cdr_date_parser_maker('startdate'), # Connect Time + _cdr_date_parser_maker('enddate'), # Disconnect Time + skip(1), # Duration + sub { my($cdr, $data, $conf, $param) = @_; + $cdr->duration($data); + $cdr->billsec( $data); + }, # Roundup Duration + skip(1), # User Name + 'dst', # DNIS + 'src', # ANI + skip(2), # Call Type, Toll Free, + 'accountcode', # Chair Conference Entry Code + skip(1), # Participant Conference Entry Code, ], ); diff --git a/FS/FS/cdr/cia_callblast.pm b/FS/FS/cdr/cia_callblast.pm new file mode 100644 index 000000000..d59cd7823 --- /dev/null +++ b/FS/FS/cdr/cia_callblast.pm @@ -0,0 +1,54 @@ +package FS::cdr::cia_callblast; + +use strict; +use vars qw( @ISA %info $date $tmp_mday $tmp_mon $tmp_year); +use FS::cdr qw(_cdr_date_parser_maker); +use Time::Local; + +@ISA = qw(FS::cdr); + +%info = ( + 'name' => 'Client Instant Access Callblast', + 'weight' => 510, + 'header' => 1, + 'type' => 'csv', + 'sep_char' => "|", + 'import_fields' => [ + 'accountcode', + skip(2), # First and last name + + sub { my($cdr, $date) = @_; + $date =~ /^(\d{1,2})\/(\d{1,2})\/(\d\d(\d\d)?)$/ + or die "unparsable date: $date"; #maybe we shouldn't die... + ($tmp_mday, $tmp_mon, $tmp_year) = ( $2, $1-1, $3 ); + }, #Date + + sub { my($cdr, $time) = @_; + #my($sec, $min, $hour, $mday, $mon, $year)= localtime($cdr->startdate); + $time =~ /^(\d{1,2}):(\d{1,2}):(\d{1,2})$/ + or die "unparsable time: $time"; #maybe we shouldn't die... + $cdr->startdate( timelocal($3, $2, $1 ,$tmp_mday, $tmp_mon, $tmp_year)); + $cdr->answerdate( timelocal($3, $2, $1 ,$tmp_mday, $tmp_mon, $tmp_year)); + + }, # Start time + + sub { my($cdr, $time) = @_; + #my($sec, $min, $hour, $mday, $mon, $year)= localtime($cdr->startdate); + $time =~ /^(\d{1,2}):(\d{1,2}):(\d{1,2})$/ + or die "unparsable time: $time"; #maybe we shouldn't die... + #$cdr->startdate( timelocal($3, $2, $1 ,$mday, $mon, $year) ); + $cdr->enddate( + timelocal($3, $2, $1 ,$tmp_mday, $tmp_mon, $tmp_year) ); + }, # End time + + 'disposition', # Disposition + 'dst', # PhoneNumber + skip(3), # Extension, Service Type, Filler + 'src', # ClientContactID + ], + +); + +sub skip { map {''} (1..$_[0]) } + +1; diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index d38f3d01b..c3b141e1b 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -3900,6 +3900,27 @@ sub cust_status { } } +=item is_status_delay_cancel + +Returns true if customer status is 'suspended' +and all suspended cust_pkg return true for +cust_pkg->is_status_delay_cancel. + +This is not a real status, this only meant for hacking display +values, because otherwise treating the customer as suspended is +really the whole point of the delay_cancel option. + +=cut + +sub is_status_delay_cancel { + my ($self) = @_; + return 0 unless $self->status eq 'suspended'; + foreach my $cust_pkg ($self->ncancelled_pkgs) { + return 0 unless $cust_pkg->is_status_delay_cancel; + } + return 1; +} + =item ucfirst_cust_status =item ucfirst_status diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 3bd210706..1cc83b6a0 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -823,6 +823,20 @@ sub cancel { my $date = $options{'date'} if $options{'date'}; # expire/cancel later $date = '' if ($date && $date <= $cancel_time); # complain instead? + my $delay_cancel = undef; + if ( !$date && $self->part_pkg->option('delay_cancel',1) + && (($self->status eq 'active') || ($self->status eq 'suspended')) + ) { + my $expdays = $conf->config('part_pkg-delay_cancel-days') || 1; + my $expsecs = 60*60*24*$expdays; + my $suspfor = $self->susp ? $cancel_time - $self->susp : 0; + $expsecs = $expsecs - $suspfor if $suspfor; + unless ($expsecs <= 0) { #if it's already been suspended long enough, don't re-suspend + $delay_cancel = 1; + $date = $cancel_time + $expsecs; + } + } + #race condition: usage could be ongoing until unprovisioned #resolved by performing a change package instead (which unprovisions) and #later cancelling @@ -893,6 +907,11 @@ sub cancel { my %hash = $self->hash; if ( $date ) { $hash{'expire'} = $date; + if ($delay_cancel) { + $hash{'susp'} = $cancel_time unless $self->susp; + $hash{'adjourn'} = undef; + $hash{'resume'} = undef; + } } else { $hash{'cancel'} = $cancel_time; } @@ -1643,7 +1662,7 @@ sub unsuspend { ) or $hash{'order_date'} == $hash{'susp'} or $self->part_pkg->option('unused_credit_suspend') - or ( defined($reason) and $reason->unused_credit ) + or ( ref($reason) and $reason->unused_credit ) ) { $adjust_bill = 0; } @@ -3343,6 +3362,31 @@ sub statuscolor { $statuscolor{$self->status}; } +=item is_status_delay_cancel + +Returns true if part_pkg has option delay_cancel, +cust_pkg status is 'suspended' and expire is set +to cancel package within the next day (or however +many days are set in global config part_pkg-delay_cancel-days. + +This is not a real status, this only meant for hacking display +values, because otherwise treating the package as suspended is +really the whole point of the delay_cancel option. + +=cut + +sub is_status_delay_cancel { + my ($self) = @_; + return 0 unless $self->part_pkg->option('delay_cancel',1); + return 0 unless $self->status eq 'suspended'; + return 0 unless $self->expire; + my $conf = new FS::Conf; + my $expdays = $conf->config('part_pkg-delay_cancel-days') || 1; + my $expsecs = 60*60*24*$expdays; + return 0 unless $self->expire < time + $expsecs; + return 1; +} + =item pkg_label Returns a label for this package. (Currently "pkgnum: pkg - comment" or diff --git a/FS/FS/part_pkg/global_Mixin.pm b/FS/FS/part_pkg/global_Mixin.pm index 263772955..2318c3e61 100644 --- a/FS/FS/part_pkg/global_Mixin.pm +++ b/FS/FS/part_pkg/global_Mixin.pm @@ -40,6 +40,10 @@ tie my %a2billing_simultaccess, 'Tie::IxHash', ( 'changing packages', 'type' => 'checkbox', }, + 'delay_cancel' => { + 'name' => 'Automatically suspend for one day before cancelling', + 'type' => 'checkbox', + }, # miscellany--maybe put this in a separate module? @@ -109,6 +113,7 @@ tie my %a2billing_simultaccess, 'Tie::IxHash', ( unused_credit_cancel unused_credit_suspend unused_credit_change + delay_cancel a2billing_tariff a2billing_type diff --git a/FS/FS/reason.pm b/FS/FS/reason.pm index 864804d26..9c34dd98a 100644 --- a/FS/FS/reason.pm +++ b/FS/FS/reason.pm @@ -174,7 +174,7 @@ sub new_or_existing { } } else { my %hash = ('class' => $opt{'class'}, 'type' => $opt{'type'}); - my $reason_type = qsearchs('reason_type', \%hash) + $reason_type = qsearchs('reason_type', \%hash) || FS::reason_type->new(\%hash); $error = $reason_type->insert unless $reason_type->typenum; |