pro-rating w/ web interface, tested (closes: Bug#313).
authorivan <ivan>
Sun, 10 Feb 2002 02:16:47 +0000 (02:16 +0000)
committerivan <ivan>
Sun, 10 Feb 2002 02:16:47 +0000 (02:16 +0000)
view/cust_bill.cgi invoice view shows invoice events!

fix bug where adding events with no name silently failed instead of giving
an error

add new comission plans

FS/FS/Conf.pm
FS/FS/cust_bill.pm
FS/FS/cust_bill_event.pm
FS/FS/cust_main.pm
Makefile
htetc/handler.pl
httemplate/browse/part_bill_event.cgi
httemplate/edit/part_pkg.cgi
httemplate/edit/process/part_bill_event.cgi
httemplate/edit/process/part_pkg.cgi
httemplate/view/cust_bill.cgi

index 873ee75..da6bf72 100644 (file)
@@ -716,6 +716,13 @@ httemplate/docs/config.html
     'type'        => 'textarea',
   },
 
+  {
+    'key'         => 'safe-part_pkg',
+    'section'     => 'UI',
+    'description' => 'Validates package definition setup and recur expressions against a preset list.  Useful for webdemos, annoying to powerusers.',
+    'type'        => 'checkbox',
+  },
+
 );
 
 1;
index ad2ae82..4306ea4 100644 (file)
@@ -19,6 +19,7 @@ use FS::cust_pay;
 use FS::cust_pkg;
 use FS::cust_credit_bill;
 use FS::cust_pay_batch;
+use FS::cust_bill_event;
 
 @ISA = qw( FS::Record );
 
@@ -251,6 +252,19 @@ sub cust_bill_pkg {
   qsearch( 'cust_bill_pkg', { 'invnum' => $self->invnum } );
 }
 
+=item cust_bill_event
+
+Returns the completed invoice events (see L<FS::cust_bill_event>) for this
+invoice.
+
+=cut
+
+sub cust_bill_event {
+  my $self = shift;
+  qsearch( 'cust_bill_event', { 'invnum' => $self->invnum } );
+}
+
+
 =item cust_main
 
 Returns the customer (see L<FS::cust_main>) for this invoice.
@@ -864,7 +878,7 @@ sub print_text {
 
 =head1 VERSION
 
-$Id: cust_bill.pm,v 1.17 2002-02-06 15:50:54 ivan Exp $
+$Id: cust_bill.pm,v 1.18 2002-02-10 02:16:46 ivan Exp $
 
 =head1 BUGS
 
index 910b4de..cc9ce7c 100644 (file)
@@ -3,6 +3,7 @@ package FS::cust_bill_event;
 use strict;
 use vars qw( @ISA );
 use FS::Record qw( qsearch qsearchs );
+use FS::part_bill_event;
 
 @ISA = qw(FS::Record);
 
@@ -117,6 +118,18 @@ sub check {
   ''; #no error
 }
 
+=item part_bill_event
+
+Returns the invoice event definition (see L<FS::part_bill_event>) for this
+completed invoice event.
+
+=cut
+
+sub part_bill_event {
+  my $self = shift;
+  qsearchs( 'part_bill_event', { 'eventpart' => $self->eventpart } );
+}
+
 =back
 
 =head1 BUGS
index 94fd97f..5cc6cfd 100644 (file)
@@ -913,6 +913,9 @@ sub bill {
       };
       $recur_prog = $1;
 
+      # shared with $recur_prog
+      $sdate = $cust_pkg->bill || $cust_pkg->setup || $time;
+
         #my $cpt = new Safe;
         ##$cpt->permit(); #what is necessary?
         #$cpt->share(qw( $cust_pkg )); #can $cpt now use $cust_pkg methods?
@@ -925,11 +928,14 @@ sub bill {
       }
       #change this bit to use Date::Manip? CAREFUL with timezones (see
       # mailing list archive)
-      #$sdate=$cust_pkg->bill || time;
-      #$sdate=$cust_pkg->bill || $time;
-      $sdate = $cust_pkg->bill || $cust_pkg->setup || $time;
       my ($sec,$min,$hour,$mday,$mon,$year) =
         (localtime($sdate) )[0,1,2,3,4,5];
+
+      #pro-rating magic - if $recur_prog fiddles $sdate, want to use that
+      # only for figuring next bill date, nothing else, so, reset $sdate again
+      # here
+      $sdate = $cust_pkg->bill || $cust_pkg->setup || $time;
+
       $mon += $part_pkg->getfield('freq');
       until ( $mon < 12 ) { $mon -= 12; $year++; }
       $cust_pkg->setfield('bill',
@@ -1118,7 +1124,7 @@ sub collect {
       sort {    $a->seconds   <=> $b->seconds
              || $a->weight    <=> $b->weight
              || $a->eventpart <=> $b->eventpart }
-        grep { $_->seconds > ( $invoice_time - ( $cust_bill->_date || 0 ) )
+        grep { $_->seconds <= ( $invoice_time - $cust_bill->_date )
                && ! qsearchs( 'cust_bill_event', {
                                 'invnum'    => $cust_bill->invnum,
                                 'eventpart' => $_->eventpart       } )
@@ -1518,11 +1524,23 @@ sub referral_cust_main {
   @cust_main;
 }
 
+=item referral_cust_main_ncancelled
+
+Same as referral_cust_main, except only returns customers with uncancelled
+packages.
+
+=cut
+
+sub referral_cust_main_ncancelled {
+  my $self = shift;
+  grep { scalar($_->ncancelled_pkgs) } $self->referral_cust_main;
+}
+
 =item referral_cust_pkg [ DEPTH ]
 
-Like referral_cust_main, except returns a flat list of all unsuspended packages
-for each customer.  The number of items in this list may be useful for
-comission calculations (perhaps after a grep).
+Like referral_cust_main, except returns a flat list of all unsuspended (and
+uncancelled) packages for each customer.  The number of items in this list may
+be useful for comission calculations (perhaps after a C<grep { my $pkgpart = $_->pkgpart; grep { $_ == $pkgpart } @commission_worthy_pkgparts> } $cust_main-> ).
 
 =cut
 
index 0f86b49..283981a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -52,7 +52,7 @@ htmlman:
        [ -e ./httemplate/docs/man/bin ] || mkdir httemplate/docs/man/bin
        [ -e ./httemplate/docs/man/FS ] || mkdir httemplate/docs/man/FS
        [ -e ./httemplate/docs/man/FS/UI ] || mkdir httemplate/docs/man/FS/UI
-       bin/pod2x
+       [ -e DONT_REBUILD_DOCS ] || bin/pod2x
 
 upload-docs:
        ssh cleanwhisker.420.am rm -rf /var/www/www.sisd.com/freeside/devdocs
index 29e759a..37f2d37 100644 (file)
@@ -68,7 +68,7 @@ sub handler
       use FS::Record qw(qsearch qsearchs fields dbdef);
       use FS::Conf;
       use FS::CGI qw(header menubar popurl table itable ntable idiot eidiot
-                     small_custviewm myexit);
+                     small_custview myexit);
 
       use FS::agent;
       use FS::agent_type;
index 7ec8a18..81228f2 100755 (executable)
@@ -1,4 +1,4 @@
-<!-- $Id: part_bill_event.cgi,v 1.3 2002-01-30 18:22:54 ivan Exp $ -->
+<!-- $Id: part_bill_event.cgi,v 1.4 2002-02-10 02:16:46 ivan Exp $ -->
 <% 
 
 my %search;
@@ -66,7 +66,7 @@ my $total = scalar(@part_bill_event);
 <% } %>
 
   <TR>
-    <TD COLSPAN=8><A HREF="<%= $p %>edit/part_bill_event.cgi"><I>Add a new billing event</I></A></TD>
+    <TD COLSPAN=8><A HREF="<%= $p %>edit/part_bill_event.cgi"><I>Add a new invoice event</I></A></TD>
   </TR>
 </TABLE>
 </BODY>
index ea3f62a..bead141 100755 (executable)
@@ -1,4 +1,4 @@
-<!-- $Id: part_pkg.cgi,v 1.9 2002-01-29 16:33:16 ivan Exp $ -->
+<!-- $Id: part_pkg.cgi,v 1.10 2002-02-10 02:16:47 ivan Exp $ -->
 
 <%
 
@@ -175,8 +175,44 @@ tie my %plans, 'Tie::IxHash',
     'recur' => 'what.recur_fee.value',
   },
 
+  'prorate' => {
+    'name' => 'First month pro-rated, then flat-rate',
+    'fields' =>  {
+      'setup_fee' => { 'name' => 'Setup fee for this package',
+                       'default' => 0,
+                     },
+      'recur_fee' => { 'name' => 'Recurring fee for this package',
+                       'default' => 0,
+                      },
+    },
+    'fieldorder' => [ 'setup_fee', 'recur_fee' ],
+    'setup' => 'what.setup_fee.value',
+    'recur' => '\'my $mnow = $sdate; my ($sec,$min,$hour,$mday,$mon,$year) = (localtime($sdate) )[0,1,2,3,4,5]; my $mstart = timelocal(0,0,0,1,$mon,$year); my $mend = timelocal(0,0,0,1, $mon == 11 ? 0 : $mon+1, $year+($mon==11)); $sdate = $mstart; ( $part_pkg->freq - 1 ) * \' + what.recur_fee.value + \' / $part_pkg->freq + \' + what.recur_fee.value + \' / $part_pkg->freq * ($mend-$mnow) / ($mend-$mstart) ; \'',
+  },
+
+  'flat_comission_cust' => {
+    'name' => 'Flat rate with recurring comission per active customer',
+    'fields' => {
+      'setup_fee' => { 'name' => 'Setup fee for this package',
+                       'default' => 0,
+                     },
+      'recur_fee' => { 'name' => 'Recurring fee for this package',
+                       'default' => 0,
+                     },
+      'comission_amount' => { 'name' => 'Comission amount per month (per active customer)',
+                              'default' => 0,
+                            },
+      'comission_depth'  => { 'name' => 'Number of layers',
+                              'default' => 1,
+                            },
+    },
+    'fieldorder' => [ 'setup_fee', 'recur_fee', 'comission_depth', 'comission_amount' ],
+    'setup' => 'what.setup_fee.value',
+    'recur' => '\'my $error = $cust_pkg->cust_main->credit( \' + what.comission_amount.value + \' * scalar($cust_pkg->cust_main->referral_cust_main_ncancelled(\' + what.comission_depth.value+ \')), "commission" ); die $error if $error; \' + what.recur_fee.value + \';\'',
+  },
+
   'flat_comission' => {
-    'name' => 'Flat rate with recurring referral comission as credit',
+    'name' => 'Flat rate with recurring comission per active package',
     'fields' => {
       'setup_fee' => { 'name' => 'Setup fee for this package',
                        'default' => 0,
@@ -184,7 +220,7 @@ tie my %plans, 'Tie::IxHash',
       'recur_fee' => { 'name' => 'Recurring fee for this package',
                        'default' => 0,
                      },
-      'comission_amount' => { 'name' => 'Comission amount',
+      'comission_amount' => { 'name' => 'Comission amount per month (per active package)',
                               'default' => 0,
                             },
       'comission_depth'  => { 'name' => 'Number of layers',
@@ -196,6 +232,36 @@ tie my %plans, 'Tie::IxHash',
     'recur' => '\'my $error = $cust_pkg->cust_main->credit( \' + what.comission_amount.value + \' * scalar($cust_pkg->cust_main->referral_cust_pkg(\' + what.comission_depth.value+ \')), "commission" ); die $error if $error; \' + what.recur_fee.value + \';\'',
   },
 
+  'flat_comission_pkg' => {
+    'name' => 'Flat rate with recurring comission per active (selected) package',
+    'fields' => {
+      'setup_fee' => { 'name' => 'Setup fee for this package',
+                       'default' => 0,
+                     },
+      'recur_fee' => { 'name' => 'Recurring fee for this package',
+                       'default' => 0,
+                     },
+      'comission_amount' => { 'name' => 'Comission amount per month (per uncancelled package)',
+                              'default' => 0,
+                            },
+      'comission_depth'  => { 'name' => 'Number of layers',
+                              'default' => 1,
+                            },
+      'comission_pkgpart' => { 'name' => 'Applicable packages<BR><FONT SIZE="-1">(hold <b>ctrl</b> to select multiple packages)</FONT>',
+                               'type' => 'select_multiple',
+                               'select_table' => 'part_pkg',
+                               'select_hash'  => { 'disabled' => '' } ,
+                               'select_key'   => 'pkgpart',
+                               'select_label' => 'pkg',
+                             },
+    },
+    'fieldorder' => [ 'setup_fee', 'recur_fee', 'comission_depth', 'comission_amount', 'comission_pkgpart' ],
+    'setup' => 'what.setup_fee.value',
+    'recur' => '""; var pkgparts = ""; for ( var c=0; c < document.flat_comission_pkg.comission_pkgpart.options.length; c++ ) { if (document.flat_comission_pkg.comission_pkgpart.options[c].selected) { pkgparts = pkgparts + document.flat_comission_pkg.comission_pkgpart.options[c].value + \', \'; } } what.recur.value = \'my $error = $cust_pkg->cust_main->credit( \' + what.comission_amount.value + \' * scalar( grep { my $pkgpart = $_->pkgpart; grep { $_ == $pkgpart } ( \' + pkgparts + \'  ) } $cust_pkg->cust_main->referral_cust_pkg(\' + what.comission_depth.value+ \')), "commission" ); die $error if $error; \' + what.recur_fee.value + \';\'',
+  },
+
+
+
   'sesmon_hour' => {
     'name' => 'Base charge plus charge per-hour from the session monitor',
     'fields' => {
@@ -345,9 +411,21 @@ if ( $cgi->param('pkgnum') ) {
                          : keys %{ $href }
                      ) {
 %>
-<TR><TD ALIGN="right"><%= $href->{$field}{'name'} %></TD>
-<TD><INPUT TYPE="text" NAME="<%= $field %>" VALUE="<%= exists($plandata{$field}) ? $plandata{$field} : $href->{$field}{'default'} %>" onChange="fchanged(this)"></TD></TR>
+  <TR><TD ALIGN="right"><%= $href->{$field}{'name'} %></TD>
+  <TD>
+  <% if ( ! exists($href->{$field}{'type'}) ) { %>
+       <INPUT TYPE="text" NAME="<%= $field %>" VALUE="<%= exists($plandata{$field}) ? $plandata{$field} : $href->{$field}{'default'} %>" onChange="fchanged(this)">
+  <% } elsif ( $href->{$field}{'type'} eq 'select_multiple' ) { %>
+       <SELECT MULTIPLE NAME="<%= $field %>" onChange="fchanged(this)">
+       <% foreach $record ( qsearch( $href->{$field}{'select_table'}, $href->{$field}{'select_hash'} ) ) {
+          my $value = $record->getfield($href->{$field}{'select_key'}); %>
+         <OPTION VALUE="<%= $value %>"<%= $plandata{$field} =~ /(^|, *)$value *(,|$)/ ? ' SELECTED' : '' %>><%= $record->getfield($href->{$field}{'select_label'}) %>
+       <% } %>
+       </SELECT>
+  <% } %>
+  </TD></TR>
 <% } %>
+
 </TABLE>
 <INPUT TYPE="hidden" NAME="plandata" VALUE="<%= join(',', keys %{ $href } ) %>">
 <BR><BR>
index 7c0b54d..1716c71 100755 (executable)
@@ -34,7 +34,6 @@ if ( ! $cgi->param('plan_weight_eventcode') ) {
     } fields('part_bill_event'),
   } );
 
-  my $error;
   if ( $eventpart ) {
     $error = $new->replace($old);
   } else {
index 5240d8c..9ad1527 100755 (executable)
@@ -1,4 +1,4 @@
-<!-- $Id: part_pkg.cgi,v 1.8 2002-02-09 18:24:01 ivan Exp $ -->
+<!-- $Id: part_pkg.cgi,v 1.9 2002-02-10 02:16:47 ivan Exp $ -->
 <%
 
 my $dbh = dbh;
@@ -11,7 +11,7 @@ my $old = qsearchs('part_pkg',{'pkgpart'=>$pkgpart}) if $pkgpart;
 my $plandata = $cgi->param('plandata');
 my @plandata = split(',', $plandata);
 $cgi->param('plandata', 
-  join('', map { "$_=". $cgi->param($_). "\n" } @plandata )
+  join('', map { "$_=". join(', ', $cgi->param($_)). "\n" } @plandata )
 );
 
 foreach (qw( setuptax recurtax disabled )) {
index 6bc1568..5860ffd 100755 (executable)
@@ -1,4 +1,4 @@
-<!-- $Id: cust_bill.cgi,v 1.7 2002-02-04 16:44:47 ivan Exp $ -->
+<!-- $Id: cust_bill.cgi,v 1.8 2002-02-10 02:16:47 ivan Exp $ -->
 <%
 
 #untaint invnum
@@ -20,10 +20,15 @@ print header('Invoice View', menubar(
 print qq!<A HREF="${p}edit/cust_pay.cgi?$invnum">Enter payments (check/cash) against this invoice</A> | !
   if $cust_bill->owed > 0;
 
-print qq!<A HREF="${p}misc/print-invoice.cgi?$invnum">Reprint this invoice</A>!.
-#     "<BR><BR>(Printed $printed times)".
-#print cust_bill_events
-      '<PRE>'.
+print qq!<A HREF="${p}misc/print-invoice.cgi?$invnum">Reprint this invoice</A>!.      '<BR><BR>';
+
+foreach my $cust_bill_event (
+  sort { $a->_date <=> $b->_date } $cust_bill->cust_bill_event
+) {
+  print time2str("%a %b %e %T %Y", $cust_bill_event->_date). ' - '.
+        $cust_bill_event->part_bill_event->event. '<BR>';
+}
+print '<BR><PRE>';
 
 print $cust_bill->print_text;