L<FS::rate_detail> - Rate plan detail for call billing
+L<FS::usage_class> - Usage class class
+
L<FS::agent> - Agent (reseller) class
L<FS::agent_type> - Agent type class
use FS::rate;
use FS::rate_region;
use FS::rate_prefix;
+ use FS::rate_detail;
+ use FS::usage_class;
use FS::payment_gateway;
use FS::agent_payment_gateway;
use FS::XMLRPC;
'min_charge', 'decimal', '', '10,5', '', '',
'sec_granularity', 'int', '', '', '', '',
#time period (link to table of periods)?
+ 'classnum', 'int', 'NULL', '', '', '',
],
'primary_key' => 'ratedetailnum',
'unique' => [ [ 'ratenum', 'orig_regionnum', 'dest_regionnum' ] ],
'index' => [ [ 'countrycode' ], [ 'regionnum' ] ],
},
+ 'usage_class' => {
+ 'columns' => [
+ 'classnum', 'serial', '', '', '', '',
+ 'classname', 'varchar', '', $char_d, '', '',
+ 'disabled', 'char', 'NULL', 1, '', '',
+ ],
+ 'primary_key' => 'classnum',
+ 'unique' => [],
+ 'index' => [ ['disabled'] ],
+ },
+
'reg_code' => {
'columns' => [
'codenum', 'serial', '', '', '', '',
#not yet....
#)
+
+ #usage classes
+ 'usage_class' => [],
+
;
\%hash;
#replace invnum and pkgnum with billpkgnum
'cust_bill_pkg_detail' => [],
+ #usage_classes if we have none
+ 'usage_class' => [],
+
;
\%hash;
=item sec_granularity - granularity in seconds, i.e. 6 or 60; 0 for per-call
+=item classnum - usage class (see L<FS::usage_class) if any for this rate
+
=back
=head1 METHODS
|| $self->ut_float('min_charge')
|| $self->ut_number('sec_granularity')
+
+ || $self->ut_foreign_keyn('classnum', 'usage_class', 'classnum' )
;
return $error if $error;
$self->dest_region->prefixes_short;
}
+=item classname
+
+Returns the name of the usage class (see L<FS::usage_class>) associated with
+this call plan rate.
+
+=cut
+
+sub classname {
+ my $self = shift;
+ my $usage_class = qsearchs('usage_class', { classnum => $self->classnum });
+ $usage_class ? $usage_class->classname : '';
+}
+
=back
--- /dev/null
+package FS::usage_class;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs );
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::usage_class - Object methods for usage_class records
+
+=head1 SYNOPSIS
+
+ use FS::usage_class;
+
+ $record = new FS::usage_class \%hash;
+ $record = new FS::usage_class { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::usage_class object represents a usage class. Every rate detail
+(see L<FS::rate_detail) has, optionally, a usage class. FS::usage_class
+inherits from FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item classnum
+
+Primary key (assigned automatically for new usage classes)
+
+=item classname
+
+Text name of this usage class
+
+=item disabled
+
+Disabled flag, empty or 'Y'
+
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new usage class. To add the usage class to the database,
+see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+sub table { 'usage_class'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+=item check
+
+Checks all fields to make sure this is a valid usage class. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('classnum')
+ || $self->ut_text('classname')
+ || $self->ut_enum('disabled', [ '', 'Y' ])
+ ;
+ return $error if $error;
+
+ $self->SUPER::check;
+}
+
+sub _populate_initial_data {
+ my ($class, %opts) = @_;
+
+ foreach ("Intrastate", "Interstate", "International") {
+ my $object = $class->new( { 'classname' => $_ } );
+ my $error = $object->insert;
+ die "error inserting $class into database: $error\n"
+ if $error;
+ }
+
+ '';
+
+}
+
+sub _upgrade_data {
+ my $class = shift;
+
+ return $class->_populate_initial_data(@_)
+ unless scalar( qsearch( 'usage_class', {} ) );
+
+ '';
+
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
FS/Yori.pm
FS/cust_svc_option.pm
t/cust_svc_option.t
+FS/usage_class.pm
+t/usage_class.t
--- /dev/null
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::usage_class;
+$loaded=1;
+print "ok 1\n";
'Included<BR>minutes',
'Charge per<BR>minute',
'Granularity',
+ 'Usage class',
],
'fields' => [
'regionname',
' <FONT SIZE="-1">(edit)</FONT>';
},
sub { $granularity{ shift->sec_granularity } },
+ 'classname',
],
- 'links' => [ '', '', $edit_link, $edit_link, '' ],
- 'link_onclicks' => [ '', '', $edit_onclick, $edit_onclick, '' ],
- 'align' => 'llrrc',
+ 'links' => [ '', '', $edit_link, $edit_link, '', '' ],
+ 'link_onclicks' => [ '', '', $edit_onclick, $edit_onclick, '', '' ],
+ 'align' => 'llrrcc',
)
%>
<%once>
--- /dev/null
+<% include( 'elements/browse.html',
+ 'title' => 'Usage classes',
+ 'html_init' => $html_init,
+ 'name' => 'usage classes',
+ 'disableable' => 1,
+ 'disabled_statuspos' => 2,
+ 'query' => { 'table' => 'usage_class',
+ 'hashref' => {},
+ 'extra_sql' => 'ORDER BY classnum',
+ },
+ 'count_query' => 'SELECT COUNT(*) FROM usage_class',
+ 'header' => [ '#', 'Class' ],
+ 'fields' => [ 'classnum', 'classname' ],
+ 'links' => [ $link, $link ],
+ )
+%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+my $html_init =
+ 'Usage classes define groups of usage for taxation purposes.<BR><BR>'.
+ qq!<A HREF="${p}edit/usage_class.html"><I>Add a usage class</I></A><BR><BR>!;
+
+my $link = [ $p.'edit/usage_class.html?', 'classnum' ];
+
+</%init>
Example:
include( 'elements/edit.html',
- 'name' =>
- 'table' =>
+ 'name_singular' => #singular name for the record
+ # (preferred, will be pluralized automatically)
+ 'name' => #name for the record
+ # (deprecated, will be pluralized simplistically)
+ 'table' =>
+
#? 'primary_key' => #required when the dbdef doesn't know...???
'labels' => {
'column' => 'Label',
if ( $opt{'menubar'} ) {
@menubar = @{ $opt{'menubar'} };
} else {
+ my $items = $opt{'name'} ? $opt{'name'}.'s' : PL($opt{'name_singular'});
@menubar = (
- #eventually use Lingua::bs to pluralize
- "View all $opt{'name'}s" => $viewall_url,
+ "View all $items" => $viewall_url,
);
}
new FS::rate_detail {
'ratenum' => $ratenum,
map { $_ => $cgi->param("$_$ratenum") }
- qw( min_included min_charge sec_granularity )
+ qw( min_included min_charge sec_granularity classnum )
};
} qsearch('rate', {} );
--- /dev/null
+<% include( 'elements/process.html',
+ 'table' => 'usage_class',
+ 'viewall_dir' => 'browse',
+ )
+%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+</%init>
'min_included' => 'Included minutes',
'min_charge' => 'Charge per minute',
'sec_granularity' => 'Granularity',
+ 'classnum' => 'Usage class',
},
'fields' => [
{ field=>'ratenum', type=>'hidden', },
labels => \%granularity,
disable_empty => 1,
},
+ { field =>'classnum',
+ type =>'select-table',
+ table =>'usage_class',
+ name_col =>'classname',
+ empty_label =>'(default)',
+ hashref =>{ disabled => '' },
+ },
],
)
<TH CLASS="grid" BGCOLOR="#cccccc">
<FONT SIZE=-1>Granularity</FONT>
</TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc">
+ <FONT SIZE=-1>Usage class</FONT>
+ </TH>
</TR>
% foreach my $rate ( qsearch('rate', {}) ) {
</SELECT>
</TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
+ <% include( '/elements/select-table.html',
+ 'element_name' => "classnum$n",
+ 'table' => 'usage_class',
+ 'name_col' => 'classname',
+ 'empty_label' => '(default)',
+ 'hashref' => { disabled => '' },
+ 'curr_value' => ( $cgi->param("classnum$n") ||
+ $rate_detail->classnum ),
+ )
+ %>
+ </TD>
+
</TR>
% }
--- /dev/null
+<% include( 'elements/edit.html',
+ 'name_singular' => 'Usage Class',
+ 'table' => 'usage_class',
+ 'fields' => [
+ 'classname',
+ { field=>'disabled',
+ type=>'checkbox',
+ value=>'Y',
+ },
+ ],
+ 'labels' => {
+ 'classnum' => 'Class number',
+ 'classname' => 'Class name',
+ 'disabled' => 'Disable class',
+ },
+ 'viewall_dir' => 'browse',
+ )
+
+%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+</%init>
tie my %config_billing_rates, 'Tie::IxHash',
'View/Edit rate plans' => [ $fsurl.'browse/rate.cgi', 'Manage rate plans' ],
'View/Edit regions and prefixes' => [ $fsurl.'browse/rate_region.html', 'Manage regions and prefixes' ],
+ 'View/Edit usage classes' => [ $fsurl.'browse/usage_class.html', 'Usage classes define groups of usage for taxation purposes.' ],
;
tie my %config_billing, 'Tie::IxHash';