registration codes
authorivan <ivan>
Sat, 29 Jan 2005 12:34:12 +0000 (12:34 +0000)
committerivan <ivan>
Sat, 29 Jan 2005 12:34:12 +0000 (12:34 +0000)
21 files changed:
FS/FS.pm
FS/FS/ClientAPI/Signup.pm
FS/FS/agent.pm
FS/FS/cust_pkg.pm
FS/FS/part_pkg.pm
FS/FS/reg_code.pm [new file with mode: 0644]
FS/FS/reg_code_pkg.pm [new file with mode: 0644]
FS/MANIFEST
FS/bin/freeside-setup
FS/t/reg_code.t [new file with mode: 0644]
FS/t/reg_code_pkg.t [new file with mode: 0644]
README.1.5.0pre7
fs_signup/FS-SignupClient/cgi/regcode.html [new file with mode: 0644]
fs_signup/FS-SignupClient/cgi/signup.cgi
fs_signup/FS-SignupClient/cgi/signup.html
httemplate/docs/install.html
httemplate/docs/schema.html
httemplate/docs/upgrade10.html
httemplate/edit/process/reg_code.cgi [new file with mode: 0644]
httemplate/edit/reg_code.cgi [new file with mode: 0644]
httemplate/search/reg_code.html [new file with mode: 0644]

index 3bbd66f..57a1f6c 100644 (file)
--- a/FS/FS.pm
+++ b/FS/FS.pm
@@ -88,6 +88,10 @@ L<FS::part_pkg_option> - Package definition option class
 L<FS::pkg_svc> - Class linking package definitions (see L<FS::part_pkg>) with
 service definitions (see L<FS::part_svc>)
 
+L<FS::reg_code> - One-time registration codes
+
+L<FS::reg_code_pkg> - Class linking registration codes (see L<FS::reg_code>) with package definitions (see L<FS::part_pkg>)
+
 L<FS::rate> - Rate plans for call billing
 
 L<FS::rate_region> - Rate regions for call billing
index dc627e9..46ef9e4 100644 (file)
@@ -14,6 +14,7 @@ use FS::cust_pkg;
 use FS::svc_acct;
 use FS::acct_snarf;
 use FS::queue;
+use FS::reg_code;
 
 use FS::ClientAPI; #hmm
 FS::ClientAPI->register_handlers(
@@ -105,7 +106,22 @@ sub signup_info {
   }
 
   $signup_info->{'part_pkg'} = [];
-  if ( $packet->{'promo_code'} ) {
+
+  if ( $packet->{'reg_code'} ) {
+    $signup_info->{'part_pkg'} = 
+      [ map { { 'payby'   => [ $_->payby ], %{$_->hashref} } }
+          grep { $_->svcpart('svc_acct') }
+          map { $_->part_pkg }
+            qsearchs( 'reg_code', { 'code'     => $packet->{'reg_code'},
+                                    'agentnum' => $agentnum,              } )
+
+      ];
+
+    $signup_info->{'error'} = 'Unknown registration code'
+      unless @{ $signup_info->{'part_pkg'} };
+
+  } elsif ( $packet->{'promo_code'} ) {
+
     $signup_info->{'part_pkg'} =
       [ map { { 'payby'   => [ $_->payby ], %{$_->hashref} } }
           grep { $_->svcpart('svc_acct') }
@@ -209,10 +225,18 @@ sub new_customer {
       or return { 'error' => "WARNING: unknown pkgpart: $pkgpart" };
   my $svcpart = $part_pkg->svcpart('svc_acct');
 
+  my $reg_code = '';
+  if ( $packet->{'reg_code'} ) {
+    $reg_code = qsearchs( 'reg_code', { 'code'     => $packet->{'reg_code'},
+                                        'agentnum' => $agentnum,             } )
+      or return { 'error' => 'Unknown registration code' };
+  }
+
   my $cust_pkg = new FS::cust_pkg ( {
     #later#'custnum' => $custnum,
     'pkgpart'    => $packet->{'pkgpart'},
     'promo_code' => $packet->{'promo_code'},
+    'reg_code'   => $packet->{'reg_code'},
   } );
   #my $error = $cust_pkg->check;
   #return { 'error' => $error } if $error;
@@ -305,6 +329,11 @@ sub new_customer {
 
   }
 
+  if ( $reg_code ) {
+    $error = $reg_code->delete;
+    return { 'error' => $error } if $error;
+  }
+
   $error = $placeholder->delete;
   return { 'error' => $error } if $error;
 
index a9e41a6..3d8e677 100644 (file)
@@ -5,6 +5,8 @@ use vars qw( @ISA );
 use FS::Record qw( dbh qsearch qsearchs );
 use FS::cust_main;
 use FS::agent_type;
+use FS::reg_code;
+#use Crypt::YAPassGen;
 
 @ISA = qw( FS::Record );
 
@@ -264,6 +266,65 @@ sub cancel_cust_main {
   shift->cust_main_sql(FS::cust_main->cancel_sql);
 }
 
+=item generate_reg_codes NUM PKGPART_ARRAYREF
+
+Generates the specified number of registration codes, allowing purchase of the
+specified package definitions.  Returns an array reference of the newly
+generated codes, or a scalar error message.
+
+=cut
+
+sub generate_reg_codes {
+  my( $self, $num, $pkgparts ) = @_;
+
+  my @codeset = ( 'A'..'Z' );
+
+  local $SIG{HUP} = 'IGNORE';
+  local $SIG{INT} = 'IGNORE';
+  local $SIG{QUIT} = 'IGNORE';
+  local $SIG{TERM} = 'IGNORE';
+  local $SIG{TSTP} = 'IGNORE';
+  local $SIG{PIPE} = 'IGNORE';
+
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  my @codes = ();
+  for ( 1 ... $num ) {
+    my $reg_code = new FS::reg_code {
+      'agentnum' => $self->agentnum,
+      'code'     => join('', map($codeset[int(rand $#codeset)], (0..7) ) ),
+    };
+    my $error = $reg_code->insert($pkgparts);
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+    push @codes, $reg_code->code;
+  }
+
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+  \@codes;
+
+}
+
+=item num_reg_code
+
+Returns the number of unused registration codes for this agent.
+
+=cut
+
+sub num_reg_code {
+  my $self = shift;
+  my $sth = dbh->prepare(
+    "SELECT COUNT(*) FROM reg_code WHERE agentnum = ?"
+  ) or die dbh->errstr;
+  $sth->execute($self->agentnum) or die $sth->errstr;
+  $sth->fetchrow_arrayref->[0];
+}
+
 =back
 
 =head1 BUGS
index 0c39f68..a6115a0 100644 (file)
@@ -12,6 +12,7 @@ use FS::type_pkgs;
 use FS::pkg_svc;
 use FS::cust_bill_pkg;
 use FS::h_cust_svc;
+use FS::reg_code;
 
 # need to 'use' these instead of 'require' in sub { cancel, suspend, unsuspend,
 # setup }
@@ -176,6 +177,15 @@ sub insert {
     return $error;
   }
 
+  #if ( $self->reg_code ) {
+  #  my $reg_code = qsearchs('reg_code', { 'code' => $self->reg_code } );
+  #  $error = $reg_code->delete;
+  #  if ( $error ) {
+  #    $dbh->rollback if $oldAutoCommit;
+  #    return $error;
+  #  }
+  #}
+
   my $conf = new FS::Conf;
   my $cust_main = $self->cust_main;
   my $part_pkg = $self->part_pkg;
@@ -289,7 +299,17 @@ sub check {
   ;
   return $error if $error;
 
-  if ( $self->promo_code ) {
+  if ( $self->reg_code ) {
+
+    unless ( grep { $self->pkgpart == $_->pkgpart }
+             map  { $_->reg_code_pkg }
+             qsearchs( 'reg_code', { 'code'     => $self->reg_code,
+                                     'agentnum' => $self->cust_main->agentnum })
+           ) {
+      return "Unknown registraiton code";
+    }
+
+  } elsif ( $self->promo_code ) {
 
     my $promo_part_pkg =
       qsearchs('part_pkg', {
@@ -297,7 +317,6 @@ sub check {
         'promo_code' => { op=>'ILIKE', value=>$self->promo_code },
       } );
     return 'Unknown promotional code' unless $promo_part_pkg;
-    $self->pkgpart($promo_part_pkg->pkgpart);
 
   } else { 
 
index cef4a61..f210a67 100644 (file)
@@ -584,7 +584,7 @@ Returns the option value for the given name, or the empty string.
 =cut
 
 sub option {
-  my( $self, $opt ) = @_;
+  my( $self, $opt, $ornull ) = @_;
   my $part_pkg_option =
     qsearchs('part_pkg_option', {
       pkgpart    => $self->pkgpart,
@@ -594,7 +594,8 @@ sub option {
   my %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); }
                      split("\n", $self->get('plandata') );
   return $plandata{$opt} if exists $plandata{$opt};
-  cluck "Package definition option $opt not found in options or plandata!\n";
+  cluck "Package definition option $opt not found in options or plandata!\n"
+    unless $ornull;
   '';
 }
 
diff --git a/FS/FS/reg_code.pm b/FS/FS/reg_code.pm
new file mode 100644 (file)
index 0000000..f48ccf0
--- /dev/null
@@ -0,0 +1,223 @@
+package FS::reg_code;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw(qsearch dbh);
+use FS::agent;
+use FS::reg_code_pkg;
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::reg_code - One-time registration codes
+
+=head1 SYNOPSIS
+
+  use FS::reg_code;
+
+  $record = new FS::reg_code \%hash;
+  $record = new FS::reg_code { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::reg_code object is a one-time registration code.  FS::reg_code inherits
+from FS::Record.  The following fields are currently supported:
+
+=over 4
+
+=item codenum - primary key
+
+=item code - registration code string
+
+=item agentnum - Agent (see L<FS::agent>)
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new registration code.  To add the code 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 { 'reg_code'; }
+
+=item insert [ PKGPART_ARRAYREF ] 
+
+Adds this record to the database.  If an arrayref of pkgparts
+(see L<FS::part_pkg>) is specified, the appropriate reg_code_pkg records
+(see L<FS::reg_code_pkg>) will be inserted.
+
+If there is an error, returns the error, otherwise returns false.
+
+=cut
+
+sub insert {
+  my $self = shift;
+
+  local $SIG{HUP} = 'IGNORE';
+  local $SIG{INT} = 'IGNORE';
+  local $SIG{QUIT} = 'IGNORE';
+  local $SIG{TERM} = 'IGNORE';
+  local $SIG{TSTP} = 'IGNORE';
+  local $SIG{PIPE} = 'IGNORE';
+
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  my $error = $self->SUPER::insert;
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
+
+  if ( @_ ) {
+    my $pkgparts = shift;
+    foreach my $pkgpart ( @$pkgparts ) {
+      my $reg_code_pkg = new FS::reg_code_pkg ( {
+        'codenum' => $self->codenum,
+        'pkgpart' => $pkgpart,
+      } );
+      $error = $reg_code_pkg->insert;
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return $error;
+      }
+    }
+  }
+
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+  '';
+
+}
+
+=item delete
+
+Delete this record (and all associated reg_code_pkg records) from the database.
+
+=cut
+
+sub delete {
+  my $self = shift;
+
+  local $SIG{HUP} = 'IGNORE';
+  local $SIG{INT} = 'IGNORE';
+  local $SIG{QUIT} = 'IGNORE';
+  local $SIG{TERM} = 'IGNORE';
+  local $SIG{TSTP} = 'IGNORE';
+  local $SIG{PIPE} = 'IGNORE';
+
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  foreach my $reg_code_pkg ( $self->reg_code_pkg ) {
+    my $error = $reg_code_pkg->delete;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
+  my $error = $self->SUPER::delete;
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
+
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+  '';
+
+}
+
+=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 registration code.  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('codenum')
+    || $self->ut_alpha('code')
+    || $self->ut_foreign_key('agentnum', 'agent', 'agentnum')
+  ;
+  return $error if $error;
+
+  $self->SUPER::check;
+}
+
+=item part_pkg
+
+Returns all package definitions (see L<FS::part_pkg> for this registration
+code.
+
+=cut
+
+sub part_pkg {
+  my $self = shift;
+  map { $_->part_pkg } $self->reg_code_pkg;
+}
+
+=item reg_code_pkg
+
+Returns all FS::reg_code_pkg records for this registration code.
+
+=cut
+
+sub reg_code_pkg {
+  my $self = shift;
+  qsearch('reg_code_pkg', { 'codenum' => $self->codenum } );
+}
+
+
+=back
+
+=head1 BUGS
+
+Feeping creaturitis.
+
+=head1 SEE ALSO
+
+L<FS::reg_code_pkg>, L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
+
diff --git a/FS/FS/reg_code_pkg.pm b/FS/FS/reg_code_pkg.pm
new file mode 100644 (file)
index 0000000..598497c
--- /dev/null
@@ -0,0 +1,135 @@
+package FS::reg_code_pkg;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw(qsearchs);
+use FS::reg_code;
+use FS::part_pkg;
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::reg_code_pkg - Class linking registration codes (see L<FS::reg_code>) with package definitions (see L<FS::part_pkg>)
+
+=head1 SYNOPSIS
+
+  use FS::reg_code_pkg;
+
+  $record = new FS::reg_code_pkg \%hash;
+  $record = new FS::reg_code_pkg { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::reg_code_pkg object links a registration code to a package definition.
+FS::table_name inherits from FS::Record.  The following fields are currently
+supported:
+
+=over 4
+
+=item codenum - registration code (see L<FS::reg_code>)
+
+=item pkgpart - package definition (see L<FS::part_pkg>)
+
+=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 { 'reg_code_pkg'; }
+
+=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 record.  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_foreign_key('codenum', 'reg_code', 'codenum')
+    || $self->ut_foreign_key('pkgpart', 'part_pkg', 'pkgpart')
+  ;
+  return $error if $error;
+
+  $self->SUPER::check;
+}
+
+=item part_pkg
+
+Returns the package definition (see L<FS::part_pkg>)
+
+=cut
+
+sub part_pkg {
+  my $self = shift;
+  qsearchs('part_pkg', { 'pkgpart' => $self->pkgpart } );
+}
+
+=back
+
+=head1 BUGS
+
+Feeping creaturitis.
+
+=head1 SEE ALSO
+
+L<FS::reg_code_pkg>, L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
+
index 32785c2..4e33efe 100644 (file)
@@ -125,6 +125,8 @@ FS/rate.pm
 FS/rate_detail.pm
 FS/rate_region.pm
 FS/rate_prefix.pm
+FS/reg_code.pm
+FS/reg_code_pkg.pm
 FS/svc_Common.pm
 FS/svc_acct.pm
 FS/svc_acct_pop.pm
@@ -248,6 +250,8 @@ t/rate_detail.t
 t/rate_region.t
 t/rate_prefix.t
 t/radius_usergroup.t
+t/reg_code.t
+t/reg_code_pkg.t
 t/session.t
 t/svc_acct.t
 t/svc_acct_pop.t
index c867a72..24b0685 100755 (executable)
@@ -1209,6 +1209,26 @@ sub tables_hash_hack {
       'index'       => [ [ 'countrycode' ], [ 'regionnum' ] ],
     },
 
+    'reg_code' => {
+      'columns' => [
+        'codenum',   'serial',    '', '',
+        'code',      'varchar',   '', $char_d,
+        'agentnum',  'int',       '', '',
+      ],
+      'primary_key' => 'codenum',
+      'unique'      => [ [ 'agentnum', 'code' ] ],
+      'index'       => [ [ 'agentnum' ] ],
+    },
+
+    'reg_code_pkg' => {
+      'columns' => [
+        'codenum',   'int',    '', '',
+        'pkgpart',   'int',    '', '',
+      ],
+      'primary_key' => '',
+      'unique'      => [ [ 'codenum', 'pkgpart' ] ],
+      'index'       => [ [ 'codenum' ] ],
+    },
 
   );
 
diff --git a/FS/t/reg_code.t b/FS/t/reg_code.t
new file mode 100644 (file)
index 0000000..4b95990
--- /dev/null
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::reg_code;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/reg_code_pkg.t b/FS/t/reg_code_pkg.t
new file mode 100644 (file)
index 0000000..7f89ffa
--- /dev/null
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::reg_code_pkg;
+$loaded=1;
+print "ok 1\n";
index dda49a7..5c136ab 100644 (file)
@@ -31,6 +31,22 @@ CREATE TABLE rate_prefix (
 CREATE INDEX rate_prefix1 ON rate_prefix ( countrycode );
 CREATE INDEX rate_prefix2 ON rate_prefix ( regionnum );
 
+CREATE TABLE reg_code (
+    codenum serial NOT NULL,
+    code varchar(80) NOT NULL,
+    agentnum int NOT NULL,
+    PRIMARY KEY (codenum)
+);
+CREATE UNIQUE INDEX reg_code1 ON reg_code ( agentnum, code );
+CREATE INDEX reg_code2 ON reg_code ( agentnum );
+
+CREATE TABLE reg_code_pkg (
+    codenum int NOT NULL,
+    pkgpart int NOT NULL
+);
+CREATE UNIQUE INDEX reg_code_pkg1 ON reg_code_pkg ( codenum, pkgpart );
+CREATE INDEX reg_code_pkg2 ON reg_code_pkg ( codenum );
+
 ALTER TABLE part_pkg ADD promo_code varchar(80) NULL;
 ALTER TABLE h_part_pkg ADD promo_code varchar(80) NULL;
 CREATE INDEX part_pkg2 ON part_pkg ( promo_code );
@@ -63,9 +79,10 @@ Installs w/integrated RT:
 
 
 dbdef-create username
-create-history-tables username rate rate_detail rate_region rate_prefix
+create-history-tables username rate rate_detail rate_region rate_prefix reg_code reg_code_pkg
 dbdef-create username
 
+install Javascript::RPC (JavaScript::RPC::Server::CGI)
 
 afterwords (for installs w/integrated RT):
 make configure-rt
diff --git a/fs_signup/FS-SignupClient/cgi/regcode.html b/fs_signup/FS-SignupClient/cgi/regcode.html
new file mode 100644 (file)
index 0000000..e639b9b
--- /dev/null
@@ -0,0 +1,14 @@
+<HTML><HEAD><TITLE>ISP Signup</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=7>ISP Signup - registration code</FONT><BR><BR>
+<SCRIPT>
+function gotoURL(object) {
+    window.location.href =  'signup.cgi?reg_code=' + object.reg_code.value;
+}
+</SCRIPT>
+<FORM>
+Enter registration code <INPUT TYPE="text" NAME="reg_code">
+<INPUT type="submit" VALUE="Signup" onClick="gotoURL(this.form)">
+
+</FORM>
+</BODY>
+</HTML>
index f49ad32..aae3fb8 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/perl -T
 #!/usr/bin/perl -Tw
 #
-# $Id: signup.cgi,v 1.54 2004-12-01 18:38:22 ivan Exp $
+# $Id: signup.cgi,v 1.55 2005-01-29 12:34:11 ivan Exp $
 
 use strict;
 use vars qw( @payby $cgi $locales $packages
@@ -134,7 +134,10 @@ if ( -e $decline_html ) {
 
 $cgi = new CGI;
 
-$init_data = signup_info( 'promo_code' => $cgi->param('promo_code') );
+$init_data = signup_info( 'agentnum'   => $agentnum,
+                          'promo_code' => scalar($cgi->param('promo_code')),
+                          'reg_code'   => uc(scalar($cgi->param('reg_code'))),
+                        );
 $error = $init_data->{'error'};
 $locales = $init_data->{'cust_main_county'};
 $packages = $init_data->{'part_pkg'};
@@ -175,7 +178,8 @@ if ( defined $cgi->param('magic') ) {
       $cgi->param('ship_county') =~ /^([\w ]*)$/
         or die "illegal county: ". $cgi->param('ship_county');
       $ship_county = $1;
-      $cgi->param('ship_country') =~ /^(\w+)$/
+      #$cgi->param('ship_country') =~ /^(\w+)$/
+      $cgi->param('ship_country') =~ /^(\w*)$/
         or die "illegal ship_country: ". $cgi->param('ship_country');
       $ship_country = $1;
     #} else {
@@ -307,7 +311,8 @@ if ( defined $cgi->param('magic') ) {
           'payname'          => $payname,
           'invoicing_list'   => $invoicing_list,
           'referral_custnum' => $referral_custnum,
-          'promo_code'       => $cgi->param('promo_code'),
+          'promo_code'       => scalar($cgi->param('promo_code')),
+          'reg_code'         => uc(scalar($cgi->param('reg_code'))),
           'pkgpart'          => $pkgpart,
           'username'         => $username,
           'sec_phrase'       => $sec_phrase,
index c0e4f73..da522f4 100755 (executable)
@@ -167,7 +167,9 @@ Contact Information
 
 </TR></TABLE><font color="#ff0000">*</font> required fields for each billing type
 <BR><BR>First package
-<INPUT TYPE="hidden" NAME="promo_code" VALUE="<%= $cgi->param('promo_code') %>"><TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<INPUT TYPE="hidden" NAME="promo_code" VALUE="<%= $cgi->param('promo_code') %>">
+<INPUT TYPE="hidden" NAME="reg_code" VALUE="<%= uc($cgi->param('reg_code')) %>">
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
 <TR>
   <TD COLSPAN=2><SELECT NAME="pkgpart">
 
index 898eb9e..a880d91 100644 (file)
@@ -59,6 +59,7 @@ Before installing, you need:
       <li><a href="http://search.cpan.org/search?dist=Chart">Chart</a>
       <li><a href="http://search.cpan.org/search?dist=Crypt-PasswdMD5">Crypt::PasswdMD5</a>
       <li><a href="http://search.cpan.org/search?dist=JavaScript-RPC">JavaScript::RPC (JavaScript::RPC::Server::CGI)</a>
+<!--      <li><a href="http://search.cpan.org/search?dist=Crypt-YAPassGen">Crypt::YAPassGen</a> -->
       <li><a href="http://search.cpan.org/search?dist=ApacheDBI">Apache::DBI</a> <i>(optional but recommended for better webinterface performance)</i>
     </ul>
 </ul>
index c5cfd51..8af8aa9 100644 (file)
         <li>optionname - option name
         <li>optionvalue - option value
       </ul>
+    <li><a name="reg_code" href="man/FS/reg_code.html">reg_code</A> - One-time registration codes
+      <ul>
+        <li>codenum - primary key
+        <li>code
+        <li>agentnum - <a href="#agent">Agent</a>
+      </ul>
+    <li><a name="reg_code_pkg" href="man/FS/reg_code_pkg.html">reg_code_pkg</A> - Registration code link to package definitions
+      <ul>
+        <li>codenum - <a href="#reg_code">Registration code</a>
+        <li>pkgpart - <a href="#part_pkg">Package definition</a>
+      </ul>
     <li><a name="part_referral" href="man/FS/part_referral.html">part_referral</a> - Referral listing
       <ul>
         <li>refnum - primary key
index d818685..7441cf1 100644 (file)
@@ -8,7 +8,8 @@ install Net::SSH 0.08
 - In httpd.conf, change &lt;Files ~ \.cgi&gt; to  &lt;Files ~ (\.cgi|\.html)&gt;
 - In httpd.conf, change <b>AddHandler perl-script .cgi</b> or <b>SetHandler perl-script</b> to <b>AddHandler perl-script .cgi .html</b>
 
-install NetAddr::IP, Chart::Base, IPC::ShareLite and Locale::SubCountry
+install NetAddr::IP, Chart::Base, IPC::ShareLite, Locale::SubCountry, 
+JavaScript::RPC (JavaScript::RPC::Server::CGI) <!-- and Crypt::YAPassGen-->
 
 INSERT INTO msgcat ( msgnum, msgcode, locale, msg ) VALUES ( 20, 'svc_external-id', 'en_US', 'External ID' );
 INSERT INTO msgcat ( msgnum, msgcode, locale, msg ) VALUES ( 21, 'svc_external-title', 'en_US', 'Title' );
@@ -223,6 +224,22 @@ CREATE TABLE rate_prefix (
 CREATE INDEX rate_prefix1 ON rate_prefix ( countrycode );
 CREATE INDEX rate_prefix2 ON rate_prefix ( regionnum );
 
+CREATE TABLE reg_code (
+    codenum serial NOT NULL,
+    code varchar(80) NOT NULL,
+    agentnum int NOT NULL,
+    PRIMARY KEY (codenum)
+);
+CREATE UNIQUE INDEX reg_code1 ON reg_code ( agentnum, code );
+CREATE INDEX reg_code2 ON reg_code ( agentnum );
+
+CREATE TABLE reg_code_pkg (
+    codenum int NOT NULL,
+    pkgpart int NOT NULL
+);
+CREATE UNIQUE INDEX reg_code_pkg1 ON reg_code_pkg ( codenum, pkgpart );
+CREATE INDEX reg_code_pkg2 ON reg_code_pkg ( codenum );
+
 DROP INDEX cust_bill_pkg1;
 
 ALTER TABLE cust_bill_pkg ADD itemdesc varchar(80) NULL;
@@ -296,7 +313,7 @@ optionally:
 mandatory again:
 
 dbdef-create username
-create-history-tables username cust_bill_pkg_detail router part_svc_router addr_block svc_broadband acct_snarf svc_external cust_pay_refund cust_pay_void part_pkg_option rate rate_detail rate_region rate_prefix
+create-history-tables username cust_bill_pkg_detail router part_svc_router addr_block svc_broadband acct_snarf svc_external cust_pay_refund cust_pay_void part_pkg_option rate rate_detail rate_region rate_prefix reg_code reg_code_pkg
 dbdef-create username
 
 apache - fix <Files> sections to include .html also
diff --git a/httemplate/edit/process/reg_code.cgi b/httemplate/edit/process/reg_code.cgi
new file mode 100644 (file)
index 0000000..581ede8
--- /dev/null
@@ -0,0 +1,41 @@
+<%
+
+$cgi->param('agentnum') =~ /^(\d+)$/
+  or eidiot 'illegal agentnum '. $cgi->param('agentnum');
+my $agentnum = $1;
+my $agent = qsearchs('agent', { 'agentnum' => $agentnum } );
+
+my $error = '';
+
+my $num = 0;
+if ( $cgi->param('num') =~ /^\s*(\d+)\s*$/ ) {
+  $num = $1;
+} else {
+  $error = 'Illegal number of codes: '. $cgi->param('num');
+}
+
+my @pkgparts = 
+  map  { /^pkgpart(.*)$/; $1 }
+  grep { $cgi->param($_) }
+  grep { /^pkgpart/ }
+  $cgi->param;
+
+$error ||= $agent->generate_reg_codes($num, \@pkgparts);
+
+unless ( ref($error) ) { %><%=
+  $cgi->redirect(popurl(3). "edit/reg_code.cgi?". $cgi->query_string )
+%><% } else { %>
+
+<%= header("$num registration codes generated for ". $agent->agent, menubar(
+  'View all agents' => popurl(3). 'browse/agent.cgi',
+) ) %>
+
+<PRE><FONT SIZE="+1">
+<% foreach my $code ( @$error ) { %>
+  <%= $code %>
+<% } %>
+
+</FONT></PRE>
+
+</BODY></HTML>
+<% } %>
diff --git a/httemplate/edit/reg_code.cgi b/httemplate/edit/reg_code.cgi
new file mode 100644 (file)
index 0000000..899d1ec
--- /dev/null
@@ -0,0 +1,36 @@
+<%
+my $agentnum = $cgi->param('agentnum');
+$agentnum =~ /^(\d+)$/ or eidiot "illegal agentnum $agentnum";
+$agentnum = $1;
+my $agent = qsearchs('agent', { 'agentnum' => $agentnum } );
+
+%>
+
+<%= header('Generate registration codes for '. $agent->agent, menubar(
+      'Main Menu' => $p,
+    ))
+%>
+
+<% if ( $cgi->param('error') ) { %>
+  <FONT SIZE="+1" COLOR="#FF0000">Error: <%= $cgi->param('error') %></FONT>
+<% } %>
+
+<FORM ACTION="<%=popurl(1)%>process/reg_code.cgi" METHOD="POST" NAME="OneTrueForm" onSubmit="document.OneTrueForm.submit.disabled=true">
+<INPUT TYPE="hidden" NAME="agentnum" VALUE="<%= $agent->agentnum %>">
+
+Generate
+<INPUT TYPE="text" NAME="num" VALUE="<%= $cgi->param('num') %>" SIZE=5 MAXLENGTH=4>
+registration codes for <B><%= $agent->agent %></B> allowing the following packages:
+<BR><BR>
+
+<% foreach my $part_pkg ( qsearch('part_pkg', { 'disabled' => '' } ) ) { %>
+  <INPUT TYPE="checkbox" NAME="pkgpart<%= $part_pkg->pkgpart %>">
+  <%= $part_pkg->pkg %> - <%= $part_pkg->comment %>
+  <BR>
+<% } %>
+
+<BR>
+<INPUT TYPE="submit" NAME="submit" VALUE="Generate">
+
+</FORM></BODY></HTML>
+
diff --git a/httemplate/search/reg_code.html b/httemplate/search/reg_code.html
new file mode 100644 (file)
index 0000000..ba1eee0
--- /dev/null
@@ -0,0 +1,35 @@
+<%
+
+my $agentnum = $cgi->param('agentnum');
+$agentnum =~ /^(\d+)$/ or eidiot "illegal agentnum $agentnum";
+$agentnum = $1;
+my $agent = qsearchs('agent', { 'agentnum' => $agentnum } );
+
+my $count_query = "SELECT COUNT(*) FROM reg_code WHERE agentnum = $agentnum";
+
+%>
+<%= include( 'elements/search.html',
+               'title'       => 'Unused Registration Codes for '. $agent->agent,
+               'name'        => 'registration codes',
+               'query'       => {  'table'   => 'reg_code',
+                                   'hashref' => { 'agentnum' => $agentnum, },
+                                },
+               'count_query' => $count_query,
+               #'redirect'    => $link,
+               'header'      => [ qw(Code Packages) ],
+               'fields'      => [
+                 'code',
+                 sub { map { 
+                         qq!<A HREF="${p}edit/part_pkg.cgi?!. $_->pkgpart. '">'.
+                         $_->pkg. ' - '. $_->comment.
+                         '</A><BR>'
+                       } $_[0]->part_pkg
+                     },
+               ],
+               'links' => [
+                 '',
+                 #$plink,
+                 '',
+               ],
+    )
+%>