[freeside-commits] branch master updated. 7b40e0e045368d350529d78208be0e6124f94b5a

Jonathan Prykop jonathan at 420.am
Mon Feb 16 11:55:33 PST 2015


The branch, master has been updated
       via  7b40e0e045368d350529d78208be0e6124f94b5a (commit)
       via  251d07aa41b6830a0a2f2a51c14fa94586d843c2 (commit)
      from  fa0e442fa889a49a0b7517567cb20beedc31c5aa (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 7b40e0e045368d350529d78208be0e6124f94b5a
Merge: 251d07a fa0e442
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Mon Feb 16 13:53:36 2015 -0600

    Merge branch 'master' of git.freeside.biz:/home/git/freeside


commit 251d07aa41b6830a0a2f2a51c14fa94586d843c2
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Mon Feb 16 13:53:20 2015 -0600

    RT#27710: Credit voiding

diff --git a/FS/FS/AccessRight.pm b/FS/FS/AccessRight.pm
index 121f83c..f395dea 100644
--- a/FS/FS/AccessRight.pm
+++ b/FS/FS/AccessRight.pm
@@ -221,6 +221,8 @@ tie my %rights, 'Tie::IxHash',
     { rightname=>'Backdate credit', desc=>'Enable credits to be posted for days other than today.' },
     'Credit line items', #NEWNEWNEW
     'Apply credit', #NEWNEW
+    'Void credit', #NEWER than things marked NEWNEWNEW
+    'Unvoid credit', #NEWER than things marked NEWNEWNEW
     { rightname=>'Unapply credit', desc=>'Enable "unapplication" of unclosed credits.' }, #aka unapplycredits
     { rightname=>'Delete credit', desc=>'Enable deletion of unclosed credits. Be very careful!  Only delete credits that were data-entry errors, not adjustments.' }, #aka. deletecredits Optionally specify one or more comma-separated email addresses to be notified when a credit is deleted.
     'View refunds',
@@ -233,6 +235,7 @@ tie my %rights, 'Tie::IxHash',
     'Refund Echeck payment',
     'Delete refund', #NEW
     'Add on-the-fly credit reason', #NEW
+    'Add on-the-fly void credit reason',
     'Add on-the-fly refund reason', #NEW
   ],
   
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 54a4680..5333b1a 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -1423,6 +1423,7 @@ sub tables_hashref {
         #void fields
         'void_date',  @date_type,                  '', '', 
         'void_reason', 'varchar', 'NULL', $char_d, '', '', 
+        'void_reasonnum', 'int', 'NULL', '', '', '', 
         'void_usernum',    'int', 'NULL',      '', '', '',
       ],
       'primary_key'  => 'crednum',
@@ -1458,6 +1459,10 @@ sub tables_hashref {
                             table      => 'cust_pkg',
                             references => [ 'pkgnum' ],
                           },
+                          { columns    => [ 'void_reasonnum' ],
+                            table      => 'reason',
+                            references => [ 'reasonnum' ],
+                          },
                           { columns    => [ 'void_usernum' ],
                             table      => 'access_user',
                             references => [ 'usernum' ],
diff --git a/FS/FS/access_right.pm b/FS/FS/access_right.pm
index d5e3b8b..1ea6e49 100644
--- a/FS/FS/access_right.pm
+++ b/FS/FS/access_right.pm
@@ -251,6 +251,9 @@ sub _upgrade_data { # class method
     'List customers' => 'List contacts',
     'Backdate payment' => 'Backdate credit',
     'Generate quotation' => 'Disable quotation',
+    'Void credit' => 'Void credit',
+    'Unvoid credit' => 'Unvoid credit',
+    'Add on-the-fly void credit reason' => 'Add on-the-fly void credit reason',
   );
 
 #  foreach my $old_acl ( keys %onetime ) {
diff --git a/FS/FS/cust_credit.pm b/FS/FS/cust_credit.pm
index deebe27..76fdecb 100644
--- a/FS/FS/cust_credit.pm
+++ b/FS/FS/cust_credit.pm
@@ -382,13 +382,18 @@ adds a record of the voided credit to the cust_credit_void table.
 
 =cut
 
-# yes, false laziness with cust_pay and cust_bill
-# but frankly I don't have time to fix it now
-
 sub void {
   my $self = shift;
   my $reason = shift;
 
+  unless (ref($reason) || !$reason) {
+    $reason = FS::reason->new_or_existing(
+      'class'  => 'X',
+      'type'   => 'Void credit',
+      'reason' => $reason
+    );
+  }
+
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
   local $SIG{QUIT} = 'IGNORE';
@@ -403,7 +408,7 @@ sub void {
   my $cust_credit_void = new FS::cust_credit_void ( {
       map { $_ => $self->get($_) } $self->fields
     } );
-  $cust_credit_void->set('void_reason', $reason);
+  $cust_credit_void->set('void_reasonnum', $reason->reasonnum);
   my $error = $cust_credit_void->insert;
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
diff --git a/FS/FS/cust_credit_void.pm b/FS/FS/cust_credit_void.pm
index f76f794..9c92068 100644
--- a/FS/FS/cust_credit_void.pm
+++ b/FS/FS/cust_credit_void.pm
@@ -1,11 +1,12 @@
 package FS::cust_credit_void; 
-use base qw( FS::otaker_Mixin FS::cust_main_Mixin FS::Record );
+use base qw( FS::otaker_Mixin FS::cust_main_Mixin FS::reason_Mixin FS::Record );
 
 use strict;
 use FS::Record qw(qsearchs); # qsearch qsearchs);
 use FS::CurrentUser;
 use FS::access_user;
 use FS::cust_credit;
+use FS::UID qw( dbh );
 
 =head1 NAME
 
@@ -85,6 +86,7 @@ sub check {
     || $self->ut_numbern('void_date')
     || $self->ut_textn('void_reason')
     || $self->ut_foreign_keyn('void_usernum', 'access_user', 'usernum')
+    || $self->ut_foreign_keyn('void_reasonnum', 'reason', 'reasonnum')
   ;
   return $error if $error;
 
@@ -96,6 +98,49 @@ sub check {
   $self->SUPER::check;
 }
 
+=item unvoid 
+
+"Un-void"s this credit: Deletes the voided credit from the database and adds
+back (but does not re-apply) a normal credit.
+
+=cut
+
+sub unvoid {
+  my $self = shift;
+
+  local $SIG{HUP} = 'IGNORE';
+  local $SIG{INT} = 'IGNORE';
+  local $SIG{QUIT} = 'IGNORE';
+  local $SIG{TERM} = 'IGNORE';
+  local $SIG{TSTP} = 'IGNORE';
+  local $SIG{PIPE} = 'IGNORE';
+
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  my $cust_credit = new FS::cust_credit ( {
+    map { $_ => $self->get($_) } grep { $_ !~ /void/ } $self->fields
+  } );
+  my $error = $cust_credit->insert;
+
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
+
+  $error ||= $self->delete;
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
+
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+  '';
+
+}
+
 =item cust_main
 
 Returns the parent customer object (see L<FS::cust_main>).
@@ -111,6 +156,40 @@ sub void_access_user {
   qsearchs('access_user', { 'usernum' => $self->void_usernum } );
 }
 
+=item void_access_user_name
+
+Returns the voiding employee name.
+
+=cut
+
+sub void_access_user_name {
+  my $self = shift;
+  my $user = $self->void_access_user;
+  return unless $user;
+  return $user->name;
+}
+
+=item void_reason
+
+Returns the text of the associated void credit reason (see L<FS::reason>) for this voided credit.
+
+The reason for the original credit remains accessible through the reason method.
+
+=cut
+
+sub void_reason {
+  my ($self, $value, %options) = @_;
+  my $reason_text;
+  if ( $self->void_reasonnum ) {
+    my $reason = FS::reason->by_key($self->void_reasonnum);
+    $reason_text = $reason->reason;
+  } else { # in case one of these somehow still exists
+    $reason_text = $self->get('void_reason');
+  }
+
+  return $reason_text;
+}
+
 =back
 
 =head1 BUGS
diff --git a/FS/FS/reason_type.pm b/FS/FS/reason_type.pm
index 00ac9a8..17a7167 100644
--- a/FS/FS/reason_type.pm
+++ b/FS/FS/reason_type.pm
@@ -11,6 +11,7 @@ our %class_name = (
   'R' => 'credit',
   'S' => 'suspend',
   'F' => 'refund',
+  'X' => 'void credit',
 );
 
 our %class_purpose = (  
@@ -18,6 +19,7 @@ our %class_purpose = (
   'R' => 'explain why a customer was credited',
   'S' => 'explain why a customer package was suspended',
   'F' => 'explain why a customer was refunded',
+  'X' => 'explain why a credit was voided',
 );
 
 =head1 NAME
@@ -48,7 +50,7 @@ inherits from FS::Record.  The following fields are currently supported:
 
 =item typenum - primary key
 
-=item class - currently 'C', 'R',  or 'S' for cancel, credit, or suspend 
+=item class - currently 'C', 'R', 'S', 'F' or 'X' for cancel, credit, suspend, refund or void credit 
 
 =item type - name of the type of reason
 
diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html
index 7d5d4f3..fe59ec5 100644
--- a/httemplate/elements/menu.html
+++ b/httemplate/elements/menu.html
@@ -340,6 +340,7 @@ tie my %report_credits, 'Tie::IxHash',
   'Credit package source detail' => [ $fsurl.'search/report_cust_credit_source_bill_pkg.html', 'Line-item detail for triggered package credits' ],
   'Credit application detail' => [ $fsurl.'search/report_cust_credit_bill_pkg.html', 'Line item application detail' ],
   'Unapplied Credits' => [ $fsurl.'search/report_cust_credit.html?unapplied=1', 'Unapplied credit report (by type and/or date range)' ],
+  'Voided Credits' => [ $fsurl.'search/report_cust_credit_void.html', 'Voided credit report (by employee and/or date range)' ],
 ;
 
 tie my %report_refunds, 'Tie::IxHash',
diff --git a/httemplate/elements/tr-select-reason.html b/httemplate/elements/tr-select-reason.html
index 14bb6e8..3565975 100755
--- a/httemplate/elements/tr-select-reason.html
+++ b/httemplate/elements/tr-select-reason.html
@@ -6,8 +6,8 @@ Example:
 
     #required 
     'field'         => 'reasonnum',
-    'reason_class'  => 'C', # currently 'C', 'R', 'F',  or 'S'
-                           # for cancel, credit, refund, or suspend
+    'reason_class'  => 'C', # currently 'C', 'R', 'F', 'S' or 'X'
+                           # for cancel, credit, refund, suspend or void credit
 
     #recommended
     'cgi' => $cgi, #easiest way for things to be properly "sticky" on errors
@@ -173,6 +173,8 @@ if ($class eq 'C') {
   $add_access_right = 'Add on-the-fly credit reason';
 } elsif ($class eq 'F') {
   $add_access_right = 'Add on-the-fly refund reason';
+} elsif ($class eq 'X') {
+  $add_access_right = 'Add on-the-fly void credit reason';
 } else {
   die "illegal class: $class";
 }
diff --git a/httemplate/misc/unvoid-cust_credit_void.cgi b/httemplate/misc/unvoid-cust_credit_void.cgi
new file mode 100755
index 0000000..5f8d9d5
--- /dev/null
+++ b/httemplate/misc/unvoid-cust_credit_void.cgi
@@ -0,0 +1,21 @@
+%if ( $error ) {
+%  errorpage($error);
+%} else {
+<% $cgi->redirect($p. "view/cust_main.cgi?custnum=". $custnum .";show=payment_history") %>
+%}
+<%init>
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Unvoid credit');
+
+#untaint crednum
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/ || die "Illegal crednum";
+my $crednum = $1;
+
+my $cust_credit_void = qsearchs('cust_credit_void', { 'crednum' => $crednum } );
+my $custnum = $cust_credit_void->custnum;
+
+my $error = $cust_credit_void->unvoid;
+
+</%init>
diff --git a/httemplate/misc/void-cust_credit.html b/httemplate/misc/void-cust_credit.html
new file mode 100755
index 0000000..1e71f00
--- /dev/null
+++ b/httemplate/misc/void-cust_credit.html
@@ -0,0 +1,74 @@
+%if ( $success ) {
+<& /elements/header-popup.html, mt("Credit voided") &>
+  <SCRIPT TYPE="text/javascript">
+    window.top.location.reload();
+  </SCRIPT>
+  </BODY>
+</HTML>
+%} else {
+<& /elements/header-popup.html, mt('Void credit')  &>
+
+<& /elements/error.html &>
+
+<P ALIGN="center"><B><% mt('Void this credit?') |h %></B>
+
+<FORM action="<% ${p} %>misc/void-cust_credit.html">
+<INPUT TYPE="hidden" NAME="crednum" VALUE="<% $crednum %>">
+
+<TABLE BGCOLOR="#cccccc" BORDER="0" CELLSPACING="2" STYLE="margin-left:auto; margin-right:auto">
+<& /elements/tr-select-reason.html,
+             'field'          => 'reasonnum',
+             'reason_class'   => 'X',
+             'cgi'            => $cgi
+&>
+</TABLE>
+
+<BR>
+<P ALIGN="CENTER">
+<INPUT TYPE="submit" NAME="confirm_void_credit" VALUE="<% mt('Void credit') |h %>"> 
+        
+<INPUT TYPE="BUTTON" VALUE="<% mt("Don't void credit") |h %>" onClick="parent.cClick();"> 
+
+</FORM>
+</BODY>
+</HTML>
+
+%}
+<%init>
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Void credit');
+
+#untaint crednum
+my $crednum = $cgi->param('crednum');
+if ($crednum) {
+  $crednum =~ /^(\d+)$/ || die "Illegal crednum";
+} else {
+  my($query) = $cgi->keywords;
+  $query =~ /^(\d+)/ || die "Illegal crednum";
+  $crednum = $1;
+}
+
+my $cust_credit = qsearchs('cust_credit',{'crednum'=>$crednum}) || die "Credit not found";
+
+my $success = 0;
+if ($cgi->param('confirm_void_credit')) {
+
+  #untaint reasonnum / create new reason
+  my ($reasonnum, $error) = $m->comp('process/elements/reason');
+  if (!$reasonnum) {
+    $error = 'Reason required';
+  } else {
+    my $reason = qsearchs('reason', { 'reasonnum' => $reasonnum })
+      || die "Reason num $reasonnum not found in database";
+	$error = $cust_credit->void($reason) unless $error;
+  }
+
+  if ($error) {
+    $cgi->param('error',$error);
+  } else {
+    $success = 1;
+  }
+}
+
+</%init>
diff --git a/httemplate/search/cust_credit_void.html b/httemplate/search/cust_credit_void.html
new file mode 100755
index 0000000..18731d1
--- /dev/null
+++ b/httemplate/search/cust_credit_void.html
@@ -0,0 +1,141 @@
+<& elements/search.html,
+                 'title'       => $title,
+                 'name'        => emt('credits'),
+                 'query'       => $sql_query,
+                 'count_query' => $count_query,
+                 'header'      => \@header,
+                 'fields'      => \@fields,
+                 'sort_fields' => \@sort_fields,
+                 'align' => $align,
+                 'links' => \@links,
+                 'color' => \@color,
+                 'style' => \@style,
+&>
+<%init>
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
+
+my $money_char = FS::Conf->new->config('money_char') || '$';
+
+my $title = emt('Voided Credit Search Results');
+
+my $clink = sub {
+  my $cust_bill = shift;
+  $cust_bill->cust_main_custnum
+    ? [ "${p}view/cust_main.cgi?", 'custnum' ]
+    : '';
+};
+
+my %void_access_users;
+
+my (@header, @fields, @sort_fields, $align, @links, @color, @style);
+$align = '';
+
+#amount
+push @header, emt('Amount');
+push @fields, sub { $money_char .sprintf('%.2f', shift->amount) };
+push @sort_fields, 'amount';
+$align .= 'r';
+push @links, '';
+push @color, '';
+push @style, '';
+
+push @header, emt('Void Date'),
+              emt('Void By'),
+              emt('Void Reason'),
+              emt('Date'), 
+              emt('By'),
+              emt('Reason'),
+              FS::UI::Web::cust_header(),
+              ;
+push @fields, sub { time2str('%b %d %Y', shift->void_date ) },
+              'void_access_user_name',
+              'void_reason',
+              sub { time2str('%b %d %Y', shift->_date ) },
+              'otaker',
+              'reason',
+              \&FS::UI::Web::cust_fields,
+              ;
+push @sort_fields, 'void_date',
+                   'void_usernum',                #not ideal, but at least groups them together
+                   'void_reasonnum, void_reason', #ditto
+                   '_date',
+                   'usernum',                     #ditto
+                   'reasonnum, reason',           #ditto 
+                   FS::UI::Web::cust_sort_fields();
+$align .= 'rllrll'.FS::UI::Web::cust_aligns();
+push @links,  '',
+              '',
+              '',
+              '',
+              '',
+              '',
+              ( map { $_ ne 'Cust. Status' ? $clink : '' }
+                         FS::UI::Web::cust_header()
+                   ),
+              ;
+push @color,  '',
+              '',
+              '',
+              '',
+              '',
+              '',
+              FS::UI::Web::cust_colors(),
+              ;
+push @style,  '',
+              '',
+              '',
+              '',
+              '',
+              '',
+              FS::UI::Web::cust_styles(),
+              ;
+
+my @search = ();
+my $addl_from = '';
+
+# note that cgi field is usernum, but we're actually searching void_usernum
+# because true laziness with tr-select-user in report_cust_credit_void.html
+if ( $cgi->param('usernum') =~ /^(\d+)$/ ) {
+  push @search, "cust_credit_void.void_usernum = $1";
+}
+
+if ( $cgi->param('agentnum') && $cgi->param('agentnum') =~ /^(\d+)$/ ) {
+  push @search, "agentnum = $1";
+  my $agent = qsearchs('agent', { 'agentnum' => $1 } );
+  die "unknown agentnum $1" unless $agent;
+  $title = $agent->agent. " $title";
+}
+
+my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi);
+push @search, "void_date >= $beginning ",
+              "void_date <= $ending";
+
+push @search, FS::UI::Web::parse_lt_gt($cgi, 'amount' );
+
+#here is the agent virtualization
+push @search, $FS::CurrentUser::CurrentUser->agentnums_sql(table=>'cust_main');
+
+my @select = (
+    'cust_credit_void.*',
+    'cust_main.custnum as cust_main_custnum',
+    FS::UI::Web::cust_sql_fields(),
+);
+
+my $where = 'WHERE '. join(' AND ', @search);
+
+my $count_query = 'SELECT COUNT(*), SUM(amount) ';
+$count_query .= 'FROM cust_credit_void'. 
+                  $addl_from. FS::UI::Web::join_cust_main('cust_credit_void').
+                  $where;
+
+my $sql_query   = {
+  'table'     => 'cust_credit_void',
+  'select'    => join(', ', at select),
+  'hashref'   => {},
+  'extra_sql' => $where,
+  'addl_from' => $addl_from. FS::UI::Web::join_cust_main('cust_credit_void')
+};
+
+</%init>
diff --git a/httemplate/search/report_cust_credit_void.html b/httemplate/search/report_cust_credit_void.html
new file mode 100644
index 0000000..e967080
--- /dev/null
+++ b/httemplate/search/report_cust_credit_void.html
@@ -0,0 +1,50 @@
+<& /elements/header.html, mt($title) &>
+
+<FORM ACTION="cust_credit_void.html" METHOD="GET">
+<INPUT TYPE="hidden" NAME="magic" VALUE="_date">
+
+<TABLE>
+
+  <& /elements/tr-select-user.html,
+                'label'       => emt('Credit voids by employee: '),
+                'access_user' => \%access_user,
+  &>
+
+  <& /elements/tr-select-agent.html,
+                 'curr_value'    => scalar( $cgi->param('agentnum') ),
+                 'label'         => emt('for agent: '),
+                 'disable_empty' => 0,
+  &>
+
+  <& /elements/tr-input-beginning_ending.html &>
+
+  <& /elements/tr-input-lessthan_greaterthan.html,
+                'label' => emt('Amount'),
+                'field' => 'amount',
+  &>
+
+</TABLE>
+
+<BR>
+<INPUT TYPE="submit" VALUE="<% mt('Get Report') |h %>">
+
+</FORM>
+
+<& /elements/footer.html &>
+
+<%init>
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
+
+my $sth = dbh->prepare("SELECT DISTINCT usernum FROM cust_credit_void")
+  or die dbh->errstr;
+$sth->execute or die $sth->errstr;
+my @usernum = map $_->[0], @{$sth->fetchall_arrayref};
+my %access_user =
+  map { $_ => qsearchs('access_user',{'usernum'=>$_})->username }
+      @usernum;
+
+my $title = 'Voided credit report';
+
+</%init>
diff --git a/httemplate/view/cust_main/payment_history.html b/httemplate/view/cust_main/payment_history.html
index 0aacb0a..04e427f 100644
--- a/httemplate/view/cust_main/payment_history.html
+++ b/httemplate/view/cust_main/payment_history.html
@@ -425,7 +425,7 @@ my %opt = (
         'Apply payment', 'Refund credit card payment', 'Refund Echeck payment',
         'Credit card void', 'Echeck void', 'Void payments', 'Unvoid payments',
         'Delete payment', 'Unapply payment',
-        'Apply credit', 'Delete credit', 'Unapply credit',
+        'Apply credit', 'Delete credit', 'Unapply credit', 'Void credit', 'Unvoid credit',
         'Delete refund',
         'Billing event reports', 'View customer billing events',
       )
diff --git a/httemplate/view/cust_main/payment_history/credit.html b/httemplate/view/cust_main/payment_history/credit.html
index 941180e..3eed833 100644
--- a/httemplate/view/cust_main/payment_history/credit.html
+++ b/httemplate/view/cust_main/payment_history/credit.html
@@ -1,4 +1,4 @@
-<% $credit. ' '. $reason. $desc. $change_pkg. $apply. $delete. $unapply %>
+<% $credit. ' '. $reason. $desc. $change_pkg. $apply. $delete. $unapply. $void %>
 <%init>
 
 my( $cust_credit, %opt ) = @_;
@@ -126,6 +126,18 @@ if ( $apply && $opt{'pkg-balances'} && $cust_credit->pkgnum ) {
    ')';
 }
 
+my $void = '';
+$void = ' ('.
+               include( '/elements/popup_link.html',
+                    'label'    => emt('void'),
+                    'action'   => "${p}misc/void-cust_credit.html?".
+                                  $cust_credit->crednum,
+                    'actionlabel' => emt('Void credit'),
+                ).
+          ')'
+  if $cust_credit->closed !~ /^Y/i
+  && $opt{'Void credit'};
+
 my $delete = '';
 $delete = areyousure_link("${p}misc/delete-cust_credit.cgi?".$cust_credit->crednum,
                             emt('Are you sure you want to delete this credit?'),
diff --git a/httemplate/view/cust_main/payment_history/voided_credit.html b/httemplate/view/cust_main/payment_history/voided_credit.html
index 9ff4c1b..3515d85 100644
--- a/httemplate/view/cust_main/payment_history/voided_credit.html
+++ b/httemplate/view/cust_main/payment_history/voided_credit.html
@@ -8,16 +8,26 @@
 % }
 <% $void_reason |h %>
 </I>
+<% $unvoid %>
 <%init>
 
 my( $cust_credit_void, %opt ) = @_;
 
 my $date_format = $opt{'date_format'} || '%m/%d/%Y';
 
-#my $unvoid = ''; # not yet available
+my $unvoid = '';
+$unvoid = areyousure_link("${p}misc/unvoid-cust_credit_void.cgi?".$cust_credit_void->crednum,
+                            emt('Are you sure you want to unvoid this credit?'),
+                            '',
+                            emt('unvoid')
+                          )
+  if $cust_credit_void->closed !~ /^Y/i
+  && $opt{'Unvoid credit'};
+
 my $reason = $cust_credit_void->reason;
 $reason = " ($reason)" if $reason;
 
 my $void_reason = $cust_credit_void->void_reason;
 $void_reason = " ($void_reason)" if $void_reason;
 </%init>
+

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/AccessRight.pm                               |    3 +
 FS/FS/Schema.pm                                    |    5 +
 FS/FS/access_right.pm                              |    3 +
 FS/FS/cust_credit.pm                               |   13 +-
 FS/FS/cust_credit_void.pm                          |   81 ++++++++++-
 FS/FS/reason_type.pm                               |    4 +-
 httemplate/elements/menu.html                      |    1 +
 httemplate/elements/tr-select-reason.html          |    6 +-
 httemplate/misc/unvoid-cust_credit_void.cgi        |   21 +++
 httemplate/misc/void-cust_credit.html              |   74 ++++++++++
 httemplate/search/cust_credit_void.html            |  141 ++++++++++++++++++++
 ...st_credit.html => report_cust_credit_void.html} |   12 +-
 httemplate/view/cust_main/payment_history.html     |    2 +-
 .../view/cust_main/payment_history/credit.html     |   14 +-
 .../cust_main/payment_history/voided_credit.html   |   12 +-
 15 files changed, 373 insertions(+), 19 deletions(-)
 create mode 100755 httemplate/misc/unvoid-cust_credit_void.cgi
 create mode 100755 httemplate/misc/void-cust_credit.html
 create mode 100755 httemplate/search/cust_credit_void.html
 copy httemplate/search/{report_cust_credit.html => report_cust_credit_void.html} (76%)




More information about the freeside-commits mailing list