CRM-13965 : refund payment handling and some major improvements
authorPratik Joshi <pratik.joshi@webaccess.co.in>
Thu, 23 Jan 2014 08:39:22 +0000 (14:09 +0530)
committerPratik Joshi <pratik.joshi@webaccess.co.in>
Fri, 24 Jan 2014 05:56:01 +0000 (11:26 +0530)
CRM/Contribute/BAO/Contribution.php
CRM/Contribute/Form/AdditionalPayment.php
CRM/Core/BAO/FinancialTrxn.php
CRM/Event/BAO/Participant.php
CRM/Event/Form/Participant.php
CRM/Event/Selector/Search.php
templates/CRM/Contribute/Form/AdditionalPayment.tpl
templates/CRM/Contribute/Page/PaymentInfo.tpl
templates/CRM/Event/Form/Participant.tpl

index 06f5e28dbc3093a975b7f29a77c501e38d9213b3..acf2dfc0b8c6fddb7619182c966175af37c80ea4 100644 (file)
@@ -2952,33 +2952,32 @@ WHERE  contribution_id = %1 ";
     return FALSE;
   }
 
-  static function recordAdditionPayment($contributionId, $trxnsData, $paymentType, $participantId = NULL) {
-    // FIXME : needs handling of partial payment validness checking, if its valid then only record new entries
-    $params = $ids = $defaults = array();
-    $getInfoOf['id'] = $contributionId;
-
-    // build params for recording financial trxn entry
-    $contributionDAO = CRM_Contribute_BAO_Contribution::retrieve($getInfoOf, $defaults, $ids);
-    $params['contribution'] = $contributionDAO;
-    $params = array_merge($defaults, $params);
-    $params['skipLineItem'] = TRUE;
-    $params['partial_payment_total'] = $contributionDAO->total_amount;
-    $params['partial_amount_pay'] = $trxnsData['total_amount'];
-    $trxnsData['trxn_date'] = !empty($trxnsData['trxn_date']) ? $trxnsData['trxn_date'] : date('YmdHis');
-
-    // record the entry
-    $financialTrxn = CRM_Contribute_BAO_Contribution::recordFinancialAccounts($params, $trxnsData);
-
+  static function recordAdditionPayment($contributionId, $trxnsData, $paymentType = 'owed', $participantId = NULL) {
     $statusId = CRM_Core_OptionGroup::getValue('contribution_status', 'Completed', 'name');
-    $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Accounts Receivable Account is' "));
-    $toFinancialAccount = CRM_Contribute_PseudoConstant::financialAccountType($contributionDAO->financial_type_id, $relationTypeId);
+    $getInfoOf['id'] = $contributionId;
+    $defaults = array();
+    $contributionDAO = CRM_Contribute_BAO_Contribution::retrieve($getInfoOf, $defaults, CRM_Core_DAO::$_nullArray);
+
+    if ($paymentType == 'owed') {
+      // build params for recording financial trxn entry
+      $params['contribution'] = $contributionDAO;
+      $params = array_merge($defaults, $params);
+      $params['skipLineItem'] = TRUE;
+      $params['partial_payment_total'] = $contributionDAO->total_amount;
+      $params['partial_amount_pay'] = $trxnsData['total_amount'];
+      $trxnsData['trxn_date'] = !empty($trxnsData['trxn_date']) ? $trxnsData['trxn_date'] : date('YmdHis');
+
+      // record the entry
+      $financialTrxn = CRM_Contribute_BAO_Contribution::recordFinancialAccounts($params, $trxnsData);
+      $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Accounts Receivable Account is' "));
+      $toFinancialAccount = CRM_Contribute_PseudoConstant::financialAccountType($contributionDAO->financial_type_id, $relationTypeId);
 
-    $trxnId = CRM_Core_BAO_FinancialTrxn::getBalanceTrxnAmt($contributionId, $contributionDAO->financial_type_id);
-    $trxnId = $trxnId['trxn_id'];
+      $trxnId = CRM_Core_BAO_FinancialTrxn::getBalanceTrxnAmt($contributionId, $contributionDAO->financial_type_id);
+      $trxnId = $trxnId['trxn_id'];
 
-    // update statuses
-    // criteria for updates contribution total_amount == financial_trxns of partial_payments
-    $sql = "SELECT SUM(ft.total_amount) as sum_of_payments
+      // update statuses
+      // criteria for updates contribution total_amount == financial_trxns of partial_payments
+      $sql = "SELECT SUM(ft.total_amount) as sum_of_payments
 FROM civicrm_financial_trxn ft
 LEFT JOIN civicrm_entity_financial_trxn eft
   ON (ft.id = eft.financial_trxn_id)
@@ -2987,20 +2986,76 @@ WHERE eft.entity_table = 'civicrm_contribution'
   AND ft.to_financial_account_id != {$toFinancialAccount}
   AND ft.status_id = {$statusId}
 ";
-    $sumOfPayments = CRM_Core_DAO::singleValueQuery($sql);
-
-    // update statuses
-    if ($contributionDAO->total_amount == $sumOfPayments) {
-      // update contribution status
-      $contributionUpdate['id'] = $contributionId;
-      $contributionUpdate['contribution_status_id'] = $statusId;
-      $contributionUpdate['skipLineItem'] = TRUE;
+      $sumOfPayments = CRM_Core_DAO::singleValueQuery($sql);
+
+      // update statuses
+      if ($contributionDAO->total_amount == $sumOfPayments) {
+        // update contribution status
+        $contributionUpdate['id'] = $contributionId;
+        $contributionUpdate['contribution_status_id'] = $statusId;
+        $contributionUpdate['skipLineItem'] = TRUE;
+        // note : not using the self::add method,
+        // the reason because it performs 'status change' related code execution for financial records
+        // which in 'Partial Paid' => 'Completed' is not useful, instead specific financial record updates
+        // are coded below i.e. just updating financial_item status to 'Paid'
+        $contributionDetails = CRM_Core_DAO::setFieldValue('CRM_Contribute_BAO_Contribution', $contributionId, 'contribution_status_id', $statusId);
+
+        if ($participantId) {
+          // update participant status
+          $participantUpdate['id'] = $participantId;
+          $participantStatuses = CRM_Event_PseudoConstant::participantStatus();
+          $participantUpdate['status_id'] = array_search('Registered', $participantStatuses);
+          CRM_Event_BAO_Participant::add($participantUpdate);
+        }
+
+        // update financial item statuses
+        $financialItemStatus = CRM_Core_PseudoConstant::get('CRM_Financial_DAO_FinancialItem', 'status_id');
+        $paidStatus = array_search('Paid', $financialItemStatus);
+
+        $sqlFinancialItemUpdate = "
+UPDATE civicrm_financial_item fi
+  LEFT JOIN civicrm_entity_financial_trxn eft
+    ON (eft.entity_id = fi.id AND eft.entity_table = 'civicrm_financial_item')
+SET status_id = {$paidStatus}
+WHERE eft.financial_trxn_id = {$trxnId}
+";
+        CRM_Core_DAO::executeQuery($sqlFinancialItemUpdate);
+      }
+    }
+    elseif ($paymentType == 'refund') {
+      // build params for recording financial trxn entry
+      $params['contribution'] = $contributionDAO;
+      $params = array_merge($defaults, $params);
+      $params['skipLineItem'] = TRUE;
+      $trxnsData['trxn_date'] = !empty($trxnsData['trxn_date']) ? $trxnsData['trxn_date'] : date('YmdHis');
+      $trxnsData['total_amount'] = - $trxnsData['total_amount'];
+
+      $trxnsData['status_id'] = CRM_Core_OptionGroup::getValue('contribution_status', 'Refunded', 'name');
+      // record the entry
+      $financialTrxn = CRM_Contribute_BAO_Contribution::recordFinancialAccounts($params, $trxnsData);
+
       // note : not using the self::add method,
       // the reason because it performs 'status change' related code execution for financial records
-      // which in 'Partial Paid' => 'Completed' is not useful, instead specific financial record updates
+      // which in 'Pending Refund' => 'Completed' is not useful, instead specific financial record updates
       // are coded below i.e. just updating financial_item status to 'Paid'
       $contributionDetails = CRM_Core_DAO::setFieldValue('CRM_Contribute_BAO_Contribution', $contributionId, 'contribution_status_id', $statusId);
 
+      // add financial item entry
+      $financialItemStatus = CRM_Core_PseudoConstant::get('CRM_Financial_DAO_FinancialItem', 'status_id');
+      $getLine['entity_id'] = $contributionDAO->id;
+      $getLine['entity_table'] = 'civicrm_contribution';
+      $lineItemId = CRM_Price_BAO_LineItem::retrieve($getLine, CRM_Core_DAO::$_nullArray);
+      $addFinancialEntry = array(
+        'transaction_date' => $financialTrxn->trxn_date,
+        'contact_id' => $contributionDAO->contact_id,
+        'amount' => $financialTrxn->total_amount,
+        'status_id' => array_search('Paid', $financialItemStatus),
+        'entity_id' => $lineItemId->id,
+        'entity_table' => 'civicrm_line_item'
+      );
+      $trxnIds['id'] =  $financialTrxn->id;
+      CRM_Financial_BAO_FinancialItem::create($addFinancialEntry, NULL, $trxnIds);
+
       if ($participantId) {
         // update participant status
         $participantUpdate['id'] = $participantId;
@@ -3008,21 +3063,9 @@ WHERE eft.entity_table = 'civicrm_contribution'
         $participantUpdate['status_id'] = array_search('Registered', $participantStatuses);
         CRM_Event_BAO_Participant::add($participantUpdate);
       }
-
-      // update financial item statuses
-      $financialItemStatus = CRM_Core_PseudoConstant::get('CRM_Financial_DAO_FinancialItem', 'status_id');
-      $paidStatus = array_search('Paid', $financialItemStatus);
-
-      $sqlFinancialItemUpdate = "
-UPDATE civicrm_financial_item fi
-  LEFT JOIN civicrm_entity_financial_trxn eft
-    ON (eft.entity_id = fi.id AND eft.entity_table = 'civicrm_financial_item')
-SET status_id = {$paidStatus}
-WHERE eft.financial_trxn_id = {$trxnId}
-";
-      CRM_Core_DAO::executeQuery($sqlFinancialItemUpdate);
     }
 
+    // activity creation
     if (!empty($financialTrxn)) {
       if ($participantId) {
         $inputParams['id'] = $participantId;
@@ -3088,12 +3131,13 @@ WHERE eft.financial_trxn_id = {$trxnId}
   function getPaymentInfo($id, $component, $getTrxnInfo = FALSE) {
     if ($component == 'event') {
       $entity = 'participant';
+      $entityTable = 'civicrm_participant';
       $contributionId = CRM_Core_DAO::getFieldValue('CRM_Event_BAO_ParticipantPayment', $id, 'contribution_id', 'participant_id');
     }
     $total = CRM_Core_BAO_FinancialTrxn::getBalanceTrxnAmt($contributionId);
     $baseTrxnId = NULL;
     if (empty($total)) {
-      $total = CRM_Price_BAO_LineItem::getLineTotal($id, 'civicrm_participant');
+      $total = CRM_Price_BAO_LineItem::getLineTotal($id, $entityTable);
     }
     else {
       $baseTrxnId = $total['trxn_id'];
index b37a5bacaa5b872b6b606e866096b65b92458f2d..27666925f1c587ce82a29b04b56614b14c33c02f 100644 (file)
@@ -99,10 +99,15 @@ class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_Abstract
       CRM_Core_Error::fatal(ts('No payment information found for this record'));
     }
 
-    list($this->_contributorDisplayName, $this->_contributorEmail) = CRM_Contact_BAO_Contact_Location::getEmailDetails($this->_contactId);
     //set the payment mode - _mode property is defined in parent class
     $this->_mode = CRM_Utils_Request::retrieve('mode', 'String', $this);
 
+    if (!empty($this->_mode) && $this->_paymentType == 'refund') {
+      CRM_Core_Error::fatal(ts('Credit card payment is not for Refund payments use'));
+    }
+
+    list($this->_contributorDisplayName, $this->_contributorEmail) = CRM_Contact_BAO_Contact_Location::getEmailDetails($this->_contactId);
+
     $this->assignProcessors();
 
     // also check for billing information
@@ -114,7 +119,7 @@ class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_Abstract
     $this->assign('component', $this->_component);
     $this->assign('id', $this->_id);
     $this->assign('paymentType', $this->_paymentType);
-    $this->assign('paymentAmt', $paymentAmt);
+    $this->assign('paymentAmt', abs($paymentAmt));
 
     $this->_paymentProcessor = array('billing_mode' => 1);
 
@@ -297,7 +302,7 @@ class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_Abstract
     if ($self->_paymentType == 'owed' && $fields['total_amount'] > $self->_owed) {
       $errors['total_amount'] = ts('Payment amount cannot be greater than owed amount');
     }
-    if ($self->_paymentType == 'refund' && $fields['total_amount'] != $self->_refund) {
+    if ($self->_paymentType == 'refund' && $fields['total_amount'] != abs($self->_refund)) {
       $errors['total_amount'] = ts('Refund amount should not differ');
     }
     $netAmt = $fields['total_amount'] - $fields['fee_amount'];
index df9bdf12f85a23e8deca0c32c337ea1c08c648b0..22bc1816401b41698692cb4f5fd852c6baed1a10 100644 (file)
@@ -406,7 +406,7 @@ WHERE ceft.entity_id = %1";
 
     if ($entityName == 'participant') {
       $contributionId = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_ParticipantPayment', $entityId, 'contribution_id', 'participant_id');
-      $financialTypeId = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $entityId, 'financial_type_id');
+      $financialTypeId = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $contributionId, 'financial_type_id');
 
       if ($contributionId && $financialTypeId) {
         $statusId = CRM_Core_OptionGroup::getValue('contribution_status', 'Completed', 'name');
@@ -423,7 +423,7 @@ FROM civicrm_financial_trxn ft
   LEFT JOIN civicrm_contribution c ON (eft.entity_id = c.id)
   LEFT JOIN civicrm_participant_payment pp ON (pp.contribution_id = c.id)
 WHERE pp.participant_id = {$entityId} AND ft.to_financial_account_id != {$toFinancialAccount}
-  AND ft.from_financial_account_id = {$toFinancialAccount} AND ft.status_id = {$statusId}
+  AND ft.status_id = {$statusId}
 ";
         $ftTotalAmt = CRM_Core_DAO::singleValueQuery($sqlFtTotalAmt);
         $value = 0;
index da697e61bb611dc64ed6bb26e6b5f12dd0cd5070..df5d78e2d0ef23f0d0ee557f2fcbb8b3d1eb3888 100644 (file)
@@ -1882,6 +1882,8 @@ WHERE (li.entity_table = 'civicrm_participant' AND li.entity_id = {$participantI
       );
       $setId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', 'default_contribution_amount', 'id', 'name');
       CRM_Price_BAO_LineItem::getLineItemArray($adjustPaymentLineParams);
+      $financialItemStatus = CRM_Core_PseudoConstant::get('CRM_Financial_DAO_FinancialItem', 'status_id');
+
       $defaultPriceSet = current(CRM_Price_BAO_PriceSet::getSetDetail($setId));
       $fieldID = key($defaultPriceSet['fields']);
       $adjustPaymentLineParams['line_item'][$setId][$fieldID]['entity_id'] = $updatedContribution->id;
@@ -1891,12 +1893,9 @@ WHERE (li.entity_table = 'civicrm_participant' AND li.entity_id = {$participantI
       // record financial item
       $financialItemStatus = CRM_Core_PseudoConstant::get('CRM_Financial_DAO_FinancialItem', 'status_id');
       $itemStatus = NULL;
-      if ($updatedContribution->contribution_status_id == array_search('Completed', $contributionStatuses)) {
+      if ($updatedContribution->contribution_status_id == array_search('Pending refund', $contributionStatuses)) {
         $itemStatus = array_search('Paid', $financialItemStatus);
       }
-      elseif ($updatedContribution->contribution_status_id == array_search('Pending', $contributionStatuses)) {
-        $itemStatus = array_search('Unpaid', $financialItemStatus);
-      }
       elseif ($updatedContribution->contribution_status_id == array_search('Partially paid', $contributionStatuses)) {
         $itemStatus = array_search('Partially paid', $financialItemStatus);
       }
@@ -1913,7 +1912,7 @@ WHERE (li.entity_table = 'civicrm_participant' AND li.entity_id = {$participantI
       );
       CRM_Financial_BAO_FinancialItem::create($params, NULL, array('id' => $adjustedTrxn->id));
     }
-    //activity creation
+    //activity creation$contributionStatuses
     self::addActivityForSelection($participantId, 'Change Registration');
   }
 
index 97410f02faeedf7951d2e5f23107e370f2c2ac84..dfbbe6cb6ce4a904d02a505672e7e55c8cd37053 100644 (file)
@@ -228,7 +228,6 @@ class CRM_Event_Form_Participant extends CRM_Contact_Form_Task {
     else {
       $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
     }
-    $participantStatuses = CRM_Event_PseudoConstant::participantStatus();
 
     if ($this->_id) {
       $this->assign('participantId', $this->_id);
@@ -259,9 +258,6 @@ class CRM_Event_Form_Participant extends CRM_Contact_Form_Task {
     $this->assign('eventNameCustomDataTypeID', $this->_eventNameCustomDataTypeID);
     $this->assign('eventTypeCustomDataTypeID', $this->_eventTypeCustomDataTypeID);
 
-    $partiallyPaidStatusId = array_search('Partially paid', $participantStatuses);
-    $this->assign('partiallyPaidStatusId', $partiallyPaidStatusId);
-
     if ($this->_mode) {
       $this->assign('participantMode', $this->_mode);
 
@@ -671,6 +667,10 @@ SELECT civicrm_custom_group.name as name,
    */
   public function buildQuickForm() {
     CRM_Core_Resources::singleton()->addScriptFile('civicrm', 'js/crm.livePage.js');
+    $participantStatuses = CRM_Event_PseudoConstant::participantStatus();
+    $partiallyPaidStatusId = array_search('Partially paid', $participantStatuses);
+    CRM_Core_Resources::singleton()->addSetting(array('partiallyPaidStatusId' => $partiallyPaidStatusId));
+
     if ($this->_showFeeBlock) {
       return CRM_Event_Form_EventFees::buildQuickForm($this);
     }
index 2dd9a069b7787ea3949b2e17a59c017c37224f48..5358eec110503cdb35eb10abe6cf9962b4285661 100644 (file)
@@ -371,6 +371,15 @@ class CRM_Event_Selector_Search extends CRM_Core_Selector_Base implements CRM_Co
         );
       }
 
+      if ($statusTypes[$row['participant_status_id']] == 'Pending refund') {
+        $links[CRM_Core_Action::ADD] = array(
+          'name' => ts('Record Refund'),
+          'url' => 'civicrm/payment/add',
+          'qs' => 'reset=1&id=%%id%%&cid=%%cid%%&action=add&component=event',
+          'title' => ts('Record Refund'),
+        );
+      }
+
       $row['action'] = CRM_Core_Action::formLink($links,
         $mask,
         array(
index d2cd57d577a1dfa79f19bf43cce720399e2f5ee8..83d4922f3d530ab79eec1e0b06020ecfbe736adf 100644 (file)
   {include file="CRM/Contribute/Form/AdditionalInfo/$formType.tpl"}
 {else}
 
+{if $paymentType eq 'refund'}
+<h3>{ts}New Event Refund{/ts}</h3>
+{else}
 <h3>{if $component eq 'event'}{if $contributionMode}{ts}Credit Card Event Payment{/ts}{else}{ts}New Event Payement{/ts}{/if}{/if}</h3>
-
+{/if}
 <div class="crm-block crm-form-block crm-payment-form-block">
 
   {if $contributionMode == 'test'}
@@ -48,7 +51,9 @@
       {if $contactId}
         {capture assign=ccModeLink}{crmURL p='civicrm/payment/add' q="reset=1&action=add&cid=`$contactId`&id=`$id`&component=`$component`&mode=live"}{/capture}
        {/if}
-      <span class="action-link crm-link-credit-card-mode">&nbsp;<a href="{$ccModeLink}">&raquo; {ts}submit credit card payment{/ts}</a>
+      {if $paymentType eq 'owed'}
+        <span class="action-link crm-link-credit-card-mode">&nbsp;<a href="{$ccModeLink}">&raquo; {ts}submit credit card payment{/ts}</a>
+      {/if}
     {/if}
   </div>
   <table class="form-layout-compressed">    
index c8c10339da227afc7703057e64804467a45cbda6..d770cfe7ce9632f632278f4ed208bc9d2950b357 100644 (file)
@@ -60,8 +60,13 @@ cj(function($){
     <td class='right'>{$paymentInfo.balance|crmMoney}</td>
   </tr>
 </table>
-{if $paymentInfo.balance > 0}
-  <a class="button" href='{crmURL p="civicrm/payment/add" q="reset=1&component=`$component`&id=`$id`&cid=`$cid`"}' title="{ts}Record Payment{/ts}"><span><div class="icon add-icon"></div> {ts}Record Payment{/ts}</span></a>
+{if $paymentInfo.balance}
+  {if $paymentInfo.balance > 0}
+     {assign var=paymentButtonName value='Record Payment'}
+  {elseif $paymentInfo.balance < 0}
+     {assign var=paymentButtonName value='Record Refund'}
+  {/if}
+  <a class="button" href='{crmURL p="civicrm/payment/add" q="reset=1&component=`$component`&id=`$id`&cid=`$cid`"}' title="{ts}{$paymentButtonName}{/ts}"><span><div class="icon add-icon"></div> {ts}{$paymentButtonName}{/ts}</span></a>
 {/if}
 {elseif $context eq 'transaction'}
   {if !empty($rows)}
index bb6705bf658a9fcbe8ca19ed08b456a961c2b48b..1167e24365da6e64d0c3a6d1b5b75ecc08dd488b 100644 (file)
   // change the status to default 'partially paid' for partial payments
   var feeAmount;
   var userModifiedAmount;
-  var partiallyPaidStatusId = {/literal}{$partiallyPaidStatusId}{literal};
 
   cj('#total_amount')
    .focus(
       userModifiedAmount = cj(this).val();
       userModifiedAmount = parseInt(userModifiedAmount);
       if (userModifiedAmount < feeAmount) {
-        cj('#status_id').val(partiallyPaidStatusId);
+        cj('#status_id').val(CRM.partiallyPaidStatusId);
       }
     }
   );
     function(e) {
       var userSubmittedStatus = cj('#status_id').val();
       var statusLabel = cj('#status_id option:selected').text();
-      if (userModifiedAmount < feeAmount && userSubmittedStatus != partiallyPaidStatusId) {
+      if (userModifiedAmount < feeAmount && userSubmittedStatus != CRM.partiallyPaidStatusId) {
         var result = confirm('Payment amount is less than the amount owed. Expected participant status is \'Partially paid\'. Are you sure you want to set the participant status to ' + statusLabel + '? Click OK to continue, Cancel to change your entries.');
         if (result == false) {
           e.preventDefault();