promo codes and separate signup addresses for hdn
authorivan <ivan>
Mon, 22 Nov 2004 18:20:21 +0000 (18:20 +0000)
committerivan <ivan>
Mon, 22 Nov 2004 18:20:21 +0000 (18:20 +0000)
15 files changed:
FS/FS/ClientAPI/Signup.pm
FS/FS/Record.pm
FS/FS/cust_pkg.pm
FS/FS/part_pkg.pm
FS/bin/freeside-setup
README.1.5.0pre7
fs_signup/FS-SignupClient/SignupClient.pm
fs_signup/FS-SignupClient/cgi/promocode.html [new file with mode: 0644]
fs_signup/FS-SignupClient/cgi/signup-billaddress.html [new file with mode: 0755]
fs_signup/FS-SignupClient/cgi/signup.cgi
fs_signup/FS-SignupClient/cgi/signup.html
httemplate/docs/schema.html
httemplate/docs/upgrade10.html
httemplate/edit/cust_main.cgi
httemplate/edit/part_pkg.cgi

index bdcd2fb..dc627e9 100644 (file)
@@ -75,6 +75,8 @@ sub signup_info {
 
     'cvv_enabled' => defined dbdef->table('cust_main')->column('paycvv'),
 
+    'ship_enabled' => defined dbdef->table('cust_main')->column('ship_last'),
+
     'msgcat' => { map { $_=>gettext($_) } qw(
       passwords_dont_match invalid_card unknown_card_type not_a empty_password
     ) },
@@ -102,11 +104,28 @@ sub signup_info {
     }
   }
 
-  if ( $agentnum ) {
+  $signup_info->{'part_pkg'} = [];
+  if ( $packet->{'promo_code'} ) {
+    $signup_info->{'part_pkg'} =
+      [ map { { 'payby'   => [ $_->payby ], %{$_->hashref} } }
+          grep { $_->svcpart('svc_acct') }
+            qsearch( 'part_pkg', { 'promo_code' => {
+                                     op=>'ILIKE',
+                                     value=>$packet->{'promo_code'}
+                                   },
+                                   'disabled'   => '',                  } )
+      ];
+
+    $signup_info->{'error'} = 'Unknown promotional code'
+      unless @{ $signup_info->{'part_pkg'} };
+  }
+
+  if ( $agentnum && ! @{ $signup_info->{'part_pkg'} } ) {
     $signup_info->{'part_pkg'} = $signup_info->{'agentnum2part_pkg'}{$agentnum};
-  } else {
-    delete $signup_info->{'part_pkg'};
   }
+  # else {
+  # delete $signup_info->{'part_pkg'};
+  #}
 
   if ( $session ) {
     my $agent_signup_info = { %$signup_info };
@@ -158,10 +177,17 @@ sub new_customer {
                        || $conf->config('signup_server-default_refnum'),
 
     map { $_ => $packet->{$_} } qw(
-      last first ss company address1 address2 city county state zip country
-      daytime night fax payby payinfo paycvv paydate payname referral_custnum
-      comments
-    ),
+
+      last first ss company address1 address2
+      city county state zip country
+      daytime night fax
+
+      ship_last ship_first ship_ss ship_company ship_address1 ship_address2
+      ship_city ship_county ship_state ship_zip ship_country
+      ship_daytime ship_night ship_fax
+
+      payby payinfo paycvv paydate payname referral_custnum comments
+    )
 
   } );
 
@@ -185,10 +211,11 @@ sub new_customer {
 
   my $cust_pkg = new FS::cust_pkg ( {
     #later#'custnum' => $custnum,
-    'pkgpart' => $packet->{'pkgpart'},
+    'pkgpart'    => $packet->{'pkgpart'},
+    'promo_code' => $packet->{'promo_code'},
   } );
-  my $error = $cust_pkg->check;
-  return { 'error' => $error } if $error;
+  #my $error = $cust_pkg->check;
+  #return { 'error' => $error } if $error;
 
   my $svc_acct = new FS::svc_acct ( {
     'svcpart'   => $svcpart,
@@ -214,15 +241,15 @@ sub new_customer {
   my $y = $svc_acct->setdefault; # arguably should be in new method
   return { 'error' => $y } if $y && !ref($y);
 
-  $error = $svc_acct->check;
-  return { 'error' => $error } if $error;
+  #$error = $svc_acct->check;
+  #return { 'error' => $error } if $error;
 
   #setup a job dependancy to delay provisioning
   my $placeholder = new FS::queue ( {
     'job'    => 'FS::ClientAPI::Signup::__placeholder',
     'status' => 'locked',
   } );
-  $error = $placeholder->insert;
+  my $error = $placeholder->insert;
   return { 'error' => $error } if $error;
 
   use Tie::RefHash;
index f0026d5..5a6bb57 100644 (file)
@@ -1424,7 +1424,7 @@ on the column first.
 sub ut_foreign_key {
   my( $self, $field, $table, $foreign ) = @_;
   qsearchs($table, { $foreign => $self->getfield($field) })
-    or return "Can't find $field ". $self->getfield($field).
+    or return "Can't find ". $self->table. ".$field ". $self->getfield($field).
               " in $table.$foreign";
   '';
 }
index 3bce653..1f1ae40 100644 (file)
@@ -145,32 +145,9 @@ sub table { 'cust_pkg'; }
 Adds this billing item to the database ("Orders" the item).  If there is an
 error, returns the error, otherwise returns false.
 
-=cut
-
-sub insert {
-  my $self = shift;
-
-  # custnum might not have have been defined in sub check (for one-shot new
-  # customers), so check it here instead
-  # (is this still necessary with transactions?)
-
-  my $error = $self->ut_number('custnum');
-  return $error if $error;
-
-  my $cust_main = $self->cust_main;
-  return "Unknown custnum: ". $self->custnum unless $cust_main;
-
-  unless ( $disable_agentcheck ) {
-    my $agent = qsearchs( 'agent', { 'agentnum' => $cust_main->agentnum } );
-    my $pkgpart_href = $agent->pkgpart_hashref;
-    return "agent ". $agent->agentnum.
-           " can't purchase pkgpart ". $self->pkgpart
-      unless $pkgpart_href->{ $self->pkgpart };
-  }
-
-  $self->SUPER::insert;
-
-}
+If the additional field I<promo_code> is defined instead of I<pkgpart>, it
+will be used to look up the package definition and agent restrictions will be
+ignored.
 
 =item delete
 
@@ -233,8 +210,8 @@ sub check {
 
   my $error = 
     $self->ut_numbern('pkgnum')
-    || $self->ut_numbern('custnum')
-    || $self->ut_number('pkgpart')
+    || $self->ut_foreign_key('custnum', 'cust_main', 'custnum')
+    || $self->ut_numbern('pkgpart')
     || $self->ut_numbern('setup')
     || $self->ut_numbern('bill')
     || $self->ut_numbern('susp')
@@ -242,12 +219,31 @@ sub check {
   ;
   return $error if $error;
 
-  if ( $self->custnum ) { 
-    return "Unknown customer ". $self->custnum unless $self->cust_main;
-  }
+  if ( $self->promo_code ) {
+
+    my $promo_part_pkg =
+      qsearchs('part_pkg', {
+        'pkgpart'    => $self->pkgpart,
+        'promo_code' => { op=>'ILIKE', value=>$self->promo_code },
+      } );
+    return 'Unknown promotional code' unless $promo_part_pkg;
+    $self->pkgpart($promo_part_pkg->pkgpart);
+
+  } else { 
+
+    unless ( $disable_agentcheck ) {
+      my $agent =
+        qsearchs( 'agent', { 'agentnum' => $self->cust_main->agentnum } );
+      my $pkgpart_href = $agent->pkgpart_hashref;
+      return "agent ". $agent->agentnum.
+             " can't purchase pkgpart ". $self->pkgpart
+        unless $pkgpart_href->{ $self->pkgpart };
+    }
 
-  return "Unknown pkgpart: ". $self->pkgpart
-    unless qsearchs( 'part_pkg', { 'pkgpart' => $self->pkgpart } );
+    $error = $self->ut_foreign_key('pkgpart', 'part_pkg', 'pkgpart' );
+    return $error if $error;
+
+  }
 
   $self->otaker(getotaker) unless $self->otaker;
   $self->otaker =~ /^([\w\.\-]{0,16})$/ or return "Illegal otaker";
index d7cc3cb..2f3cb8b 100644 (file)
@@ -54,6 +54,8 @@ inherits from FS::Record.  The following fields are currently supported:
 
 =item comment - Text name of this package definition (non-customer-viewable)
 
+=item promo_code - Promotional code
+
 =item setup - Setup fee expression (deprecated)
 
 =item freq - Frequency of recurring fee
@@ -288,6 +290,7 @@ sub check {
   my $error = $self->ut_numbern('pkgpart')
     || $self->ut_text('pkg')
     || $self->ut_text('comment')
+    || $self->ut_textn('promo_code')
     || $self->ut_alphan('plan')
     || $self->ut_enum('setuptax', [ '', 'Y' ] )
     || $self->ut_enum('recurtax', [ '', 'Y' ] )
index 288b086..49953b8 100755 (executable)
@@ -680,6 +680,7 @@ sub tables_hash_hack {
         'pkgpart',    'serial',    '',   '',
         'pkg',        'varchar',   '',   $char_d,
         'comment',    'varchar',   '',   $char_d,
+        'promo_code', 'varchar', 'NULL', $char_d,
         'setup',      @perl_type,
         'freq',       'varchar',   '',   $char_d,  #billing frequency
         'recur',      @perl_type,
@@ -691,8 +692,8 @@ sub tables_hash_hack {
         'taxclass',   'varchar', 'NULL', $char_d,
       ],
       'primary_key' => 'pkgpart',
-      'unique' => [],
-      'index' => [ [ 'disabled' ], ],
+      'unique' => [ [ 'promo_code' ] ],
+      'index' => [ [ 'disabled' ] ],
     },
 
 #    'part_title' => {
index 074f3a5..cd7e5a2 100644 (file)
@@ -31,6 +31,11 @@ CREATE TABLE rate_prefix (
 CREATE INDEX rate_prefix1 ON rate_prefix ( countrycode );
 CREATE INDEX rate_prefix2 ON rate_prefix ( regionnum );
 
+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 );
+CREATE INDEX h_part_pkg2 ON h_part_pkg ( promo_code );
+
 dbdef-create username
 create-history-tables username rate rate_detail rate_region rate_prefix
 dbdef-create username
index 284fddd..d673030 100644 (file)
@@ -196,7 +196,8 @@ sub popselector {
 =head1 BUGS
 
 This is just a wrapper around FS::SelfService functions for backwards
-compatibility and will probably be deprecated soon.
+compatibility.  It is only necessary if you're using a signup.cgi from before
+1.5.0pre7.
 
 =head1 SEE ALSO
 
diff --git a/fs_signup/FS-SignupClient/cgi/promocode.html b/fs_signup/FS-SignupClient/cgi/promocode.html
new file mode 100644 (file)
index 0000000..f8ee7f6
--- /dev/null
@@ -0,0 +1,14 @@
+<HTML><HEAD><TITLE>ISP Signup</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=7>ISP Signup - promotional code</FONT><BR><BR>
+<SCRIPT>
+function gotoURL(object) {
+    window.location.href =  'signup.cgi?promo_code=' + object.promo_code.value;
+}
+</SCRIPT>
+<FORM>
+Enter promotional code <INPUT TYPE="text" NAME="promo_code">
+<INPUT type="submit" VALUE="Signup" onClick="gotoURL(this.form)">
+
+</FORM>
+</BODY>
+</HTML>
diff --git a/fs_signup/FS-SignupClient/cgi/signup-billaddress.html b/fs_signup/FS-SignupClient/cgi/signup-billaddress.html
new file mode 100755 (executable)
index 0000000..3cf9d25
--- /dev/null
@@ -0,0 +1,307 @@
+<HTML><HEAD><TITLE>ISP Signup form</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8" onUnload="myclose()">
+<script language="JavaScript"><!--
+  var mywindow = -1;
+  function myopen(filename,windowname,properties) {
+    myclose();
+    mywindow = window.open(filename,windowname,properties);
+  }
+  function myclose() {
+    if ( mywindow != -1 )
+      mywindow.close();
+    mywindow = -1
+  }
+//--></script>
+<FONT SIZE=7>ISP Signup form</FONT><BR><BR>
+<FONT SIZE="+1" COLOR="#ff0000"><%= $error %></FONT>
+<FORM NAME="OneTrueForm" ACTION="<%= $self_url %>" METHOD=POST onSubmit="document.OneTrueForm.signup.disabled=true">
+<INPUT TYPE="hidden" NAME="magic" VALUE="process">
+<INPUT TYPE="hidden" NAME="ref" VALUE="<%= $referral_custnum %>">
+<INPUT TYPE="hidden" NAME="ss" VALUE="">
+Where did you hear about our service? <SELECT NAME="refnum">
+<%=
+  $OUT .= '<OPTION VALUE="">' unless $refnum;
+  foreach my $part_referral ( @{$init_data->{'part_referral'}} ) {
+    $OUT .= '<OPTION VALUE="'. $part_referral->{'refnum'}. '"';
+    $OUT .= ' SELECTED' if $part_referral->{'refnum'} eq $refnum;
+    $OUT .= '>'. $part_referral->{'referral'};
+  }
+%>
+</SELECT><BR><BR>
+Billing Address (where credit card statement is sent)
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+  <TH ALIGN="right"><font color="#ff0000">*</font>Exact name on card<BR>(last, first)</TH>
+  <TD COLSPAN=5><INPUT TYPE="text" NAME="last" VALUE="<%= $last %>" onChange="changed(this)">,
+                <INPUT TYPE="text" NAME="first" VALUE="<%= $first %>" onChange="changed(this)"></TD>
+</TR>
+<TR>
+  <TD ALIGN="right">Company</TD>
+  <TD COLSPAN=5><INPUT TYPE="text" NAME="company" SIZE=70 VALUE="<%= $company %>" onChange="changed(this)"></TD>
+</TR>
+<TR>
+  <TH ALIGN="right"><font color="#ff0000">*</font>Address</TH>
+  <TD COLSPAN=5><INPUT TYPE="text" NAME="address1" SIZE=70 VALUE="<%= $address1 %>" onChange="changed(this)"></TD>
+</TR>
+<TR>
+  <TD ALIGN="right">&nbsp;</TD>
+  <TD COLSPAN=5><INPUT TYPE="text" NAME="address2" SIZE=70 VALUE="<%= $address2 %>" onChange="changed(this)"></TD>
+</TR>
+<TR>
+  <TH ALIGN="right"><font color="#ff0000">*</font>City</TH>
+  <TD><INPUT TYPE="text" NAME="city" VALUE="<%= $city %>" onChange="changed(this)"></TD>
+  <TH ALIGN="right"><font color="#ff0000">*</font>State/Country</TH>
+  <TD>
+    <%=
+        ($county_html, $state_html, $country_html) =
+          regionselector( $county, $state, $country, '', 'changed(this)' );
+        "$county_html $state_html";
+    %>
+  </TD>
+  <TH><font color="#ff0000">*</font>Zip</TH>
+  <TD><INPUT TYPE="text" NAME="zip" SIZE=10 VALUE="<%= $zip %>" onChange="changed(this)"></TD>
+</TR>
+<TR>
+  <TH ALIGN="right"><font color="#ff0000">*</font>Country</TH>
+  <TD><%= $country_html %></TD>
+<TR>
+  <TD ALIGN="right">Day Phone</TD>
+  <TD COLSPAN=5><INPUT TYPE="text" NAME="daytime" VALUE="<%= $daytime %>" SIZE=18 onChange="changed(this)"></TD>
+</TR>
+<TR>
+  <TD ALIGN="right">Night Phone</TD>
+  <TD COLSPAN=5><INPUT TYPE="text" NAME="night" VALUE="<%= $night %>" SIZE=18 onChange="changed(this)"></TD>
+</TR>
+<TR>
+  <TD ALIGN="right">Fax</TD>
+  <TD COLSPAN=5><INPUT TYPE="text" NAME="fax" VALUE="<%= $fax %>" SIZE=12 onChange="changed(this)"></TD>
+</TR>
+</TABLE>
+
+<SCRIPT>
+function changed(what) {
+  what.form.same.checked = false;
+}
+function samechanged(what) {
+  if ( what.checked ) {
+
+    <%= foreach (qw(
+          last first company address1 address2 city zip daytime night fax
+        )) {
+          $OUT .= "what.form.ship_$_.value = what.form.$_.value;\n";
+        }
+    %>
+
+    what.form.ship_country.selectedIndex = what.form.country.selectedIndex;
+    ship_country_changed(what.form.ship_country);
+    what.form.ship_state.selectedIndex = what.form.state.selectedIndex;
+    ship_state_changed(what.form.ship_state);
+    what.form.ship_county.selectedIndex = what.form.county.selectedIndex;
+  }
+}
+</SCRIPT>
+
+<BR><BR>
+Service Address
+(<INPUT TYPE="checkbox" NAME="same" VALUE="Y" onClick="samechanged(this)" <%= $same eq 'Y' ? 'CHECKED' : '' %>>same as billing address)<BR>
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+  <TH ALIGN="right"><font color="#ff0000">*</font>Contact name<BR>(last, first)</TH>
+  <TD COLSPAN=5><INPUT TYPE="text" NAME="ship_last" VALUE="<%= $ship_last %>" onChange="changed(this)">,
+                <INPUT TYPE="text" NAME="ship_first" VALUE="<%= $ship_first %>" onChange="changed(this)"></TD>
+</TR>
+<TR>
+  <TD ALIGN="right">Company</TD>
+  <TD COLSPAN=5><INPUT TYPE="text" NAME="ship_company" SIZE=70 VALUE="<%= $ship_company %>" onChange="changed(this)"></TD>
+</TR>
+<TR>
+  <TH ALIGN="right"><font color="#ff0000">*</font>Address</TH>
+  <TD COLSPAN=5><INPUT TYPE="text" NAME="ship_address1" SIZE=70 VALUE="<%= $ship_address1 %>" onChange="changed(this)"></TD>
+</TR>
+<TR>
+  <TD ALIGN="right">&nbsp;</TD>
+  <TD COLSPAN=5><INPUT TYPE="text" NAME="ship_address2" SIZE=70 VALUE="<%= $ship_address2 %>" onChange="changed(this)"></TD>
+</TR>
+<TR>
+  <TH ALIGN="right"><font color="#ff0000">*</font>City</TH>
+  <TD><INPUT TYPE="text" NAME="ship_city" VALUE="<%= $ship_city %>" onChange="changed(this)"></TD>
+  <TH ALIGN="right"><font color="#ff0000">*</font>State/Country</TH>
+  <TD>
+    <%=
+        ($ship_county_html, $ship_state_html, $ship_country_html) =
+          regionselector( $ship_county,
+                          $ship_state,
+                          $ship_country,
+                          'ship_',
+                          'changed(this)',
+                        );
+        "$ship_county_html $ship_state_html";
+    %>
+  </TD>
+  <TH><font color="#ff0000">*</font>Zip</TH>
+  <TD><INPUT TYPE="text" NAME="ship_zip" SIZE=10 VALUE="<%= $ship_zip %>" onChange="changed(this)"></TD>
+</TR>
+<TR>
+  <TH ALIGN="right"><font color="#ff0000">*</font>Country</TH>
+  <TD><%= $ship_country_html %></TD>
+<TR>
+  <TD ALIGN="right">Day Phone</TD>
+  <TD COLSPAN=5><INPUT TYPE="text" NAME="ship_daytime" VALUE="<%= $ship_daytime %>" SIZE=18 onChange="changed(this)"></TD>
+</TR>
+<TR>
+  <TD ALIGN="right">Night Phone</TD>
+  <TD COLSPAN=5><INPUT TYPE="text" NAME="ship_night" VALUE="<%= $ship_night %>" SIZE=18 onChange="changed(this)"></TD>
+</TR>
+<TR>
+  <TD ALIGN="right">Fax</TD>
+  <TD COLSPAN=5><INPUT TYPE="text" NAME="ship_fax" VALUE="<%= $ship_fax %>" SIZE=12 onChange="changed(this)"></TD>
+</TR>
+</TABLE>
+
+<font color="#ff0000">*</font> required fields<BR>
+
+<BR>Billing information<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR><TD>
+
+  <%=
+    $OUT .= '<INPUT TYPE="checkbox" NAME="invoicing_list_POST" VALUE="POST"';
+    my @invoicing_list = split(', ', $invoicing_list );
+    $OUT .= ' CHECKED'
+      if ! @invoicing_list || grep { $_ eq 'POST' } @invoicing_list;
+    $OUT .= '>';
+  %>
+
+  Postal mail invoice
+</TD></TR>
+<TR><TD>Email invoice <INPUT TYPE="text" NAME="invoicing_list" VALUE="<%= join(', ', grep { $_ ne 'POST' } split(', ', $invoicing_list ) ) %>">
+</TD></TR>
+<%= scalar(@payby) > 1 ? '<TR><TD>Billing type</TD></TR>' : '' %>
+</TABLE>
+<TABLE BGCOLOR="#c0c0c0" BORDER=1 WIDTH="100%">
+<TR>
+
+  <%=
+
+    my $cardselect = '<SELECT NAME="CARD_type"><OPTION></OPTION>';
+    my %types = (
+                  'VISA' => 'VISA card',
+                  'MasterCard' => 'MasterCard',
+                  'Discover' => 'Discover card',
+                  'American Express' => 'American Express card',
+                );
+    foreach ( keys %types ) {
+      $selected = $cgi->param('CARD_type') eq $types{$_} ? 'SELECTED' : '';
+      $cardselect .= qq!<OPTION $selected VALUE="$types{$_}">$_</OPTION>!;
+    }
+    $cardselect .= '</SELECT>';
+  
+    my %payby = (
+      'CARD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("CARD"), #. qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="">!,
+      'DCRD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("DCRD"), #. qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="">!,
+      'CHEK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="">!,
+      'DCHK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="">!,
+      'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+      'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE=""><BR><font color="#ff0000">*</font>Exp !. expselect("BILL", "12-2037"). qq!<BR><font color="#ff0000">*</font>Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="Accounts Payable">!,
+      'COMP' => qq!Complimentary<BR><font color="#ff0000">*</font>Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE=""><BR><font color="#ff0000">*</font>Exp !. expselect("COMP"),
+      'PREPAY' => qq!Prepaid card<BR><font color="#ff0000">*</font><INPUT TYPE="text" NAME="PREPAY_payinfo" VALUE="" MAXLENGTH=80>!,
+    );
+
+    if ( $init_data->{'cvv_enabled'} ) {
+      foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5
+        $payby{$payby} .= qq!<BR>CVV2&nbsp;(<A HREF="javascript:myopen('cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>)&nbsp;<INPUT TYPE="text" NAME=${payby}_paycvv VALUE="" SIZE=4 MAXLENGTH=4>!;
+      }
+    }
+
+    my( $account, $aba ) = split('@', $payinfo);
+    my %paybychecked = (
+      'CARD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("CARD", $paydate), #. qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="$payname">!,
+      'DCRD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("DCRD", $paydate), #. qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="$payname">!,
+      'CHEK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="$account" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="$payname">!,
+      'DCHK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="$account" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="$payname">!,
+      'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="$payinfo" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+      'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE="$payinfo"><BR><font color="#ff0000">*</font>Exp !. expselect("BILL", $paydate). qq!<BR><font color="#ff0000">*</font>Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="$payname">!,
+      'COMP' => qq!Complimentary<BR><font color="#ff0000">*</font>Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE="$payinfo"><BR><font color="#ff0000">*</font>Exp !. expselect("COMP", $paydate),
+      'PREPAY' => qq!Prepaid card<BR><font color="#ff0000">*</font><INPUT TYPE="text" NAME="PREPAY_payinfo" VALUE="$payinfo" MAXLENGTH=80>!,
+    );
+
+    if ( $init_data->{'cvv_enabled'} ) {
+      foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5
+        $paybychecked{$payby} .= qq!<BR>CVV2&nbsp;(<A HREF="javascript:myopen('cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>)&nbsp;<INPUT TYPE="text" NAME=${payby}_paycvv VALUE="$paycvv" SIZE=4 MAXLENGTH=4>!;
+      }
+    }
+
+    for (@payby) {
+      if ( scalar(@payby) == 1) {
+        $OUT .= '<TD VALIGN=TOP>'.
+                qq!<INPUT TYPE="hidden" NAME="payby" VALUE="$_">!.
+                "$paybychecked{$_}</TD>";
+      } else {
+        $OUT .= qq!<TD VALIGN=TOP><INPUT TYPE="radio" NAME="payby" VALUE="$_"!;
+        if ($payby eq $_) {
+          $OUT .= qq! CHECKED> $paybychecked{$_}</TD>!;
+        } else {
+          $OUT .= qq!> $payby{$_}</TD>!;
+        }
+
+      }
+    }
+  %>
+
+</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%">
+<TR>
+  <TD COLSPAN=2><SELECT NAME="pkgpart">
+
+  <%=
+    $OUT .= '<OPTION VALUE="">(none)' unless scalar(@$packages) == 1;
+    foreach my $package ( @{$packages} ) {
+      $OUT .= '<OPTION VALUE="'. $package->{'pkgpart'}. '"';
+      $OUT .= ' SELECTED'
+        if ( $pkgpart && $package->{'pkgpart'} == $pkgpart )
+           || scalar(@$packages) == 1;
+      $OUT .= '>'. $package->{'pkg'};
+    }
+  %>
+
+  </SELECT></TD>
+</TR>
+<TR>
+  <TD ALIGN="right">Username</TD>
+  <TD><INPUT TYPE="text" NAME="username" VALUE="<%= $username %>"></TD>
+</TR>
+<TR>
+  <TD ALIGN="right">Password</TD>
+  <TD><INPUT TYPE="password" NAME="_password" VALUE="<%= $password %>"></TD>
+</TR>
+<TR>
+  <TD ALIGN="right">Re-enter Password</TD>
+  <TD><INPUT TYPE="password" NAME="_password2" VALUE="<%= $password2 %>"></TD>
+</TR>
+<%=
+  if ( $init_data->{'security_phrase'} ) {
+    $OUT .= <<ENDOUT;
+<TR>
+  <TD ALIGN="right">Security Phrase</TD>
+  <TD><INPUT TYPE="text" NAME="sec_phrase" VALUE="$sec_phrase">
+  </TD>
+</TR>
+ENDOUT
+  } else {
+    $OUT .= '<INPUT TYPE="hidden" NAME="sec_phrase" VALUE="">';
+  }
+%>
+<%=
+  if ( scalar(@$pops) ) {
+    $OUT .= '<TR><TD ALIGN="right">Access number</TD><TD>'.
+            popselector($popnum). '</TD></TR>';
+  } else {
+    $OUT .= popselector($popnum);
+  }
+%>
+</TABLE>
+<BR><BR><INPUT TYPE="submit" NAME="signup" VALUE="Signup">
+</FORM></BODY></HTML>
index 4f9efff..a1b9ed4 100755 (executable)
@@ -1,14 +1,22 @@
 #!/usr/bin/perl -T
 #!/usr/bin/perl -Tw
 #
-# $Id: signup.cgi,v 1.52 2004-10-01 01:38:02 ivan Exp $
+# $Id: signup.cgi,v 1.53 2004-11-22 18:20:21 ivan Exp $
 
 use strict;
 use vars qw( @payby $cgi $locales $packages
              $pops %pop %popnum2pop
              $init_data $error
-             $last $first $ss $company $address1 $address2 $city $state $county
-             $country $zip $daytime $night $fax $invoicing_list $payby $payinfo
+
+             $last $first $ss $company $address1
+             $address2 $city $state $county
+             $country $zip $daytime $night $fax
+
+             $ship_last $ship_first $ship_ss $ship_company $ship_address1
+             $ship_address2 $ship_city $ship_state $ship_county
+             $ship_country $ship_zip $ship_daytime $ship_night $ship_fax
+
+             $invoicing_list $payby $payinfo
              $paycvv $paydate $payname $referral_custnum $init_popstate
              $pkgpart $username $password $password2 $sec_phrase $popnum
              $agentnum $refnum
@@ -21,14 +29,14 @@ use vars qw( @payby $cgi $locales $packages
              $self_url
            );
 use subs qw( print_form print_okay print_decline
-             success_default decline_default );
+             success_default decline_default
+           );
 use CGI;
 #use CGI::Carp qw(fatalsToBrowser);
 use Text::Template;
 use Business::CreditCard;
 use HTTP::BrowserDetect;
-use FS::SignupClient 0.03 qw( signup_info new_customer
-                              regionselector expselect popselector);
+use FS::SelfService qw( signup_info new_customer expselect );
 
 #acceptable payment methods
 #
@@ -124,8 +132,13 @@ if ( -e $decline_html ) {
     or die $Text::Template::ERROR;
 }
 
+$cgi = new CGI;
 
-( $locales, $packages, $pops, $init_data ) = signup_info();
+$init_data = signup_info( 'promo_code' => $cgi->param('promo_code') );
+$error = $init_data->{'error'};
+$locales = $init_data->{'cust_main_county'};
+$packages = $init_data->{'part_pkg'};
+$pops = $init_data->{'svc_acct_pop'};
 @payby = @{$init_data->{'payby'}} if @{$init_data->{'payby'}};
 $packages = $init_data->{agentnum2part_pkg}{$agentnum} if $agentnum;
 %pop = ();
@@ -135,8 +148,6 @@ foreach (@$pops) {
   $popnum2pop{$_->{popnum}} = $_;
 }
 
-$cgi = new CGI;
-
 if ( defined $cgi->param('magic') ) {
   if ( $cgi->param('magic') eq 'process' ) {
 
@@ -193,6 +204,22 @@ if ( defined $cgi->param('magic') ) {
     $daytime          = $cgi->param('daytime');
     $night            = $cgi->param('night');
     $fax              = $cgi->param('fax');
+
+    $ship_last        = $cgi->param('ship_last');
+    $ship_first       = $cgi->param('ship_first');
+    $ship_ss          = $cgi->param('ship_ss');
+    $ship_company     = $cgi->param('ship_company');
+    $ship_address1    = $cgi->param('ship_address1');
+    $ship_address2    = $cgi->param('ship_address2');
+    $ship_city        = $cgi->param('ship_city');
+    #$ship_county,
+    #$ship_state,
+    $ship_zip         = $cgi->param('ship_zip');
+    #$ship_country,
+    $ship_daytime     = $cgi->param('ship_daytime');
+    $ship_night       = $cgi->param('ship_night');
+    $ship_fax         = $cgi->param('ship_fax');
+
     #$payby,
     #$payinfo,
     #$paydate,
@@ -228,37 +255,56 @@ if ( defined $cgi->param('magic') ) {
           or $error ||= $init_data->{msgcat}{not_a}. $cgi->param('CARD_type');
       }
 
-      $error ||= new_customer ( {
-        'last'             => $last,
-        'first'            => $first,
-        'ss'               => $ss,
-        'company'          => $company,
-        'address1'         => $address1,
-        'address2'         => $address2,
-        'city'             => $city,
-        'county'           => $county,
-        'state'            => $state,
-        'zip'              => $zip,
-        'country'          => $country,
-        'daytime'          => $daytime,
-        'night'            => $night,
-        'fax'              => $fax,
-        'payby'            => $payby,
-        'payinfo'          => $payinfo,
-        'paycvv'           => $paycvv,
-        'paydate'          => $paydate,
-        'payname'          => $payname,
-        'invoicing_list'   => $invoicing_list,
-        'referral_custnum' => $referral_custnum,
-        'pkgpart'          => $pkgpart,
-        'username'         => $username,
-        'sec_phrase'       => $sec_phrase,
-        '_password'        => $password,
-        'popnum'           => $popnum,
-        'agentnum'         => $agentnum,
-        'refnum'           => $refnum,
-        map { $_ => $cgi->param($_) } grep { /^snarf_/ } $cgi->param
-      } );
+      unless ( $error ) {
+
+        my $r = new_customer ( {
+          'last'             => $last,
+          'first'            => $first,
+          'ss'               => $ss,
+          'company'          => $company,
+          'address1'         => $address1,
+          'address2'         => $address2,
+          'city'             => $city,
+          'county'           => $county,
+          'state'            => $state,
+          'zip'              => $zip,
+          'country'          => $country,
+          'daytime'          => $daytime,
+          'night'            => $night,
+          'fax'              => $fax,
+          'ship_last'        => $ship_last,
+          'ship_first'       => $ship_first,
+          'ship_company'     => $ship_company,
+          'ship_address1'    => $ship_address1,
+          'ship_address2'    => $ship_address2,
+          'ship_city'        => $ship_city,
+          'ship_county'      => $ship_county,
+          'ship_state'       => $ship_state,
+          'ship_zip'         => $ship_zip,
+          'ship_country'     => $ship_country,
+          'ship_daytime'     => $ship_daytime,
+          'ship_night'       => $ship_night,
+          'ship_fax'         => $ship_fax,
+          'payby'            => $payby,
+          'payinfo'          => $payinfo,
+          'paycvv'           => $paycvv,
+          'paydate'          => $paydate,
+          'payname'          => $payname,
+          'invoicing_list'   => $invoicing_list,
+          'referral_custnum' => $referral_custnum,
+          'promo_code'       => $cgi->param('promo_code'),
+          'pkgpart'          => $pkgpart,
+          'username'         => $username,
+          'sec_phrase'       => $sec_phrase,
+          '_password'        => $password,
+          'popnum'           => $popnum,
+          'agentnum'         => $agentnum,
+          'refnum'           => $refnum,
+          map { $_ => $cgi->param($_) } grep { /^snarf_/ } $cgi->param
+        } );
+        $error ||= $r->{'error'};
+
+      }
 
     }
     
@@ -277,7 +323,7 @@ if ( defined $cgi->param('magic') ) {
     die "unrecognized magic: ". $cgi->param('magic');
   }
 } else {
-  $error = '';
+  #$error = '';
   $last = '';
   $first = '';
   $ss = '';
@@ -292,6 +338,19 @@ if ( defined $cgi->param('magic') ) {
   $daytime = '';
   $night = '';
   $fax = '';
+  $ship_last = '';
+  $ship_first = '';
+  $ship_company = '';
+  $ship_address1 = '';
+  $ship_address2 = '';
+  $ship_city = '';
+  $ship_state = $init_data->{statedefault};
+  $ship_county = '';
+  $ship_country = $init_data->{countrydefault};
+  $ship_zip = '';
+  $ship_daytime = '';
+  $ship_night = '';
+  $ship_fax = '';
   $invoicing_list = '';
   $payby = '';
   $payinfo = '';
@@ -331,17 +390,17 @@ sub print_okay {
   my $user_agent = new HTTP::BrowserDetect $ENV{HTTP_USER_AGENT};
 
   $cgi->param('username') =~ /^(.+)$/
-    or die "fatal: invalid username got past FS::SignupClient::new_customer";
+    or die "fatal: invalid username got past FS::SelfService::new_customer";
   my $username = $1;
   $cgi->param('_password') =~ /^(.+)$/
-    or die "fatal: invalid password got past FS::SignupClient::new_customer";
+    or die "fatal: invalid password got past FS::SelfService::new_customer";
   my $password = $1;
   ( $cgi->param('first'). ' '. $cgi->param('last') ) =~ /^(.*)$/
-    or die "fatal: invalid email_name got past FS::SignupClient::new_customer";
+    or die "fatal: invalid email_name got past FS::SelfService::new_customer";
   $email_name = $1; #global for template
 
   my $pop = $popnum2pop{$cgi->param('popnum')};
-    #or die "fatal: invalid popnum got past FS::SignupClient::new_customer";
+    #or die "fatal: invalid popnum got past FS::SelfService::new_customer";
   if ( $pop ) {
     ( $ac, $exch, $loc ) = ( $pop->{'ac'}, $pop->{'exch'}, $pop->{'loc'} );
   } else {
@@ -387,3 +446,40 @@ support.
 END
 }
 
+# subs for the templates...
+
+=item regionselector SELECTED_COUNTY, SELECTED_STATE, SELECTED_COUNTRY, PREFIX, ONCHANGE
+
+=cut
+
+sub regionselector {
+  my ( $selected_county, $selected_state, $selected_country,
+       $prefix, $onchange ) = @_;
+  signup_info() unless $init_data;
+  FS::SelfService::regionselector({
+    selected_county  => $selected_county,
+    selected_state   => $selected_state,
+    selected_country => $selected_country,
+    prefix           => $prefix,
+    onchange         => $onchange,
+    default_country  => $init_data->{countrydefault},
+    locales          => $init_data->{cust_main_county},
+  });
+    #default_state    => $init_data->{statedefault},
+}
+
+=item popselector 
+
+=cut
+
+sub popselector {
+  my( $popnum ) = @_;
+  signup_info() unless $init_data;
+  FS::SelfService::popselector({
+    popnum => $popnum,
+    pops   => $init_data->{svc_acct_pop},
+  });
+    #popac =>
+    #acstate =>
+}
+
index a6cbf21..c0e4f73 100755 (executable)
@@ -167,14 +167,17 @@ Contact Information
 
 </TR></TABLE><font color="#ff0000">*</font> required fields for each billing type
 <BR><BR>First package
-<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<INPUT TYPE="hidden" NAME="promo_code" VALUE="<%= $cgi->param('promo_code') %>"><TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
 <TR>
-  <TD COLSPAN=2><SELECT NAME="pkgpart"><OPTION VALUE="">(none)
+  <TD COLSPAN=2><SELECT NAME="pkgpart">
 
   <%=
+    $OUT .= '<OPTION VALUE="">(none)' unless scalar(@$packages) == 1;
     foreach my $package ( @{$packages} ) {
       $OUT .= '<OPTION VALUE="'. $package->{'pkgpart'}. '"';
-      $OUT .= ' SELECTED' if $pkgpart && $package->{'pkgpart'} == $pkgpart;
+      $OUT .= ' SELECTED'
+        if ( $pkgpart && $package->{'pkgpart'} == $pkgpart )
+           || scalar(@$packages) == 1;
       $OUT .= '>'. $package->{'pkg'};
     }
   %>
index 2e78f6e..c5cfd51 100644 (file)
         <li>pkgpart - primary key
         <li>pkg - package name
         <li>comment - non-customer visable package comment
-        <li>setup - setup fee expression
+        <li>promo_code - promotional code
+        <li><i>deprecated</i> setup - setup fee expression
         <li>freq - recurring frequency (months)
-        <li>recur - recurring fee expression
+        <li><i>deprecated</i> recur - recurring fee expression
         <li>setuptax - Setup fee tax exempt flag, empty or `Y'
         <li>recurtax - Recurring fee tax exempt flag, empty or `Y'
         <li>plan - price plan
-        <li>plandata - additional price plan data
+        <li><i>deprecated</i> plandata - additional price plan data
         <li>disabled - Disabled flag, empty or `Y'
       </ul>
     <li><a name="part_pkg_option" href="man/FS/part_pkg_option.html">part_pkg_option</a> - Package definition options
index e17f7ad..9dacf91 100644 (file)
@@ -250,6 +250,10 @@ ALTER TABLE pkg_svc ADD primary_svc char(1) NULL;
 ALTER TABLE h_pkg_svc ADD primary_svc char(1) NULL;
 ALTER TABLE svc_forward ADD src varchar(255) NULL;
 ALTER TABLE h_svc_forward ADD src varchar(255) NULL;
+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 );
+CREATE INDEX h_part_pkg2 ON h_part_pkg ( promo_code );
 
 On recent Pg versions:
 
index 4a8f705..f5826f3 100755 (executable)
@@ -168,8 +168,8 @@ print "<BR><BR>Billing address", &itable("#cccccc"), <<END;
 END
 
 print <<END;
-<INPUT TYPE="text" NAME="last" VALUE="$last"> , 
-<INPUT TYPE="text" NAME="first" VALUE="$first">
+<INPUT TYPE="text" NAME="last" VALUE="$last" onChange="changed(this)"> , 
+<INPUT TYPE="text" NAME="first" VALUE="$first" onChange="changed(this)">
 </TD>
 END
 
@@ -181,10 +181,10 @@ if ( $conf->exists('show_ss') ) {
 
 print <<END;
 </TR>
-<TR><TD ALIGN="right">Company</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="company" VALUE="$company" SIZE=70></TD></TR>
-<TR><TH ALIGN="right">${r}Address</TH><TD COLSPAN=5><INPUT TYPE="text" NAME="address1" VALUE="$address1" SIZE=70></TD></TR>
-<TR><TD ALIGN="right">&nbsp;</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="address2" VALUE="$address2" SIZE=70></TD></TR>
-<TR><TH ALIGN="right">${r}City</TH><TD><INPUT TYPE="text" NAME="city" VALUE="$city"></TD><TH ALIGN="right">${r}State</TH><TD>
+<TR><TD ALIGN="right">Company</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="company" VALUE="$company" SIZE=70 onChange="changed(this)"></TD></TR>
+<TR><TH ALIGN="right">${r}Address</TH><TD COLSPAN=5><INPUT TYPE="text" NAME="address1" VALUE="$address1" SIZE=70 onChange="changed(this)"></TD></TR>
+<TR><TD ALIGN="right">&nbsp;</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="address2" VALUE="$address2" SIZE=70 onChange="changed(this)"></TD></TR>
+<TR><TH ALIGN="right">${r}City</TH><TD><INPUT TYPE="text" NAME="city" VALUE="$city" onChange="changed(this)"></TD><TH ALIGN="right">${r}State</TH><TD>
 END
 
 #false laziness with ship state
@@ -203,12 +203,14 @@ my($county_html, $state_html, $country_html) =
 
 print "$county_html $state_html";
 
-print qq!</TD><TH>${r}Zip</TH><TD><INPUT TYPE="text" NAME="zip" VALUE="$zip" SIZE=10></TD></TR>!;
+print qq!</TD><TH>${r}Zip</TH><TD><INPUT TYPE="text" NAME="zip" VALUE="$zip" SIZE=10 onChange="changed(this)"></TD></TR>!;
 
 my($daytime,$night,$fax)=(
   $cust_main->daytime,
   $cust_main->night,
   $cust_main->fax,
+  '',
+  'changed(this)',
 );
 
 my $daytime_label = FS::Msgcat::_gettext('daytime') || 'Day Phone';
@@ -216,9 +218,9 @@ my $night_label = FS::Msgcat::_gettext('night') || 'Night Phone';
 
 print <<END;
 <TR><TH ALIGN="right">${r}Country</TH><TD>$country_html</TD></TR>
-<TR><TD ALIGN="right">$daytime_label</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="daytime" VALUE="$daytime" SIZE=18></TD></TR>
-<TR><TD ALIGN="right">$night_label</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="night" VALUE="$night" SIZE=18></TD></TR>
-<TR><TD ALIGN="right">Fax</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="fax" VALUE="$fax" SIZE=12></TD></TR>
+<TR><TD ALIGN="right">$daytime_label</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="daytime" VALUE="$daytime" SIZE=18 onChange="changed(this)"></TD></TR>
+<TR><TD ALIGN="right">$night_label</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="night" VALUE="$night" SIZE=18 onChange="changed(this)"></TD></TR>
+<TR><TD ALIGN="right">Fax</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="fax" VALUE="$fax" SIZE=12 onChange="changed(this)"></TD></TR>
 END
 
 print "</TABLE>${r}required fields<BR>";
index dc29924..b3c389c 100755 (executable)
@@ -93,7 +93,12 @@ Package information
       <INPUT TYPE="text" NAME="comment" SIZE=32 VALUE="<%=$part_pkg->comment%>">
     </TD>
   </TR>
-
+  <TR>
+    <TD ALIGN="right">Promotional code</TD>
+    <TD>
+      <INPUT TYPE="text" NAME="promo_code" SIZE=32 VALUE="<%=$part_pkg->promo_code%>">
+    </TD>
+  </TR>
   <TR>
     <TD ALIGN="right">Disable new orders</TD>
     <TD>
@@ -257,7 +262,9 @@ my $widget = new HTML::Widgets::SelectLayers(
   'options'        => \%options,
   'form_name'      => 'dummy',
   'form_action'    => 'process/part_pkg.cgi',
-  'form_text'      => [ qw(pkg comment clone pkgnum pkgpart), @fixups ],
+  'form_text'      => [ qw(pkg comment promo_code clone pkgnum pkgpart),
+                        @fixups
+                      ],
   'form_checkbox'  => [ qw(setuptax recurtax disabled) ],
   'form_radio'     => \@form_radio,
   'form_select'    => \@form_select,