discounts, RT#6679
authorivan <ivan>
Sat, 30 Jan 2010 08:55:12 +0000 (08:55 +0000)
committerivan <ivan>
Sat, 30 Jan 2010 08:55:12 +0000 (08:55 +0000)
FS/FS/cust_pkg.pm
FS/FS/cust_pkg_discount.pm
httemplate/edit/process/quick-cust_pkg.cgi
httemplate/elements/select-discount.html [new file with mode: 0644]
httemplate/elements/tr-select-discount.html [new file with mode: 0644]
httemplate/misc/order_pkg.html
httemplate/view/cust_main/packages/package.html
httemplate/view/cust_main/packages/status.html

index a95a67d..5cdca09 100644 (file)
@@ -25,6 +25,8 @@ use FS::reg_code;
 use FS::part_svc;
 use FS::cust_pkg_reason;
 use FS::reason;
+use FS::cust_pkg_discount;
+use FS::discount;
 use FS::UI::Web;
 
 # need to 'use' these instead of 'require' in sub { cancel, suspend, unsuspend,
@@ -274,6 +276,22 @@ sub insert {
                       'params'       => $self->refnum,
                     );
 
+  if ( $self->discountnum ) {
+    #XXX new/custom discount case
+    my $cust_pkg_discount = new FS::cust_pkg_discount {
+      'pkgnum'      => $self->pkgnum,
+      'discountnum' => $self->discountnum,
+      'months_used' => 0,
+      'end_date'    => '', #XXX
+      'otaker'      => $self->otaker,
+    };
+    my $error = $cust_pkg_discount->insert;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
   #if ( $self->reg_code ) {
   #  my $reg_code = qsearchs('reg_code', { 'code' => $self->reg_code } );
   #  $error = $reg_code->delete;
@@ -2211,6 +2229,141 @@ sub reexport {
 
 }
 
+=item insert_reason
+
+Associates this package with a (suspension or cancellation) reason (see
+L<FS::cust_pkg_reason>, possibly inserting a new reason on the fly (see
+L<FS::reason>).
+
+Available options are:
+
+=over 4
+
+=item reason
+
+can be set to a cancellation reason (see L<FS:reason>), either a reasonnum of an existing reason, or passing a hashref will create a new reason.  The hashref should have the following keys: typenum - Reason type (see L<FS::reason_type>, reason - Text of the new reason.
+
+=item reason_otaker
+
+the access_user (see L<FS::access_user>) providing the reason
+
+=item date
+
+a unix timestamp 
+
+=item action
+
+the action (cancel, susp, adjourn, expire) associated with the reason
+
+=back
+
+If there is an error, returns the error, otherwise returns false.
+
+=cut
+
+sub insert_reason {
+  my ($self, %options) = @_;
+
+  my $otaker = $options{reason_otaker} ||
+               $FS::CurrentUser::CurrentUser->username;
+
+  my $reasonnum;
+  if ( $options{'reason'} =~ /^(\d+)$/ ) {
+
+    $reasonnum = $1;
+
+  } elsif ( ref($options{'reason'}) ) {
+  
+    return 'Enter a new reason (or select an existing one)'
+      unless $options{'reason'}->{'reason'} !~ /^\s*$/;
+
+    my $reason = new FS::reason({
+      'reason_type' => $options{'reason'}->{'typenum'},
+      'reason'      => $options{'reason'}->{'reason'},
+    });
+    my $error = $reason->insert;
+    return $error if $error;
+
+    $reasonnum = $reason->reasonnum;
+
+  } else {
+    return "Unparsable reason: ". $options{'reason'};
+  }
+
+  my $cust_pkg_reason =
+    new FS::cust_pkg_reason({ 'pkgnum'    => $self->pkgnum,
+                              'reasonnum' => $reasonnum, 
+                             'otaker'    => $otaker,
+                             'action'    => substr(uc($options{'action'}),0,1),
+                             'date'      => $options{'date'}
+                                              ? $options{'date'}
+                                              : time,
+                           });
+
+  $cust_pkg_reason->insert;
+}
+
+=item set_usage USAGE_VALUE_HASHREF 
+
+USAGE_VALUE_HASHREF is a hashref of svc_acct usage columns and the amounts
+to which they should be set (see L<FS::svc_acct>).  Currently seconds,
+upbytes, downbytes, and totalbytes are appropriate keys.
+
+All svc_accts which are part of this package have their values reset.
+
+=cut
+
+sub set_usage {
+  my ($self, $valueref, %opt) = @_;
+
+  foreach my $cust_svc ($self->cust_svc){
+    my $svc_x = $cust_svc->svc_x;
+    $svc_x->set_usage($valueref, %opt)
+      if $svc_x->can("set_usage");
+  }
+}
+
+=item recharge USAGE_VALUE_HASHREF 
+
+USAGE_VALUE_HASHREF is a hashref of svc_acct usage columns and the amounts
+to which they should be set (see L<FS::svc_acct>).  Currently seconds,
+upbytes, downbytes, and totalbytes are appropriate keys.
+
+All svc_accts which are part of this package have their values incremented.
+
+=cut
+
+sub recharge {
+  my ($self, $valueref) = @_;
+
+  foreach my $cust_svc ($self->cust_svc){
+    my $svc_x = $cust_svc->svc_x;
+    $svc_x->recharge($valueref)
+      if $svc_x->can("recharge");
+  }
+}
+
+=item cust_pkg_discount
+
+=cut
+
+sub cust_pkg_discount {
+  my $self = shift;
+  qsearch('cust_pkg_discount', { 'pkgnum' => $self->pkgnum } );
+}
+
+=item cust_pkg_discount_active
+
+=cut
+
+sub cust_pkg_discount_active {
+  my $self = shift;
+  grep { my $d = $_->discount;
+         ! $d->months || $_->months_used < $d->months; # XXX also end date
+       }
+       $self->cust_pkg_discount;
+}
+
 =back
 
 =head1 CLASS METHODS
@@ -2631,7 +2784,7 @@ sub search {
                                 'cust_pkg.*',
                                 ( map "part_pkg.$_", qw( pkg freq ) ),
                                 'pkg_class.classname',
-                                'cust_main.custnum as cust_main_custnum',
+                                'cust_main.custnum AS cust_main_custnum',
                                 FS::UI::Web::cust_sql_fields(
                                   $params->{'cust_fields'}
                                 ),
@@ -2937,120 +3090,6 @@ sub bulk_change {
   '';
 }
 
-=item insert_reason
-
-Associates this package with a (suspension or cancellation) reason (see
-L<FS::cust_pkg_reason>, possibly inserting a new reason on the fly (see
-L<FS::reason>).
-
-Available options are:
-
-=over 4
-
-=item reason
-
-can be set to a cancellation reason (see L<FS:reason>), either a reasonnum of an existing reason, or passing a hashref will create a new reason.  The hashref should have the following keys: typenum - Reason type (see L<FS::reason_type>, reason - Text of the new reason.
-
-=item reason_otaker
-
-the access_user (see L<FS::access_user>) providing the reason
-
-=item date
-
-a unix timestamp 
-
-=item action
-
-the action (cancel, susp, adjourn, expire) associated with the reason
-
-=back
-
-If there is an error, returns the error, otherwise returns false.
-
-=cut
-
-sub insert_reason {
-  my ($self, %options) = @_;
-
-  my $otaker = $options{reason_otaker} ||
-               $FS::CurrentUser::CurrentUser->username;
-
-  my $reasonnum;
-  if ( $options{'reason'} =~ /^(\d+)$/ ) {
-
-    $reasonnum = $1;
-
-  } elsif ( ref($options{'reason'}) ) {
-  
-    return 'Enter a new reason (or select an existing one)'
-      unless $options{'reason'}->{'reason'} !~ /^\s*$/;
-
-    my $reason = new FS::reason({
-      'reason_type' => $options{'reason'}->{'typenum'},
-      'reason'      => $options{'reason'}->{'reason'},
-    });
-    my $error = $reason->insert;
-    return $error if $error;
-
-    $reasonnum = $reason->reasonnum;
-
-  } else {
-    return "Unparsable reason: ". $options{'reason'};
-  }
-
-  my $cust_pkg_reason =
-    new FS::cust_pkg_reason({ 'pkgnum'    => $self->pkgnum,
-                              'reasonnum' => $reasonnum, 
-                             'otaker'    => $otaker,
-                             'action'    => substr(uc($options{'action'}),0,1),
-                             'date'      => $options{'date'}
-                                              ? $options{'date'}
-                                              : time,
-                           });
-
-  $cust_pkg_reason->insert;
-}
-
-=item set_usage USAGE_VALUE_HASHREF 
-
-USAGE_VALUE_HASHREF is a hashref of svc_acct usage columns and the amounts
-to which they should be set (see L<FS::svc_acct>).  Currently seconds,
-upbytes, downbytes, and totalbytes are appropriate keys.
-
-All svc_accts which are part of this package have their values reset.
-
-=cut
-
-sub set_usage {
-  my ($self, $valueref, %opt) = @_;
-
-  foreach my $cust_svc ($self->cust_svc){
-    my $svc_x = $cust_svc->svc_x;
-    $svc_x->set_usage($valueref, %opt)
-      if $svc_x->can("set_usage");
-  }
-}
-
-=item recharge USAGE_VALUE_HASHREF 
-
-USAGE_VALUE_HASHREF is a hashref of svc_acct usage columns and the amounts
-to which they should be set (see L<FS::svc_acct>).  Currently seconds,
-upbytes, downbytes, and totalbytes are appropriate keys.
-
-All svc_accts which are part of this package have their values incremented.
-
-=cut
-
-sub recharge {
-  my ($self, $valueref) = @_;
-
-  foreach my $cust_svc ($self->cust_svc){
-    my $svc_x = $cust_svc->svc_x;
-    $svc_x->recharge($valueref)
-      if $svc_x->can("recharge");
-  }
-}
-
 =back
 
 =head1 BUGS
index 76118ad..87f8c52 100644 (file)
@@ -2,7 +2,7 @@ package FS::cust_pkg_discount;
 
 use strict;
 use base qw( FS::Record );
-use FS::Record; # qw( qsearch qsearchs );
+use FS::Record qw( qsearchs ); # qsearch );
 use FS::cust_pkg;
 use FS::discount;
 
@@ -131,6 +131,24 @@ sub check {
   $self->SUPER::check;
 }
 
+=item cust_pkg
+
+=cut
+
+sub cust_pkg {
+  my $self = shift;
+  qsearchs('cust_pkg', { 'pkgnum' => $self->pkgnum } );
+}
+
+=item discount
+
+=cut
+
+sub discount {
+  my $self = shift;
+  qsearchs('discount', { 'discountnum' => $self->discountnum } );
+}
+
 =back
 
 =head1 BUGS
index 7a0f082..c601567 100644 (file)
@@ -53,6 +53,7 @@ my $cust_pkg = new FS::cust_pkg {
                        ? str2time($cgi->param('start_date'))
                        : ''
                    ),
+  'discountnum' => scalar($cgi->param('discountnum')),
   'refnum'      => $refnum,
   'locationnum' => $locationnum,
 };
diff --git a/httemplate/elements/select-discount.html b/httemplate/elements/select-discount.html
new file mode 100644 (file)
index 0000000..e0b6e6c
--- /dev/null
@@ -0,0 +1,20 @@
+<% include( '/elements/select-table.html',
+                 'table'       => 'discount',
+                 'name_col'    => 'description',
+                 'order_by'    => 'ORDER BY discountnum', #XXX weight
+                 'value'       => $discountnum,
+                 'empty_label' => '(none)',
+                 'hashref'     => { 'disabled' => '' },
+                 %opt,
+             )
+%>
+<%init>
+
+my %opt = @_;
+my $discountnum = $opt{'curr_value'} || $opt{'value'};
+
+$opt{'records'} = delete $opt{'discount'}
+  if $opt{'discount'};
+
+</%init>
+
diff --git a/httemplate/elements/tr-select-discount.html b/httemplate/elements/tr-select-discount.html
new file mode 100644 (file)
index 0000000..4ff8d13
--- /dev/null
@@ -0,0 +1,27 @@
+% if ( scalar(@{ $opt{'discount'} }) == 0 ) { 
+
+  <INPUT TYPE="hidden" NAME="<% $opt{'element_name'} || $opt{'field'} || 'discountnum' %>" VALUE="">
+
+% } else { 
+
+  <TR>
+    <TD ALIGN="right"><% $opt{'label'} || '<B>Discount</B>' %></TD>
+    <TD>
+      <% include( '/elements/select-discount.html',
+                    'curr_value' => $discountnum,
+                    %opt,
+                )
+      %>
+    </TD>
+  </TR>
+
+% } 
+<%init>
+
+my %opt = @_;
+my $discountnum = $opt{'curr_value'} || $opt{'value'};
+
+$opt{'discount'} ||= [ qsearch( 'discount', { disabled=>'' } ) ];
+
+</%init>
+
index a7571ca..684f94e 100644 (file)
   });
 </SCRIPT>
 
+% if ( $curuser->access_right('Discount customer package') ) {
+  <% include('/elements/tr-select-discount.html') %>
+% }
+
 % if ( $conf->exists('pkg_referral') ) {
   <% include('/elements/tr-select-part_referral.html',
                'curr_value'    => scalar( $cgi->param('refnum') ), #get rid of empty_label first# || $cust_main->refnum,
 </HTML>
 <%init>
 
+my $curuser = $FS::CurrentUser::CurrentUser;
+
 die "access denied"
-  unless $FS::CurrentUser::CurrentUser->access_right('Order customer package');
+  unless $curuser->access_right('Order customer package');
 
 my $conf = new FS::Conf;
 
index 280a016..33bcd2a 100644 (file)
@@ -1,4 +1,4 @@
-<TD CLASS="inv" BGCOLOR="<% $bgcolor %>">
+<TD CLASS="inv" BGCOLOR="<% $bgcolor %>" VALIGN="top">
   <TABLE CLASS="inv" BORDER=0 CELLSPACING=0 CELLPADDING=0 WIDTH="100%">
     <TR>
       <TD COLSPAN=2>
index 6667a55..40d6438 100644 (file)
@@ -42,6 +42,8 @@
        )
     %>
 
+    <% pkg_status_row_discount( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
+
 %   unless ( $cust_pkg->get('setup') ) { 
       <% pkg_status_row_colspan( $cust_pkg, 'Never billed', '', 'colspan'=>$colspan, %opt ) %>
 %   } else { 
 %
 %     unless ( $cust_pkg->get('setup') ) { #not setup
 %
-%       unless ( $part_pkg->freq ) { 
+%       unless ( $part_pkg->freq ) {
 
           <% pkg_status_row_colspan( $cust_pkg, 'Not&nbsp;yet&nbsp;billed&nbsp;(one-time&nbsp;charge)', '', 'colspan'=>$colspan, %opt ) %>
 
+         <% pkg_status_row_discount( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
+
           <% pkg_status_row_if(
                $cust_pkg,
                ( $part_pkg->freq ? 'Start billing' : 'Bill on' ),
@@ -94,7 +98,9 @@
 
 %       } else { 
 
-         <% pkg_status_row_colspan($cust_pkg, "Not&nbsp;yet&nbsp;billed&nbsp;($billed_or_prepaid&nbsp;". myfreq($part_pkg). ')', '', 'colspan'=>$colspan, %opt ) %>
+          <% pkg_status_row_colspan($cust_pkg, "Not&nbsp;yet&nbsp;billed&nbsp;($billed_or_prepaid&nbsp;". myfreq($part_pkg). ')', '', 'colspan'=>$colspan, %opt ) %>
+
+          <% pkg_status_row_discount( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
 
           <% pkg_status_row_if($cust_pkg, 'Start billing', 'start_date', %opt) %>
 
 
           <% pkg_status_row($cust_pkg, 'Billed', 'setup', %opt) %>
 
+          <% pkg_status_row_discount( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
+
 %       } else { 
 %
 %         if (scalar($cust_pkg->overlimit)) {
             %>
 %         } 
 
+          <% pkg_status_row_discount( $cust_pkg, %opt, 'colspan'=>$colspan ) %>
+
           <% pkg_status_row($cust_pkg, 'Setup', 'setup', %opt) %>
 
 %       } 
@@ -273,12 +283,37 @@ sub pkg_status_row_changed {
                                      'size'    => '-1',
                                      'align'   => 'right',
                                      'colspan' => $opt{'colspan'},
+                                     #%opt,
                                    );
   }
 
   $html;
 }
 
+sub pkg_status_row_discount {
+  my( $cust_pkg, %opt ) = @_;
+
+  my $html;
+
+  foreach my $cust_pkg_discount ( $cust_pkg->cust_pkg_discount_active ) {
+
+    my $discount = $cust_pkg_discount->discount;
+
+    my $label = '<B>Discount</B>: '. $discount->description;
+    $label .= ' ('. ( $discount->months - $cust_pkg_discount->months_used ).
+              ' months remaining)'
+      if $discount->months;
+
+    $html .= pkg_status_row_colspan( $cust_pkg, $label, '',
+                                     'colspan' => $opt{'colspan'},
+                                     #%opt,
+                                   );
+
+  }
+
+  $html;
+}
+
 sub pkg_status_row_colspan {
   my($cust_pkg, $title, $addl, %opt) = @_;