/** * Get a 'complex' invoice. * * Only call this via the api... I made it public static because of the move away from 'real' BAO * classes in preparation for doctrine but the api is the way to go. * * @param array $params * * @return array */ public static function getDerived($params) { try { // ok this chaining is a bit heavy but it would be good to work towards API returning this more efficiently // ie. not keen on the fact you can't easily get line items for contributions related to participants // & TBH the communication with Xero takes 90% of the script time ... // @todo - set return properties on contribution.get // @todo at the moment we use getsingle because we are only dealing with 1 but should alter to 'get' // as in theory any params could be passed in - resulting in many - there are some api // issues around getfields to resolve though - see notes on api $contribution = civicrm_api3('contribution', 'getsingle', array_merge(array('api.participant_payment.get' => array('return' => 'api.participant., participant_id', 'api.participant.get' => array('api.line_item.get' => 1, 'return' => 'participant_source, event_id, financial_type_id'))), $params)); // There is a chaining bug on line item because chaining passes contribution_id along as entity_id. // CRM-16522. $contribution['api.line_item.get'] = civicrm_api3('line_item', 'get', array('contribution_id' => $contribution['id'])); if ($contribution['api.line_item.get']['count']) { $contribution['line_items'] = $contribution['api.line_item.get']['values']; } else { //we'll keep the participant record for anyone trying to do hooks $contribution['participant'] = $contribution['api.participant_payment.get']['values'][0]['api.participant.get']['values'][0]; $contribution['line_items'] = $contribution['participant']['api.line_item.get']['values']; //if multiple participants one line item each self::_getAdditionalParticipanLineItems($contribution); } foreach ($contribution['line_items'] as &$lineItem) { $lineItem['accounting_code'] = CRM_Financial_BAO_FinancialAccount::getAccountingCode($lineItem['financial_type_id']); $lineItem['accounts_contact_id'] = self::getAccountsContact($lineItem['financial_type_id']); $contributionAccountsContactIDs[$lineItem['accounts_contact_id']] = TRUE; if (!isset($lineItem['contact_id'])) { //this would have been set for a secondary participant above so we are ensuring primary ones have it // for conformity & ease downstream $lineItem['contact_id'] = $contribution['contact_id']; } if (!isset($lineItem['display_name'])) { //this would have been set for a secondary participant above so we are ensuring primary ones have it // for conformity & ease downstream $lineItem['display_name'] = $contribution['display_name']; } } //@todo move the getAccountingCode to a fn that caches it $contribution['accounting_code'] = CRM_Financial_BAO_FinancialAccount::getAccountingCode($contribution['financial_type_id']); $contribution['accounts_contact_id'] = array_keys($contributionAccountsContactIDs); } catch (Exception $e) { // probably shouldn't catch & let calling class catch } // In 4.6 this might be more reliable as Monish did some tidy up on BAO_Search stuff. // Relying on it being unique makes me nervous... if (empty($contribution['payment_instrument_id'])) { $paymentInstruments = civicrm_api3('contribution', 'getoptions', array('field' => 'payment_instrument_id')); $contribution['payment_instrument_id'] = array_search($contribution['payment_instrument'], $paymentInstruments['values']); } $instrumentFinancialAccounts = CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount(); $contribution['payment_instrument_financial_account_id'] = $instrumentFinancialAccounts[$contribution['payment_instrument_id']]; try { $contribution['payment_instrument_accounting_code'] = civicrm_api3('financial_account', 'getvalue', array('id' => $contribution['payment_instrument_financial_account_id'], 'return' => 'accounting_code')); } catch (Exception $e) { } return array($contribution['id'] => $contribution); }
private function addContributionFinancialItem() { $sql = " SELECT cc.id contribution_id, cli.id as line_item_id, cc.contact_id, cc.receive_date, cc.total_amount, cc.currency, cli.label, cli.financial_type_id, cefa.financial_account_id, cc.payment_instrument_id, cc.check_number, cc.trxn_id\nFROM `civicrm_contribution` cc\nINNER JOIN civicrm_line_item cli ON cli.entity_id = cc.id and cli.entity_table = 'civicrm_contribution'\nINNER JOIN civicrm_entity_financial_account cefa ON cefa.entity_id = cli.financial_type_id\nWHERE cefa.account_relationship = 1; "; $result = CRM_Core_DAO::executeQuery($sql); $financialAccountId = CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount(); $this->addFinancialItem($result, $financialAccountId); }
/** * Function to record additional payment for partial and refund contributions. * * @param int $contributionId * is the invoice contribution id (got created after processing participant payment). * @param array $trxnsData * to take user provided input of transaction details. * @param string $paymentType * 'owed' for purpose of recording partial payments, 'refund' for purpose of recording refund payments. * @param int $participantId * * @return null|object */ public static function recordAdditionalPayment($contributionId, $trxnsData, $paymentType = 'owed', $participantId = NULL) { $statusId = CRM_Core_OptionGroup::getValue('contribution_status', 'Completed', 'name'); $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'); $trxnsData['net_amount'] = !empty($trxnsData['net_amount']) ? $trxnsData['net_amount'] : $trxnsData['total_amount']; // 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); if (!empty($trxnId)) { $trxnId = $trxnId['trxn_id']; } elseif (!empty($contributionDAO->payment_instrument_id)) { $trxnId = CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount($contributionDAO->payment_instrument_id); } else { $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('financial_account_type', NULL, " AND v.name LIKE 'Asset' ")); $queryParams = array(1 => array($relationTypeId, 'Integer')); $trxnId = CRM_Core_DAO::singleValueQuery("SELECT id FROM civicrm_financial_account WHERE is_default = 1 AND financial_account_type_id = %1", $queryParams); } // update statuses // criteria for updates contribution total_amount == financial_trxns of partial_payments $sql = "SELECT SUM(ft.total_amount) as sum_of_payments, SUM(ft.net_amount) as net_amount_total\nFROM civicrm_financial_trxn ft\nLEFT JOIN civicrm_entity_financial_trxn eft\n ON (ft.id = eft.financial_trxn_id)\nWHERE eft.entity_table = 'civicrm_contribution'\n AND eft.entity_id = {$contributionId}\n AND ft.to_financial_account_id != {$toFinancialAccount}\n AND ft.status_id = {$statusId}\n"; $query = CRM_Core_DAO::executeQuery($sql); $query->fetch(); $sumOfPayments = $query->sum_of_payments; // update statuses if ($contributionDAO->total_amount == $sumOfPayments) { // update contribution status and // clean cancel info (if any) if prev. contribution was updated in case of 'Refunded' => 'Completed' $contributionDAO->contribution_status_id = $statusId; $contributionDAO->cancel_date = 'null'; $contributionDAO->cancel_reason = NULL; $netAmount = !empty($trxnsData['net_amount']) ? NULL : $trxnsData['total_amount']; $contributionDAO->net_amount = $query->net_amount_total + $netAmount; $contributionDAO->fee_amount = $contributionDAO->total_amount - $contributionDAO->net_amount; $contributionDAO->save(); //Change status of financial record too $financialTrxn->status_id = $statusId; $financialTrxn->save(); // 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' if ($participantId) { // update participant status $participantStatuses = CRM_Event_PseudoConstant::participantStatus(); $ids = CRM_Event_BAO_Participant::getParticipantIds($contributionId); foreach ($ids as $val) { $participantUpdate['id'] = $val; $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); $baseTrxnId = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($contributionId); $sqlFinancialItemUpdate = "\nUPDATE civicrm_financial_item fi\n LEFT JOIN civicrm_entity_financial_trxn eft\n ON (eft.entity_id = fi.id AND eft.entity_table = 'civicrm_financial_item')\nSET status_id = {$paidStatus}\nWHERE eft.financial_trxn_id IN ({$trxnId}, {$baseTrxnId['financialTrxnId']})\n"; 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']; $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Accounts Receivable Account is' ")); $trxnsData['from_financial_account_id'] = CRM_Contribute_PseudoConstant::financialAccountType($contributionDAO->financial_type_id, $relationTypeId); $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 '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); if (!empty($lineItemId->id)) { $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 $participantStatuses = CRM_Event_PseudoConstant::participantStatus(); $ids = CRM_Event_BAO_Participant::getParticipantIds($contributionId); foreach ($ids as $val) { $participantUpdate['id'] = $val; $participantUpdate['status_id'] = array_search('Registered', $participantStatuses); CRM_Event_BAO_Participant::add($participantUpdate); } } } // activity creation if (!empty($financialTrxn)) { if ($participantId) { $inputParams['id'] = $participantId; $values = array(); $ids = array(); $component = 'event'; $entityObj = CRM_Event_BAO_Participant::getValues($inputParams, $values, $ids); $entityObj = $entityObj[$participantId]; } $activityType = $paymentType == 'refund' ? 'Refund' : 'Payment'; self::addActivityForPayment($entityObj, $financialTrxn, $activityType, $component, $contributionId); } return $financialTrxn; }
/** * Check financial transaction. * * @todo break this down into sensible functions - most calls to it only use a few lines out of the big if. * * @param array $contribution * @param string $context * @param int $instrumentId * @param array $extraParams */ public function _checkFinancialTrxn($contribution, $context, $instrumentId = NULL, $extraParams = array()) { $trxnParams = array('entity_id' => $contribution['id'], 'entity_table' => 'civicrm_contribution'); $trxn = current(CRM_Financial_BAO_FinancialItem::retrieveEntityFinancialTrxn($trxnParams, TRUE)); $params = array('id' => $trxn['financial_trxn_id']); if ($context == 'payLater') { $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Accounts Receivable Account is' ")); $compareParams = array('status_id' => 1, 'from_financial_account_id' => CRM_Contribute_PseudoConstant::financialAccountType($contribution['financial_type_id'], $relationTypeId)); } elseif ($context == 'refund') { $compareParams = array('to_financial_account_id' => 6, 'total_amount' => -100, 'status_id' => 7, 'trxn_date' => '2015-01-01 09:00:00', 'trxn_id' => 'the refund'); } elseif ($context == 'cancelPending') { $compareParams = array('to_financial_account_id' => 7, 'total_amount' => -100, 'status_id' => 3); } elseif ($context == 'changeFinancial' || $context == 'paymentInstrument') { $entityParams = array('entity_id' => $contribution['id'], 'entity_table' => 'civicrm_contribution', 'amount' => -100); $trxn = current(CRM_Financial_BAO_FinancialItem::retrieveEntityFinancialTrxn($entityParams)); $trxnParams1 = array('id' => $trxn['financial_trxn_id']); $compareParams = array('total_amount' => -100, 'status_id' => 1); if ($context == 'paymentInstrument') { $compareParams += array('to_financial_account_id' => CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount(4), 'payment_instrument_id' => 4); } else { $compareParams['to_financial_account_id'] = 12; } $this->assertDBCompareValues('CRM_Financial_DAO_FinancialTrxn', $trxnParams1, array_merge($compareParams, $extraParams)); $compareParams['total_amount'] = 100; if ($context == 'paymentInstrument') { $compareParams['to_financial_account_id'] = CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount($instrumentId); $compareParams['payment_instrument_id'] = $instrumentId; } else { $compareParams['to_financial_account_id'] = 12; } } $this->assertDBCompareValues('CRM_Financial_DAO_FinancialTrxn', $params, array_merge($compareParams, $extraParams)); }
/** * check method getInstrumentFinancialAccount() */ function testGetInstrumentFinancialAccount() { $paymentInstrumentValue = 1; $params = array('name' => 'Donations', 'is_deductible' => 0, 'is_active' => 1); $ids = array(); $financialAccount = CRM_Financial_BAO_FinancialAccount::add($params, $ids); $optionParams = array('name' => 'Credit Card', 'value' => $paymentInstrumentValue); $optionValue = CRM_Core_BAO_OptionValue::retrieve($optionParams, $defaults); $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Asset Account is' ")); $financialParams = array('entity_table' => 'civicrm_option_value', 'entity_id' => $optionValue->id, 'account_relationship' => $relationTypeId, 'financial_account_id' => $financialAccount->id); CRM_Financial_BAO_FinancialTypeAccount::add($financialParams, $ids); $financialAccountId = CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount($paymentInstrumentValue); $this->assertEquals($financialAccountId, $financialAccount->id, 'Verify Payment Instrument'); }
/** * This function is used to record partial payments for contribution * * @param array $contribution * * @param array $params * * @return object */ public static function recordPartialPayment($contribution, $params) { $contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'); $pendingStatus = array(array_search('Pending', $contributionStatuses), array_search('In Progress', $contributionStatuses)); $statusId = array_search('Completed', $contributionStatuses); if (in_array(CRM_Utils_Array::value('contribution_status_id', $contribution), $pendingStatus)) { $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Accounts Receivable Account is' ")); $balanceTrxnParams['to_financial_account_id'] = CRM_Contribute_PseudoConstant::financialAccountType($contribution['financial_type_id'], $relationTypeId); } elseif (!empty($params['payment_processor'])) { $balanceTrxnParams['to_financial_account_id'] = CRM_Financial_BAO_FinancialTypeAccount::getFinancialAccount($contribution['payment_processor'], 'civicrm_payment_processor', 'financial_account_id'); } elseif (!empty($params['payment_instrument_id'])) { $balanceTrxnParams['to_financial_account_id'] = CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount($contribution['payment_instrument_id']); } else { $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('financial_account_type', NULL, " AND v.name LIKE 'Asset' ")); $queryParams = array(1 => array($relationTypeId, 'Integer')); $balanceTrxnParams['to_financial_account_id'] = CRM_Core_DAO::singleValueQuery("SELECT id FROM civicrm_financial_account WHERE is_default = 1 AND financial_account_type_id = %1", $queryParams); } $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Accounts Receivable Account is' ")); $fromFinancialAccountId = CRM_Contribute_PseudoConstant::financialAccountType($contribution['financial_type_id'], $relationTypeId); $balanceTrxnParams['from_financial_account_id'] = $fromFinancialAccountId; $balanceTrxnParams['total_amount'] = $params['total_amount']; $balanceTrxnParams['contribution_id'] = $params['contribution_id']; $balanceTrxnParams['trxn_date'] = !empty($params['contribution_receive_date']) ? $params['contribution_receive_date'] : date('YmdHis'); $balanceTrxnParams['fee_amount'] = CRM_Utils_Array::value('fee_amount', $params); $balanceTrxnParams['net_amount'] = CRM_Utils_Array::value('total_amount', $params); $balanceTrxnParams['currency'] = $contribution['currency']; $balanceTrxnParams['trxn_id'] = CRM_Utils_Array::value('contribution_trxn_id', $params, NULL); $balanceTrxnParams['status_id'] = $statusId; $balanceTrxnParams['payment_instrument_id'] = CRM_Utils_Array::value('payment_instrument_id', $params, $contribution['payment_instrument_id']); $balanceTrxnParams['check_number'] = CRM_Utils_Array::value('check_number', $params); if ($fromFinancialAccountId != NULL && ($statusId == array_search('Completed', $contributionStatuses) || $statusId == array_search('Partially paid', $contributionStatuses))) { $balanceTrxnParams['is_payment'] = 1; } if (!empty($params['payment_processor'])) { $balanceTrxnParams['payment_processor_id'] = $params['payment_processor']; } return CRM_Core_BAO_FinancialTrxn::create($balanceTrxnParams); }
/** * Function to create all financial accounts entry * * @param array $params contribution object, line item array and params for trxn * * * @access public * @static */ static function recordFinancialAccounts(&$params) { $skipRecords = $update = FALSE; $additionalParticipantId = array(); $contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'); if (CRM_Utils_Array::value('contribution_mode', $params) == 'participant') { $entityId = $params['participant_id']; $entityTable = 'civicrm_participant'; $additionalParticipantId = CRM_Event_BAO_Participant::getAdditionalParticipantIds($entityId); } else { $entityId = $params['contribution']->id; $entityTable = 'civicrm_contribution'; } $entityID[] = $entityId; if (!empty($additionalParticipantId)) { $entityID += $additionalParticipantId; } // prevContribution appears to mean - original contribution object- ie copy of contribution from before the update started that is being updated if (!CRM_Utils_Array::value('prevContribution', $params)) { $entityID = NULL; } else { $update = TRUE; } // build line item array if its not set in $params if (!CRM_Utils_Array::value('line_item', $params) || $additionalParticipantId) { CRM_Price_BAO_LineItem::getLineItemArray($params, $entityID, str_replace('civicrm_', '', $entityTable)); } if (CRM_Utils_Array::value('contribution_status_id', $params) != array_search('Failed', $contributionStatuses) && !(CRM_Utils_Array::value('contribution_status_id', $params) == array_search('Pending', $contributionStatuses) && !$params['contribution']->is_pay_later)) { $skipRecords = TRUE; $pendingStatus = array(array_search('Pending', $contributionStatuses), array_search('In Progress', $contributionStatuses)); if (in_array(CRM_Utils_Array::value('contribution_status_id', $params), $pendingStatus)) { $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Accounts Receivable Account is' ")); $params['to_financial_account_id'] = CRM_Contribute_PseudoConstant::financialAccountType($params['financial_type_id'], $relationTypeId); } elseif (CRM_Utils_Array::value('payment_processor', $params)) { $params['to_financial_account_id'] = CRM_Financial_BAO_FinancialTypeAccount::getFinancialAccount($params['payment_processor'], 'civicrm_payment_processor', 'financial_account_id'); } elseif (CRM_Utils_Array::value('payment_instrument_id', $params)) { $params['to_financial_account_id'] = CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount($params['payment_instrument_id']); } else { $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('financial_account_type', NULL, " AND v.name LIKE 'Asset' ")); $queryParams = array(1 => array($relationTypeId, 'Integer')); $params['to_financial_account_id'] = CRM_Core_DAO::singleValueQuery("SELECT id FROM civicrm_financial_account WHERE is_default = 1 AND financial_account_type_id = %1", $queryParams); } $totalAmount = CRM_Utils_Array::value('total_amount', $params); if (!isset($totalAmount) && CRM_Utils_Array::value('prevContribution', $params)) { $totalAmount = $params['total_amount'] = $params['prevContribution']->total_amount; } //build financial transaction params $trxnParams = array('contribution_id' => $params['contribution']->id, 'to_financial_account_id' => $params['to_financial_account_id'], 'trxn_date' => date('YmdHis'), 'total_amount' => $totalAmount, 'fee_amount' => CRM_Utils_Array::value('fee_amount', $params), 'net_amount' => CRM_Utils_Array::value('net_amount', $params), 'currency' => $params['contribution']->currency, 'trxn_id' => $params['contribution']->trxn_id, 'status_id' => $params['contribution']->contribution_status_id, 'payment_instrument_id' => $params['contribution']->payment_instrument_id, 'check_number' => CRM_Utils_Array::value('check_number', $params)); if (CRM_Utils_Array::value('payment_processor', $params)) { $trxnParams['payment_processor_id'] = $params['payment_processor']; } $params['trxnParams'] = $trxnParams; if (CRM_Utils_Array::value('prevContribution', $params)) { $params['trxnParams']['total_amount'] = $trxnParams['total_amount'] = $params['total_amount'] = $params['prevContribution']->total_amount; $params['trxnParams']['fee_amount'] = $params['prevContribution']->fee_amount; $params['trxnParams']['net_amount'] = $params['prevContribution']->net_amount; $params['trxnParams']['trxn_id'] = $params['prevContribution']->trxn_id; $params['trxnParams']['status_id'] = $params['prevContribution']->contribution_status_id; $params['trxnParams']['payment_instrument_id'] = $params['prevContribution']->payment_instrument_id; $params['trxnParams']['check_number'] = $params['prevContribution']->check_number; //if financial type is changed if (CRM_Utils_Array::value('financial_type_id', $params) && $params['contribution']->financial_type_id != $params['prevContribution']->financial_type_id) { $incomeTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Income Account is' ")); $oldFinancialAccount = CRM_Contribute_PseudoConstant::financialAccountType($params['prevContribution']->financial_type_id, $incomeTypeId); $newFinancialAccount = CRM_Contribute_PseudoConstant::financialAccountType($params['financial_type_id'], $incomeTypeId); if ($oldFinancialAccount != $newFinancialAccount) { $params['total_amount'] = 0; if (in_array($params['contribution']->contribution_status_id, $pendingStatus)) { $params['trxnParams']['to_financial_account_id'] = CRM_Contribute_PseudoConstant::financialAccountType($params['prevContribution']->financial_type_id, $relationTypeId); } else { $lastFinancialTrxnId = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($params['prevContribution']->id, 'DESC'); if (CRM_Utils_Array::value('financialTrxnId', $lastFinancialTrxnId)) { $params['trxnParams']['to_financial_account_id'] = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialTrxn', $lastFinancialTrxnId['financialTrxnId'], 'to_financial_account_id'); } } self::updateFinancialAccounts($params, 'changeFinancialType'); /* $params['trxnParams']['to_financial_account_id'] = $trxnParams['to_financial_account_id']; */ $params['financial_account_id'] = $newFinancialAccount; $params['total_amount'] = $params['trxnParams']['total_amount'] = $trxnParams['total_amount']; self::updateFinancialAccounts($params); $params['trxnParams']['to_financial_account_id'] = $trxnParams['to_financial_account_id']; } } //Update contribution status $params['trxnParams']['status_id'] = $params['contribution']->contribution_status_id; if (CRM_Utils_Array::value('contribution_status_id', $params) && $params['prevContribution']->contribution_status_id != $params['contribution']->contribution_status_id) { //Update Financial Records self::updateFinancialAccounts($params, 'changedStatus'); } // change Payment Instrument for a Completed contribution // first handle special case when contribution is changed from Pending to Completed status when initial payment // instrument is null and now new payment instrument is added along with the payment $params['trxnParams']['payment_instrument_id'] = $params['contribution']->payment_instrument_id; $params['trxnParams']['check_number'] = CRM_Utils_Array::value('check_number', $params); if (array_key_exists('payment_instrument_id', $params)) { $params['trxnParams']['total_amount'] = -$trxnParams['total_amount']; if (CRM_Utils_System::isNull($params['prevContribution']->payment_instrument_id) && !CRM_Utils_System::isNull($params['contribution']->payment_instrument_id)) { //check if status is changed from Pending to Completed // do not update payment instrument changes for Pending to Completed if (!($params['contribution']->contribution_status_id == array_search('Completed', $contributionStatuses) && in_array($params['prevContribution']->contribution_status_id, $pendingStatus))) { // for all other statuses create new financial records self::updateFinancialAccounts($params, 'changePaymentInstrument'); $params['total_amount'] = $params['trxnParams']['total_amount'] = $trxnParams['total_amount']; self::updateFinancialAccounts($params, 'changePaymentInstrument'); } } else { if ((!CRM_Utils_System::isNull($params['contribution']->payment_instrument_id) || !CRM_Utils_System::isNull($params['prevContribution']->payment_instrument_id)) && $params['contribution']->payment_instrument_id != $params['prevContribution']->payment_instrument_id) { // for any other payment instrument changes create new financial records self::updateFinancialAccounts($params, 'changePaymentInstrument'); $params['total_amount'] = $params['trxnParams']['total_amount'] = $trxnParams['total_amount']; self::updateFinancialAccounts($params, 'changePaymentInstrument'); } else { if (!CRM_Utils_System::isNull($params['contribution']->check_number) && $params['contribution']->check_number != $params['prevContribution']->check_number) { // another special case when check number is changed, create new financial records // create financial trxn with negative amount $params['trxnParams']['check_number'] = $params['prevContribution']->check_number; self::updateFinancialAccounts($params, 'changePaymentInstrument'); // create financial trxn with positive amount $params['trxnParams']['check_number'] = $params['contribution']->check_number; $params['total_amount'] = $params['trxnParams']['total_amount'] = $trxnParams['total_amount']; self::updateFinancialAccounts($params, 'changePaymentInstrument'); } } } } //if Change contribution amount $params['trxnParams']['fee_amount'] = CRM_Utils_Array::value('fee_amount', $params); $params['trxnParams']['net_amount'] = CRM_Utils_Array::value('net_amount', $params); $params['trxnParams']['total_amount'] = $trxnParams['total_amount'] = $params['total_amount'] = $totalAmount; $params['trxnParams']['trxn_id'] = $params['contribution']->trxn_id; if (isset($totalAmount) && $totalAmount != $params['prevContribution']->total_amount) { //Update Financial Records $params['trxnParams']['from_financial_account_id'] = NULL; self::updateFinancialAccounts($params, 'changedAmount'); } } if (!$update) { //records finanical trxn and entity financial trxn $financialTxn = CRM_Core_BAO_FinancialTrxn::create($trxnParams); $params['entity_id'] = $financialTxn->id; } } // record line items and finacial items if (!CRM_Utils_Array::value('skipLineItem', $params)) { CRM_Price_BAO_LineItem::processPriceSet($entityId, CRM_Utils_Array::value('line_item', $params), $params['contribution'], $entityTable, $update); } // create batch entry if batch_id is passed if (CRM_Utils_Array::value('batch_id', $params)) { $entityParams = array('batch_id' => $params['batch_id'], 'entity_table' => 'civicrm_financial_trxn', 'entity_id' => $financialTxn->id); CRM_Batch_BAO_Batch::addBatchEntity($entityParams); } // when a fee is charged if (CRM_Utils_Array::value('fee_amount', $params) && (!CRM_Utils_Array::value('prevContribution', $params) || $params['contribution']->fee_amount != $params['prevContribution']->fee_amount) && $skipRecords) { CRM_Core_BAO_FinancialTrxn::recordFees($params); } if (CRM_Utils_Array::value('prevContribution', $params) && $entityTable == 'civicrm_participant' && $params['prevContribution']->contribution_status_id != $params['contribution']->contribution_status_id) { $eventID = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Participant', $entityId, 'event_id'); $feeLevel[] = str_replace('', '', $params['prevContribution']->amount_level); CRM_Event_BAO_Participant::createDiscountTrxn($eventID, $params, $feeLevel); } unset($params['line_item']); }
private function addAccountingEntries() { $components = array('contribution', 'membership', 'participant'); $select = 'SELECT contribution.id contribution_id, cli.id as line_item_id, contribution.contact_id, contribution.receive_date, contribution.total_amount, contribution.currency, cli.label, cli.financial_type_id, cefa.financial_account_id, contribution.payment_instrument_id, contribution.check_number, contribution.trxn_id'; $where = 'WHERE cefa.account_relationship = 1'; $financialAccountId = CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount(); foreach ($components as $component) { if ($component == 'contribution') { $from = 'FROM `civicrm_contribution` contribution'; } else { $from = " FROM `civicrm_{$component}` {$component}\n INNER JOIN civicrm_{$component}_payment cpp ON cpp.{$component}_id = {$component}.id\n INNER JOIN civicrm_contribution contribution on contribution.id = cpp.contribution_id"; } $from .= " INNER JOIN civicrm_line_item cli ON cli.entity_id = {$component}.id and cli.entity_table = 'civicrm_{$component}'\n INNER JOIN civicrm_entity_financial_account cefa ON cefa.entity_id = cli.financial_type_id "; $sql = " {$select} {$from} {$where} "; $result = CRM_Core_DAO::executeQuery($sql); $this->addFinancialItem($result, $financialAccountId); } }