[freeside-commits] branch FREESIDE_3_BRANCH updated. e3004bbda87eaba918f5742a7ccb53fe3aa38031

Jonathan Prykop jonathan at 420.am
Mon Feb 23 14:21:57 PST 2015


The branch, FREESIDE_3_BRANCH has been updated
       via  e3004bbda87eaba918f5742a7ccb53fe3aa38031 (commit)
      from  40bb49d12cf25f147b1ce4494b3a7b4c1104b23c (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 e3004bbda87eaba918f5742a7ccb53fe3aa38031
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Mon Feb 23 16:18:19 2015 -0600

    RT#27710: Credit voiding

diff --git a/FS/FS/AccessRight.pm b/FS/FS/AccessRight.pm
index 2494241..e97cc54 100644
--- a/FS/FS/AccessRight.pm
+++ b/FS/FS/AccessRight.pm
@@ -222,6 +222,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',
@@ -234,6 +236,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',
   ],
   
   ###
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 8087304..23bd81d 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -1036,6 +1036,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',
diff --git a/FS/FS/access_right.pm b/FS/FS/access_right.pm
index ea3bd42..b44c21c 100644
--- a/FS/FS/access_right.pm
+++ b/FS/FS/access_right.pm
@@ -248,6 +248,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 badb673..752d842 100644
--- a/FS/FS/cust_credit.pm
+++ b/FS/FS/cust_credit.pm
@@ -348,13 +348,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';
@@ -369,7 +374,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 ac47d95..8d06a72 100644
--- a/FS/FS/cust_credit_void.pm
+++ b/FS/FS/cust_credit_void.pm
@@ -6,6 +6,7 @@ use FS::Record qw(qsearch qsearchs dbh fields);
 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>).
@@ -118,6 +163,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 a603809..4a8c036 100644
--- a/FS/FS/reason_type.pm
+++ b/FS/FS/reason_type.pm
@@ -10,12 +10,14 @@ our %class_name = (
   'C' => 'cancel',
   'R' => 'credit',
   'S' => 'suspend',
+  'X' => 'void credit',
 );
 
 our %class_purpose = (  
   'C' => 'explain why a customer package was cancelled',
   'R' => 'explain why a customer was credited',
   'S' => 'explain why a customer package was suspended',
+  'X' => 'explain why a credit was voided',
 );
 
 =head1 NAME
@@ -46,7 +48,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' 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 0615ff7..8899fb6 100644
--- a/httemplate/elements/menu.html
+++ b/httemplate/elements/menu.html
@@ -345,6 +345,7 @@ tie my %report_credits, 'Tie::IxHash',
   'Credit Report' => [ $fsurl.'search/report_cust_credit.html', 'Credit report (by employee and/or date range)' ],
   '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 8b43dd3..70f21c9 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',  or 'S'
-                           # for cancel, credit, or suspend
+    'reason_class'  => 'C', # currently 'C', 'R', 'S' or 'X'
+                           # for cancel, credit, suspend or void credit
 
     #recommended
     'cgi' => $cgi, #easiest way for things to be properly "sticky" on errors
@@ -170,6 +170,8 @@ if ($class eq 'C') {
   $add_access_right = 'Add on-the-fly suspend reason';
 } elsif ($class eq 'R') {
   $add_access_right = 'Add on-the-fly credit 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 46abfbb..d79d843 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                                    |    1 +
 FS/FS/access_right.pm                              |    3 +
 FS/FS/cust_credit.pm                               |   13 +-
 FS/FS/cust_credit_void.pm                          |   79 +++++++++++
 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, 368 insertions(+), 18 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