[freeside-commits] branch master updated. 708baebde34a2442ec41db38902e04f3c6ec4269

Ivan ivan at 420.am
Thu Aug 30 00:48:24 PDT 2012


The branch, master has been updated
       via  708baebde34a2442ec41db38902e04f3c6ec4269 (commit)
       via  7c9457296c5dd8985eda5a8325ba1254223ec953 (commit)
      from  56fbf4de4af0a18b611daaa50e42b5dac047a937 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 708baebde34a2442ec41db38902e04f3c6ec4269
Merge: 7c94572 56fbf4d
Author: Ivan Kohler <ivan at freeside.biz>
Date:   Thu Aug 30 00:48:19 2012 -0700

    Merge branch 'master' of git.freeside.biz:/home/git/freeside


commit 7c9457296c5dd8985eda5a8325ba1254223ec953
Author: Ivan Kohler <ivan at freeside.biz>
Date:   Thu Aug 30 00:48:08 2012 -0700

    commissions per agent and package class, RT#18232

diff --git a/FS/FS.pm b/FS/FS.pm
index 8bbff12..5ab3f71 100644
--- a/FS/FS.pm
+++ b/FS/FS.pm
@@ -270,6 +270,8 @@ L<FS::sales> - Sales person class
 
 L<FS::agent> - Agent (reseller) class
 
+L<FS::agent_pkg_class> - Agent (reseller) package class commission class
+
 L<FS::agent_type> - Agent type class
 
 L<FS::type_pkgs> - Class linking agent types (see L<FS::agent_type>) with package definitions (see L<FS::part_pkg>)
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 0f1d151..4f4390c 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -473,16 +473,16 @@ sub tables_hashref {
       'index' => [ ['typenum'], ['disabled'], ['agent_custnum'] ],
     },
 
-    'sales' => {
+    'agent_pkg_class' => {
       'columns' => [
-        'salesnum',          'serial',    '',       '', '', '', 
-        'salesperson',      'varchar',    '',  $char_d, '', '', 
-        'agentnum',             'int', 'NULL',      '', '', '', 
-        'disabled',            'char', 'NULL',       1, '', '', 
+        'agentpkgclassnum',    'serial',     '',    '', '', '',
+        'agentnum',               'int',     '',    '', '', '',
+        'classnum',               'int', 'NULL',    '', '', '',
+        'commission_percent', 'decimal',     '', '7,4', '', '',
       ],
-      'primary_key' => 'salesnum',
-      'unique' => [],
-      'index' => [ ['salesnum'], ['disabled'] ],
+      'primary_key' => 'agentpkgclassnum',
+      'unique'      => [ [ 'agentnum', 'classnum' ], ],
+      'index'       => [ [ 'agentnum' ], [ 'classnum' ] ],
     },
 
     'agent_type' => {
@@ -506,6 +506,18 @@ sub tables_hashref {
       'index' => [ ['typenum'] ],
     },
 
+    'sales' => {
+      'columns' => [
+        'salesnum',          'serial',    '',       '', '', '', 
+        'salesperson',      'varchar',    '',  $char_d, '', '', 
+        'agentnum',             'int', 'NULL',      '', '', '', 
+        'disabled',            'char', 'NULL',       1, '', '', 
+      ],
+      'primary_key' => 'salesnum',
+      'unique' => [],
+      'index' => [ ['salesnum'], ['disabled'] ],
+    },
+
     'cust_attachment' => {
       'columns' => [
         'attachnum', 'serial', '', '', '', '',
diff --git a/FS/FS/agent_pkg_class.pm b/FS/FS/agent_pkg_class.pm
new file mode 100644
index 0000000..1683c1a
--- /dev/null
+++ b/FS/FS/agent_pkg_class.pm
@@ -0,0 +1,117 @@
+package FS::agent_pkg_class;
+
+use strict;
+use base qw( FS::Record );
+use FS::Record qw( qsearch qsearchs );
+
+=head1 NAME
+
+FS::agent_pkg_class - Object methods for agent_pkg_class records
+
+=head1 SYNOPSIS
+
+  use FS::agent_pkg_class;
+
+  $record = new FS::agent_pkg_class \%hash;
+  $record = new FS::agent_pkg_class { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::agent_pkg_class object represents an commission for a specific agent
+and package class.  FS::agent_pkg_class inherits from FS::Record.  The
+following fields are currently supported:
+
+=over 4
+
+=item agentpkgclassnum
+
+primary key
+
+=item agentnum
+
+agentnum
+
+=item classnum
+
+classnum
+
+=item commission_percent
+
+commission_percent
+
+
+=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<hash> method.
+
+=cut
+
+sub table { 'agent_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('agentpkgclassnum')
+    || $self->ut_foreign_key('agentnum', 'agent', 'agentnum')
+    || $self->ut_foreign_keyn('classnum', 'pkg_class', 'classnum')
+    || $self->ut_float('commission_percent')
+  ;
+  return $error if $error;
+
+  $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/part_event/Action/Mixin/credit_agent_pkg_class.pm b/FS/FS/part_event/Action/Mixin/credit_agent_pkg_class.pm
new file mode 100644
index 0000000..73d32e0
--- /dev/null
+++ b/FS/FS/part_event/Action/Mixin/credit_agent_pkg_class.pm
@@ -0,0 +1,25 @@
+package FS::part_event::Action::Mixin::credit_agent_pkg_class;
+use base qw( FS::part_event::Action::Mixin::credit_pkg );
+
+use strict;
+
+sub option_fields {
+  my $class = shift;
+  my %option_fields = $class->SUPER::option_fields;
+  delete $option_fields{'percent'};
+  %option_fields;
+}
+
+sub _calc_credit_percent {
+  my( $self, $cust_pkg ) = @_;
+
+  my $agent_pkg_class = qsearchs( 'agent_pkg_class', {
+    'agentnum' => $self->cust_main($cust_pkg)->agentnum,
+    'classnum' => $cust_pkg->classnum,
+  });
+
+  $agent_pkg_class ? $agent_pkg_class->commission_percent : 0;
+
+}
+
+1;
diff --git a/FS/FS/part_event/Action/Mixin/credit_pkg.pm b/FS/FS/part_event/Action/Mixin/credit_pkg.pm
index aeda92f..9dcd701 100644
--- a/FS/FS/part_event/Action/Mixin/credit_pkg.pm
+++ b/FS/FS/part_event/Action/Mixin/credit_pkg.pm
@@ -51,7 +51,7 @@ sub _calc_credit {
     }
   }
 
-  my $percent = $self->option('percent');
+  my $percent = $self->_calc_credit_percent($cust_pkg);
 
   #my @arg = $no_cust_pkg{$what} ? () : ($cust_pkg);
   my @arg = ($what eq 'setup_cost') ? () : ($cust_pkg);
@@ -60,4 +60,9 @@ sub _calc_credit {
 
 }
 
+sub _calc_credit_percent {
+  my( $self, $cust_pkg ) = @_;
+  $self->option('percent');
+}
+
 1;
diff --git a/FS/FS/part_event/Action/pkg_agent_credit_pkg_class.pm b/FS/FS/part_event/Action/pkg_agent_credit_pkg_class.pm
new file mode 100644
index 0000000..3dcf668
--- /dev/null
+++ b/FS/FS/part_event/Action/pkg_agent_credit_pkg_class.pm
@@ -0,0 +1,9 @@
+package FS::part_event::Action::pkg_agent_credit_pkg_class;
+
+use strict;
+use base qw( FS::part_event::Action::Mixin::credit_agent_pkg_class
+             FS::part_event::Action::pkg_agent_credit );
+
+sub description { 'Credit the agent an amount based on their commission percentage for the referred package class'; }
+
+1;
diff --git a/FS/t/agent_pkg_class.t b/FS/t/agent_pkg_class.t
new file mode 100644
index 0000000..dc0fa12
--- /dev/null
+++ b/FS/t/agent_pkg_class.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::agent_pkg_class;
+$loaded=1;
+print "ok 1\n";
diff --git a/httemplate/browse/agent.cgi b/httemplate/browse/agent.cgi
index 64288b8..fc9ce54 100755
--- a/httemplate/browse/agent.cgi
+++ b/httemplate/browse/agent.cgi
@@ -25,6 +25,7 @@ full offerings (via their type).<BR><BR>
   <TH CLASS="grid" BGCOLOR="#cccccc" COLSPAN=<% ( $cgi->param('showdisabled') || !dbdef->table('agent')->column('disabled') ) ? 2 : 3 %>>Agent</TH>
   <TH CLASS="grid" BGCOLOR="#cccccc">Type</TH>
   <TH CLASS="grid" BGCOLOR="#cccccc">Master Customer</TH>
+  <TH CLASS="grid" BGCOLOR="#cccccc">Commissions</TH>
   <TH CLASS="grid" BGCOLOR="#cccccc">Access Groups</TH>
   <TH CLASS="grid" BGCOLOR="#cccccc"><FONT SIZE=-1>Invoice<BR>Template</FONT></TH>
   <TH CLASS="grid" BGCOLOR="#cccccc">Customers</TH>
@@ -93,6 +94,33 @@ full offerings (via their type).<BR><BR>
         </TD>
 
         <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
+
+          <TABLE>
+
+%           #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};
+
+              <TR>
+                <TD><% $agent_pkg_class->commission_percent || 0 %>%</TD>
+                <TD><% $pkg_class ? $pkg_class->classname : mt('(no package class)') |h %>
+                </TD>
+              </TR>
+
+%           }
+
+          </TABLE>
+
+        </TD>
+
+        <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
 %         foreach my $access_group (
 %           map $_->access_group,
 %               qsearch('access_groupagent', { 'agentnum' => $agent->agentnum })
diff --git a/httemplate/edit/agent.cgi b/httemplate/edit/agent.cgi
index 6707d66..b043d1e 100755
--- a/httemplate/edit/agent.cgi
+++ b/httemplate/edit/agent.cgi
@@ -19,9 +19,12 @@
 </SCRIPT>
 
 <INPUT TYPE="hidden" NAME="agentnum" VALUE="<% $agent->agentnum %>">
-Agent #<% $agent->agentnum ? $agent->agentnum : "(NEW)" %>
 
-<% &ntable("#cccccc", 2, '') %>
+<FONT CLASS="fsinnerbox-title">
+  Agent #<% $agent->agentnum ? $agent->agentnum : "(NEW)" %>
+</FONT>
+
+<TABLE CLASS="fsinnerbox">
 
   <TR>
     <TH ALIGN="right">Agent</TH>
@@ -117,8 +120,13 @@ Agent #<% $agent->agentnum ? $agent->agentnum : "(NEW)" %>
     </TR>
 % } 
 
+</TABLE>
+<BR>
+
+<FONT CLASS="fsinnerbox-title"><% mt('Access Groups') |h %></FONT>
+<TABLE CLASS="fsinnerbox">
+
   <TR>
-    <TD ALIGN="right">Access Groups</TD>
     <TD><% include('/elements/checkboxes-table.html',
                      'source_obj'   => $agent,
                      'link_table'   => 'access_groupagent',
@@ -131,6 +139,38 @@ Agent #<% $agent->agentnum ? $agent->agentnum : "(NEW)" %>
   </TR>
 
 </TABLE>
+<BR>
+
+<FONT CLASS="fsinnerbox-title"><% mt('Commissions') |h %></FONT>
+<TABLE CLASS="fsinnerbox">
+
+% #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};
+
+    <TR>
+      <TD><INPUT TYPE      = "text"
+                 NAME      = "<% $param %>"
+                 VALUE     = "<% $cgi->param($param) || $agent_pkg_class->commission_percent |h %>"
+                 SIZE      = 6
+                 MAXLENGTH = 7
+          >%
+      </TD>
+      <TD><% $pkg_class ? $pkg_class->classname : mt('(no package class)') |h %>
+      </TD>
+    </TR>
+
+% }
+
+</TABLE>
+
 
 <BR>
 <INPUT TYPE="submit" VALUE="<% $agent->agentnum ? "Apply changes" : "Add agent" %>">
diff --git a/httemplate/edit/process/agent.cgi b/httemplate/edit/process/agent.cgi
index e776d28..034c4cc 100755
--- a/httemplate/edit/process/agent.cgi
+++ b/httemplate/edit/process/agent.cgi
@@ -1,11 +1,12 @@
 <% include( 'elements/process.html',
-              'table'       => 'agent',
-              'viewall_dir' => 'browse',
-              'viewall_ext' => 'cgi',
-              'process_m2m' => { 'link_table'   => 'access_groupagent',
-                                 'target_table' => 'access_group',
-                               },
-              'edit_ext'    => 'cgi',
+              'table'            => 'agent',
+              'viewall_dir'      => 'browse',
+              'viewall_ext'      => 'cgi',
+              'process_m2m'      => { 'link_table'   => 'access_groupagent',
+                                      'target_table' => 'access_group',
+                                    },
+              'edit_ext'         => 'cgi',
+              'noerror_callback' => $process_agent_pkg_class,
           )
 %>
 <%init>
@@ -18,4 +19,30 @@ if ( FS::Conf->new->exists('disable_acl_changes') ) {
   die "shouldn't be reached";
 }
 
+my $process_agent_pkg_class = sub {
+  my( $cgi, $agent ) = @_;
+
+  #surprising amount of false laziness w/ edit/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};
+
+    $agent_pkg_class->commission_percent( $cgi->param($param) );
+
+    my $method = $agent_pkg_class->agentpkgclassnum ? 'replace' : 'insert';
+
+    my $error = $agent_pkg_class->$method;
+    die $error if $error; #XXX push this down into agent.pm w/better/transactional error handling
+
+  }
+
+};
+
 </%init>

-----------------------------------------------------------------------

Summary of changes:
 FS/FS.pm                                           |    2 +
 FS/FS/Schema.pm                                    |   28 +++++++---
 ...bill_pkg_display_void.pm => agent_pkg_class.pm} |   59 +++++++------------
 .../Action/Mixin/credit_agent_pkg_class.pm         |   25 ++++++++
 FS/FS/part_event/Action/Mixin/credit_pkg.pm        |    7 ++-
 .../Action/pkg_agent_credit_pkg_class.pm           |    9 +++
 FS/t/{AccessRight.t => agent_pkg_class.t}          |    2 +-
 httemplate/browse/agent.cgi                        |   28 +++++++++
 httemplate/edit/agent.cgi                          |   46 ++++++++++++++-
 httemplate/edit/process/agent.cgi                  |   41 +++++++++++--
 10 files changed, 190 insertions(+), 57 deletions(-)
 copy FS/FS/{cust_bill_pkg_display_void.pm => agent_pkg_class.pm} (55%)
 create mode 100644 FS/FS/part_event/Action/Mixin/credit_agent_pkg_class.pm
 create mode 100644 FS/FS/part_event/Action/pkg_agent_credit_pkg_class.pm
 copy FS/t/{AccessRight.t => agent_pkg_class.t} (80%)




More information about the freeside-commits mailing list