add in support for sales people, #16586
authorBrian Medley <bpm@snafu.org>
Sun, 29 Apr 2012 20:29:16 +0000 (15:29 -0500)
committerBrian Medley <bpm@snafu.org>
Sun, 29 Apr 2012 20:29:16 +0000 (15:29 -0500)
12 files changed:
FS/FS.pm
FS/FS/Mason.pm
FS/FS/Schema.pm
FS/FS/access_groupsales.pm [new file with mode: 0644]
FS/FS/sales.pm [new file with mode: 0644]
FS/MANIFEST
FS/t/access_groupsales.t [new file with mode: 0644]
FS/t/sales.t [new file with mode: 0644]
httemplate/browse/sales.cgi [new file with mode: 0755]
httemplate/edit/process/sales.cgi [new file with mode: 0644]
httemplate/edit/sales.cgi [new file with mode: 0755]
httemplate/elements/menu.html

index 3716212..8c78179 100644 (file)
--- a/FS/FS.pm
+++ b/FS/FS.pm
@@ -95,6 +95,8 @@ L<FS::access_usergroup> - Employee group membership
 
 L<FS::access_groupagent> - Group reseller access
 
+L<FS::access_groupsales> - Group sales access
+
 L<FS::access_right> - Access rights
 
 L<FS::svc_acct_pop> - POP (Point of Presence, not Post
@@ -262,6 +264,8 @@ L<FS::rate_tier_details> - Rater tier details for call billing
 
 L<FS::usage_class> - Usage class class
 
+L<FS::sales> - Sales person class
+
 L<FS::agent> - Agent (reseller) class
 
 L<FS::agent_type> - Agent type class
index 7143c72..cc501c0 100644 (file)
@@ -303,6 +303,8 @@ if ( -e $addl_handler_use_file ) {
   use FS::discount_plan;
   use FS::tower;
   use FS::tower_sector;
+  use FS::sales;
+  use FS::access_groupsales;
   use FS::contact_class;
   # Sammath Naur
 
index d42b946..ab72175 100644 (file)
@@ -473,6 +473,18 @@ sub tables_hashref {
       'index' => [ ['typenum'], ['disabled'], ['agent_custnum'] ],
     },
 
+    'sales' => {
+      'columns' => [
+        'salesnum',          'serial',    '',       '', '', '', 
+        'salesperson',      'varchar',    '',  $char_d, '', '', 
+        'agentnum',             'int', 'NULL',      '', '', '', 
+        'disabled',            'char', 'NULL',       1, '', '', 
+      ],
+      'primary_key' => 'salesnum',
+      'unique' => [],
+      'index' => [ ['salesnum'], ['disabled'] ],
+    },
+
     'agent_type' => {
       'columns' => [
         'typenum',   'serial',  '', '', '', '', 
@@ -3235,6 +3247,17 @@ sub tables_hashref {
       'index'  => [ [ 'groupnum' ] ],
     },
 
+    'access_groupsales' => {
+      'columns' => [
+        'groupsalesnum', 'serial', '', '', '', '',
+        'groupnum',         'int', '', '', '', '',
+        'salesnum',         'int', '', '', '', '',
+      ],
+      'primary_key' => 'groupsalesnum',
+      'unique' => [ [ 'groupnum', 'salesnum' ] ],
+      'index'  => [ [ 'groupnum' ] ],
+    },
+
     'access_right' => {
       'columns' => [
         'rightnum',   'serial', '',      '', '', '',
diff --git a/FS/FS/access_groupsales.pm b/FS/FS/access_groupsales.pm
new file mode 100644 (file)
index 0000000..31b07d9
--- /dev/null
@@ -0,0 +1,153 @@
+package FS::access_groupsales;
+
+use strict;
+use base qw( FS::Record );
+use FS::Record qw( qsearch qsearchs );
+
+=head1 NAME
+
+FS::access_groupsales - Object methods for access_groupsales records
+
+=head1 SYNOPSIS
+
+  use FS::access_groupsales;
+
+  $record = new FS::access_groupsales \%hash;
+  $record = new FS::access_groupsales { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::access_groupsales object represents an example.  FS::access_groupsales inherits from
+FS::Record.  The following fields are currently supported:
+
+=over 4
+
+=item groupsalesnum
+
+primary key
+
+=item groupnum
+
+groupnum
+
+=item salesnum
+
+salesnum
+
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new example.  To add the example 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
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'access_groupsales'; }
+
+=item insert
+
+Adds this record to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=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
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid example.  If there is
+an error, returns the error, otherwise returns false.  Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+  my $self = shift;
+
+  my $error = 
+    $self->ut_numbern('groupsalesnum')
+    || $self->ut_number('groupnum')
+    || $self->ut_number('salesnum')
+  ;
+  return $error if $error;
+
+  $self->SUPER::check;
+}
+
+=back
+
+=item sales
+
+Returns the associated FS::agent object.
+
+=cut
+
+sub sales {
+  my $self = shift;
+  qsearchs('sales', { 'salesnum' => $self->salesnum } );
+}
+
+=item access_group
+
+Returns the associated FS::access_group object.
+
+=cut
+
+sub access_group {
+  my $self = shift;
+  qsearchs('access_group', { 'groupnum' => $self->groupnum } );
+}
+
+=back
+
+
+=head1 BUGS
+
+The author forgot to customize this manpage.
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/sales.pm b/FS/FS/sales.pm
new file mode 100644 (file)
index 0000000..3cb61fd
--- /dev/null
@@ -0,0 +1,142 @@
+package FS::sales;
+
+use strict;
+use vars qw( @ISA );
+use base qw( FS::Record );
+use Business::CreditCard 0.28;
+use FS::Record qw( dbh qsearch qsearchs );
+use FS::cust_main;
+use FS::cust_pkg;
+use FS::agent_type;
+use FS::reg_code;
+use FS::TicketSystem;
+#use FS::Conf;
+
+@ISA = qw( FS::m2m_Common FS::Record );
+
+=head1 NAME
+
+FS::sales - Object methods for sales records
+
+=head1 SYNOPSIS
+
+  use FS::sales;
+
+  $record = new FS::sales \%hash;
+  $record = new FS::sales { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::sales object represents an example.  FS::sales inherits from
+FS::Record.  The following fields are currently supported:
+
+=over 4
+
+=item salesnum
+
+primary key
+
+=item agentnum
+
+agentnum
+
+=item disabled
+
+disabled
+
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new example.  To add the example 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
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'sales'; }
+
+=item insert
+
+Adds this record to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=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
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid example.  If there is
+an error, returns the error, otherwise returns false.  Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+  my $self = shift;
+
+  my $error = 
+    $self->ut_numbern('salesnum')
+    || $self->ut_numbern('agentnum')
+  ;
+  return $error if $error;
+
+  if ( $self->dbdef_table->column('disabled') ) {
+    $error = $self->ut_enum('disabled', [ '', 'Y' ] );
+    return $error if $error;
+  }
+
+  $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+The author forgot to customize this manpage.
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
index 0c9cc54..91711d3 100644 (file)
@@ -634,3 +634,7 @@ FS/contact_class.pm
 t/contact_class.t
 FS/upgrade_journal.pm
 t/upgrade_journal.t
+FS/sales.pm
+t/sales.t
+FS/access_groupsales.pm
+t/access_groupsales.t
diff --git a/FS/t/access_groupsales.t b/FS/t/access_groupsales.t
new file mode 100644 (file)
index 0000000..50993cf
--- /dev/null
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::access_groupsales;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/sales.t b/FS/t/sales.t
new file mode 100644 (file)
index 0000000..e47eb39
--- /dev/null
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::sales;
+$loaded=1;
+print "ok 1\n";
diff --git a/httemplate/browse/sales.cgi b/httemplate/browse/sales.cgi
new file mode 100755 (executable)
index 0000000..af09812
--- /dev/null
@@ -0,0 +1,100 @@
+<% include("/elements/header.html",'Sales Listing', menubar(
+  'Add new sales person' => '../edit/sales.cgi'
+)) %>
+Sales people bring in business.<BR><BR>
+% if ( dbdef->table('sales')->column('disabled') ) { 
+
+  <% $cgi->param('showdisabled')
+      ? do { $cgi->param('showdisabled', 0);
+             '( <a href="'. $cgi->self_url. '">hide disabled sales people</a> )'; }
+      : do { $cgi->param('showdisabled', 1);
+             '( <a href="'. $cgi->self_url. '">show disabled sales people</a> )'; }
+  %>
+% } 
+
+
+<% include('/elements/table-grid.html') %>
+% my $bgcolor1 = '#eeeeee';
+%   my $bgcolor2 = '#ffffff';
+%   my $bgcolor = '';
+
+<TR>
+  <TH CLASS="grid" BGCOLOR="#cccccc" COLSPAN=<% ( $cgi->param('showdisabled') || !dbdef->table('sales')->column('disabled') ) ? 2 : 3 %>>Sales person</TH>
+  <TH CLASS="grid" BGCOLOR="#cccccc">Agent</TH>
+  <TH CLASS="grid" BGCOLOR="#cccccc">Access Groups</TH>
+</TR>
+
+%foreach my $sales ( sort { 
+%  $a->getfield('salesnum') cmp $b->getfield('salesnum')
+%} qsearch('sales', \%search ) ) {
+%
+%  if ( $bgcolor eq $bgcolor1 ) {
+%    $bgcolor = $bgcolor2;
+%  } else {
+%    $bgcolor = $bgcolor1;
+%  }
+
+      <TR>
+
+        <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
+          <A HREF="<%$p%>edit/sales.cgi?<% $sales->salesnum %>"><% $sales->salesnum %></A>
+        </TD>
+
+        <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
+          <A HREF="<%$p%>edit/sales.cgi?<% $sales->salesnum %>"><% $sales->salesperson %></A>
+        </TD>
+
+%       if ( ! $cgi->param('showdisabled') ) { 
+          <TD CLASS="grid" BGCOLOR="<% $bgcolor %>" ALIGN="center">
+            <% $sales->disabled ? '<FONT COLOR="#FF0000"><B>DISABLED</B></FONT>'
+                                : '<FONT COLOR="#00CC00"><B>Active</B></FONT>'
+            %>
+          </TD>
+%       } 
+
+%       my ($agent) = qsearch('agent', { 'agentnum' => $sales->agentnum });
+
+        <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
+          <A HREF="<%$p%>edit/sales.cgi?<% $sales->agentnum %>"><% $sales->agentnum %></A>
+          <A HREF="<%$p%>edit/agent.cgi?<% $agent->agentnum %>">(<% $agent->agent %>)<BR>
+        </TD>
+
+        <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
+%         foreach my $access_group (
+%           map $_->access_group,
+%               qsearch('access_groupsales', { 'salesnum' => $sales->salesnum })
+%         ) {
+            <A HREF="<%$p%>edit/access_group.html?<% $access_group->groupnum %>"><% $access_group->groupname |h %><BR>
+%         }
+        </TD>
+
+      </TR>
+% } 
+
+    </TABLE>
+
+<SCRIPT TYPE="text/javascript">
+  function areyousure(what, href) {
+    if ( confirm("Are you sure you want to " + what + "?") == true )
+      window.location.href = href;
+  }
+</SCRIPT>
+
+  </BODY>
+</HTML>
+<%init>
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+my %search;
+if ( $cgi->param('showdisabled')
+     || !dbdef->table('agent')->column('disabled') ) {
+  %search = ();
+} else {
+  %search = ( 'disabled' => '' );
+}
+
+my $conf = new FS::Conf;
+
+</%init>
diff --git a/httemplate/edit/process/sales.cgi b/httemplate/edit/process/sales.cgi
new file mode 100644 (file)
index 0000000..edef4d6
--- /dev/null
@@ -0,0 +1,23 @@
+<% include( 'elements/process.html',
+              'table'       => 'sales',
+              'viewall_dir' => 'browse',
+              'viewall_ext' => 'cgi',
+              'debug'       => '1',
+              'process_m2m' => { 'link_table'   => 'access_groupsales',
+                                 'target_table' => 'access_group',
+                               },
+              'edit_ext'    => 'cgi',
+          )
+%>
+<%init>
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+if ( FS::Conf->new->exists('disable_acl_changes') ) {
+  errorpage('ACL changes disabled in public demo.');
+  die "shouldn't be reached";
+}
+
+</%init>
+
diff --git a/httemplate/edit/sales.cgi b/httemplate/edit/sales.cgi
new file mode 100755 (executable)
index 0000000..3497de5
--- /dev/null
@@ -0,0 +1,79 @@
+<% include("/elements/header.html","$action Sales Person", menubar(
+  'View all sales people' => $p. 'browse/sales.cgi',
+)) %>
+
+<% include('/elements/error.html') %>
+
+<FORM METHOD   = POST
+      ACTION   = "<%popurl(1)%>process/sales.cgi"
+>
+
+<INPUT TYPE="hidden" NAME="salesnum" VALUE="<% $sales->salesnum %>">
+Sales #<% $sales->salesnum ? $sales->salesnum : "(NEW)" %>
+
+<% &ntable("#cccccc", 2, '') %>
+
+  <TR>
+    <TH ALIGN="right">Sales</TH>
+    <TD><INPUT TYPE="text" NAME="salesperson" SIZE=32 VALUE="<% $sales->salesperson %>"></TD>
+  </TR>
+
+  <TR>
+    <TD ALIGN="right"><% emt('Agent') %></TD>
+    <TD>
+      <& /elements/select-agent.html,
+                     'curr_value' => $sales->salesnum,
+                     'disable_empty' => 1,
+      &>
+    </TD>
+  </TR>
+
+  <TR>
+    <TD ALIGN="right">Disable</TD>
+    <TD><INPUT TYPE="checkbox" NAME="disabled" VALUE="Y"<% $sales->disabled eq 'Y' ? ' CHECKED' : '' %>></TD>
+  </TR>
+
+  <TR>
+    <TD ALIGN="right">Access Groups</TD>
+    <TD><% include('/elements/checkboxes-table.html',
+                     'source_obj'   => $sales,
+                     'link_table'   => 'access_groupsales',
+                     'target_table' => 'access_group',
+                     'name_col'     => 'groupname',
+                     'target_link'  => $p. 'edit/access_group.html?',
+                  )
+        %>
+    </TD>
+  </TR>
+
+</TABLE>
+
+<BR>
+<INPUT TYPE="submit" VALUE="<% $sales->salesnum ? "Apply changes" : "Add sales" %>">
+
+</FORM>
+
+<% include('/elements/footer.html') %>
+
+<%init>
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+my $sales;
+if ( $cgi->param('error') ) {
+  $sales = new FS::sales ( {
+    map { $_, scalar($cgi->param($_)) } fields('sales')
+  } );
+} elsif ( $cgi->keywords ) {
+  my($query) = $cgi->keywords;
+  $query =~ /^(\d+)$/;
+  $sales = qsearchs( 'sales', { 'salesnum' => $1 } );
+} else { #adding
+  $sales = new FS::sales {};
+}
+my $action = $sales->salesnum ? 'Edit' : 'Add';
+
+my $conf = new FS::Conf;
+
+</%init>
index 0f36500..fc8664a 100644 (file)
@@ -508,6 +508,10 @@ tie my %config_agent, 'Tie::IxHash',
   'Agent payment gateways'         => [ $fsurl.'browse/payment_gateway.html', 'Credit card and electronic check processors for agent overrides' ];
 ;
 
+tie my %config_sales, 'Tie::IxHash',
+  'Sales'      => [ $fsurl.'browse/sales.cgi', 'Sales bring in new business.' ],
+;
+
 tie my %config_billing_rates, 'Tie::IxHash',
   'Rate plans' => [ $fsurl.'browse/rate.cgi', 'Manage rate plans' ],
   'Regions and prefixes' => [ $fsurl.'browse/rate_region.html', 'Manage regions and prefixes' ],
@@ -580,6 +584,7 @@ if ( $curuser->access_right('Configuration' ) ) {
     'separator'     => '', #its a separator!
     'Employees'     => [ \%config_employees, '' ],
     'Resellers'     => [ \%config_agent, '' ],
+    'Sales People'  => [ \%config_sales, '' ],
     'separator2'    => '', #its a separator!
     'Customers'     => [ \%config_cust, '' ],
     #or this? 'Customers and Contacts' => [ \%config_cust, '' ],