use FS::cust_pkg_discount;
use FS::discount;
use FS::UI::Web;
+use Data::Dumper;
# need to 'use' these instead of 'require' in sub { cancel, suspend, unsuspend,
# setup }
Previous locationnum
+=item waive_setup
+
=back
Note: setup, last_bill, bill, adjourn, susp, expire, cancel and change_date
sub insert {
my( $self, %options ) = @_;
+ my $error = $self->check_pkgpart;
+ return $error if $error;
+
if ( $self->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;
local $FS::UID::AutoCommit = 0;
my $dbh = dbh;
- my $error = $self->SUPER::insert($options{options} ? %{$options{options}} : ());
+ $error = $self->SUPER::insert($options{options} ? %{$options{options}} : ());
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
return $error;
This method now works but you probably shouldn't use it.
-You don't want to delete billing items, because there would then be no record
-the customer ever purchased the item. Instead, see the cancel method.
+You don't want to delete packages, because there would then be no record
+the customer ever purchased the package. Instead, see the cancel method and
+hide cancelled packages.
=cut
-#sub delete {
-# return "Can't delete cust_pkg records!";
-#}
+sub delete {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ foreach my $cust_pkg_discount ($self->cust_pkg_discount) {
+ my $error = $cust_pkg_discount->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+ #cust_bill_pkg_discount?
+
+ foreach my $cust_pkg_detail ($self->cust_pkg_detail) {
+ my $error = $cust_pkg_detail->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ foreach my $cust_pkg_reason (
+ qsearchs( {
+ 'table' => 'cust_pkg_reason',
+ 'hashref' => { 'pkgnum' => $self->pkgnum },
+ }
+ )
+ ) {
+ my $error = $cust_pkg_reason->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ #pkg_referral?
+
+ my $error = $self->SUPER::delete(@_);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+
+}
=item replace [ OLD_RECORD ] [ HASHREF | OPTION => VALUE ... ]
#trigger export of new RADIUS Expiration attribute when cust_pkg.bill changes
foreach my $old_svc_acct ( @svc_acct ) {
my $new_svc_acct = new FS::svc_acct { $old_svc_acct->hash };
- my $s_error = $new_svc_acct->replace($old_svc_acct);
+ my $s_error =
+ $new_svc_acct->replace( $old_svc_acct,
+ 'depend_jobnum' => $options->{depend_jobnum},
+ );
if ( $s_error ) {
$dbh->rollback if $oldAutoCommit;
return $s_error;
$self->ut_numbern('pkgnum')
|| $self->ut_foreign_key('custnum', 'cust_main', 'custnum')
|| $self->ut_numbern('pkgpart')
+ || $self->check_pkgpart
|| $self->ut_foreign_keyn('locationnum', 'cust_location', 'locationnum')
|| $self->ut_numbern('start_date')
|| $self->ut_numbern('setup')
|| $self->ut_numbern('adjourn')
|| $self->ut_numbern('expire')
|| $self->ut_enum('no_auto', [ '', 'Y' ])
+ || $self->ut_enum('waive_setup', [ '', 'Y' ])
+ || $self->ut_numbern('agent_pkgid')
;
return $error if $error;
+ return "A package with both start date (future start) and setup date (already started) will never bill"
+ if $self->start_date && $self->setup;
+
+ $self->usernum($FS::CurrentUser::CurrentUser->usernum) unless $self->usernum;
+
+ if ( $self->dbdef_table->column('manual_flag') ) {
+ $self->manual_flag('') if $self->manual_flag eq ' ';
+ $self->manual_flag =~ /^([01]?)$/
+ or return "Illegal manual_flag ". $self->manual_flag;
+ $self->manual_flag($1);
+ }
+
+ $self->SUPER::check;
+}
+
+=item check_pkgpart
+
+=cut
+
+sub check_pkgpart {
+ my $self = shift;
+
+ my $error = $self->ut_numbern('pkgpart');
+ return $error if $error;
+
if ( $self->reg_code ) {
unless ( grep { $self->pkgpart == $_->pkgpart }
}
- $self->usernum($FS::CurrentUser::CurrentUser->usernum) unless $self->usernum;
-
- if ( $self->dbdef_table->column('manual_flag') ) {
- $self->manual_flag('') if $self->manual_flag eq ' ';
- $self->manual_flag =~ /^([01]?)$/
- or return "Illegal manual_flag ". $self->manual_flag;
- $self->manual_flag($1);
- }
+ '';
- $self->SUPER::check;
}
=item cancel [ OPTION => VALUE ... ]
}
}
- my %svc;
- if ( $date ) {
-# copied from below
- foreach my $cust_svc (
- #schwartz
- map { $_->[0] }
- sort { $a->[1] <=> $b->[1] }
- map { [ $_, $_->svc_x->table_info->{'cancel_weight'} ]; }
- qsearch( 'cust_svc', { 'pkgnum' => $self->pkgnum } )
- ) {
- my $error = $cust_svc->cancel( ('date' => $date) );
+ unless ( $date ) {
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return "Error expiring cust_svc: $error";
- }
- }
- } else { #!date
foreach my $cust_svc (
#schwartz
map { $_->[0] }
return "Error cancelling cust_svc: $error";
}
}
- } #if $date
- # Add a credit for remaining service
- my $last_bill = $self->getfield('last_bill') || 0;
- my $next_bill = $self->getfield('bill') || 0;
- my $do_credit;
- if ( exists($options{'unused_credit'}) ) {
- $do_credit = $options{'unused_credit'};
- }
- else {
- $do_credit = $self->part_pkg->option('unused_credit_cancel', 1);
- }
- if ( $do_credit
- and $last_bill > 0 # the package has been billed
- and $next_bill > 0 # the package has a next bill date
- and $next_bill >= $cancel_time # which is in the future
- ) {
- my $remaining_value = $self->calc_remain('time' => $cancel_time);
- if ( $remaining_value > 0 ) {
- # && !$options{'no_credit'} ) {
- # Undocumented, unused option.
- # part_pkg configuration should decide this anyway.
- my $error = $self->cust_main->credit(
- $remaining_value,
- 'Credit for unused time on '. $self->part_pkg->pkg,
- 'reason_type' => $conf->config('cancel_credit_type'),
- );
- if ($error) {
- $dbh->rollback if $oldAutoCommit;
- return "Error crediting customer \$$remaining_value for unused time on".
- $self->part_pkg->pkg. ": $error";
- }
- } #if $remaining_value
- } #if $do_credit
+ # Add a credit for remaining service
+ my $last_bill = $self->getfield('last_bill') || 0;
+ my $next_bill = $self->getfield('bill') || 0;
+ my $do_credit;
+ if ( exists($options{'unused_credit'}) ) {
+ $do_credit = $options{'unused_credit'};
+ }
+ else {
+ $do_credit = $self->part_pkg->option('unused_credit_cancel', 1);
+ }
+ if ( $do_credit
+ and $last_bill > 0 # the package has been billed
+ and $next_bill > 0 # the package has a next bill date
+ and $next_bill >= $cancel_time # which is in the future
+ ) {
+ my $remaining_value = $self->calc_remain('time' => $cancel_time);
+ if ( $remaining_value > 0 ) {
+ my $error = $self->cust_main->credit(
+ $remaining_value,
+ 'Credit for unused time on '. $self->part_pkg->pkg,
+ 'reason_type' => $conf->config('cancel_credit_type'),
+ );
+ if ($error) {
+ $dbh->rollback if $oldAutoCommit;
+ return "Error crediting customer \$$remaining_value for unused time".
+ " on ". $self->part_pkg->pkg. ": $error";
+ }
+ } #if $remaining_value
+ } #if $do_credit
+
+ } #unless $date
my %hash = $self->hash;
$date ? ($hash{'expire'} = $date) : ($hash{'cancel'} = $cancel_time);
}
-use Data::Dumper;
use Storable 'thaw';
use MIME::Base64;
sub process_bulk_cust_pkg {
sub h_cust_svc {
my $self = shift;
+ warn "$me _h_cust_svc called on $self\n"
+ if $DEBUG;
+
my ($end, $start, $mode) = @_;
my @cust_svc = $self->_sort_cust_svc(
[ qsearch( 'h_cust_svc',
if ( $mode eq 'I' ) {
my %hidden_svcpart = map { $_->svcpart => $_->hidden } $self->part_svc;
return grep { !$hidden_svcpart{$_->svcpart} } @cust_svc;
- }
- else {
+ } else {
return @cust_svc;
}
}
sub h_labels {
my $self = shift;
+ warn "$me _h_labels called on $self\n"
+ if $DEBUG;
map { [ $_->label(@_) ] } $self->h_cust_svc(@_);
}
sub _labels_short {
my( $self, $method ) = ( shift, shift );
+ warn "$me _labels_short called on $self with $method method\n"
+ if $DEBUG;
+
my $conf = new FS::Conf;
my $max_same_services = $conf->config('cust_bill-max_same_services') || 5;
+ warn "$me _labels_short populating \%labels\n"
+ if $DEBUG;
+
my %labels;
#tie %labels, 'Tie::IxHash';
push @{ $labels{$_->[0]} }, $_->[1]
foreach $self->$method(@_);
+
+ warn "$me _labels_short populating \@labels\n"
+ if $DEBUG;
+
my @labels;
foreach my $label ( keys %labels ) {
my %seen = ();
my @values = grep { ! $seen{$_}++ } @{ $labels{$label} };
my $num = scalar(@values);
+ warn "$me _labels_short $num items for $label\n"
+ if $DEBUG;
+
if ( $num > $max_same_services ) {
+ warn "$me _labels_short more than $max_same_services, so summarizing\n"
+ if $DEBUG;
push @labels, "$label ($num)";
} else {
if ( $conf->exists('cust_bill-consolidate_services') ) {
+ warn "$me _labels_short consolidating services\n"
+ if $DEBUG;
# push @labels, "$label: ". join(', ', @values);
while ( @values ) {
my $detail = "$label: ";
$detail .= shift(@values). ', '
- while @values && length($detail.$values[0]) < 78;
+ while @values
+ && ( length($detail.$values[0]) < 78 || $detail eq "$label: " );
$detail =~ s/, $//;
push @labels, $detail;
}
+ warn "$me _labels_short done consolidating services\n"
+ if $DEBUG;
} else {
+ warn "$me _labels_short adding service data\n"
+ if $DEBUG;
push @labels, map { "$label: $_" } @values;
}
}
'discountnum' => $self->discountnum,
'months_used' => 0,
'end_date' => '', #XXX
- 'otaker' => $self->otaker,
#for the create a new discount case
'_type' => $self->discountnum__type,
'amount' => $self->discountnum_amount,
'percent' => $self->discountnum_percent,
'months' => $self->discountnum_months,
+ 'setup' => $self->discountnum_setup,
#'disabled' => $self->discountnum_disabled,
};
'UPDATE cust_pkg SET bill = bill + (365*24*60*60) WHERE bill < last_bill
AND bill > 1259654400 AND bill < 1262332800 AND (SELECT plan FROM part_pkg
WHERE part_pkg.pkgpart = cust_pkg.pkgpart) = \'prorate\'',
+ # RT6628, add order_date to cust_pkg
+ 'update cust_pkg set order_date = (select history_date from h_cust_pkg
+ where h_cust_pkg.pkgnum = cust_pkg.pkgnum and
+ history_action = \'insert\') where order_date is null',
);
foreach my $sql (@statements) {
my $sth = dbh->prepare($sql);