use FS::Conf;
use FS::Record qw(qsearch);
use FS::agent;
-#use FS::cust_main;
+use FS::cust_main;
@EXPORT_OK = qw ( reconcile_breakage );
# -l: debugging level
sub reconcile_breakage {
- return;
- #nothing yet
+ my %opt = @_;
my $conf = new FS::Conf;
my $days = $conf->config('breakage-days', $agent->agentnum)
or next;
- #find customers w/a balance older than $days (and no activity since)
+ my $since = int( $^T - ($days * 86400) );
- # - 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
+ warn 'searching '. $agent->agent. " for customers with unapplied payments more than $days days old\n"
+ if $opt{'v'};
+
+ #find customers w/negative balance older than $days (and no activity since)
+ # no invoices / payments (/credits/refunds?) newer than $since
+ # (except antother breakage invoice???)
+
+ my $extra_sql = ' AND 0 > '. FS::cust_main->balance_sql;
+ $extra_sql .= " AND ". join(' AND ',
+ map {"
+ NOT EXISTS ( SELECT 1 FROM $_
+ WHERE $_.custnum = cust_main.custnum
+ AND _date >= $since
+ )
+ ";}
+ qw( cust_bill cust_pay ) # cust_credit cust_refund );
+ );
+
+ my @customers = qsearch({
+ 'table' => 'cust_main',
+ 'hashref' => { 'agentnum' => $agent->agentnum,
+ 'payby' => { op=>'!=', value=>'COMP', },
+ },
+ 'extra_sql' => $extra_sql,
+ });
+
+ #and then create a "breakage" charge & invoice for them
+
+ foreach my $cust_main ( @customers ) {
+
+ warn 'reconciling breakage for customer '. $cust_main->custnum.
+ ': '. $cust_main->name. "\n"
+ if $opt{'v'};
+
+ my $error =
+ $cust_main->charge({
+ 'amount' => sprintf('%.2f', 0 - $cust_main->balance ),
+ 'pkg' => 'Breakage',
+ 'comment' => 'breakage reconciliation',
+ 'classnum' => scalar($conf->config('breakage-pkg_class')),
+ 'setuptax' => 'Y',
+ 'bill_now' => 1,
+ })
+ || $cust_main->apply_payments_and_credits;
+
+ if ( $error ) {
+ warn "error charging for breakage reconciliation: $error\n";
+ }
+
+ }
}
+<% header('Configuration set') %>
+ <SCRIPT TYPE="text/javascript">
+% my $n = 0;
+% foreach my $type ( ref($i->type) ? @{$i->type} : $i->type ) {
+ var configCell = window.top.document.getElementById('<% $agentnum. $i->key. $n %>');
+ if ( ! configCell ) {
+ window.top.location.reload();
+ }
+ //alert('found cell ' + configCell);
+% if ( $type eq 'textarea'
+% || $type eq 'editlist'
+% || $type eq 'selectmultiple' ) {
+ configCell.innerHTML =
+ '<font size="-2"><pre>' + "\n" +
+ <% encode_entities(join("\n",
+ map { length($_) > 88 ? substr($_,0,88).'...' : $_ }
+ $conf->config($i->key, $agentnum)
+ ) )
+ |js_string %> +
+ '</pre></font>';
+
+% } elsif ( $type eq 'checkbox' ) {
+% if ( $conf->exists($i->key, $agentnum) ) {
+ configCell.style.backgroundColor = '#00ff00';
+ configCell.innerHTML = 'YES';
+% } else {
+ configCell.style.backgroundColor = '#ff0000';
+ configCell.innerHTML = 'NO';
+% }
+% } elsif ( $type eq 'select' && $i->select_hash ) {
+% my %hash;
+% if ( ref($i->select_hash) eq 'ARRAY' ) {
+% tie %hash, 'Tie::IxHash', '' => '', @{ $i->select_hash };
+% } else {
+% tie %hash, 'Tie::IxHash', '' => '', %{ $i->select_hash };
+% }
+ configCell.innerHTML = <% $conf->exists($i->key, $agentnum) ? $hash{ $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|pkg_class)$/ && ! $i->multiple ) {
+% my $table = $1;
+% my $namecol = $namecol{$table};
+% my $pkey = dbdef->table($table)->primary_key;
+% my $key = $conf->config($i->key, $agentnum);
+% my $record = qsearchs($table, { $pkey => $key });
+% my $value = $record ? "$key: ".$record->$namecol() : $key;
+ configCell.innerHTML = <% $value |js_string %>;
+% } elsif ( $type eq 'select-sub' ) {
+ configCell.innerHTML =
+ <% $conf->config($i->key, $agentnum) |js_string %> + ': ' +
+ <% &{ $i->option_sub }( $conf->config($i->key, $agentnum) ) |js_string %>;
+% } else {
+ //alert('unknown type <% $type %>');
+ window.top.location.reload();
+% }
+
+% $n++;
+% }
+ parent.cClick();
+ </SCRIPT>
+</BODY>
+</HTML>
+<%once>
+#false laziness w/config-view.cgi
+my %namecol = (
+ 'part_svc' => 'svc',
+ 'part_pkg' => 'pkg',
+ 'pkg_class' => 'classname',
+);
+</%once>
<%init>
die "access denied\n"
unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
$conf->delete($_, $agentnum) foreach @delete;
</%init>
-<% header('Configuration set') %>
- <SCRIPT TYPE="text/javascript">
-% my $n = 0;
-% foreach my $type ( ref($i->type) ? @{$i->type} : $i->type ) {
- var configCell = window.top.document.getElementById('<% $agentnum. $i->key. $n %>');
- if ( ! configCell ) {
- window.top.location.reload();
- }
- //alert('found cell ' + configCell);
-% if ( $type eq 'textarea'
-% || $type eq 'editlist'
-% || $type eq 'selectmultiple' ) {
- configCell.innerHTML =
- '<font size="-2"><pre>' + "\n" +
- <% encode_entities(join("\n",
- map { length($_) > 88 ? substr($_,0,88).'...' : $_ }
- $conf->config($i->key, $agentnum)
- ) )
- |js_string %> +
- '</pre></font>';
-
-% } elsif ( $type eq 'checkbox' ) {
-% if ( $conf->exists($i->key, $agentnum) ) {
- configCell.style.backgroundColor = '#00ff00';
- configCell.innerHTML = 'YES';
-% } else {
- configCell.style.backgroundColor = '#ff0000';
- configCell.innerHTML = 'NO';
-% }
-% } elsif ( $type eq 'select' && $i->select_hash ) {
-% my %hash;
-% if ( ref($i->select_hash) eq 'ARRAY' ) {
-% tie %hash, 'Tie::IxHash', '' => '', @{ $i->select_hash };
-% } else {
-% tie %hash, 'Tie::IxHash', '' => '', %{ $i->select_hash };
-% }
- configCell.innerHTML = <% $conf->exists($i->key, $agentnum) ? $hash{ $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|pkg_class)$/ && ! $i->multiple ) {
- configCell.innerHTML =
- <% $conf->config($i->key, $agentnum) |js_string %>
-%# + ': ' +
-%# <% &{ $i->option_sub }( $conf->config($i->key, $agentnum) ) |js_string %>;
-% } elsif ( $type eq 'select-sub' ) {
- configCell.innerHTML =
- <% $conf->config($i->key, $agentnum) |js_string %> + ': ' +
- <% &{ $i->option_sub }( $conf->config($i->key, $agentnum) ) |js_string %>;
-% } else {
- //alert('unknown type <% $type %>');
- window.top.location.reload();
-% }
-
-% $n++;
-% }
- parent.cClick();
- </SCRIPT>
- </BODY></HTML>