package categories (meta package classes) and grouping invoices by them
authorjeff <jeff>
Thu, 19 Jun 2008 03:18:19 +0000 (03:18 +0000)
committerjeff <jeff>
Thu, 19 Jun 2008 03:18:19 +0000 (03:18 +0000)
16 files changed:
FS/FS.pm
FS/FS/Schema.pm
FS/FS/cust_bill.pm
FS/FS/part_pkg.pm
FS/FS/pkg_category.pm [new file with mode: 0644]
FS/FS/pkg_class.pm
FS/MANIFEST
FS/t/pkg_category.t [new file with mode: 0644]
htetc/handler.pl
httemplate/browse/pkg_category.html [new file with mode: 0644]
httemplate/browse/pkg_class.html
httemplate/edit/elements/edit.html
httemplate/edit/pkg_category.html [new file with mode: 0644]
httemplate/edit/pkg_class.html
httemplate/edit/process/pkg_category.html [new file with mode: 0644]
httemplate/elements/menu.html

index 26f8c18..b3a6dcd 100644 (file)
--- 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
index ec046cb..22a7317 100644 (file)
@@ -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' => [],
index 06eec57..4618958 100644 (file)
@@ -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;
index 0d77ed9..7bb434d 100644 (file)
@@ -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 (file)
index 0000000..69578c9
--- /dev/null
@@ -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;
+
index bab6e5e..254282f 100644 (file)
@@ -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
index 23df385..74342e9 100644 (file)
@@ -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 (file)
index 0000000..ee256d5
--- /dev/null
@@ -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";
index be6f2f7..4361a78 100644 (file)
@@ -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 (file)
index 0000000..20bf1a8
--- /dev/null
@@ -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>
index 4f02ca2..75969db 100644 (file)
@@ -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>
index 04ca81c..86eb2b3 100644 (file)
@@ -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 (file)
index 0000000..fdc8da6
--- /dev/null
@@ -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>
index eddbfc1..2e4e9d1 100644 (file)
@@ -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 (file)
index 0000000..50cd5cb
--- /dev/null
@@ -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>
index fcca775..9ace19e 100644 (file)
@@ -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.' ];