(start of) reconcile breakage from stale accounts, RT#6407
authorivan <ivan>
Tue, 3 Nov 2009 03:13:46 +0000 (03:13 +0000)
committerivan <ivan>
Tue, 3 Nov 2009 03:13:46 +0000 (03:13 +0000)
FS/FS/Conf.pm
FS/FS/Cron/breakage.pm [new file with mode: 0644]
FS/bin/freeside-daily
httemplate/config/config-process.cgi
httemplate/config/config-view.cgi
httemplate/config/config.cgi
httemplate/elements/tr-select-part_pkg.html

index 3887293..1542efe 100644 (file)
@@ -1033,19 +1033,7 @@ worry that config_items is freeside-specific and icky.
     'key'         => 'finance_pkgclass',
     'section'     => 'billing',
     'description' => 'The package class for finance charges',
     'key'         => 'finance_pkgclass',
     'section'     => 'billing',
     'description' => 'The package class for finance charges',
-    'type'        => 'select-sub',
-    'options_sub' => sub { require FS::Record;
-                           require FS::pkg_class;
-                           map { $_->classnum => $_->classname }
-                               FS::Record::qsearch('pkg_class', {} );
-                        },
-    'option_sub'  => sub { require FS::Record;
-                           require FS::pkg_class;
-                           my $pkg_class = FS::Record::qsearchs(
-                            'pkg_class', { 'classnum'=>shift }
-                          );
-                           $pkg_class ? $pkg_class->classname : '';
-                        },
+    'type'        => 'select-pkg_class',
   },
 
   { 
   },
 
   { 
@@ -1540,38 +1528,14 @@ worry that config_items is freeside-specific and icky.
     'key'         => 'signup_server-classnum2',
     'section'     => '',
     'description' => 'Package Class for first optional purchase',
     'key'         => 'signup_server-classnum2',
     'section'     => '',
     'description' => 'Package Class for first optional purchase',
-    'type'        => 'select-sub',
-    'options_sub' => sub { require FS::Record;
-                           require FS::pkg_class;
-                           map { $_->classnum => $_->classname }
-                               FS::Record::qsearch('pkg_class', {} );
-                        },
-    'option_sub'  => sub { require FS::Record;
-                           require FS::pkg_class;
-                           my $pkg_class = FS::Record::qsearchs(
-                            'pkg_class', { 'classnum'=>shift }
-                          );
-                           $pkg_class ? $pkg_class->classname : '';
-                        },
+    'type'        => 'select-pkg_class',
   },
 
   {
     'key'         => 'signup_server-classnum3',
     'section'     => '',
     'description' => 'Package Class for second optional purchase',
   },
 
   {
     'key'         => 'signup_server-classnum3',
     'section'     => '',
     'description' => 'Package Class for second optional purchase',
-    'type'        => 'select-sub',
-    'options_sub' => sub { require FS::Record;
-                           require FS::pkg_class;
-                           map { $_->classnum => $_->classname }
-                               FS::Record::qsearch('pkg_class', {} );
-                        },
-    'option_sub'  => sub { require FS::Record;
-                           require FS::pkg_class;
-                           my $pkg_class = FS::Record::qsearchs(
-                            'pkg_class', { 'classnum'=>shift }
-                          );
-                           $pkg_class ? $pkg_class->classname : '';
-                        },
+    'type'        => 'select-pkg_class',
   },
 
   {
   },
 
   {
@@ -3245,6 +3209,22 @@ worry that config_items is freeside-specific and icky.
     'type'        => 'checkbox',
   },
 
     'type'        => 'checkbox',
   },
 
+  {
+    'key'         => 'breakage-days',
+    'section'     => 'billing',
+    'description' => 'If set to a number of days, after an account goes that long without activity, recognizes any outstanding payments and credits as "breakage" by creating a breakage charge and invoice.',
+    'type'        => 'text',
+    'per_agent'   => 1,
+  },
+
+  {
+    'key'         => 'breakage-pkg_class',
+    'section'     => 'billing',
+    'description' => 'Package class to use for breakage reconciliation.',
+    'type'        => 'select-pkg_class',
+  },
+
+
   { key => "apacheroot", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
   { key => "apachemachine", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
   { key => "apachemachines", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
   { key => "apacheroot", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
   { key => "apachemachine", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
   { key => "apachemachines", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
diff --git a/FS/FS/Cron/breakage.pm b/FS/FS/Cron/breakage.pm
new file mode 100644 (file)
index 0000000..6312667
--- /dev/null
@@ -0,0 +1,41 @@
+package FS::Cron::breakage;
+
+use strict;
+use base 'Exporter';
+use vars qw( @EXPORT_OK );
+use FS::Conf;
+use FS::Record qw(qsearch);
+use FS::agent;
+#use FS::cust_main;
+
+@EXPORT_OK = qw ( reconcile_breakage );
+
+#freeside-daily %opt
+# -v: enable debugging
+# -l: debugging level
+
+sub reconcile_breakage {
+  return;
+  #nothing yet
+
+  my $conf = new FS::Conf;
+
+  foreach my $agent (qsearch('agent', {})) {
+
+    my $days = $conf->config('breakage-days', $agent->agentnum)
+      or next;
+
+    #find customers w/a balance older than $days (and no activity since)
+
+    # - do a one time charge in the total amount of old unapplied payments.
+    #     'pkg' => 'Breakage', #or whatever.
+    #     'setuptax' => 'Y',
+    #     'classnum' => scalar($conf->config('breakage-pkg_class')),
+    # - use the new $cust_main->charge( 'bill_now' => 1 ) option to generate an invoice, etc.
+    # - apply_payments_and_credits
+
+  }
+
+}
+
+1;
index 728fa96..04073d4 100755 (executable)
@@ -16,6 +16,10 @@ use FS::Cron::bill qw(bill);
 bill(%opt);
 
 #you can skip this just by not having the config
 bill(%opt);
 
 #you can skip this just by not having the config
+use FS::Cron::breakage qw(reconcile_breakage);
+reconcile_breakage(%opt);
+
+#you can skip this just by not having the config
 use FS::Cron::upload qw(upload);
 upload(%opt);
 
 use FS::Cron::upload qw(upload);
 upload(%opt);
 
index a241de8..50db40c 100644 (file)
@@ -43,14 +43,15 @@ foreach my $type ( ref($i->type) ? @{$i->type} : $i->type ) {
     }
   } elsif (
     $type =~ /^(editlist|selectmultiple)$/
     }
   } elsif (
     $type =~ /^(editlist|selectmultiple)$/
-    or ( $type =~ /^select(-(sub|part_svc|part_pkg))?$/ || $i->multiple )
+    or ( $type =~ /^select(-(sub|part_svc|part_pkg|pkg_class))?$/
+         || $i->multiple )
   ) {
     if ( scalar(@{[ $cgi->param($i->key.$n) ]}) ) {
       $conf->set($i->key, join("\n", @{[ $cgi->param($i->key.$n) ]} ), $agentnum);
     } else {
       $conf->delete($i->key, $agentnum);
     }
   ) {
     if ( scalar(@{[ $cgi->param($i->key.$n) ]}) ) {
       $conf->set($i->key, join("\n", @{[ $cgi->param($i->key.$n) ]} ), $agentnum);
     } else {
       $conf->delete($i->key, $agentnum);
     }
-  } elsif ( $type =~ /^(text|select(-(sub|part_svc|part_pkg))?)$/ ) {
+  } elsif ( $type =~ /^(text|select(-(sub|part_svc|part_pkg|pkg_class))?)$/ ) {
     if ( $cgi->param($i->key.$n) ne '' ) {
       $conf->set($i->key, $cgi->param($i->key.$n), $agentnum);
     } else {
     if ( $cgi->param($i->key.$n) ne '' ) {
       $conf->set($i->key, $cgi->param($i->key.$n), $agentnum);
     } else {
@@ -104,7 +105,7 @@ $conf->delete($_, $agentnum) foreach @delete;
 
 %     } elsif ( $type eq 'text' || $type eq 'select' ) {
         configCell.innerHTML = <% $conf->exists($i->key, $agentnum) ? $conf->config($i->key, $agentnum) : '' |js_string %>;
 
 %     } elsif ( $type eq 'text' || $type eq 'select' ) {
         configCell.innerHTML = <% $conf->exists($i->key, $agentnum) ? $conf->config($i->key, $agentnum) : '' |js_string %>;
-%     } elsif ( $type =~ /^select-(part_svc|part_pkg)$/ && ! $i->multiple ) {
+%     } elsif ( $type =~ /^select-(part_svc|part_pkg|pkg_class)$/ && ! $i->multiple ) {
         configCell.innerHTML =
           <% $conf->config($i->key, $agentnum) |js_string %>
 %# + ': ' +
         configCell.innerHTML =
           <% $conf->config($i->key, $agentnum) |js_string %>
 %# + ': ' +
index 51535d7..856a2ea 100644 (file)
@@ -209,7 +209,7 @@ Click on a configuration value to change it.
               </td>
             </tr>
 
               </td>
             </tr>
 
-%   } elsif ( $type =~ /^select-(part_svc|part_pkg)$/ ) {
+%   } elsif ( $type =~ /^select-(part_svc|part_pkg|pkg_class)$/ ) {
 %     my @keys = $conf->config($i->key, $agentnum);
 
             <tr>
 %     my @keys = $conf->config($i->key, $agentnum);
 
             <tr>
index 45d77ff..c2b3e6d 100644 (file)
@@ -308,7 +308,7 @@ my @config_items = $conf->config_items;
 my %confitems = map { $_->key => $_ } @config_items;
 
 my %element_types = map { $_ => 1 } qw(
 my %confitems = map { $_->key => $_ } @config_items;
 
 my %element_types = map { $_ => 1 } qw(
-  select-part_svc select-part_pkg
+  select-part_svc select-part_pkg select-pkg_class
 );
 
 </%once>
 );
 
 </%once>
index db9afd2..88653f4 100644 (file)
@@ -1,7 +1,7 @@
 % if ( $opt{'part_pkg'} && scalar(@{ $opt{'part_pkg'} }) == 0 ) { 
 %   unless ( $opt{'js_only'} ) {
 
 % if ( $opt{'part_pkg'} && scalar(@{ $opt{'part_pkg'} }) == 0 ) { 
 %   unless ( $opt{'js_only'} ) {
 
-      <INPUT TYPE="hidden" NAME="<% $opt{'field'} || 'pkgpart' %>" VALUE="">
+      <INPUT TYPE="hidden" NAME="<% $opt{'element_name'} || $opt{'field'} || 'pkgpart' %>" VALUE="">
 
 %   }
 %
 
 %   }
 %