From dc797c21faf993cec12ae92c190043c4f8bb2ab2 Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Sun, 18 Aug 2013 16:09:39 -0700 Subject: [PATCH] continue sales person work: customer and package selection, commissions, reporting. RT#23402 --- FS/FS.pm | 2 + FS/FS/Mason.pm | 1 + FS/FS/Schema.pm | 27 +++++-- FS/FS/agent_pkg_class.pm | 10 ++- FS/FS/sales_pkg_class.pm | 124 +++++++++++++++++++++++++++++ FS/MANIFEST | 2 + FS/t/sales_pkg_class.t | 5 ++ httemplate/browse/sales.html | 44 +++++++++- httemplate/edit/agent.cgi | 34 ++------ httemplate/edit/process/sales.html | 35 +++++++- httemplate/edit/sales.html | 10 +++ httemplate/elements/table-commissions.html | 44 ++++++++++ httemplate/search/agent_commission.html | 3 +- 13 files changed, 294 insertions(+), 47 deletions(-) create mode 100644 FS/FS/sales_pkg_class.pm create mode 100644 FS/t/sales_pkg_class.t create mode 100644 httemplate/elements/table-commissions.html diff --git a/FS/FS.pm b/FS/FS.pm index 9ba5ba152..348444431 100644 --- a/FS/FS.pm +++ b/FS/FS.pm @@ -276,6 +276,8 @@ L - Usage class class L - Sales person class +L - Sales person package class commission class + L - Agent (reseller) class L - Agent (reseller) currency class diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index 79930487e..5cecefd7c 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -351,6 +351,7 @@ if ( -e $addl_handler_use_file ) { use FS::vend_bill; use FS::vend_pay; use FS::vend_bill_pay; + use FS::sales_pkg_class; # Sammath Naur if ( $FS::Mason::addl_handler_use ) { diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 2e9a10af7..6fca62e73 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -525,6 +525,17 @@ sub tables_hashref { 'index' => [ ['typenum'] ], }, + 'agent_currency' => { + 'columns' => [ + 'agentcurrencynum', 'serial', '', '', '', '', + 'agentnum', 'int', '', '', '', '', + 'currency', 'char', '', 3, '', '', + ], + 'primary_key' => 'agentcurrencynum', + 'unique' => [], + 'index' => [ ['agentnum'] ], + }, + 'sales' => { 'columns' => [ 'salesnum', 'serial', '', '', '', '', @@ -537,15 +548,17 @@ sub tables_hashref { 'index' => [ ['salesnum'], ['disabled'] ], }, - 'agent_currency' => { + 'sales_pkg_class' => { 'columns' => [ - 'agentcurrencynum', 'serial', '', '', '', '', - 'agentnum', 'int', '', '', '', '', - 'currency', 'char', '', 3, '', '', + 'salespkgclassnum', 'serial', '', '', '', '', + 'salesnum', 'int', '', '', '', '', + 'classnum', 'int', 'NULL', '', '', '', + 'commission_percent', 'decimal', '', '7,4', '', '', + 'commission_duration', 'int', 'NULL', '', '', '', ], - 'primary_key' => 'agentcurrencynum', - 'unique' => [], - 'index' => [ ['agentnum'] ], + 'primary_key' => 'salespkgclassnum', + 'unique' => [ [ 'salesnum', 'classnum' ], ], + 'index' => [], }, 'cust_attachment' => { diff --git a/FS/FS/agent_pkg_class.pm b/FS/FS/agent_pkg_class.pm index 1683c1a14..5c5c3f7ed 100644 --- a/FS/FS/agent_pkg_class.pm +++ b/FS/FS/agent_pkg_class.pm @@ -1,8 +1,10 @@ package FS::agent_pkg_class; +use base qw( FS::Record ); use strict; -use base qw( FS::Record ); -use FS::Record qw( qsearch qsearchs ); +#use FS::Record qw( qsearch qsearchs ); +use FS::agent; +use FS::pkg_class; =head1 NAME @@ -25,7 +27,7 @@ FS::agent_pkg_class - Object methods for agent_pkg_class records =head1 DESCRIPTION -An FS::agent_pkg_class object represents an commission for a specific agent +An FS::agent_pkg_class object represents a commission for a specific agent and package class. FS::agent_pkg_class inherits from FS::Record. The following fields are currently supported: @@ -109,7 +111,7 @@ sub check { =head1 SEE ALSO -L, schema.html from the base documentation. +L, L, L. =cut diff --git a/FS/FS/sales_pkg_class.pm b/FS/FS/sales_pkg_class.pm new file mode 100644 index 000000000..0fb7e8698 --- /dev/null +++ b/FS/FS/sales_pkg_class.pm @@ -0,0 +1,124 @@ +package FS::sales_pkg_class; +use base qw( FS::Record ); + +use strict; +#use FS::Record qw( qsearch qsearchs ); +use FS::sales; +use FS::pkg_class; + +=head1 NAME + +FS::sales_pkg_class - Object methods for sales_pkg_class records + +=head1 SYNOPSIS + + use FS::sales_pkg_class; + + $record = new FS::sales_pkg_class \%hash; + $record = new FS::sales_pkg_class { 'column' => 'value' }; + + $error = $record->insert; + + $error = $new_record->replace($old_record); + + $error = $record->delete; + + $error = $record->check; + +=head1 DESCRIPTION + +An FS::sales_pkg_class object represents a commission for a specific sales +person and package class. FS::sales_pkg_class inherits from FS::Record. The +following fields are currently supported: + +=over 4 + +=item salespkgclassnum + +primary key + +=item salesnum + +salesnum + +=item classnum + +classnum + +=item commission_percent + +commission_percent + +=item commission_duration + +commission_duration + + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Creates a new record. To add the record 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 method. + +=cut + +sub table { 'sales_pkg_class'; } + +=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 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; + + $self->commission_percent(0) unless length($self->commission_percent); + + my $error = + $self->ut_numbern('salespkgclassnum') + || $self->ut_foreign_key('salesnum', 'sales', 'salesnum') + || $self->ut_foreign_keyn('classnum', 'pkg_class', 'classnum') + || $self->ut_float('commission_percent') + || $self->ut_numbern('commission_duration') + ; + return $error if $error; + + $self->SUPER::check; +} + +=back + +=head1 BUGS + +=head1 SEE ALSO + +L, L. + +=cut + +1; + diff --git a/FS/MANIFEST b/FS/MANIFEST index a6e87f6e3..1bb5cbd63 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -716,3 +716,5 @@ FS/vend_pay.pm t/vend_pay.t FS/vend_bill_pay.pm t/vend_bill_pay.t +FS/sales_pkg_class.pm +t/sales_pkg_class.t diff --git a/FS/t/sales_pkg_class.t b/FS/t/sales_pkg_class.t new file mode 100644 index 000000000..a07cf090b --- /dev/null +++ b/FS/t/sales_pkg_class.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::sales_pkg_class; +$loaded=1; +print "ok 1\n"; diff --git a/httemplate/browse/sales.html b/httemplate/browse/sales.html index 1cdc49085..6fac058f9 100644 --- a/httemplate/browse/sales.html +++ b/httemplate/browse/sales.html @@ -14,9 +14,10 @@ <%init> my $curuser = $FS::CurrentUser::CurrentUser; - die "access denied" unless $curuser->access_right('Edit sales people'); +#Sales people bring in business.

+ my @header = ( 'Sales person' ); my @fields = ( 'salesperson' ); my @links = ( [$p.'edit/sales.html?', 'salesnum'] ); @@ -27,6 +28,45 @@ if ( $curuser->access_right('Configuration') ) { push @links, [ $p.'edit/agent.cgi?', 'agentnum' ]; } -#Sales people bring in business.

+push @header, 'Commissions'; +push @fields, sub { + + my $sales = shift; + + #started out as false laziness w/browse/agent.cgi + # (which said surprising amount of false laziness w/ edit/process/agent.cgi) + # but this now returns an edit.html data structure that renders to a table + # instead of HTML + + my @pkg_class = qsearch('pkg_class', { 'disabled'=>'' }); + + [ + map { + my %sales_pkg_class = ( 'salesnum' => $sales->salesnum, + 'classnum' => $_ ? $_->classnum : '' + ); + my $sales_pkg_class = + qsearchs( 'sales_pkg_class', \%sales_pkg_class ) + || new FS::sales_pkg_class \%sales_pkg_class; + #my $param = 'classnum'. $sales_pkg_class{classnum}; + + [ + { align => 'right', + data => ($sales_pkg_class->commission_percent || 0). '%', + }, + { align => 'left', + data => ' '. encode_entities( + $_ ? $_->classname : mt('(no package class)') + ), + }, + ]; + + } + ( '', @pkg_class ) + + ]; + +}; +#push @links, ''; diff --git a/httemplate/edit/agent.cgi b/httemplate/edit/agent.cgi index 2eddd30a4..15da2f043 100755 --- a/httemplate/edit/agent.cgi +++ b/httemplate/edit/agent.cgi @@ -141,35 +141,11 @@
-<% mt('Commissions') |h %> - - -% #surprising amount of false laziness w/ edit/process/agent.cgi -% my @pkg_class = qsearch('pkg_class', { 'disabled'=>'' }); -% foreach my $pkg_class ( '', @pkg_class ) { -% my %agent_pkg_class = ( 'agentnum' => $agent->agentnum, -% 'classnum' => $pkg_class ? $pkg_class->classnum : '' -% ); -% my $agent_pkg_class = -% qsearchs( 'agent_pkg_class', \%agent_pkg_class ) -% || new FS::agent_pkg_class \%agent_pkg_class; -% my $param = 'classnum'. $agent_pkg_class{classnum}; - - - - - - -% } - -
% - <% $pkg_class ? $pkg_class->classname : mt('(no package class)') |h %> -
+<& /elements/table-commissions.html, + 'source_obj' => $agent, + 'link_table' => 'agent_pkg_class', + #'target_table' => 'pkg_class', +&>
% if ( $conf->config('currencies') ) { diff --git a/httemplate/edit/process/sales.html b/httemplate/edit/process/sales.html index b60276dcb..1bb1797df 100644 --- a/httemplate/edit/process/sales.html +++ b/httemplate/edit/process/sales.html @@ -1,12 +1,41 @@ <& elements/process.html, - 'table' => 'sales', - 'viewall_dir' => 'browse', - 'agent_virt' => 1, + 'table' => 'sales', + 'viewall_dir' => 'browse', + 'agent_virt' => 1, + 'noerror_callback' => $process_sales_pkg_class, &> <%init> die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Edit sales people'); +#false laziness w/process/agent.cgi +my $process_sales_pkg_class = sub { + my( $cgi, $sales ) = @_; + + #surprising amount of false laziness w/ edit/agent.cgi + my @pkg_class = qsearch('pkg_class', { 'disabled'=>'' }); + foreach my $pkg_class ( '', @pkg_class ) { + my %sales_pkg_class = ( 'salesnum' => $sales->salesnum, + 'classnum' => $pkg_class ? $pkg_class->classnum : '' + ); + my $sales_pkg_class = + qsearchs( 'sales_pkg_class', \%sales_pkg_class ) + || new FS::sales_pkg_class \%sales_pkg_class; + + my $param = 'classnum'. $sales_pkg_class{classnum}; + + $sales_pkg_class->commission_percent( $cgi->param($param) ); + + my $method = $sales_pkg_class->salespkgclassnum ? 'replace' : 'insert'; + + my $error = $sales_pkg_class->$method; + die $error if $error; #XXX push this down into sales.pm w/better/transactional error handling + + } + +}; + + diff --git a/httemplate/edit/sales.html b/httemplate/edit/sales.html index 65cddfc13..763f86124 100755 --- a/httemplate/edit/sales.html +++ b/httemplate/edit/sales.html @@ -12,6 +12,16 @@ }, 'viewall_dir' => 'browse', 'agent_virt' => 1, + 'html_bottom' => sub { + my $sales = shift; + + '
'. + include('/elements/table-commissions.html', + 'source_obj' => $sales, + 'link_table' => 'sales_pkg_class', + #'target_table' => 'pkg_class', + ); + }, &> <%init> diff --git a/httemplate/elements/table-commissions.html b/httemplate/elements/table-commissions.html new file mode 100644 index 000000000..ce5808ded --- /dev/null +++ b/httemplate/elements/table-commissions.html @@ -0,0 +1,44 @@ +<% mt('Commissions') |h %> + + +% my $pkey = $object->primary_key; +% my $pkey_value = $object->$pkey(); +% my $link_class = 'FS::'.$link_table; +% +% #surprising amount of false laziness w/ edit/process/agent.cgi +% # (somewhat less now that we're more generic) +% my @pkg_class = qsearch($target_table, { 'disabled'=>'' }); +% foreach my $pkg_class ( '', @pkg_class ) { +% my %thing_pkg_class = ( $pkey => $pkey_value, +% classnum => $pkg_class ? $pkg_class->classnum : '' +% ); +% my $thing_pkg_class = +% qsearchs( $link_table, \%thing_pkg_class ) +% || $link_class->new( \%thing_pkg_class ); +% my $param = 'classnum'. $thing_pkg_class{classnum}; + + + + + + +% } + +
% + <% $pkg_class ? $pkg_class->classname : mt('(no package class)') |h %> +
+ +<%init> + +my %opt = @_; + +my $object = $opt{'source_obj'}; +my $link_table = $opt{'link_table'}; +my $target_table = $opt{'target_table'} || 'pkg_class'; + + diff --git a/httemplate/search/agent_commission.html b/httemplate/search/agent_commission.html index b94ae9f6e..2818d2ee5 100644 --- a/httemplate/search/agent_commission.html +++ b/httemplate/search/agent_commission.html @@ -33,11 +33,10 @@ td.money:before { content: '<% $money_char %>'; } % if ( $custnum ne $cust_pkg->custnum ) { % # start of a new customer section % my $cust_main = $cust_pkg->cust_main; -% my $label = $cust_main->custnum . ': '. $cust_main->name; % $bgcolor = 0; - <% $label %> + <% $cust_main->display_custnum %>: <% $cust_main->name |h %> % } -- 2.11.0