X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fpart_pkg.pm;h=e4c13aade932a22f45c8b731c998994870596e22;hb=83a6a677f62ca501011d9bac6371344dbb5a13b3;hp=182be87ea4ae05998c400492dd935acdbda31c02;hpb=1755a73ccf8881a132ffd702471f455543871683;p=freeside.git diff --git a/FS/FS/part_pkg.pm b/FS/FS/part_pkg.pm index 182be87ea..e4c13aade 100644 --- a/FS/FS/part_pkg.pm +++ b/FS/FS/part_pkg.pm @@ -1,8 +1,8 @@ package FS::part_pkg; use strict; -use vars qw( @ISA %freq %plans $DEBUG ); -use Carp qw(carp cluck); +use vars qw( @ISA %plans $DEBUG ); +use Carp qw(carp cluck confess); use Tie::IxHash; use FS::Conf; use FS::Record qw( qsearch qsearchs dbh dbdef ); @@ -12,8 +12,11 @@ use FS::cust_pkg; use FS::agent_type; use FS::type_pkgs; use FS::part_pkg_option; +use FS::pkg_class; -@ISA = qw( FS::Record ); +@ISA = qw( FS::m2m_Common FS::Record ); # FS::option_Common ); # this can use option_Common + # when all the plandata bs is + # gone $DEBUG = 0; @@ -56,6 +59,8 @@ inherits from FS::Record. The following fields are currently supported: =item comment - Text name of this package definition (non-customer-viewable) +=item classnum - Optional package class (see L) + =item promo_code - Promotional code =item setup - Setup fee expression (deprecated) @@ -76,6 +81,10 @@ inherits from FS::Record. The following fields are currently supported: =item disabled - Disabled flag, empty or `Y' +=item pay_weight - Weight (relative to credit_weight and other package definitions) that controls payment application to specific line items. + +=item credit_weight - Weight (relative to other package definitions) that controls credit application to specific line items. + =back =head1 METHODS @@ -302,6 +311,12 @@ FS::pkg_svc record will be updated. sub replace { my( $new, $old ) = ( shift, shift ); my %options = @_; + + # We absolutely have to have an old vs. new record to make this work. + if (!defined($old)) { + $old = qsearchs( 'part_pkg', { 'pkgpart' => $new->pkgpart } ); + } + warn "FS::part_pkg::replace called on $new to replace $old ". "with options %options" if $DEBUG; @@ -375,6 +390,7 @@ sub replace { next unless $old_quantity != $quantity || $old_primary_svc ne $primary_svc; my $new_pkg_svc = new FS::pkg_svc( { + 'pkgsvcnum' => ( $old_pkg_svc ? $old_pkg_svc->pkgsvcnum : '' ), 'pkgpart' => $new->pkgpart, 'svcpart' => $part_svc->svcpart, 'quantity' => $quantity, @@ -417,7 +433,7 @@ sub check { my $error = $self->ut_number('freq'); return $error if $error; } else { - $self->freq =~ /^(\d+[dw]?)$/ + $self->freq =~ /^(\d+[hdw]?)$/ or return "Illegal or empty freq: ". $self->freq; $self->freq($1); } @@ -431,16 +447,60 @@ sub check { || $self->ut_enum('recurtax', [ '', 'Y' ] ) || $self->ut_textn('taxclass') || $self->ut_enum('disabled', [ '', 'Y' ] ) + || $self->ut_floatn('pay_weight') + || $self->ut_floatn('credit_weight') || $self->SUPER::check ; return $error if $error; + if ( $self->classnum !~ /^$/ ) { + my $error = $self->ut_foreign_key('classnum', 'pkg_class', 'classnum'); + return $error if $error; + } else { + $self->classnum(''); + } + return 'Unknown plan '. $self->plan unless exists($plans{$self->plan}); + my $conf = new FS::Conf; + return 'Taxclass is required' + if ! $self->taxclass && $conf->exists('require_taxclasses'); + ''; } +=item pkg_class + +Returns the package class, as an FS::pkg_class object, or the empty string +if there is no package class. + +=cut + +sub pkg_class { + my $self = shift; + if ( $self->classnum ) { + qsearchs('pkg_class', { 'classnum' => $self->classnum } ); + } else { + return ''; + } +} + +=item classname + +Returns the package class name, or the empty string if there is no package +class. + +=cut + +sub classname { + my $self = shift; + my $pkg_class = $self->pkg_class; + $pkg_class + ? $pkg_class->classname + : ''; +} + =item pkg_svc Returns all FS::pkg_svc objects (see L) for this package @@ -523,6 +583,34 @@ sub is_free { } } + +sub freqs_href { + #method, class method or sub? #my $self = shift; + + tie my %freq, 'Tie::IxHash', + '0' => '(no recurring fee)', + '1h' => 'hourly', + '1d' => 'daily', + '2d' => 'every two days', + '1w' => 'weekly', + '2w' => 'biweekly (every 2 weeks)', + '1' => 'monthly', + '45d' => 'every 45 days', + '2' => 'bimonthly (every 2 months)', + '3' => 'quarterly (every 3 months)', + '6' => 'semiannually (every 6 months)', + '12' => 'annually', + '24' => 'biannually (every 2 years)', + '36' => 'triannually (every 3 years)', + '48' => '(every 4 years)', + '60' => '(every 5 years)', + '120' => '(every 10 years)', + ; + + \%freq; + +} + =item freq_pretty Returns an english representation of the I field, such as "monthly", @@ -530,32 +618,19 @@ Returns an english representation of the I field, such as "monthly", =cut -tie %freq, 'Tie::IxHash', - '0' => '(no recurring fee)', - '1d' => 'daily', - '1w' => 'weekly', - '2w' => 'biweekly (every 2 weeks)', - '1' => 'monthly', - '2' => 'bimonthly (every 2 months)', - '3' => 'quarterly (every 3 months)', - '6' => 'semiannually (every 6 months)', - '12' => 'annually', - '24' => 'biannually (every 2 years)', - '36' => 'triannually (every 3 years)', - '48' => '(every 4 years)', - '60' => '(every 5 years)', - '120' => '(every 10 years)', -; - sub freq_pretty { my $self = shift; my $freq = $self->freq; - if ( exists($freq{$freq}) ) { - $freq{$freq}; + + #my $freqs_href = $self->freqs_href; + my $freqs_href = freqs_href(); + + if ( exists($freqs_href->{$freq}) ) { + $freqs_href->{$freq}; } else { my $interval = 'month'; - if ( $freq =~ /^(\d+)([dw])$/ ) { - my %interval = ( 'd'=>'day', 'w'=>'week' ); + if ( $freq =~ /^(\d+)([hdw])$/ ) { + my %interval = ( 'h' => 'hour', 'd'=>'day', 'w'=>'week' ); $interval = $interval{$2}; } if ( $1 == 1 ) { @@ -626,7 +701,8 @@ sub option { my %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); } split("\n", $self->get('plandata') ); return $plandata{$opt} if exists $plandata{$opt}; - cluck "Package definition option $opt not found in options or plandata!\n" + cluck "WARNING: (pkgpart ". $self->pkgpart. ") Package def option $opt ". + "not found in options or plandata!\n" unless $ornull; ''; } @@ -642,9 +718,16 @@ on how to create new price plans, but until then, see L. sub _rebless { my $self = shift; my $plan = $self->plan; + unless ( $plan ) { + confess "no price plan found for pkgpart ". $self->pkgpart. "\n" + if $DEBUG; + return $self; + } + return $self if ref($self) =~ /::$plan$/; #already blessed into plan subclass my $class = ref($self). "::$plan"; + warn "reblessing $self into $class" if $DEBUG; eval "use $class;"; - #die $@ if $@; + die $@ if $@; bless($self, $class) unless $@; $self; } @@ -696,6 +779,7 @@ sub calc_cancel { 0; } my %info; foreach my $INC ( @INC ) { + warn "globbing $INC/FS/part_pkg/*.pm\n" if $DEBUG; foreach my $file ( glob("$INC/FS/part_pkg/*.pm") ) { warn "attempting to load plan info from $file\n" if $DEBUG; $file =~ /\/(\w+)\.pm$/ or do { @@ -736,15 +820,18 @@ sub plan_info { =head1 NEW PLAN CLASSES -A module should be added in FS/FS/part_pkg/ (an example may be found in -eg/plan_template.pm) +A module should be added in FS/FS/part_pkg/ Eventually, an example may be +found in eg/plan_template.pm. Until then, it is suggested that you use the +other modules in FS/FS/part_pkg/ as a guide. =head1 BUGS The delete method is unimplemented. setup and recur semantics are not yet defined (and are implemented in -FS::cust_bill. hmm.). +FS::cust_bill. hmm.). now they're deprecated and need to go. + +plandata should go =head1 SEE ALSO