Merge branch 'master' of git.freeside.biz:/home/git/freeside
authorIvan Kohler <ivan@freeside.biz>
Mon, 2 Apr 2012 17:37:52 +0000 (10:37 -0700)
committerIvan Kohler <ivan@freeside.biz>
Mon, 2 Apr 2012 17:37:52 +0000 (10:37 -0700)
18 files changed:
FS/FS/Conf.pm
FS/FS/Report/Table.pm
FS/FS/Schema.pm
FS/FS/cust_bill.pm
FS/FS/cust_pay.pm
FS/FS/part_event/Condition.pm
FS/FS/part_event/Condition/has_cust_tag.pm [new file with mode: 0644]
FS/FS/part_pkg.pm
httemplate/browse/part_pkg.cgi
httemplate/edit/cust_pay.cgi
httemplate/edit/part_pkg.cgi
httemplate/edit/process/cust_pay.cgi
httemplate/elements/city.html
httemplate/elements/tr-select-cust_tag.html
httemplate/graph/cust_signup.html
httemplate/graph/report_cust_signup.html
httemplate/view/cust_main/payment_history.html
httemplate/view/cust_pay.html

index 2bc1f19..1b01aa6 100644 (file)
@@ -694,6 +694,13 @@ sub reason_type_options {
   },
 
   {
+    'key'         => 'part_pkg-lineage',
+    'section'     => '',
+    'description' => 'When editing a package definition, if setup or recur fees are changed, create a new package rather than changing the existing package.',
+    'type'        => 'checkbox',
+  },
+
+  {
     'key'         => 'apacheip',
     #not actually deprecated yet
     #'section'     => 'deprecated',
@@ -2284,6 +2291,13 @@ and customer address. Include units.',
   },
 
   {
+    'key'         => 'require_cash_deposit_info',
+    'section'     => 'billing',
+    'description' => 'When recording cash payments, display bank deposit information fields.',
+    'type'        => 'checkbox',
+  },
+
+  {
     'key'         => 'paymentforcedtobatch',
     'section'     => 'deprecated',
     'description' => 'See batch-enable_payby and realtime-disable_payby.  Used to (for CHEK): Cause per customer payment entry to be forced to a batch processor rather than performed realtime.',
@@ -2926,7 +2940,7 @@ and customer address. Include units.',
     'section'     => 'invoicing',
     'description' => 'Enable FTP of raw invoice data - format.',
     'type'        => 'select',
-    'select_enum' => [ '', 'default', 'billco', ],
+    'select_enum' => [ '', 'default', 'oneline', 'billco', ],
   },
 
   {
@@ -2962,7 +2976,7 @@ and customer address. Include units.',
     'section'     => 'invoicing',
     'description' => 'Enable spooling of raw invoice data - format.',
     'type'        => 'select',
-    'select_enum' => [ '', 'default', 'billco', ],
+    'select_enum' => [ '', 'default', 'oneline', 'billco', ],
   },
 
   {
index 3942543..b0e911f 100644 (file)
@@ -32,21 +32,32 @@ options in %opt.
 
 =over 4
 
-=item signups: The number of customers signed up.
+=item signups: The number of customers signed up.  Options are "refnum" 
+(limit by advertising source) and "indirect" (boolean, tells us to limit 
+to customers that have a referral_custnum that matches the advertising source).
 
 =cut
 
 sub signups {
   my( $self, $speriod, $eperiod, $agentnum, %opt ) = @_;
-  my @where = (
-    $self->in_time_period_and_agent($speriod, $eperiod, $agentnum, 'signupdate')
+  my @where = ( $self->in_time_period_and_agent($speriod, $eperiod, $agentnum, 
+      'cust_main.signupdate')
   );
-  if ( $opt{'refnum'} ) {
+  my $join = '';
+  if ( $opt{'indirect'} ) {
+    $join = " JOIN cust_main AS referring_cust_main".
+            " ON (cust_main.referral_custnum = referring_cust_main.custnum)";
+
+    if ( $opt{'refnum'} ) {
+      push @where, "referring_cust_main.refnum = ".$opt{'refnum'};
+    }
+  }
+  elsif ( $opt{'refnum'} ) {
     push @where, "refnum = ".$opt{'refnum'};
   }
 
   $self->scalar_sql(
-    "SELECT COUNT(*) FROM cust_main WHERE ".join(' AND ', @where)
+    "SELECT COUNT(*) FROM cust_main $join WHERE ".join(' AND ', @where)
   );
 }
 
index ab853e6..5147432 100644 (file)
@@ -1343,12 +1343,17 @@ sub tables_hashref {
                                                  # index into payby table
                                                  # eventually
         'payinfo',  'varchar',   'NULL', 512, '', '', #see cust_main above
-       'paymask', 'varchar', 'NULL', $char_d, '', '', 
+        'paymask', 'varchar', 'NULL', $char_d, '', '', 
         'paydate',  'varchar', 'NULL', 10, '', '', 
         'paybatch', 'varchar',   'NULL', $char_d, '', '', #for auditing purposes.
         'payunique', 'varchar', 'NULL', $char_d, '', '', #separate paybatch "unique" functions from current usage
         'closed',    'char', 'NULL', 1, '', '', 
         'pkgnum', 'int', 'NULL', '', '', '', #desired pkgnum for pkg-balances
+        # cash/check deposit info fields
+        'bank',       'varchar', 'NULL', $char_d, '', '',
+        'depositor',  'varchar', 'NULL', $char_d, '', '',
+        'account',    'varchar', 'NULL', 20,      '', '',
+        'teller',     'varchar', 'NULL', 20,      '', '',
       ],
       'primary_key' => 'paynum',
       #i guess not now, with cust_pay_pending, if we actually make it here, we _do_ want to record it# 'unique' => [ [ 'payunique' ] ],
@@ -1690,6 +1695,8 @@ sub tables_hashref {
         'no_auto',          'char', 'NULL',  1, '', '', 
         'recur_show_zero',  'char', 'NULL',  1, '', '',
         'setup_show_zero',  'char', 'NULL',  1, '', '',
+        'successor',     'int',     'NULL', '', '', '',
+        'family_pkgpart','int',     'NULL', '', '', '',
       ],
       'primary_key' => 'pkgpart',
       'unique' => [],
index 3aa75ec..945771e 100644 (file)
@@ -2005,6 +2005,36 @@ sub print_csv {
       '0',                        # 29 | Other Taxes & Fees***         NUM*   9
     );
 
+  } elsif ( lc($opt{'format'}) eq 'oneline' ) { #name?
+   
+    my ($previous_balance) = $self->previous; 
+    my $totaldue = sprintf('%.2f', $self->owed + $previous_balance);
+    my @items = map {
+      ($_->{pkgnum} || ''),
+      $_->{description},
+      $_->{amount}
+    } $self->_items_pkg;
+
+    $csv->combine(
+      $cust_main->agentnum,
+      $self->custnum,
+      $cust_main->first,
+      $cust_main->last,
+      $cust_main->address1,
+      $cust_main->address2,
+      $cust_main->city,
+      $cust_main->state,
+      $cust_main->zip,
+
+      # invoice fields
+      time2str("%x", $self->_date),
+      $self->invnum,
+      $self->charged,
+      $totaldue,
+
+      @items,
+    );
+
   } else {
   
     $csv->combine(
@@ -2044,6 +2074,10 @@ sub print_csv {
 
     }
 
+  } elsif ( lc($opt{'format'}) eq 'oneline' ) {
+
+    #do nothing
+
   } else {
 
     foreach my $cust_bill_pkg ( $self->cust_bill_pkg ) {
index d98d11e..ef30809 100644 (file)
@@ -113,6 +113,22 @@ books closed flag, empty or `Y'
 
 Desired pkgnum when using experimental package balances.
 
+=item bank
+
+The bank where the payment was deposited.
+
+=item depositor
+
+The name of the depositor.
+
+=item account
+
+The deposit account number.
+
+=item teller
+
+The teller number.
+
 =back
 
 =head1 METHODS
@@ -493,8 +509,11 @@ sub check {
     || $self->ut_textn('payunique')
     || $self->ut_enum('closed', [ '', 'Y' ])
     || $self->ut_foreign_keyn('pkgnum', 'cust_pkg', 'pkgnum')
+    || $self->ut_textn('bank')
+    || $self->ut_alphan('depositor')
+    || $self->ut_numbern('account')
+    || $self->ut_numbern('teller')
     || $self->payinfo_check()
-    || $self->ut_numbern('discount_term')
   ;
   return $error if $error;
 
@@ -509,6 +528,12 @@ sub check {
   return "invalid discount_term"
    if ($self->discount_term && $self->discount_term < 2);
 
+  if ( $self->payby eq 'CASH' and $conf->exists('require_cash_deposit_info') ) {
+    foreach (qw(bank depositor account teller)) {
+      return "$_ required" if $self->get($_) eq '';
+    }
+  }
+
 #i guess not now, with cust_pay_pending, if we actually make it here, we _do_ want to record it
 #  # UNIQUE index should catch this too, without race conditions, but this
 #  # should give a better error message the other 99.9% of the time...
index 3275197..b394815 100644 (file)
@@ -360,7 +360,7 @@ sub condition_sql_option_option {
 
 }
 
-#used for part_event/Condition/cust_bill_has_service.pm
+#used for part_event/Condition/cust_bill_has_service.pm and has_cust_tag.pm
 #a little false laziness w/above and condition_sql_option_integer
 sub condition_sql_option_option_integer {
   my( $class, $option, $driver_name ) = @_;
diff --git a/FS/FS/part_event/Condition/has_cust_tag.pm b/FS/FS/part_event/Condition/has_cust_tag.pm
new file mode 100644 (file)
index 0000000..cde9338
--- /dev/null
@@ -0,0 +1,49 @@
+package FS::part_event::Condition::has_cust_tag;
+
+use strict;
+
+use base qw( FS::part_event::Condition );
+use FS::Record qw( qsearch );
+
+sub description {
+  'Customer has tag',
+}
+
+sub eventtable_hashref {
+    { 'cust_main' => 1,
+      'cust_bill' => 1,
+      'cust_pkg'  => 1,
+    };
+}
+
+#something like this
+sub option_fields {
+  (
+    'tagnum'  => { 'label'    => 'Customer tag',
+                   'type'     => 'select-cust_tag',
+                   'multiple' => 1,
+                 },
+  );
+}
+
+sub condition {
+  my( $self, $object ) = @_;
+
+  my $cust_main = $self->cust_main($object);
+
+  my $hashref = $self->option('tagnum') || {};
+  grep $hashref->{ $_->tagnum }, $cust_main->cust_tag;
+}
+
+sub condition_sql {
+  my( $self, $table ) = @_;
+
+  my $matching_tags = 
+    "SELECT tagnum FROM cust_tag WHERE cust_tag.custnum = $table.custnum".
+    " AND cust_tag.tagnum IN ".
+    $self->condition_sql_option_option_integer('tagnum');
+
+  "EXISTS($matching_tags)";
+}
+
+1;
index 373982b..061001b 100644 (file)
@@ -103,6 +103,13 @@ inherits from FS::Record.  The following fields are currently supported:
 
 =item fcc_ds0s - Optional DS0 equivalency number for FCC form 477
 
+=item successor - Foreign key for the part_pkg that replaced this record.
+If this record is not obsolete, will be null.
+
+=item family_pkgpart - Foreign key for the part_pkg that was the earliest
+ancestor of this record.  If this record is not a successor to another 
+part_pkg, will be equal to pkgpart.
+
 =back
 
 =head1 METHODS
@@ -192,6 +199,16 @@ sub insert {
     return $error;
   }
 
+  # set family_pkgpart
+  if ( $self->get('family_pkgpart') eq '' ) {
+    $self->set('family_pkgpart' => $self->pkgpart);
+    $error = $self->SUPER::replace;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
   my $conf = new FS::Conf;
   if ( $conf->exists('agent_defaultpkg') ) {
     warn "  agent_defaultpkg set; allowing all agents to purchase package"
@@ -294,7 +311,7 @@ sub insert {
       }
   }
 
-  warn "  commiting transaction" if $DEBUG;
+  warn "  committing transaction" if $DEBUG and $oldAutoCommit;
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
 
   '';
@@ -360,6 +377,28 @@ sub replace {
   my $oldAutoCommit = $FS::UID::AutoCommit;
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
+  
+  my $conf = new FS::Conf;
+  if ( $conf->exists('part_pkg-lineage') ) {
+    if ( grep { $options->{options}->{$_} ne $old->option($_, 1) }
+          qw(setup_fee recur_fee) #others? config?
+        ) { 
+    
+      warn "  superseding package" if $DEBUG;
+
+      my $error = $new->supersede($old, %$options);
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return $error;
+      }
+      else {
+        warn "  committing transaction" if $DEBUG and $oldAutoCommit;
+        $dbh->commit if $oldAutoCommit;
+        return $error;
+      }
+    }
+    #else nothing
+  }
 
   #plandata shit stays in replace for upgrades until after 2.0 (or edit
   #_upgrade_data)
@@ -501,8 +540,18 @@ sub replace {
         }
       }
   }
+  
+  # propagate changes to certain core fields
+  if ( $conf->exists('part_pkg-lineage') ) {
+    warn "  propagating changes to family" if $DEBUG;
+    my $error = $new->propagate($old);
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
 
-  warn "  commiting transaction" if $DEBUG;
+  warn "  committing transaction" if $DEBUG and $oldAutoCommit;
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
   '';
 }
@@ -573,6 +622,8 @@ sub check {
            : $self->ut_agentnum_acl('agentnum', \@null_agentnum_right)
        )
     || $self->ut_numbern('fcc_ds0s')
+    || $self->ut_foreign_keyn('successor', 'part_pkg', 'pkgpart')
+    || $self->ut_foreign_keyn('family_pkgpart', 'part_pkg', 'pkgpart')
     || $self->SUPER::check
   ;
   return $error if $error;
@@ -587,6 +638,76 @@ sub check {
   '';
 }
 
+=item supersede OLD [, OPTION => VALUE ... ]
+
+Inserts this package as a successor to the package OLD.  All options are as
+for C<insert>.  After inserting, disables OLD and sets the new package as its
+successor.
+
+=cut
+
+sub supersede {
+  my ($new, $old, %options) = @_;
+  my $error;
+
+  $new->set('pkgpart' => '');
+  $new->set('family_pkgpart' => $old->family_pkgpart);
+  warn "    inserting successor package\n" if $DEBUG;
+  $error = $new->insert(%options);
+  return $error if $error;
+  warn "    disabling superseded package\n" if $DEBUG; 
+  $old->set('successor' => $new->pkgpart);
+  $old->set('disabled' => 'Y');
+  $error = $old->SUPER::replace; # don't change its options/pkg_svc records
+  return $error if $error;
+
+  warn "  propagating changes to family" if $DEBUG;
+  $new->propagate($old);
+}
+
+=item propagate OLD
+
+If any of certain fields have changed from OLD to this package, then,
+for all packages in the same lineage as this one, sets those fields 
+to their values in this package.
+
+=cut
+
+my @propagate_fields = (
+  qw( pkg classnum setup_cost recur_cost taxclass
+  setuptax recurtax pay_weight credit_weight
+  )
+);
+
+sub propagate {
+  my $new = shift;
+  my $old = shift;
+  my %fields = (
+    map { $_ => $new->get($_) }
+    grep { $new->get($_) ne $old->get($_) }
+    @propagate_fields
+  );
+
+  my @part_pkg = qsearch('part_pkg', { 
+      'family_pkgpart' => $new->family_pkgpart 
+  });
+  my @error;
+  foreach my $part_pkg ( @part_pkg ) {
+    my $pkgpart = $part_pkg->pkgpart;
+    next if $pkgpart == $new->pkgpart; # don't modify $new
+    warn "    propagating to pkgpart $pkgpart\n" if $DEBUG;
+    foreach ( keys %fields ) {
+      $part_pkg->set($_, $fields{$_});
+    }
+    # SUPER::replace to avoid changing non-core fields
+    my $error = $part_pkg->SUPER::replace;
+    push @error, "pkgpart $pkgpart: $error"
+      if $error;
+  }
+  join("\n", @error);
+}
+
 =item pkg_comment [ OPTION => VALUE... ]
 
 Returns an (internal) string representing this package.  Currently,
@@ -1277,7 +1398,7 @@ sub _rebless {
   }
   return $self if ref($self) =~ /::$plan$/; #already blessed into plan subclass
   my $class = ref($self). "::$plan";
-  warn "reblessing $self into $class" if $DEBUG;
+  warn "reblessing $self into $class" if $DEBUG > 1;
   eval "use $class;";
   die $@ if $@;
   bless($self, $class) unless $@;
@@ -1410,6 +1531,14 @@ sub _upgrade_data { # class method
     die $error if $error;
   }
 
+  # set family_pkgpart on any packages that don't have it
+  @part_pkg = qsearch('part_pkg', { 'family_pkgpart' => '' });
+  foreach my $part_pkg (@part_pkg) {
+    $part_pkg->set('family_pkgpart' => $part_pkg->pkgpart);
+    my $error = $part_pkg->SUPER::replace;
+    die $error if $error;
+  }
+
   my @part_pkg_option = qsearch('part_pkg_option',
     { 'optionname'  => 'unused_credit',
       'optionvalue' => 1,
index 7668060..4ca78d7 100755 (executable)
@@ -45,6 +45,7 @@ my $select = '*';
 my $orderby = 'pkgpart';
 my %hash = ();
 my $extra_count = '';
+my $family_pkgpart;
 
 if ( $cgi->param('active') ) {
   $orderby = 'num_active DESC';
@@ -77,6 +78,16 @@ if ( $cgi->param('missing_recur_fee') ) {
                     )";
 }
 
+if ( $cgi->param('family') =~ /^(\d+)$/ ) {
+  $family_pkgpart = $1;
+  push @where, "family_pkgpart = $1";
+  # Hiding disabled or one-time charges and limiting by classnum aren't 
+  # very useful in this mode, so all links should still refer back to the 
+  # non-family-limited display.
+  $cgi->param('showdisabled', 1);
+  $cgi->delete('family');
+}
+
 push @where, FS::part_pkg->curuser_pkgs_sql
   unless $acl_edit_global;
 
@@ -209,6 +220,16 @@ push @fields, sub {
                   $part_pkg->part_pkg_discount;
 
   [
+    ( !$family_pkgpart &&
+      $part_pkg->pkgpart == $part_pkg->family_pkgpart ? () : [
+      {
+        'align'=> 'center',
+        'colspan' => 2,
+        'size' => '-1',
+        'data' => '<b>Show all versions</b>',
+        'link' => $p.'browse/part_pkg.cgi?family='.$part_pkg->family_pkgpart,
+      }
+    ] ),
     [
       { data =>$plan,
         align=>'center',
index 3fd9c79..7a1bb00 100755 (executable)
@@ -18,7 +18,7 @@
 <INPUT TYPE="hidden" NAME="payby" VALUE="<% $payby %>">
 <INPUT TYPE="hidden" NAME="paybatch" VALUE="<% $paybatch %>">
 
-<BR><BR>
+<BR>
 
 <% mt('Payment') |h %> 
 <% ntable("#cccccc", 2) %>
     <TD ALIGN="right"><% mt('Check #') |h %></TD>
     <TD COLSPAN=2><INPUT TYPE="text" NAME="payinfo" VALUE="<% $payinfo %>" SIZE=10></TD>
   </TR>
-% } 
+% }
+% elsif ( $payby eq 'CASH' and $conf->exists('require_cash_deposit_info') ) {
+  <TR>
+    <TD ALIGN="right"><% mt('Bank') |h %></TD>
+    <TD COLSPAN=3><INPUT TYPE="text" NAME="bank" VALUE="<% $cgi->param('bank') %>"></TD>
+  </TR>
+  <TR>
+    <TD ALIGN="right"><% mt('Check #') |h %></TD>
+    <TD COLSPAN=2><INPUT TYPE="text" NAME="payinfo" VALUE="<% $payinfo %>" SIZE=10></TD>
+  </TR>
+  <TR>
+    <TD ALIGN="right"><% mt('Teller #') |h %></TD>
+    <TD COLSPAN=2><INPUT TYPE="text" NAME="teller" VALUE="<% $cgi->param('teller') %>" SIZE=10></TD>
+  </TR>
+  <TR>
+    <TD ALIGN="right"><% mt('Depositor') |h %></TD>
+    <TD COLSPAN=3><INPUT TYPE="text" NAME="depositor" VALUE="<% $cgi->param('depositor') %>"></TD>
+  </TR>
+  <TR>
+    <TD ALIGN="right"><% mt('Account #') |h %></TD>
+    <TD COLSPAN=2><INPUT TYPE="text" NAME="account" VALUE="<% $cgi->param('account') %>" SIZE=18></TD>
+  </TR>
+% }
 
 <TR>
 % if ( $link eq 'custnum' || $link eq 'popup' ) { 
index e5edcde..cd07313 100755 (executable)
@@ -24,6 +24,8 @@
               'error_callback'        => $error_callback,
               'field_callback'        => $field_callback,
 
+              'onsubmit'              => 'confirm_submit',
+
               'labels' => { 
                             'pkgpart'          => 'Package Definition',
                             'pkg'              => 'Package (customer-visible)',
@@ -66,6 +68,8 @@
                             },
 
                             { field=>'custom',  type=>'hidden' },
+                            { field=>'family_pkgpart', type=>'hidden' },
+                            { field=>'successor', type=>'hidden' },
 
                             { type => 'columnstart' },
                             
@@ -593,7 +597,7 @@ my $javascript = <<'END';
 
     }
 
-    function aux_planchanged(what) {
+    function aux_planchanged(what) { //?
 
       alert('called!');
       var plan = what.options[what.selectedIndex].value;
@@ -609,9 +613,29 @@ my $javascript = <<'END';
 
     }
 
-  </SCRIPT>
 END
 
+my $warning =
+  'Changing the setup or recurring fee will create a new package definition. '.
+  'Continue?';
+              
+if ( $conf->exists('part_pkg-lineage') ) {
+  $javascript .= "
+    function confirm_submit(f) {
+    
+      var fields = Array('setup_fee','recur_fee');
+      for(var i=0; i < fields.length; i++) {
+          if ( f[fields[i]].value != f[fields[i]].defaultValue ) {
+              return confirm('$warning');
+          }
+      }
+      return true;
+    }
+";
+}
+
+$javascript .= '</SCRIPT>';
+
 tie my %plans, 'Tie::IxHash', %{ FS::part_pkg::plan_info() };
 
 tie my %plan_labels, 'Tie::IxHash',
index e74f902..06f5e64 100755 (executable)
@@ -28,6 +28,8 @@
 %}
 <%init>
 
+my $conf = FS::Conf->new;
+
 $cgi->param('linknum') =~ /^(\d+)$/
   or die "Illegal linknum: ". $cgi->param('linknum');
 my $linknum = $1;
@@ -46,6 +48,7 @@ my $new = new FS::cust_pay ( {
     $_, scalar($cgi->param($_));
   } qw( paid payby payinfo paybatch
         pkgnum discount_term
+        bank depositor account teller
       )
   #} fields('cust_pay')
 } );
@@ -57,6 +60,6 @@ push @rights, 'Post cash payment'  if $new->payby eq 'CASH';
 die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right(\@rights);
 
-my $error = $new->insert( 'manual' => 1 );
+my $error ||= $new->insert( 'manual' => 1 );
 
 </%init>
index f6d2b4b..6a2142f 100644 (file)
@@ -107,7 +107,11 @@ function <% $pre %>county_changed(what, callback) {}
        <% $text_style %>
 >
 
-% if ( !$disable_select ) {
+% if ( $disable_select ) {
+%# avoid JS errors
+<INPUT TYPE="hidden" ID="city_select">
+% }
+% else {
 
 <SELECT NAME     = "<%$pre%>city_select"
         ID       = "<%$pre%>city_select"
index b2b6d96..5312644 100644 (file)
@@ -28,7 +28,7 @@ my $cgi = $opt{'cgi'};
 my $is_report = $opt{'is_report'};
 
 my @curr_tagnum = ();
-if ( $cgi->param('error') ) {
+if ( $cgi && $cgi->param('error') ) {
   @curr_tagnum = $cgi->param('tagnum');
 } elsif ( $opt{'custnum'} ) {
   @curr_tagnum = map $_->tagnum,
index dd9100f..a3eb702 100644 (file)
@@ -9,7 +9,7 @@
   'agentnum'        => $agentnum,
   'sprintf'         => '%u',
   'disable_money'   => 1,
-  'bottom_total'    => (scalar @items > 1 ? 1 : 0),
+  'bottom_total'    => (scalar @items > 1 && !$indirect ? 1 : 0),
   'bottom_link'     => $bottom_link,
   'link_fromparam'  => 'signupdate_begin',
   'link_toparam'    => 'signupdate_end',
@@ -59,25 +59,34 @@ elsif ( $cgi->param('refnum') =~ /^(\d*)$/ ) {
   }
 }
 
+my $indirect = ($cgi->param('indirect') eq 'Y' ? 1 : 0);
+
 my (@items, @labels, @colors, @params, @links);
 
 my $hue = 0;
-my $hue_increment = 125;
+my $hue_increment = 75;
 my @signup_colors;
 
 foreach my $referral (@referral) {
+  my %params = ('refnum' => $referral->refnum) unless $all_referral;
+
   push @items, 'signups';
   push @labels, ( $all_referral ? 'Signups' : $referral->referral );
-  push @params, ( $all_referral ? [] : [ 'refnum' => $referral->refnum ] );
+  push @params, [ %params ];
   push @links, $link . ($all_referral ? '' : "refnum=".$referral->refnum.';');
-  if ( !@signup_colors ) {
-    @signup_colors = Color::Scheme->new
-                        ->from_hue($hue)
-                        ->scheme('analogic')
-                        ->colors;
-    $hue += $hue_increment;
+  # rotate hue for each referral type
+  @signup_colors = Color::Scheme->new->from_hue($hue)->colors;
+  $hue += $hue_increment;
+  push @colors, $signup_colors[0];
+  if ( $indirect ) {
+    push @items, 'signups';
+    push @labels, $all_referral ?
+                  'Referrals' : 
+                  $referral->referral . ' referrals';
+    push @params, [ %params, 'indirect' => 1 ];
+    push @links, '';
+    push @colors, $signup_colors[1];
   }
-  push @colors, shift @signup_colors;
 }
 
 </%init>
index 9d3f500..12dec8e 100644 (file)
           )
 %>
 
+<& /elements/tr-td-label.html, label => 'Show customer referrals' &>
+<TD>
+  <INPUT TYPE="checkbox" NAME="indirect" VALUE="Y">
+</TD>
+</TR>
+
 </TABLE>
 
 <BR><INPUT TYPE="submit" VALUE="Display">
index b5b7161..c453ffa 100644 (file)
@@ -13,6 +13,7 @@
                'cust_main'   => $cust_main,
                'actionlabel' => emt('Enter check payment'),
                'width'       => 392,
+               'height'      => 392,
   &>
 % } 
 
@@ -24,6 +25,7 @@
                'cust_main'   => $cust_main,
                'actionlabel' => emt('Enter cash payment'),
                'width'       => 392,
+               'height'      => 392,
   &>
 % } 
 
index d02f154..f9c8bc1 100644 (file)
 
 % }
 
+% if ( $cust_pay->payby eq 'CASH' && $cust_pay->payinfo ) {
+    <TR>
+      <TD ALIGN="right"><% mt('Bank') |h %></TD>
+      <TD BGCOLOR="#FFFFFF"><B><% $cust_pay->bank %></B></TD>
+    </TR>
+
+    <TR>
+      <TD ALIGN="right"><% mt('Teller #') |h %></TD>
+      <TD BGCOLOR="#FFFFFF"><B><% $cust_pay->teller %></B></TD>
+    </TR>
+
+    <TR>
+      <TD ALIGN="right"><% mt('Depositor') |h %></TD>
+      <TD BGCOLOR="#FFFFFF"><B><% $cust_pay->depositor %></B></TD>
+    </TR>
+
+    <TR>
+      <TD ALIGN="right"><% mt('Account #') |h %></TD>
+      <TD BGCOLOR="#FFFFFF"><B><% $cust_pay->account %></B></TD>
+    </TR>
+% }
+
 % if ( $conf->exists('pkg-balances') && $cust_pay->pkgnum ) {
 %   my $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $cust_pay->pkgnum } );
     <TR>