From 34c878349988d97957f1d53427896a4d70afb392 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Tue, 2 Aug 2016 11:41:51 -0700 Subject: [PATCH] agent commission schedules for consecutive invoices, #71217 --- FS/FS/Mason.pm | 2 + FS/FS/Schema.pm | 40 ++++ FS/FS/commission_rate.pm | 116 ++++++++++ FS/FS/commission_schedule.pm | 235 +++++++++++++++++++++ FS/FS/cust_credit.pm | 1 + .../Action/bill_agent_credit_schedule.pm | 76 +++++++ FS/MANIFEST | 4 + FS/t/commission_rate.t | 5 + FS/t/commission_schedule.t | 5 + httemplate/browse/commission_schedule.html | 70 ++++++ httemplate/edit/commission_schedule.html | 53 +++++ httemplate/edit/process/commission_schedule.html | 36 ++++ httemplate/elements/commission_rate.html | 68 ++++++ httemplate/elements/menu.html | 5 +- httemplate/elements/tr-select-reason.html | 3 +- 15 files changed, 716 insertions(+), 3 deletions(-) create mode 100644 FS/FS/commission_rate.pm create mode 100644 FS/FS/commission_schedule.pm create mode 100644 FS/FS/part_event/Action/bill_agent_credit_schedule.pm create mode 100644 FS/t/commission_rate.t create mode 100644 FS/t/commission_schedule.t create mode 100644 httemplate/browse/commission_schedule.html create mode 100644 httemplate/edit/commission_schedule.html create mode 100644 httemplate/edit/process/commission_schedule.html create mode 100644 httemplate/elements/commission_rate.html diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index 1008fd5d8..245bdea88 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -413,6 +413,8 @@ if ( -e $addl_handler_use_file ) { use FS::olt_site; use FS::access_user_page_pref; use FS::part_svc_msgcat; + use FS::commission_schedule; + use FS::commission_rate; # Sammath Naur if ( $FS::Mason::addl_handler_use ) { diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index ac585108e..8661c4b97 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -1361,6 +1361,7 @@ sub tables_hashref { 'commission_agentnum', 'int', 'NULL', '', '', '', # 'commission_salesnum', 'int', 'NULL', '', '', '', # 'commission_pkgnum', 'int', 'NULL', '', '', '', # + 'commission_invnum', 'int', 'NULL', '', '', '', 'credbatch', 'varchar', 'NULL', $char_d, '', '', ], 'primary_key' => 'crednum', @@ -1396,6 +1397,10 @@ sub tables_hashref { table => 'cust_pkg', references => [ 'pkgnum' ], }, + { columns => [ 'commission_invnum' ], + table => 'cust_bill', + references => [ 'invnum' ], + }, ], }, @@ -1417,6 +1422,7 @@ sub tables_hashref { 'commission_agentnum', 'int', 'NULL', '', '', '', 'commission_salesnum', 'int', 'NULL', '', '', '', 'commission_pkgnum', 'int', 'NULL', '', '', '', + 'commission_invnum', 'int', 'NULL', '', '', '', #void fields 'void_date', @date_type, '', '', 'void_reason', 'varchar', 'NULL', $char_d, '', '', @@ -1456,6 +1462,10 @@ sub tables_hashref { table => 'cust_pkg', references => [ 'pkgnum' ], }, + { columns => [ 'commission_invnum' ], + table => 'cust_bill', + references => [ 'invnum' ], + }, { columns => [ 'void_reasonnum' ], table => 'reason', references => [ 'reasonnum' ], @@ -7438,6 +7448,36 @@ sub tables_hashref { ], }, + 'commission_schedule' => { + 'columns' => [ + 'schedulenum', 'serial', '', '', '', '', + 'schedulename', 'varchar', '', $char_d, '', '', + 'reasonnum', 'int', 'NULL', '', '', '', + 'basis', 'varchar', 'NULL', 32, '', '', + ], + 'primary_key' => 'schedulenum', + 'unique' => [], + 'index' => [], + }, + + 'commission_rate' => { + 'columns' => [ + 'commissionratenum', 'serial', '', '', '', '', + 'schedulenum', 'int', '', '', '', '', + 'cycle', 'int', '', '', '', '', + 'amount', @money_type, '', '', + 'percent', 'decimal','', '7,4', '', '', + ], + 'primary_key' => 'commissionratenum', + 'unique' => [ [ 'schedulenum', 'cycle', ] ], + 'index' => [], + 'foreign_keys' => [ + { columns => [ 'schedulenum' ], + table => 'commission_schedule', + }, + ], + }, + # name type nullability length default local #'new_table' => { diff --git a/FS/FS/commission_rate.pm b/FS/FS/commission_rate.pm new file mode 100644 index 000000000..dcb596d60 --- /dev/null +++ b/FS/FS/commission_rate.pm @@ -0,0 +1,116 @@ +package FS::commission_rate; +use base qw( FS::Record ); + +use strict; +use FS::Record qw( qsearch qsearchs ); + +=head1 NAME + +FS::commission_rate - Object methods for commission_rate records + +=head1 SYNOPSIS + + use FS::commission_rate; + + $record = new FS::commission_rate \%hash; + $record = new FS::commission_rate { 'column' => 'value' }; + + $error = $record->insert; + + $error = $new_record->replace($old_record); + + $error = $record->delete; + + $error = $record->check; + +=head1 DESCRIPTION + +An FS::commission_rate object represents a commission rate (a percentage or a +flat amount) that will be paid on a customer's N-th invoice. The sequence of +commissions that will be paid on consecutive invoices is the parent object, +L. + +FS::commission_rate inherits from FS::Record. The following fields are +currently supported: + +=over 4 + +=item commissionratenum - primary key + +=item schedulenum - L foreign key + +=item cycle - the ordinal of the billing cycle this commission will apply +to. cycle = 1 applies to the customer's first invoice, cycle = 2 to the +second, etc. + +=item amount - the flat amount to pay per invoice in commission + +=item percent - the percentage of the invoice amount to pay in +commission + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Creates a new commission rate. To add it to the database, see L<"insert">. + +=cut + +sub table { 'commission_rate'; } + +=item insert + +Adds this record to the database. If there is an error, returns the error, +otherwise returns false. + +=item delete + +Delete this record from the database. + +=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. + +=item check + +Checks all fields to make sure this is a valid commission rate. 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->set('amount', '0.00') + if $self->get('amount') eq ''; + $self->set('percent', '0') + if $self->get('percent') eq ''; + + my $error = + $self->ut_numbern('commissionratenum') + || $self->ut_number('schedulenum') + || $self->ut_number('cycle') + || $self->ut_money('amount') + || $self->ut_decimal('percent') + ; + return $error if $error; + + $self->SUPER::check; +} + +=back + +=head1 SEE ALSO + +L + +=cut + +1; + diff --git a/FS/FS/commission_schedule.pm b/FS/FS/commission_schedule.pm new file mode 100644 index 000000000..375386c33 --- /dev/null +++ b/FS/FS/commission_schedule.pm @@ -0,0 +1,235 @@ +package FS::commission_schedule; +use base qw( FS::o2m_Common FS::Record ); + +use strict; +use FS::Record qw( qsearch qsearchs ); +use FS::commission_rate; +use Tie::IxHash; + +tie our %basis_options, 'Tie::IxHash', ( + setuprecur => 'Total sales', + setup => 'One-time and setup charges', + recur => 'Recurring charges', + setup_cost => 'Setup costs', + recur_cost => 'Recurring costs', + setup_margin => 'Setup charges minus costs', + recur_margin_permonth => 'Monthly recurring charges minus costs', +); + +=head1 NAME + +FS::commission_schedule - Object methods for commission_schedule records + +=head1 SYNOPSIS + + use FS::commission_schedule; + + $record = new FS::commission_schedule \%hash; + $record = new FS::commission_schedule { 'column' => 'value' }; + + $error = $record->insert; + + $error = $new_record->replace($old_record); + + $error = $record->delete; + + $error = $record->check; + +=head1 DESCRIPTION + +An FS::commission_schedule object represents a bundle of one or more +commission rates for invoices. FS::commission_schedule inherits from +FS::Record. The following fields are currently supported: + +=over 4 + +=item schedulenum - primary key + +=item schedulename - descriptive name + +=item reasonnum - the credit reason (L) that will be assigned +to these commission credits + +=item basis - for percentage credits, which component of the invoice charges +the percentage will be calculated on: +- setuprecur (total charges) +- setup +- recur +- setup_cost +- recur_cost +- setup_margin (setup - setup_cost) +- recur_margin_permonth ((recur - recur_cost) / freq) + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Creates a new commission schedule. To add the object to the database, see +L<"insert">. + +=cut + +sub table { 'commission_schedule'; } + +=item insert + +Adds this record to the database. If there is an error, returns the error, +otherwise returns false. + +=item delete + +Delete this record from the database. + +=cut + +sub delete { + my $self = shift; + # don't allow the schedule to be removed if it's still linked to events + if ($self->part_event) { + return 'This schedule is still in use.'; # UI should be smarter + } + $self->process_o2m( + 'table' => 'commission_rate', + 'params' => [], + ) || $self->delete; +} + +=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. + +=item check + +Checks all fields to make sure this is a valid record. 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('schedulenum') + || $self->ut_text('schedulename') + || $self->ut_number('reasonnum') + || $self->ut_enum('basis', [ keys %basis_options ]) + ; + return $error if $error; + + $self->SUPER::check; +} + +=item part_event + +Returns a list of billing events (L objects) that pay +commission on this schedule. + +=cut + +sub part_event { + my $self = shift; + map { $_->part_event } + qsearch('part_event_option', { + optionname => 'schedulenum', + optionvalue => $self->schedulenum, + } + ); +} + +=item calc_credit INVOICE + +Takes an L object and calculates credit on this schedule. +Returns the amount to credit. If there's no rate defined for this invoice, +returns nothing. + +=cut + +# Some false laziness w/ FS::part_event::Action::Mixin::credit_bill. +# this is a little different in that we calculate the credit on the whole +# invoice. + +sub calc_credit { + my $self = shift; + my $cust_bill = shift; + die "cust_bill record required" if !$cust_bill or !$cust_bill->custnum; + # count invoices before or including this one + my $cycle = FS::cust_bill->count('custnum = ? AND _date <= ?', + $cust_bill->custnum, + $cust_bill->_date + ); + my $rate = qsearchs('commission_rate', { + schedulenum => $self->schedulenum, + cycle => $cycle, + }); + # we might do something with a rate that applies "after the end of the + # schedule" (cycle = 0 or something) so that this can do commissions with + # no end date. add that here if there's a need. + return unless $rate; + + my $amount; + if ( $rate->percent ) { + my $what = $self->basis; + my $cost = ($what =~ /_cost/ ? 1 : 0); + my $margin = ($what =~ /_margin/ ? 1 : 0); + my %part_pkg_cache; + foreach my $cust_bill_pkg ( $cust_bill->cust_bill_pkg ) { + + my $charge = 0; + next if !$cust_bill_pkg->pkgnum; # exclude taxes and fees + + my $cust_pkg = $cust_bill_pkg->cust_pkg; + if ( $margin or $cost ) { + # look up package costs only if we need them + my $pkgpart = $cust_bill_pkg->pkgpart_override || $cust_pkg->pkgpart; + my $part_pkg = $part_pkg_cache{$pkgpart} + ||= FS::part_pkg->by_key($pkgpart); + + if ( $cost ) { + $charge = $part_pkg->get($what); + } else { # $margin + $charge = $part_pkg->$what($cust_pkg); + } + + $charge = ($charge || 0) * ($cust_pkg->quantity || 1); + + } else { + + if ( $what eq 'setup' ) { + $charge = $cust_bill_pkg->get('setup'); + } elsif ( $what eq 'recur' ) { + $charge = $cust_bill_pkg->get('recur'); + } elsif ( $what eq 'setuprecur' ) { + $charge = $cust_bill_pkg->get('setup') + + $cust_bill_pkg->get('recur'); + } + } + + $amount += ($charge * $rate->percent / 100); + + } + } # if $rate->percent + + if ( $rate->amount ) { + $amount += $rate->amount; + } + + $amount = sprintf('%.2f', $amount + 0.005); + return $amount; +} + +=back + +=head1 SEE ALSO + +L, L, L + +=cut + +1; + diff --git a/FS/FS/cust_credit.pm b/FS/FS/cust_credit.pm index 85463724c..e4b1fc07d 100644 --- a/FS/FS/cust_credit.pm +++ b/FS/FS/cust_credit.pm @@ -315,6 +315,7 @@ sub check { || $self->ut_foreign_keyn('commission_agentnum', 'agent', 'agentnum') || $self->ut_foreign_keyn('commission_salesnum', 'sales', 'salesnum') || $self->ut_foreign_keyn('commission_pkgnum', 'cust_pkg', 'pkgnum') + || $self->ut_foreign_keyn('commission_invnum', 'cust_bill', 'invnum') ; return $error if $error; diff --git a/FS/FS/part_event/Action/bill_agent_credit_schedule.pm b/FS/FS/part_event/Action/bill_agent_credit_schedule.pm new file mode 100644 index 000000000..31189a237 --- /dev/null +++ b/FS/FS/part_event/Action/bill_agent_credit_schedule.pm @@ -0,0 +1,76 @@ +package FS::part_event::Action::bill_agent_credit_schedule; + +use base qw( FS::part_event::Action ); +use FS::Conf; +use FS::cust_credit; +use FS::commission_schedule; +use Date::Format qw(time2str); + +use strict; + +sub description { 'Credit the agent based on a commission schedule' } + +sub option_fields { + 'schedulenum' => { 'label' => 'Schedule', + 'type' => 'select-table', + 'table' => 'commission_schedule', + 'name_col' => 'schedulename', + 'disable_empty'=> 1, + }, +} + +sub eventtable_hashref { + { 'cust_bill' => 1 }; +} + +our $date_format; + +sub do_action { + my( $self, $cust_bill, $cust_event ) = @_; + + $date_format ||= FS::Conf->new->config('date_format') || '%x'; + + my $cust_main = $self->cust_main($cust_bill); + my $agent = $cust_main->agent; + return "No customer record for agent ". $agent->agent + unless $agent->agent_custnum; + + my $agent_cust_main = $agent->agent_cust_main; + + my $schedulenum = $self->option('schedulenum') + or return "no commission schedule selected"; + my $schedule = FS::commission_schedule->by_key($schedulenum) + or return "commission schedule #$schedulenum not found"; + # commission_schedule::delete tries to prevent this, but just in case + + my $amount = $schedule->calc_credit($cust_bill) + or return; + + my $reasonnum = $schedule->reasonnum; + + #XXX shouldn't do this here, it's a localization problem. + # credits with commission_invnum should know how to display it as part + # of invoice rendering. + my $desc = 'from invoice #'. $cust_bill->display_invnum . + ' ('. time2str($date_format, $cust_bill->_date) . ')'; + # could also show custnum and pkgnums here? + my $cust_credit = FS::cust_credit->new({ + 'custnum' => $agent_cust_main->custnum, + 'reasonnum' => $reasonnum, + 'amount' => $amount, + 'eventnum' => $cust_event->eventnum, + 'addlinfo' => $desc, + 'commission_agentnum' => $cust_main->agentnum, + 'commission_invnum' => $cust_bill->invnum, + }); + my $error = $cust_credit->insert; + die "Error crediting customer ". $agent_cust_main->custnum. + " for agent commission: $error" + if $error; + + #return $warning; # currently don't get warnings here + return; + +} + +1; diff --git a/FS/MANIFEST b/FS/MANIFEST index 83359f118..4184b9ce6 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -870,3 +870,7 @@ FS/webservice_log.pm t/webservice_log.t FS/access_user_page_pref.pm t/access_user_page_pref.t +FS/commission_schedule.pm +t/commission_schedule.t +FS/commission_rate.pm +t/commission_rate.t diff --git a/FS/t/commission_rate.t b/FS/t/commission_rate.t new file mode 100644 index 000000000..fb5f43cc5 --- /dev/null +++ b/FS/t/commission_rate.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::commission_rate; +$loaded=1; +print "ok 1\n"; diff --git a/FS/t/commission_schedule.t b/FS/t/commission_schedule.t new file mode 100644 index 000000000..bbe6b42dc --- /dev/null +++ b/FS/t/commission_schedule.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::commission_schedule; +$loaded=1; +print "ok 1\n"; diff --git a/httemplate/browse/commission_schedule.html b/httemplate/browse/commission_schedule.html new file mode 100644 index 000000000..5a4f9840e --- /dev/null +++ b/httemplate/browse/commission_schedule.html @@ -0,0 +1,70 @@ +<& elements/browse.html, + 'title' => "Commission schedules", + 'name' => "commission schedules", + 'menubar' => [ 'Add a new schedule' => + $p.'edit/commission_schedule.html' + ], + 'query' => { 'table' => 'commission_schedule', }, + 'count_query' => 'SELECT COUNT(*) FROM commission_schedule', + 'header' => [ '#', + 'Name', + 'Rates', + ], + 'fields' => [ 'schedulenum', + 'schedulename', + $rates_sub, + ], + 'links' => [ $link, + $link, + '', + ], + 'disable_total' => 1, +&> +<%init> + +my $money_char = FS::Conf->new->config('money_char') || '$'; + +my $ordinal_sub = sub { + # correct from 1 to 12... + my $num = shift; + $num == 1 ? '1st' : + $num == 2 ? '2nd' : + $num == 3 ? '3rd' : + $num . 'th' +}; + +my $rates_sub = sub { + my $schedule = shift; + my @rates = sort { $a->cycle <=> $b->cycle } $schedule->commission_rate; + my @data; + my $basis = emt(lc( $FS::commission_schedule::basis_options{$schedule->basis} )); + foreach my $rate (@rates) { + my $desc = ''; + if ( $rate->amount > 0 ) { + $desc = $money_char . sprintf('%.2f', $rate->amount); + } + if ( $rate->percent > 0 ) { + $desc .= ' + ' if $desc; + $desc .= $rate->percent . '% ' . emt('of') . ' ' . $basis; + } + next if !$desc; + $desc = &$ordinal_sub($rate->cycle) . ' ' . emt('invoice') . + ': ' . $desc; + + push @data, + [ + { + 'data' => $desc, + 'align' => 'right', + } + ]; + } + \@data; +}; + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); + +my $link = [ $p.'edit/commission_schedule.html?', 'schedulenum' ]; + + diff --git a/httemplate/edit/commission_schedule.html b/httemplate/edit/commission_schedule.html new file mode 100644 index 000000000..c76a3618e --- /dev/null +++ b/httemplate/edit/commission_schedule.html @@ -0,0 +1,53 @@ +<& elements/edit.html, + name_singular => 'schedule', + table => 'commission_schedule', + viewall_dir => 'browse', + fields => [ 'schedulename', + { field => 'reasonnum', + type => 'select-reason', + reason_class => 'R', + }, + { field => 'basis', + type => 'select', + options => [ keys %FS::commission_schedule::basis_options ], + labels => { %FS::commission_schedule::basis_options }, + }, + { type => 'tablebreak-tr-title', value => 'Billing cycles' }, + { field => 'commissionratenum', + type => 'commission_rate', + o2m_table => 'commission_rate', + m2_label => ' ', + m2_error_callback => $m2_error_callback, + colspan => 2, + }, + ], + labels => { 'schedulenum' => '', + 'schedulename' => 'Name', + 'basis' => 'Based on', + 'commissionratenum' => '', + }, +&> +<%init> + +my $m2_error_callback = sub { + my ($cgi, $object) = @_; + + my @rates; + foreach my $k ( grep /^commissionratenum\d+/, $cgi->param ) { + my $num = $cgi->param($k); + my $cycle = $cgi->param($k.'_cycle'); + my $amount = $cgi->param($k.'_amount'); + my $percent = $cgi->param($k.'_percent'); + if ($cycle > 0) { + push @rates, FS::commission_rate->new({ + 'commissionratenum' => $num, + 'cycle' => $cycle, + 'amount' => $amount, + 'percent' => $percent, + }); + } + } + @rates; +}; + + diff --git a/httemplate/edit/process/commission_schedule.html b/httemplate/edit/process/commission_schedule.html new file mode 100644 index 000000000..50e0371da --- /dev/null +++ b/httemplate/edit/process/commission_schedule.html @@ -0,0 +1,36 @@ +<& elements/process.html, + 'table' => 'commission_schedule', + 'viewall_dir' => 'browse', + 'process_o2m' => { + 'table' => 'commission_rate', + 'fields' => [qw( cycle amount percent )], + }, + 'precheck_callback' => $precheck, + 'debug' => 1, +&> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); + +my $precheck = sub { + my $cgi = shift; + $cgi->param('reasonnum') =~ /^(-?\d+)$/ or die "Illegal reasonnum"; + + my ($reasonnum, $error) = $m->comp('/misc/process/elements/reason'); + if (!$reasonnum) { + $error ||= 'Reason required' + } + $cgi->param('reasonnum', $reasonnum) unless $error; + + # remove rate entries with no cycle selected + foreach my $k (grep /^commissionratenum\d+$/, $cgi->param) { + if (! $cgi->param($k.'_cycle') ) { + $cgi->delete($k); + } + } + + $error; +}; + + diff --git a/httemplate/elements/commission_rate.html b/httemplate/elements/commission_rate.html new file mode 100644 index 000000000..071ebb1e3 --- /dev/null +++ b/httemplate/elements/commission_rate.html @@ -0,0 +1,68 @@ +% unless ( $opt{'js_only'} ) { + + + + <& select.html, + field => "${name}_cycle", + options => [ '', 1 .. 12 ], + option_labels => { + '' => '', + 1 => '1st', + 2 => '2nd', + 3 => '3rd', + map { $_ => $_.'th' } 4 .. 12 + }, + onchange => $onchange, + curr_value => $commission_rate->get("cycle"), + &> + <% $money_char %> + <& input-text.html, + field => "${name}_amount", + size => 8, + curr_value => $commission_rate->get("amount") + || '0.00', + 'text-align' => 'right' + &> + + + <& input-text.html, + field => "${name}_percent", + size => 8, + curr_value => $commission_rate->get("percent") + || '0', + 'text-align' => 'right' + &>% +% } +<%init> + +my( %opt ) = @_; + +my $conf = new FS::Conf; +my $money_char = $conf->config('money_char') || '$'; + +my $name = $opt{'field'} || 'commissionratenum'; +my $id = $opt{'id'} || 'commissionratenum'; + +my $curr_value = $opt{'curr_value'} || $opt{'value'}; + +my $onchange = ''; +if ( $opt{'onchange'} ) { + $onchange = $opt{'onchange'}; + $onchange .= '(this)' unless $onchange =~ /\(\w*\);?$/; + $onchange =~ s/\(what\);/\(this\);/g; #ugh, terrible hack. all onchange + #callbacks should act the same + $onchange = 'onChange="'. $onchange. '"'; +} + +my $commission_rate; +if ( $curr_value ) { + $commission_rate = qsearchs('commission_rate', { 'commissionratenum' => $curr_value } ); +} else { + $commission_rate = new FS::commission_rate {}; +} + +foreach my $field (qw( amount percent cycle)) { + my $value = $cgi->param("${name}_${field}"); + $commission_rate->set($field, $value) if $value; +} + + diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html index 0f98bc960..88c1df3c8 100644 --- a/httemplate/elements/menu.html +++ b/httemplate/elements/menu.html @@ -672,7 +672,10 @@ $config_cust{'Note classes'} = [ $fsurl.'browse/cust_note_class.html', 'Note cla tie my %config_agent, 'Tie::IxHash', 'Agent types' => [ $fsurl.'browse/agent_type.cgi', 'Agent types define groups of package definitions that you can then assign to particular agents' ], 'Agents' => [ $fsurl.'browse/agent.cgi', 'Agents are resellers of your service. Agents may be limited to a subset of your full offerings (via their type)' ], - 'Agent payment gateways' => [ $fsurl.'browse/payment_gateway.html', 'Credit card and electronic check processors for agent overrides' ]; + 'Agent payment gateways' => [ $fsurl.'browse/payment_gateway.html', 'Credit card and electronic check processors for agent overrides' ], + 'separator' => '', + 'Commission schedules' => [ $fsurl.'browse/commission_schedule.html', + 'Commission schedules for consecutive billing periods' ], ; tie my %config_sales, 'Tie::IxHash', diff --git a/httemplate/elements/tr-select-reason.html b/httemplate/elements/tr-select-reason.html index 97466f175..9a430222c 100755 --- a/httemplate/elements/tr-select-reason.html +++ b/httemplate/elements/tr-select-reason.html @@ -188,9 +188,8 @@ my $class = $opt{'reason_class'}; my $init_reason; if ( $opt{'cgi'} ) { $init_reason = $opt{'cgi'}->param($name); -} else { - $init_reason = $opt{'curr_value'}; } +$init_reason ||= $opt{'curr_value'}; my $id = $opt{'id'} || $name; $id =~ s/\./_/g; # for edit/part_event -- 2.11.0