CiviCRM Community Forums (archive)

*

News:

Have a question about CiviCRM?
Get it answered quickly at the new
CiviCRM Stack Exchange Q+A site

This forum was archived on 25 November 2017. Learn more.
How to get involved.
What to do if you think you've found a bug.



  • CiviCRM Community Forums (archive) »
  • Old sections (read-only, deprecated) »
  • Developer Discussion (Moderator: Donald Lobo) »
  • Recurring contributions with Pledges
Pages: [1]

Author Topic: Recurring contributions with Pledges  (Read 1039 times)

Eileen

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4195
  • Karma: 218
    • Fuzion
Recurring contributions with Pledges
November 02, 2011, 04:38:40 pm
We have 2 customers who very much want to be able to use recurring contributions against pledges. I have a patch in place in BaseIPN (along with a tpl tweak) that seems to be working adequately for their needs but obviously they'd like it in core so just exploring what the spec would be

Basic implementation
1)   Expose ability to create a recurring against a pledge (via tpl tweak)
2)   In Base IPN look up the contribution id, see if it’s linked to a pledge OR another contribution attached to the recurring_contribution is linked to a pledge – if so
a.   If payment is not complete then update it
b.   If payment is complete then this is a subsequent payment & getOldestPayment (pending or in progress status) & update that

Above implementation works reasonably well in my use case as my users are pretty savvy but I presume for Core the following safeguards would be needed
1)   If a pledge has been linked with a recurring payment (ie. has a contribution with contribution_recur_id IS NOT NULL) then the ability to edit payment schedule should be disabled
2)   When creating a recurring payment against a pledge the number of recurring payments should be locked to the number of outstanding pledge payments & the instalment amount should be locked
3)   Note that recording a recurring payment with only a single instalment is a valid scenario as that is the only way Authorize.net (& others??) support future start dates

Patch I am using currently using

Index: CRM/Core/Payment/BaseIPN.php
===================================================================
--- CRM/Core/Payment/BaseIPN.php   (revision 37196)
+++ CRM/Core/Payment/BaseIPN.php   (working copy)
@@ -563,12 +563,23 @@
             require_once 'CRM/Core/BAO/FinancialTrxn.php';
             $trxn = CRM_Core_BAO_FinancialTrxn::create( $trxnParams );
         }
-       
         //update corresponding pledge payment record
         require_once 'CRM/Core/DAO.php';
         $returnProperties = array( 'id', 'pledge_id' );
-        if ( CRM_Core_DAO::commonRetrieveAll( 'CRM_Pledge_DAO_PledgePayment', 'contribution_id', $contribution->id,
-                                              $paymentDetails, $returnProperties ) ) {
+        require_once 'CRM/Contribute/DAO/Contribution.php';
+        $relatedContributions = new CRM_Contribute_DAO_Contribution( );
+        $relatedContributions->contribution_recur_id = $recurContrib->id ;
+        $relatedContributions->find(  ) ;
+        while($relatedContributions->fetch()){
+           $pledgeDetail = CRM_Core_DAO::commonRetrieveAll( 'CRM_Pledge_DAO_PledgePayment', 'contribution_id', $relatedContributions->id,
+                                              $paymentDetails, $returnProperties ) ;
+         }       
+        //update corresponding pledge payment record
+        require_once 'CRM/Core/DAO.php';
+        $returnProperties = array( 'id', 'pledge_id' );
+        if ( (is_array($pledgeDetail) || !empty($pledgeDetail['pledge_id'])) || CRM_Core_DAO::commonRetrieveAll( 'CRM_Pledge_DAO_PledgePayment', 'contribution_id', $contribution->id,
+                                              $paymentDetails, $returnProperties )
+             ) {
             $paymentIDs = array( );
             foreach ( $paymentDetails as $key => $value ) {
                 $paymentIDs[] = $value['id'];
@@ -597,8 +608,9 @@
         CRM_Core_Error::debug_log_message( "Contribution record updated successfully" );
         $transaction->commit( );
         
-        self::sendMail( $input, $ids, $objects, $values, $recur, false );
-
+        if(CRM_Utils_Array::value('is_email_receipt',$values)){
+          self::sendMail( $input, $ids, $objects, $values, $recur, false );
+          }
         CRM_Core_Error::debug_log_message( "Success: Database updated and mail sent" );
     }
     
« Last Edit: November 02, 2011, 04:40:50 pm by Eileen »
Make today the day you step up to support CiviCRM and all the amazing organisations that are using it to improve our world - http://civicrm.org/contribute

Eileen

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4195
  • Karma: 218
    • Fuzion
Re: Recurring contributions with Pledges
November 03, 2011, 03:14:33 pm
I've spent a bit more time working on this & this code is working for us.

I had a bit of a think about it & this is simpler than I realised.

I think it's a reasonable assumption that if ANY of the recurring contributions in a sequence is linked with a pledge then they all should be. (given that the only way to create that situation is to pay a pledge with a recurring payment.).

If for any reason the amount received is different to the amount expected then a reasonable default is not to change the total amount. The update CRM_Pledge_BAO_Payment::updatePledgePaymentStatus  function doesn't have any pre-function documentation but it appears to adjust the amounts / number of payment to keep the total the same - which seems fine.



Code: [Select]
Index: CRM/Core/Payment/BaseIPN.php
===================================================================
--- CRM/Core/Payment/BaseIPN.php (revision 37169)
+++ CRM/Core/Payment/BaseIPN.php (working copy)
@@ -562,21 +563,7 @@
             $trxn =& CRM_Core_BAO_FinancialTrxn::create( $trxnParams );
         }
         
-        //update corresponding pledge payment record
-        require_once 'CRM/Core/DAO.php';
-        $returnProperties = array( 'id', 'pledge_id' );
-        if ( CRM_Core_DAO::commonRetrieveAll( 'CRM_Pledge_DAO_Payment', 'contribution_id', $contribution->id,
-                                              $paymentDetails, $returnProperties ) ) {
-            $paymentIDs = array( );
-            foreach ( $paymentDetails as $key => $value ) {
-                $paymentIDs[] = $value['id'];
-                $pledgeId     = $value['pledge_id'];
-            }
-           
-            // update pledge and corresponding payment statuses
-            require_once 'CRM/Pledge/BAO/Payment.php';
-            CRM_Pledge_BAO_Payment::updatePledgePaymentStatus( $pledgeId, $paymentIDs, $contribution->contribution_status_id );
-        }
+        self::updateRecurLinkedPledge( $contribution);
 
         // create an activity record
         require_once "CRM/Activity/BAO/Activity.php";
 
@@ -1058,6 +1045,65 @@
         
         return $statusId;
     }
+   
+    /*
+     * Update pledge associated with a recurring contribution
+     *
+     * If the contribution has a pledge_payment record pledge, then update the pledge_payment record & pledge based on that linkage.
+     *
+     * If a previous contribution in the recurring contribution sequence is linked with a pledge then we assume this contribution
+     * should be  linked with the same pledge also. Currently only back-office users can apply a recurring payment to a pledge & it should be assumed they
+     * do so with the intention that all payments will be linked
+     *
+     * The pledge payment record should already exist & will need to be updated with the new contribution ID.
+     * If not the contribution will also need to be linked to the pledge
+     */
+    function updateRecurLinkedPledge( &$contribution){
+        $returnProperties = array( 'id', 'pledge_id' );
+        $paymentDetails = array();
+        $paymentIDs = array( );
+        require_once 'CRM/Core/DAO.php';
+        require_once 'CRM/Pledge/BAO/Payment.php';
+        if(CRM_Core_DAO::commonRetrieveAll( 'CRM_Pledge_DAO_Payment', 'contribution_id', $contribution->id,
+                                              $paymentDetails, $returnProperties )) {
+           foreach ( $paymentDetails as $key => $value ) {
+               $paymentIDs[] = $value['id'];
+               $pledgeId     = $value['pledge_id']; 
+          }
+                                               
+        }else{
+          //payment is not already linked - if it is linked with a pledge we need to create a link.
+          require_once 'CRM/Contribute/DAO/Contribution.php';
+          $relatedContributions = new CRM_Contribute_DAO_Contribution( );
+          $relatedContributions->contribution_recur_id = $contribution->contribution_recur_id ;
+          $relatedContributions->find(  ) ;
+          require_once 'CRM/Core/DAO.php';
+          while($relatedContributions->fetch()){
+             CRM_Core_DAO::commonRetrieveAll( 'CRM_Pledge_DAO_Payment', 'contribution_id', $relatedContributions->id,
+                                              $paymentDetails, $returnProperties ) ;
+           
+           }
+          if(empty($paymentDetails)){
+           return; // payment is not linked with a pledge and neither are any other contributions on this
+          }
+          foreach ( $paymentDetails as $key => $value ) {
+            $paymentIDs[] = $value['id'];
+            $pledgeId     = $value['pledge_id']; 
+          }   
+          // we have a pledge now we need to get the oldest unpaid payment
+                   
+          $paymentDetails = CRM_Pledge_BAO_Payment::getOldestPledgePayment( $pledgeId);       
+          $paymentDetails['contribution_id'] = $contribution->id;
+          require_once 'CRM/Pledge/BAO/Payment.php';// put contribution against it
+          CRM_Pledge_BAO_Payment::add($paymentDetails);
+          $paymentIDs[] = $paymentDetails['id'];                                     
+       }
+
+       // update pledge and corresponding payment statuses
+
+       CRM_Pledge_BAO_Payment::updatePledgePaymentStatus( $pledgeId, $paymentIDs, $contribution->contribution_status_id ,null,$contribution->total_amount);
+     }
+   
 }

 
« Last Edit: November 03, 2011, 03:20:07 pm by Eileen »
Make today the day you step up to support CiviCRM and all the amazing organisations that are using it to improve our world - http://civicrm.org/contribute

Eileen

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4195
  • Karma: 218
    • Fuzion
Re: Recurring contributions with Pledges
November 03, 2011, 03:19:17 pm
NB - it's easy to do the UI stuff for this as a customisation but hard to 'get to' the BaseIPN code as it won't call hooks as Drupal isn't loaded. Would be good to get the BaseIPN support for linked pledges into 4.1 even if the UI relies on people 'enabling' it by tweaking their Contribution.tpl (until further debate has happened)
Make today the day you step up to support CiviCRM and all the amazing organisations that are using it to improve our world - http://civicrm.org/contribute

Dave Greenberg

  • Administrator
  • I’m (like) Lobo ;)
  • *****
  • Posts: 5760
  • Karma: 226
    • My CiviCRM Blog
Re: Recurring contributions with Pledges
November 04, 2011, 02:51:56 pm
Two questions to help think about this a bit more:
1. If pledge payments are being made via a recurring contribution (subscription) with the payment processor - then based on earlier conversations it seems like this is no longer a pledge under some definitions at least. Why do your customers need to use the pledge mechanism? What is it giving them that just creating a recurring contribution "normally" is not?

2. Where did you expose the ability to trigger a recurring contribution in the UI? Did you expose the recurring contribution block in the back-office Contribution form (e.g. contact/view/contribution?reset=1&action=add&cid=102&ppid=9&context=pledge&mode=live) - which is normally suppressed when that form is used to make a pledge payment. OR did you add the recurring contribution fields to the Pledge form (and "drive" the recurring contribution properties like 'installments' off of the pledge form values)?
Protect your investment in CiviCRM by  becoming a Member!

Eileen

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4195
  • Karma: 218
    • Fuzion
Re: Recurring contributions with Pledges
November 04, 2011, 05:01:09 pm
1) Pledges are pledges as far as our customers are concerned - commitments to pay an amount over a period of time. If they get a credit card then it's better than receiving cash but if the credit card fails on one or more payments that's the equivalent to a cheque not turning up.

Importantly the reporting of pledges needs to include all pledges, whether or not a credit card was received. Pledges work on the assumption that the pledge itself is the important thing. Recurring contributions don't place a lot of emphasis on that side of it (the recurring contribution itself isn't exposed).

Basically it's making the treatment of pledges with credit cards the same as pledges without. At some later point when accounting integration is in place they will also want the same treatment for all pledges in that integration

2) "Did you expose the recurring contribution block in the back-office Contribution form (e.g. contact/view/contribution?reset=1&action=add&cid=102&ppid=9&context=pledge&mode=live) - which is normally suppressed when that form is used to make a pledge payment.".   Yes - in theory there might actually be more than one sequence of recurring contributions against a single pledge &  potentially some cheques mixed in. (e.g. because the pledge goes beyond the expiry date). But I believe that each recurring contribution subscription
should only ever relate to one pledge.

3) As an aside, the only way in which Authorize.net supports future start dates for credit card payments is by creating a recurring contribution subscription with only one payment - one of our customers regularly offers to put the payment through in the future (e.g. after pay day). The same approach facilitates this
Make today the day you step up to support CiviCRM and all the amazing organisations that are using it to improve our world - http://civicrm.org/contribute

Eileen

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4195
  • Karma: 218
    • Fuzion
Re: Recurring contributions with Pledges
November 04, 2011, 11:28:07 pm
NB - a specific reporting example is the $ value of pledges solicited in a day (broken down according to various custom fields - like who called them & whether it was targeted towards a specific initiative)
Make today the day you step up to support CiviCRM and all the amazing organisations that are using it to improve our world - http://civicrm.org/contribute

Pages: [1]
  • CiviCRM Community Forums (archive) »
  • Old sections (read-only, deprecated) »
  • Developer Discussion (Moderator: Donald Lobo) »
  • Recurring contributions with Pledges

This forum was archived on 2017-11-26.