[freeside-commits] branch FREESIDE_4_BRANCH updated. 7de0e4d649d2c9930720363c858f64b4f2f62efc

Jonathan Prykop jonathan at 420.am
Tue Feb 23 07:11:19 PST 2016


The branch, FREESIDE_4_BRANCH has been updated
       via  7de0e4d649d2c9930720363c858f64b4f2f62efc (commit)
       via  5fb8b90c0358e69523075a9dc8a153cd431a72db (commit)
       via  1bb85d2484b3d9f45c2b1142951503ff1c54e2e9 (commit)
      from  7d44517cf03a15c0b65b77c01720f3758374af22 (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 7de0e4d649d2c9930720363c858f64b4f2f62efc
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Tue Feb 23 09:04:46 2016 -0600

    RT#39586 Manual check refunds cannot be unapplied [nbsp]

diff --git a/httemplate/view/cust_main/payment_history/credit.html b/httemplate/view/cust_main/payment_history/credit.html
index da8ca2e..1e7a7df 100644
--- a/httemplate/view/cust_main/payment_history/credit.html
+++ b/httemplate/view/cust_main/payment_history/credit.html
@@ -45,7 +45,7 @@ if (    scalar(@cust_credit_bill)   == 0
     if ( $opt{total_unapplied_refunds} > 0 ) {
       $apply.= ' ('.
                include( '/elements/popup_link.html',
-                          'label'    => emt('apply refund'),
+                          'label'    => emt('apply').' '.emt('refund'),
                           'action'   => "${p}edit/cust_credit_refund.cgi?".
                                         $cust_credit->crednum,
                           'actionlabel' => emt('Apply credit to refund'),
@@ -100,7 +100,7 @@ if (    scalar(@cust_credit_bill)   == 0
       if ( $opt{total_unapplied_refunds} > 0 ) {
         $apply.= ' ('.
                  include( '/elements/popup_link.html',
-                            'label'       => emt('apply refund'),
+                            'label'       => emt('apply').' '.emt('refund'),
                             'action'      => "${p}edit/cust_credit_refund.cgi?".
                                              $cust_credit->crednum,
                             'actionlabel' => emt('Apply credit to refund'),
@@ -150,7 +150,7 @@ if ($opt{'Unapply credit'} && !$cust_credit->closed) {
   $unapply .= areyousure_link("${p}misc/unapply-cust_credit_refund.cgi?".$cust_credit->crednum,
                                emt('Are you sure you want to unapply this credit from refunds?'),
                                emt('Keep this credit, but dissociate it from the refunds it is currently applied to'),
-                               emt('unapply refunds')
+                               emt('unapply').' '.emt('refunds')
                              )
     if $cust_credit->refund_to_unapply;
 }
diff --git a/httemplate/view/cust_main/payment_history/payment.html b/httemplate/view/cust_main/payment_history/payment.html
index 8faed3c..f65c903 100644
--- a/httemplate/view/cust_main/payment_history/payment.html
+++ b/httemplate/view/cust_main/payment_history/payment.html
@@ -103,7 +103,7 @@ if ($unapplied > 0) {
     if ( $opt{total_unapplied_refunds} > 0 ) {
       $apply.= ' ('.
                include( '/elements/popup_link.html',
-                          'label'       => emt('apply refund'),
+                          'label'       => emt('apply').' '.emt('refund'),
                           'action'      => "${p}edit/cust_pay_refund.cgi?".
                                            $cust_pay->paynum,
                           'actionlabel' => emt('Apply payment to refund'),
@@ -207,7 +207,7 @@ if ($opt{'Unapply payment'} && !$cust_pay->closed) {
   $unapply .= areyousure_link("${p}misc/unapply-cust_pay_refund.cgi?".$cust_pay->paynum,
                                emt('Are you sure you want to unapply this payment from refunds?'),
                                emt('Keep this payment, but dissociate it from the refunds it is currently applied to'),
-                               emt('unapply refunds')
+                               emt('unapply').' '.emt('refunds')
                              )
     if $cust_pay->refund_to_unapply;
 }

commit 5fb8b90c0358e69523075a9dc8a153cd431a72db
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Mon Feb 22 17:14:07 2016 -0600

    RT#39586 Manual check refunds cannot be unapplied [source_paynum field, reason bug fixes, link text]

diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 85c8519..be12c03 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -3077,6 +3077,7 @@ sub tables_hashref {
 	'paymask', 'varchar', 'NULL', $char_d, '', '', 
         'paybatch',     'varchar',   'NULL', $char_d, '', '', 
         'closed',    'char', 'NULL', 1, '', '', 
+        'source_paynum', 'int', 'NULL', '', '', '', # link to cust_payby, to prevent unapply of gateway-generated refunds
         # credit card/EFT fields (formerly in paybatch)
         'gatewaynum',     'int', 'NULL', '', '', '', # payment_gateway FK
         'processor',  'varchar', 'NULL', $char_d, '', '', # module name
@@ -3099,6 +3100,10 @@ sub tables_hashref {
                           { columns    => [ 'gatewaynum' ],
                             table      => 'payment_gateway',
                           },
+                          { columns    => [ 'source_paynum' ],
+                            table      => 'cust_pay',
+                            references => [ 'paynum' ],
+                          },
                         ],
     },
 
diff --git a/FS/FS/cust_credit.pm b/FS/FS/cust_credit.pm
index a598b37..4be4b17 100644
--- a/FS/FS/cust_credit.pm
+++ b/FS/FS/cust_credit.pm
@@ -1045,7 +1045,7 @@ sub refund_to_unapply {
     'table'   => 'cust_credit_refund',
     'hashref' => { 'crednum' => $self->crednum },
     'addl_from' => 'LEFT JOIN cust_refund USING (refundnum)',
-    'extra_sql' => "AND (cust_refund.closed = '' OR cust_refund.closed IS NULL)",
+    'extra_sql' => "AND cust_refund.closed IS NULL AND cust_refund.source_paynum IS NULL",
   });
 }
 
diff --git a/FS/FS/cust_main/Billing_Realtime.pm b/FS/FS/cust_main/Billing_Realtime.pm
index 3396ec4..747f4af 100644
--- a/FS/FS/cust_main/Billing_Realtime.pm
+++ b/FS/FS/cust_main/Billing_Realtime.pm
@@ -1323,14 +1323,14 @@ L<http://420.am/business-onlinepayment> for supported gateways.
 
 Available methods are: I<CC>, I<ECHECK> and I<LEC>
 
-Available options are: I<amount>, I<reason>, I<paynum>, I<paydate>
+Available options are: I<amount>, I<reasonnum>, I<paynum>, I<paydate>
 
 Most gateways require a reference to an original payment transaction to refund,
 so you probably need to specify a I<paynum>.
 
 I<amount> defaults to the original amount of the payment if not specified.
 
-I<reason> specifies a reason for the refund.
+I<reasonnum> specified an existing refund reason for the refund
 
 I<paydate> specifies the expiration date for a credit card overriding the
 value from the customer record or the payment record. Specified as yyyy-mm-dd
@@ -1373,6 +1373,8 @@ sub realtime_refund_bop {
     warn "  $_ => $options{$_}\n" foreach keys %options;
   }
 
+  return "No reason specified" unless $options{'reasonnum'} =~ /^\d+$/;
+
   my %content = ();
 
   ###
@@ -1531,7 +1533,12 @@ sub realtime_refund_bop {
       if $conf->exists('business-onlinepayment-test_transaction');
     $void->submit();
     if ( $void->is_success ) {
-      my $error = $cust_pay->void($options{'reason'});
+      # specified as a refund reason, but now we want a payment void reason
+      # extract just the reason text, let cust_pay::void handle new_or_existing
+      my $reason = qsearchs('reason',{ 'reasonnum' => $options{'reasonnum'} });
+      my $error;
+      $error = 'Reason could not be loaded' unless $reason;      
+      $error = $cust_pay->void($reason->reason) unless $error;
       if ( $error ) {
         # gah, even with transactions.
         my $e = 'WARNING: Card/ACH voided but database not updated - '.
@@ -1652,11 +1659,12 @@ sub realtime_refund_bop {
   my $cust_refund = new FS::cust_refund ( {
     'custnum'  => $self->custnum,
     'paynum'   => $options{'paynum'},
+    'source_paynum' => $options{'paynum'},
     'refund'   => $amount,
     '_date'    => '',
     'payby'    => $bop_method2payby{$options{method}},
     'payinfo'  => $payinfo,
-    'reason'   => $options{'reason'} || 'card or ACH refund',
+    'reasonnum'     => $options{'reasonnum'},
     'gatewaynum'    => $gatewaynum, # may be null
     'processor'     => $processor,
     'auth'          => $refund->authorization,
@@ -1665,6 +1673,7 @@ sub realtime_refund_bop {
   my $error = $cust_refund->insert;
   if ( $error ) {
     $cust_refund->paynum(''); #try again with no specific paynum
+    $cust_refund->source_paynum('');
     my $error2 = $cust_refund->insert;
     if ( $error2 ) {
       # gah, even with transactions.
diff --git a/FS/FS/cust_pay.pm b/FS/FS/cust_pay.pm
index af76b89..620f6c6 100644
--- a/FS/FS/cust_pay.pm
+++ b/FS/FS/cust_pay.pm
@@ -444,7 +444,7 @@ sub void {
 
   unless (ref($reason) || !$reason) {
     $reason = FS::reason->new_or_existing(
-      'class'  => 'X',
+      'class'  => 'P',
       'type'   => 'Void payment',
       'reason' => $reason
     );
@@ -920,7 +920,7 @@ sub refund_to_unapply {
     'table'   => 'cust_pay_refund',
     'hashref' => { 'paynum' => $self->paynum },
     'addl_from' => 'LEFT JOIN cust_refund USING (refundnum)',
-    'extra_sql' => "AND (cust_refund.closed = '' OR cust_refund.closed IS NULL)",
+    'extra_sql' => "AND cust_refund.closed IS NULL AND cust_refund.source_paynum IS NULL",
   });
 }
 
diff --git a/FS/FS/cust_refund.pm b/FS/FS/cust_refund.pm
index efbdcee..ced9540 100644
--- a/FS/FS/cust_refund.pm
+++ b/FS/FS/cust_refund.pm
@@ -143,16 +143,23 @@ sub insert {
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
 
-  unless ($self->reasonnum) {
-    my $result = $self->reason( $self->getfield('reason'),
-                                exists($options{ 'reason_type' })
-                                  ? ('reason_type' => $options{ 'reason_type' })
-                                  : (),
-                              );
-    unless($result) {
+  if (!$self->reasonnum) {
+    my $reason_text = $self->get('reason')
+      or return "reason text or existing reason required";
+    my $reason_type = $options{'reason_type'}
+      or return "reason type required";
+
+    local $@;
+    my $reason = FS::reason->new_or_existing(
+      reason => $reason_text,
+      type   => $reason_type,
+      class  => 'F',
+    );
+    if ($@) {
       $dbh->rollback if $oldAutoCommit;
-      return "failed to set reason for $me"; #: ". $dbh->errstr;
+      return "failed to set refund reason: $@";
     }
+    $self->set('reasonnum', $reason->reasonnum);
   }
 
   $self->setfield('reason', '');
@@ -303,6 +310,7 @@ sub check {
     || $self->ut_numbern('_date')
     || $self->ut_textn('paybatch')
     || $self->ut_enum('closed', [ '', 'Y' ])
+    || $self->ut_foreign_keyn('source_paynum', 'cust_pay', 'paynum')
   ;
   return $error if $error;
 
diff --git a/httemplate/edit/process/cust_refund.cgi b/httemplate/edit/process/cust_refund.cgi
index 6ad468b..8977ced 100755
--- a/httemplate/edit/process/cust_refund.cgi
+++ b/httemplate/edit/process/cust_refund.cgi
@@ -47,12 +47,11 @@ if ( $error ) {
   my $refund = "$1$2";
   $cgi->param('paynum') =~ /^(\d*)$/ or die "Illegal paynum!";
   my $paynum = $1;
-  my $reason = $cgi->param('reason');
   my $paydate = $cgi->param('exp_year'). '-'. $cgi->param('exp_month'). '-01';
   $options{'paydate'} = $paydate if $paydate =~ /^\d{2,4}-\d{1,2}-01$/;
   $error = $cust_main->realtime_refund_bop( $bop, 'amount' => $refund,
                                                   'paynum' => $paynum,
-                                                  'reason' => $reason,
+                                                  'reasonnum' => scalar($cgi->param('reasonnum')),
                                                   %options );
 } else {
   my %hash = map {
diff --git a/httemplate/view/cust_main/payment_history/credit.html b/httemplate/view/cust_main/payment_history/credit.html
index 85911a0..da8ca2e 100644
--- a/httemplate/view/cust_main/payment_history/credit.html
+++ b/httemplate/view/cust_main/payment_history/credit.html
@@ -45,7 +45,7 @@ if (    scalar(@cust_credit_bill)   == 0
     if ( $opt{total_unapplied_refunds} > 0 ) {
       $apply.= ' ('.
                include( '/elements/popup_link.html',
-                          'label'    => emt('apply to refund'),
+                          'label'    => emt('apply refund'),
                           'action'   => "${p}edit/cust_credit_refund.cgi?".
                                         $cust_credit->crednum,
                           'actionlabel' => emt('Apply credit to refund'),
@@ -100,7 +100,7 @@ if (    scalar(@cust_credit_bill)   == 0
       if ( $opt{total_unapplied_refunds} > 0 ) {
         $apply.= ' ('.
                  include( '/elements/popup_link.html',
-                            'label'       => emt('apply to refund'),
+                            'label'       => emt('apply refund'),
                             'action'      => "${p}edit/cust_credit_refund.cgi?".
                                              $cust_credit->crednum,
                             'actionlabel' => emt('Apply credit to refund'),
@@ -141,20 +141,18 @@ $void = ' ('.
 my $unapply = '';
 
 if ($opt{'Unapply credit'} && !$cust_credit->closed) {
-  my $refund_to_unapply = $cust_credit->refund_to_unapply;
-  my $usepre = $refund_to_unapply && @cust_credit_bill;
   $unapply = areyousure_link("${p}misc/unapply-cust_credit.cgi?".$cust_credit->crednum,
                               emt('Are you sure you want to unapply this credit from invoices?'),
                               emt('Keep this credit, but dissociate it from the invoices it is currently applied against'),
-                              emt('unapply') . ($usepre ? ' ' . emt('invoices') : '')
+                              emt('unapply')
                             )
     if @cust_credit_bill;
   $unapply .= areyousure_link("${p}misc/unapply-cust_credit_refund.cgi?".$cust_credit->crednum,
                                emt('Are you sure you want to unapply this credit from refunds?'),
                                emt('Keep this credit, but dissociate it from the refunds it is currently applied to'),
-                               emt('unapply') . ($usepre ? ' ' . emt('refunds') : '')
+                               emt('unapply refunds')
                              )
-    if $refund_to_unapply;
+    if $cust_credit->refund_to_unapply;
 }
 
 my $reason = $cust_credit->reason;
diff --git a/httemplate/view/cust_main/payment_history/payment.html b/httemplate/view/cust_main/payment_history/payment.html
index 16b91c2..8faed3c 100644
--- a/httemplate/view/cust_main/payment_history/payment.html
+++ b/httemplate/view/cust_main/payment_history/payment.html
@@ -103,7 +103,7 @@ if ($unapplied > 0) {
     if ( $opt{total_unapplied_refunds} > 0 ) {
       $apply.= ' ('.
                include( '/elements/popup_link.html',
-                          'label'       => emt('apply to refund'),
+                          'label'       => emt('apply refund'),
                           'action'      => "${p}edit/cust_pay_refund.cgi?".
                                            $cust_pay->paynum,
                           'actionlabel' => emt('Apply payment to refund'),
@@ -198,20 +198,18 @@ $void = ' ('.
 
 my $unapply = '';
 if ($opt{'Unapply payment'} && !$cust_pay->closed) {
-  my $refund_to_unapply = $cust_pay->refund_to_unapply;
-  my $usepre = $refund_to_unapply && @cust_bill_pay;
   $unapply = areyousure_link("${p}misc/unapply-cust_pay.cgi?".$cust_pay->paynum,
                               emt('Are you sure you want to unapply this payment from invoices?'),
                               emt('Keep this payment, but dissociate it from the invoices it is currently applied against'),
-                              emt('unapply') . ($usepre ? ' ' . emt('invoices') : '')
+                              emt('unapply')
                             )
     if @cust_bill_pay;
   $unapply .= areyousure_link("${p}misc/unapply-cust_pay_refund.cgi?".$cust_pay->paynum,
                                emt('Are you sure you want to unapply this payment from refunds?'),
                                emt('Keep this payment, but dissociate it from the refunds it is currently applied to'),
-                               emt('unapply') . ($usepre ? ' ' . emt('refunds') : '')
+                               emt('unapply refunds')
                              )
-    if $refund_to_unapply;
+    if $cust_pay->refund_to_unapply;
 }
 
 </%init>

commit 1bb85d2484b3d9f45c2b1142951503ff1c54e2e9
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Fri Feb 5 15:16:12 2016 -0600

    RT#39586 Manual check refunds cannot be unapplied

diff --git a/FS/FS/cust_credit.pm b/FS/FS/cust_credit.pm
index 6b21d69..a598b37 100644
--- a/FS/FS/cust_credit.pm
+++ b/FS/FS/cust_credit.pm
@@ -1028,6 +1028,58 @@ sub credit_lineitems {
 
 }
 
+### refund_to_unapply/unapply_refund false laziness with FS::cust_pay
+
+=item refund_to_unapply
+
+Returns L<FS::cust_credit_refund> objects that will be deleted by L</unapply_refund>
+(all currently applied refunds that aren't closed.)
+Returns empty list if credit itself is closed.
+
+=cut
+
+sub refund_to_unapply {
+  my $self = shift;
+  return () if $self->closed;
+  qsearch({
+    'table'   => 'cust_credit_refund',
+    'hashref' => { 'crednum' => $self->crednum },
+    'addl_from' => 'LEFT JOIN cust_refund USING (refundnum)',
+    'extra_sql' => "AND (cust_refund.closed = '' OR cust_refund.closed IS NULL)",
+  });
+}
+
+=item unapply_refund
+
+Deletes all objects returned by L</refund_to_unapply>.
+
+=cut
+
+sub unapply_refund {
+  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;
+
+  foreach my $cust_credit_refund ($self->refund_to_unapply) {
+    my $error = $cust_credit_refund->delete;
+    if ($error) {
+      dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
+  dbh->commit or die dbh->errstr if $oldAutoCommit;
+  return '';
+}
+
 =back
 
 =head1 SUBROUTINES
diff --git a/FS/FS/cust_pay.pm b/FS/FS/cust_pay.pm
index 4d06862..af76b89 100644
--- a/FS/FS/cust_pay.pm
+++ b/FS/FS/cust_pay.pm
@@ -903,6 +903,58 @@ sub refund {
   return '';
 }
 
+### refund_to_unapply/unapply_refund false laziness with FS::cust_credit
+
+=item refund_to_unapply
+
+Returns L<FS::cust_pay_refund> objects that will be deleted by L</unapply_refund>
+(all currently applied refunds that aren't closed.)
+Returns empty list if payment itself is closed.
+
+=cut
+
+sub refund_to_unapply {
+  my $self = shift;
+  return () if $self->closed;
+  qsearch({
+    'table'   => 'cust_pay_refund',
+    'hashref' => { 'paynum' => $self->paynum },
+    'addl_from' => 'LEFT JOIN cust_refund USING (refundnum)',
+    'extra_sql' => "AND (cust_refund.closed = '' OR cust_refund.closed IS NULL)",
+  });
+}
+
+=item unapply_refund
+
+Deletes all objects returned by L</refund_to_unapply>.
+
+=cut
+
+sub unapply_refund {
+  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;
+
+  foreach my $cust_pay_refund ($self->refund_to_unapply) {
+    my $error = $cust_pay_refund->delete;
+    if ($error) {
+      dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
+  dbh->commit or die dbh->errstr if $oldAutoCommit;
+  return '';
+}
+
 =back
 
 =head1 CLASS METHODS
@@ -990,7 +1042,7 @@ sub batch_insert {
 
 Returns an SQL fragment to retreive the unapplied amount.
 
-=cut 
+=cut
 
 sub unapplied_sql {
   my ($class, $start, $end) = @_;
diff --git a/httemplate/misc/unapply-cust_credit_refund.cgi b/httemplate/misc/unapply-cust_credit_refund.cgi
new file mode 100755
index 0000000..55a81b0
--- /dev/null
+++ b/httemplate/misc/unapply-cust_credit_refund.cgi
@@ -0,0 +1,18 @@
+<% $cgi->redirect($p. "view/cust_main.cgi?custnum=". $custnum. ";show=payment_history") %>
+<%init>
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Unapply credit');
+
+#untaint crednum
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/ || die "Illegal crednum";
+my $crednum = $1;
+
+my $cust_credit = qsearchs('cust_credit', { 'crednum' => $crednum } );
+my $custnum = $cust_credit->custnum;
+
+my $error = $cust_credit->unapply_refund;
+errorpage($error) if $error;
+
+</%init>
diff --git a/httemplate/misc/unapply-cust_pay_refund.cgi b/httemplate/misc/unapply-cust_pay_refund.cgi
new file mode 100755
index 0000000..9e470b6
--- /dev/null
+++ b/httemplate/misc/unapply-cust_pay_refund.cgi
@@ -0,0 +1,18 @@
+<% $cgi->redirect($p. "view/cust_main.cgi?custnum=". $custnum. ";show=payment_history") %>
+<%init>
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Unapply payment');
+
+#untaint paynum
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/ || die "Illegal paynum";
+my $paynum = $1;
+
+my $cust_pay = qsearchs('cust_pay', { 'paynum' => $paynum } );
+my $custnum = $cust_pay->custnum;
+
+my $error = $cust_pay->unapply_refund;
+errorpage($error) if $error;
+
+</%init>
diff --git a/httemplate/view/cust_main/payment_history/credit.html b/httemplate/view/cust_main/payment_history/credit.html
index db2e5e5..85911a0 100644
--- a/httemplate/view/cust_main/payment_history/credit.html
+++ b/httemplate/view/cust_main/payment_history/credit.html
@@ -139,14 +139,23 @@ $void = ' ('.
   && $opt{'Void credit'};
 
 my $unapply = '';
-$unapply = areyousure_link("${p}misc/unapply-cust_credit.cgi?".$cust_credit->crednum,
-                            emt('Are you sure you want to unapply this credit?'),
-                            '',
-                            emt('unapply')
-                          )
-  if $cust_credit->closed !~ /^Y/i
-  && scalar(@cust_credit_bill)
-  && $opt{'Unapply credit'};
+
+if ($opt{'Unapply credit'} && !$cust_credit->closed) {
+  my $refund_to_unapply = $cust_credit->refund_to_unapply;
+  my $usepre = $refund_to_unapply && @cust_credit_bill;
+  $unapply = areyousure_link("${p}misc/unapply-cust_credit.cgi?".$cust_credit->crednum,
+                              emt('Are you sure you want to unapply this credit from invoices?'),
+                              emt('Keep this credit, but dissociate it from the invoices it is currently applied against'),
+                              emt('unapply') . ($usepre ? ' ' . emt('invoices') : '')
+                            )
+    if @cust_credit_bill;
+  $unapply .= areyousure_link("${p}misc/unapply-cust_credit_refund.cgi?".$cust_credit->crednum,
+                               emt('Are you sure you want to unapply this credit from refunds?'),
+                               emt('Keep this credit, but dissociate it from the refunds it is currently applied to'),
+                               emt('unapply') . ($usepre ? ' ' . emt('refunds') : '')
+                             )
+    if $refund_to_unapply;
+}
 
 my $reason = $cust_credit->reason;
 $reason = $reason ? " ($reason)" : '';
diff --git a/httemplate/view/cust_main/payment_history/payment.html b/httemplate/view/cust_main/payment_history/payment.html
index 6c93f7b..16b91c2 100644
--- a/httemplate/view/cust_main/payment_history/payment.html
+++ b/httemplate/view/cust_main/payment_history/payment.html
@@ -197,13 +197,21 @@ $void = ' ('.
      );
 
 my $unapply = '';
-$unapply = areyousure_link("${p}misc/unapply-cust_pay.cgi?".$cust_pay->paynum,
-                            emt('Are you sure you want to unapply this payment?'),
-                            emt('Keep this payment, but dissociate it from the invoices it is currently applied against'),
-                            emt('unapply')
-                          )
-  if $cust_pay->closed !~ /^Y/i
-  && scalar(@cust_bill_pay)           
-  && $opt{'Unapply payment'};
+if ($opt{'Unapply payment'} && !$cust_pay->closed) {
+  my $refund_to_unapply = $cust_pay->refund_to_unapply;
+  my $usepre = $refund_to_unapply && @cust_bill_pay;
+  $unapply = areyousure_link("${p}misc/unapply-cust_pay.cgi?".$cust_pay->paynum,
+                              emt('Are you sure you want to unapply this payment from invoices?'),
+                              emt('Keep this payment, but dissociate it from the invoices it is currently applied against'),
+                              emt('unapply') . ($usepre ? ' ' . emt('invoices') : '')
+                            )
+    if @cust_bill_pay;
+  $unapply .= areyousure_link("${p}misc/unapply-cust_pay_refund.cgi?".$cust_pay->paynum,
+                               emt('Are you sure you want to unapply this payment from refunds?'),
+                               emt('Keep this payment, but dissociate it from the refunds it is currently applied to'),
+                               emt('unapply') . ($usepre ? ' ' . emt('refunds') : '')
+                             )
+    if $refund_to_unapply;
+}
 
 </%init>

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

Summary of changes:
 FS/FS/Schema.pm                                    |    5 ++
 FS/FS/cust_credit.pm                               |   52 ++++++++++++++++++
 FS/FS/cust_main/Billing_Realtime.pm                |   17 ++++--
 FS/FS/cust_pay.pm                                  |   56 +++++++++++++++++++-
 FS/FS/cust_refund.pm                               |   24 ++++++---
 httemplate/edit/process/cust_refund.cgi            |    3 +-
 ...t_credit.cgi => unapply-cust_credit_refund.cgi} |    6 +--
 ...ly-cust_pay.cgi => unapply-cust_pay_refund.cgi} |    2 +-
 .../view/cust_main/payment_history/credit.html     |   27 ++++++----
 .../view/cust_main/payment_history/payment.html    |   24 +++++----
 10 files changed, 176 insertions(+), 40 deletions(-)
 copy httemplate/misc/{unapply-cust_credit.cgi => unapply-cust_credit_refund.cgi} (75%)
 copy httemplate/misc/{unapply-cust_pay.cgi => unapply-cust_pay_refund.cgi} (90%)




More information about the freeside-commits mailing list