From e8cf3013448fe07574c63de0726f4b34cb171b07 Mon Sep 17 00:00:00 2001 From: Pratik Joshi Date: Thu, 23 Jan 2014 14:09:22 +0530 Subject: [PATCH] CRM-13965 : refund payment handling and some major improvements --- CRM/Contribute/BAO/Contribution.php | 138 ++++++++++++------ CRM/Contribute/Form/AdditionalPayment.php | 11 +- CRM/Core/BAO/FinancialTrxn.php | 4 +- CRM/Event/BAO/Participant.php | 9 +- CRM/Event/Form/Participant.php | 8 +- CRM/Event/Selector/Search.php | 9 ++ .../CRM/Contribute/Form/AdditionalPayment.tpl | 9 +- templates/CRM/Contribute/Page/PaymentInfo.tpl | 9 +- templates/CRM/Event/Form/Participant.tpl | 5 +- 9 files changed, 134 insertions(+), 68 deletions(-) diff --git a/CRM/Contribute/BAO/Contribution.php b/CRM/Contribute/BAO/Contribution.php index 06f5e28dbc..acf2dfc0b8 100644 --- a/CRM/Contribute/BAO/Contribution.php +++ b/CRM/Contribute/BAO/Contribution.php @@ -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']; diff --git a/CRM/Contribute/Form/AdditionalPayment.php b/CRM/Contribute/Form/AdditionalPayment.php index b37a5bacaa..27666925f1 100644 --- a/CRM/Contribute/Form/AdditionalPayment.php +++ b/CRM/Contribute/Form/AdditionalPayment.php @@ -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']; diff --git a/CRM/Core/BAO/FinancialTrxn.php b/CRM/Core/BAO/FinancialTrxn.php index df9bdf12f8..22bc181640 100644 --- a/CRM/Core/BAO/FinancialTrxn.php +++ b/CRM/Core/BAO/FinancialTrxn.php @@ -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; diff --git a/CRM/Event/BAO/Participant.php b/CRM/Event/BAO/Participant.php index da697e61bb..df5d78e2d0 100644 --- a/CRM/Event/BAO/Participant.php +++ b/CRM/Event/BAO/Participant.php @@ -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'); } diff --git a/CRM/Event/Form/Participant.php b/CRM/Event/Form/Participant.php index 97410f02fa..dfbbe6cb6c 100644 --- a/CRM/Event/Form/Participant.php +++ b/CRM/Event/Form/Participant.php @@ -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); } diff --git a/CRM/Event/Selector/Search.php b/CRM/Event/Selector/Search.php index 2dd9a069b7..5358eec110 100644 --- a/CRM/Event/Selector/Search.php +++ b/CRM/Event/Selector/Search.php @@ -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( diff --git a/templates/CRM/Contribute/Form/AdditionalPayment.tpl b/templates/CRM/Contribute/Form/AdditionalPayment.tpl index d2cd57d577..83d4922f3d 100644 --- a/templates/CRM/Contribute/Form/AdditionalPayment.tpl +++ b/templates/CRM/Contribute/Form/AdditionalPayment.tpl @@ -27,8 +27,11 @@ {include file="CRM/Contribute/Form/AdditionalInfo/$formType.tpl"} {else} +{if $paymentType eq 'refund'} +

{ts}New Event Refund{/ts}

+{else}

{if $component eq 'event'}{if $contributionMode}{ts}Credit Card Event Payment{/ts}{else}{ts}New Event Payement{/ts}{/if}{/if}

- +{/if}
{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} -  » {ts}submit credit card payment{/ts} + {if $paymentType eq 'owed'} +  » {ts}submit credit card payment{/ts} + {/if} {/if}
diff --git a/templates/CRM/Contribute/Page/PaymentInfo.tpl b/templates/CRM/Contribute/Page/PaymentInfo.tpl index c8c10339da..d770cfe7ce 100644 --- a/templates/CRM/Contribute/Page/PaymentInfo.tpl +++ b/templates/CRM/Contribute/Page/PaymentInfo.tpl @@ -60,8 +60,13 @@ cj(function($){
{$paymentInfo.balance|crmMoney}
-{if $paymentInfo.balance > 0} -
{ts}Record Payment{/ts}
+{if $paymentInfo.balance} + {if $paymentInfo.balance > 0} + {assign var=paymentButtonName value='Record Payment'} + {elseif $paymentInfo.balance < 0} + {assign var=paymentButtonName value='Record Refund'} + {/if} +
{ts}{$paymentButtonName}{/ts}
{/if} {elseif $context eq 'transaction'} {if !empty($rows)} diff --git a/templates/CRM/Event/Form/Participant.tpl b/templates/CRM/Event/Form/Participant.tpl index bb6705bf65..1167e24365 100644 --- a/templates/CRM/Event/Form/Participant.tpl +++ b/templates/CRM/Event/Form/Participant.tpl @@ -131,7 +131,6 @@ // change the status to default 'partially paid' for partial payments var feeAmount; var userModifiedAmount; - var partiallyPaidStatusId = {/literal}{$partiallyPaidStatusId}{literal}; cj('#total_amount') .focus( @@ -145,7 +144,7 @@ userModifiedAmount = cj(this).val(); userModifiedAmount = parseInt(userModifiedAmount); if (userModifiedAmount < feeAmount) { - cj('#status_id').val(partiallyPaidStatusId); + cj('#status_id').val(CRM.partiallyPaidStatusId); } } ); @@ -154,7 +153,7 @@ 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(); -- 2.25.1