summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjeff <jeff>2008-06-19 03:18:19 +0000
committerjeff <jeff>2008-06-19 03:18:19 +0000
commitf13afe5e228a220311557e1ca6dacbf847c26baf (patch)
tree9cd6b6e511234d72dfa9e8dd8278a721e5ad03eb
parent795a85c10d898120a2a6341c4df32fb60b069a64 (diff)
package categories (meta package classes) and grouping invoices by them
-rw-r--r--FS/FS.pm2
-rw-r--r--FS/FS/Schema.pm18
-rw-r--r--FS/FS/cust_bill.pm4
-rw-r--r--FS/FS/part_pkg.pm15
-rw-r--r--FS/FS/pkg_category.pm113
-rw-r--r--FS/FS/pkg_class.pm30
-rw-r--r--FS/MANIFEST2
-rw-r--r--FS/t/pkg_category.t5
-rw-r--r--htetc/handler.pl1
-rw-r--r--httemplate/browse/pkg_category.html33
-rw-r--r--httemplate/browse/pkg_class.html21
-rw-r--r--httemplate/edit/elements/edit.html3
-rw-r--r--httemplate/edit/pkg_category.html22
-rw-r--r--httemplate/edit/pkg_class.html5
-rw-r--r--httemplate/edit/process/pkg_category.html11
-rw-r--r--httemplate/elements/menu.html1
16 files changed, 276 insertions, 10 deletions
diff --git a/FS/FS.pm b/FS/FS.pm
index 26f8c18..b3a6dcd 100644
--- a/FS/FS.pm
+++ b/FS/FS.pm
@@ -161,6 +161,8 @@ L<FS::part_export> - External provisioning export class
L<FS::part_export_option> - Export option class
+L<FS::pkg_category> - Package category class
+
L<FS::pkg_class> - Package class class
L<FS::part_pkg> - Package definition class
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index ec046cb..22a7317 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -1778,11 +1778,23 @@ sub tables_hashref {
'index' => [],
},
+ 'pkg_category' => {
+ 'columns' => [
+ 'categorynum', 'serial', '', '', '', '',
+ 'categoryname', 'varchar', '', $char_d, '', '',
+ 'disabled', 'char', 'NULL', 1, '', '',
+ ],
+ 'primary_key' => 'categorynum',
+ 'unique' => [],
+ 'index' => [ ['disabled'] ],
+ },
+
'pkg_class' => {
'columns' => [
- 'classnum', 'serial', '', '', '', '',
- 'classname', 'varchar', '', $char_d, '', '',
- 'disabled', 'char', 'NULL', 1, '', '',
+ 'classnum', 'serial', '', '', '', '',
+ 'classname', 'varchar', '', $char_d, '', '',
+ 'categorynum', 'int', 'NULL', '', '', '',
+ 'disabled', 'char', 'NULL', 1, '', '',
],
'primary_key' => 'classnum',
'unique' => [],
diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm
index 06eec57..4618958 100644
--- a/FS/FS/cust_bill.pm
+++ b/FS/FS/cust_bill.pm
@@ -2506,7 +2506,7 @@ sub _items_sections {
if ( $cust_bill_pkg->pkgnum > 0 ) {
- my $desc = $cust_bill_pkg->part_pkg->classname;
+ my $desc = $cust_bill_pkg->part_pkg->categoryname;
$s{$desc} += $cust_bill_pkg->setup
if ( $cust_bill_pkg->setup != 0 );
@@ -2576,7 +2576,7 @@ sub _items_pkg {
my @cust_bill_pkg =
grep { $_->pkgnum &&
( defined($section)
- ? $_->part_pkg->classname eq $section->{'description'}
+ ? $_->part_pkg->categoryname eq $section->{'description'}
: 1
)
} $self->cust_bill_pkg;
diff --git a/FS/FS/part_pkg.pm b/FS/FS/part_pkg.pm
index 0d77ed9..7bb434d 100644
--- a/FS/FS/part_pkg.pm
+++ b/FS/FS/part_pkg.pm
@@ -475,6 +475,21 @@ sub pkg_class {
}
}
+=item categoryname
+
+Returns the package category name, or the empty string if there is no package
+category.
+
+=cut
+
+sub categoryname {
+ my $self = shift;
+ my $pkg_class = $self->pkg_class;
+ $pkg_class
+ ? $pkg_class->categoryname
+ : '';
+}
+
=item classname
Returns the package class name, or the empty string if there is no package
diff --git a/FS/FS/pkg_category.pm b/FS/FS/pkg_category.pm
new file mode 100644
index 0000000..69578c9
--- /dev/null
+++ b/FS/FS/pkg_category.pm
@@ -0,0 +1,113 @@
+package FS::pkg_category;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch );
+use FS::part_pkg;
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::pkg_category - Object methods for pkg_category records
+
+=head1 SYNOPSIS
+
+ use FS::pkg_category;
+
+ $record = new FS::pkg_category \%hash;
+ $record = new FS::pkg_category { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::pkg_category object represents an package category. Every package class
+(see L<FS::pkg_class>) has, optionally, a package category. FS::pkg_category
+inherits from FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item categorynum - primary key (assigned automatically for new package categoryes)
+
+=item categoryname - Text name of this package category
+
+=item disabled - Disabled flag, empty or 'Y'
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new package category. To add the package category to the database, see
+L<"insert">.
+
+=cut
+
+sub table { 'pkg_category'; }
+
+=item insert
+
+Adds this package category to the database. If there is an error, returns the
+error, otherwise returns false.
+
+=item delete
+
+Deletes this package category from the database. Only package categoryes with no
+associated package definitions can be deleted. If there is an error, returns
+the error, otherwise returns false.
+
+=cut
+
+sub delete {
+ my $self = shift;
+
+ return "Can't delete an pkg_category with pkg_class records!"
+ if qsearch( 'pkg_class', { 'categorynum' => $self->categorynum } );
+
+ $self->SUPER::delete;
+}
+
+=item replace OLD_RECORD
+
+Replaces 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 package category. If there is an
+error, returns the error, otherwise returns false. Called by the insert and
+replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ $self->ut_numbern('categorynum')
+ or $self->ut_text('categoryname')
+ or $self->SUPER::check;
+
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::part_pkg>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/pkg_class.pm b/FS/FS/pkg_class.pm
index bab6e5e..254282f 100644
--- a/FS/FS/pkg_class.pm
+++ b/FS/FS/pkg_class.pm
@@ -2,8 +2,9 @@ package FS::pkg_class;
use strict;
use vars qw( @ISA );
-use FS::Record qw( qsearch );
+use FS::Record qw( qsearchs qsearch );
use FS::part_pkg;
+use FS::pkg_category;
@ISA = qw( FS::Record );
@@ -38,6 +39,8 @@ from FS::Record. The following fields are currently supported:
=item classname - Text name of this package class
+=item categorynum - Number of associated pkg_category (see L<FS::pkg_category>)
+
=item disabled - Disabled flag, empty or 'Y'
=back
@@ -95,10 +98,35 @@ sub check {
$self->ut_numbern('classnum')
or $self->ut_text('classname')
+ or $self->ut_foreign_keyn('categorynum', 'pkg_category', 'categorynum')
or $self->SUPER::check;
}
+=item pkg_category
+
+Returns the pkg_category record associated with this class, or false if there
+is none.
+
+=cut
+
+sub pkg_category {
+ my $self = shift;
+ qsearchs('pkg_category', { 'categorynum' => $self->categorynum } );
+}
+
+=item categoryname
+
+Returns the category name associated with this class, or false if there
+is none.
+
+=cut
+
+sub categoryname {
+ my $pkg_category = shift->pkg_category;
+ $pkg_category->categoryname if $pkg_category;
+}
+
=back
=head1 BUGS
diff --git a/FS/MANIFEST b/FS/MANIFEST
index 23df385..74342e9 100644
--- a/FS/MANIFEST
+++ b/FS/MANIFEST
@@ -409,3 +409,5 @@ FS/part_pkg_taxoverride.pm
t/part_pkg_taxoverride.t
FS/part_pkg_taxrate.pm
t/part_pkg_taxrate.t
+FS/pkg_category.pm
+t/pkg_category.t
diff --git a/FS/t/pkg_category.t b/FS/t/pkg_category.t
new file mode 100644
index 0000000..ee256d5
--- /dev/null
+++ b/FS/t/pkg_category.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::pkg_category;
+$loaded=1;
+print "ok 1\n";
diff --git a/htetc/handler.pl b/htetc/handler.pl
index be6f2f7..4361a78 100644
--- a/htetc/handler.pl
+++ b/htetc/handler.pl
@@ -205,6 +205,7 @@ sub handler
use FS::cdr;
use FS::inventory_class;
use FS::inventory_item;
+ use FS::pkg_category;
use FS::pkg_class;
use FS::access_user;
use FS::access_user_pref;
diff --git a/httemplate/browse/pkg_category.html b/httemplate/browse/pkg_category.html
new file mode 100644
index 0000000..20bf1a8
--- /dev/null
+++ b/httemplate/browse/pkg_category.html
@@ -0,0 +1,33 @@
+<% include( 'elements/browse.html',
+ 'title' => 'Package categories',
+ 'html_init' => $html_init,
+ 'name' => 'package categories',
+ 'disableable' => 1,
+ 'disabled_statuspos' => 2,
+ 'query' => { 'table' => 'pkg_category',
+ 'hashref' => {},
+ 'extra_sql' => 'ORDER BY categorynum',
+ },
+ 'count_query' => $count_query,
+ 'header' => [ '#', 'Category' ],
+ 'fields' => [ 'categorynum', 'categoryname' ],
+ 'links' => [ $link, $link ],
+ )
+%>
+
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+my $html_init =
+ qq!<A HREF="${p}browse/pkg_class.html">Package classes</A><BR><BR>!.
+ 'Package categories define groups of package classes, for reporting and '.
+ 'convenience purposes.<BR><BR>'.
+ qq!<A HREF="${p}edit/pkg_category.html"><I>Add a package category</I></A><BR><BR>!;
+
+my $count_query = 'SELECT COUNT(*) FROM pkg_category';
+
+my $link = [ $p.'edit/pkg_category.html?', 'categorynum' ];
+
+</%init>
diff --git a/httemplate/browse/pkg_class.html b/httemplate/browse/pkg_class.html
index 4f02ca2..75969db 100644
--- a/httemplate/browse/pkg_class.html
+++ b/httemplate/browse/pkg_class.html
@@ -9,9 +9,9 @@
'extra_sql' => 'ORDER BY classnum',
},
'count_query' => $count_query,
- 'header' => [ '#', 'Class', ],
- 'fields' => [ 'classnum', 'classname' ],
- 'links' => [ $link, $link ],
+ 'header' => $header,
+ 'fields' => $fields,
+ 'links' => $links,
)
%>
<%init>
@@ -28,4 +28,19 @@ my $count_query = 'SELECT COUNT(*) FROM pkg_class';
my $link = [ $p.'edit/pkg_class.html?', 'classnum' ];
+my $header = [ '#', 'Class' ];
+my $fields = [ 'classnum', 'classname' ];
+my $links = [ $link, $link ];
+
+my $cat_query = 'SELECT COUNT(*) FROM pkg_class where categorynum IS NOT NULL';
+my $sth = dbh->prepare($cat_query)
+ or die "Error preparing $cat_query: ". dbh->errstr;
+$sth->execute
+ or die "Error executing $cat_query: ". $sth->errstr;
+if ($sth->fetchrow_arrayref->[0]) {
+ push @$header, 'Category';
+ push @$fields, 'categoryname';
+ push @$links, $link;
+}
+
</%init>
diff --git a/httemplate/edit/elements/edit.html b/httemplate/edit/elements/edit.html
index 04ca81c..86eb2b3 100644
--- a/httemplate/edit/elements/edit.html
+++ b/httemplate/edit/elements/edit.html
@@ -106,7 +106,7 @@ Example:
'new_callback' => sub { my( $cgi, $object, $fields_listref ) = @_; },
#run before display to return a different value
- 'value_callback' => sub { my( $columname, $value } ) = @_; },
+ 'value_callback' => sub { my( $columname, $value ) = @_; },
#XXX describe
'field_callback' => sub { },
@@ -212,6 +212,7 @@ Example:
% #select(-*)
% 'options' => $f->{'options'},
% 'labels' => $f->{'labels'},
+% 'empty_label' => $f->{'empty_label'},
% 'multiple' => $f->{'multiple'},
% 'disable_empty' => $f->{'disable_empty'},
% #select-reason
diff --git a/httemplate/edit/pkg_category.html b/httemplate/edit/pkg_category.html
new file mode 100644
index 0000000..fdc8da6
--- /dev/null
+++ b/httemplate/edit/pkg_category.html
@@ -0,0 +1,22 @@
+<% include( 'elements/edit.html',
+ 'name' => 'Package Category',
+ 'table' => 'pkg_category',
+ 'fields' => [
+ 'categoryname',
+ { field=>'disabled', type=>'checkbox', value=>'Y', },
+ ],
+ 'labels' => {
+ 'categorynum' => 'Category number',
+ 'categoryname' => 'Category name',
+ 'disabled' => 'Disable category',
+ },
+ 'viewall_dir' => 'browse',
+ )
+
+%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+</%init>
diff --git a/httemplate/edit/pkg_class.html b/httemplate/edit/pkg_class.html
index eddbfc1..2e4e9d1 100644
--- a/httemplate/edit/pkg_class.html
+++ b/httemplate/edit/pkg_class.html
@@ -3,6 +3,10 @@
'table' => 'pkg_class',
'fields' => [
'classname',
+ (scalar(@category)
+ ? { field=>'categorynum', type=>'select-table', 'empty_label'=>'(none)', 'table'=>'pkg_category', 'name_col'=>'categoryname' }
+ : { field=>'categorynum', type=>'hidden' }
+ ),
{ field=>'disabled', type=>'checkbox', value=>'Y', },
],
'labels' => {
@@ -19,4 +23,5 @@
die "access denied"
unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+my @category = qsearch('pkg_category', { 'disabled' => '' });
</%init>
diff --git a/httemplate/edit/process/pkg_category.html b/httemplate/edit/process/pkg_category.html
new file mode 100644
index 0000000..50cd5cb
--- /dev/null
+++ b/httemplate/edit/process/pkg_category.html
@@ -0,0 +1,11 @@
+<% include( 'elements/process.html',
+ 'table' => 'pkg_category',
+ 'viewall_dir' => 'browse',
+ )
+%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+</%init>
diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html
index fcca775..9ace19e 100644
--- a/httemplate/elements/menu.html
+++ b/httemplate/elements/menu.html
@@ -262,6 +262,7 @@ $config_export_svc_pkg{'View/Edit package definitions'} = [ $fsurl.'browse/part_
if $curuser->access_right('Edit package definitions')
|| $curuser->access_right('Edit global package definitions');
if ( $curuser->access_right('Configuration') ) {
+ $config_export_svc_pkg{'View/Edit package categories'} = [ $fsurl.'browse/pkg_category.html', 'Package categories define groups of package classes, for reporting and convenience purposes.' ];
$config_export_svc_pkg{'View/Edit package classes'} = [ $fsurl.'browse/pkg_class.html', 'Package classes define groups of packages, for reporting and convenience purposes.' ];
$config_export_svc_pkg{'View/Edit cancel reason types'} = [ $fsurl.'browse/reason_type.html?class=C', 'Cancel reason types define groups of reasons, for reporting and convenience purposes.' ];
$config_export_svc_pkg{'View/Edit cancel reasons'} = [ $fsurl.'browse/reason.html?class=C', 'Cancel reasons explain why a service was cancelled.' ];