First commit

This commit is contained in:
Theodotos Andreou 2018-01-14 13:10:16 +00:00
commit c6e2478c40
13918 changed files with 2303184 additions and 0 deletions

View file

@ -0,0 +1,259 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
/**
* Base class for Export Formats
* Create a subclass for a specific format.
* @see http://wiki.civicrm.org/confluence/display/CRM/CiviAccounts+Specifications+-++Batches#CiviAccountsSpecifications-Batches-%C2%A0Overviewofimplementation
*/
abstract class CRM_Financial_BAO_ExportFormat {
/**
* data which the individual export formats will output in the desired format.
* @var array
*/
protected $_exportParams;
/**
* smarty template.
* @var CRM_Core_Smarty
*/
static protected $_template;
/**
* Class constructor.
*/
public function __construct() {
if (!isset(self::$_template)) {
self::$_template = CRM_Core_Smarty::singleton();
}
}
/**
* Override to assemble the appropriate subset of financial data for the specific export format.
* @param array $exportParams
*
* @return mixed
*/
public function export($exportParams) {
$this->_exportParams = $exportParams;
return $exportParams;
}
/**
* Exports sbatches in $this->_batchIds, and saves to file.
*
* @param string $fileName - use this file name (if applicable)
*/
public function output($fileName = NULL) {
// Default behaviour, override if needed:
self::createActivityExport($this->_batchIds, $fileName);
}
/**
* Abstract function that generates exports, and downloads them as zip file.
*
* @param $exportDaos array with DAO's for queries to be exported.
*/
public abstract function makeExport($exportDaos);
/**
* @return string
*/
public function getMimeType() {
return 'text/plain';
}
/**
* Returns some kind of identification for your export format.
*
* This does not really has to be a file extension, you can name your
* file as you wish as you override output.
*
* @return string
*/
public abstract function getFileExtension();
/**
* @return object
*/
public static function &getTemplate() {
return self::$_template;
}
/**
* @param $var
* @param null $value
*/
public function assign($var, $value = NULL) {
self::$_template->assign($var, $value);
}
/*
* This gets called for every item of data being compiled before being sent to the exporter for output.
*
* Depending on the output format might want to override this, e.g. for IIF tabs need to be escaped etc,
* but for CSV it doesn't make sense because php has built in csv output functions.
*/
/**
* @param $s
* @param string $type
*
* @return null
*/
public static function format($s, $type = 'string') {
if (!empty($s)) {
return $s;
}
else {
return NULL;
}
}
public function initiateDownload() {
$config = CRM_Core_Config::singleton();
// zip files if more than one.
if (count($this->_downloadFile) > 1) {
$zip = $config->customFileUploadDir . 'Financial_Transactions_' . date('YmdHis') . '.zip';
$result = $this->createZip($this->_downloadFile, $zip, TRUE);
if ($result) {
CRM_Utils_System::setHttpHeader('Content-Type', 'application/zip');
CRM_Utils_System::setHttpHeader('Content-Disposition', 'attachment; filename=' . CRM_Utils_File::cleanFileName(basename($zip)));
CRM_Utils_System::setHttpHeader('Content-Length', '' . filesize($zip));
ob_clean();
flush();
readfile($config->customFileUploadDir . CRM_Utils_File::cleanFileName(basename($zip)));
unlink($zip); //delete the zip to avoid clutter.
CRM_Utils_System::civiExit();
}
}
else {
CRM_Utils_System::setHttpHeader('Content-Type', 'text/plain');
CRM_Utils_System::setHttpHeader('Content-Disposition', 'attachment; filename=' . CRM_Utils_File::cleanFileName(basename($this->_downloadFile[0])));
CRM_Utils_System::setHttpHeader('Content-Length', '' . filesize($this->_downloadFile[0]));
ob_clean();
flush();
readfile($config->customFileUploadDir . CRM_Utils_File::cleanFileName(basename($this->_downloadFile[0])));
CRM_Utils_System::civiExit();
}
}
/**
* @param $batchIds
* @param string $fileName
*
* @throws CRM_Core_Exception
*/
public static function createActivityExport($batchIds, $fileName) {
$session = CRM_Core_Session::singleton();
$values = array();
$params = array('id' => $batchIds);
CRM_Batch_BAO_Batch::retrieve($params, $values);
$createdBy = CRM_Contact_BAO_Contact::displayName($values['created_id']);
$modifiedBy = CRM_Contact_BAO_Contact::displayName($values['modified_id']);
$values['payment_instrument_id'] = '';
if (isset($values['payment_instrument_id'])) {
$paymentInstrument = array_flip(CRM_Contribute_PseudoConstant::paymentInstrument('label'));
$values['payment_instrument_id'] = array_search($values['payment_instrument_id'], $paymentInstrument);
}
$details = '<p>' . ts('Record:') . ' ' . $values['title'] . '</p><p>' . ts('Description:') . '</p><p>' . ts('Created By:') . " $createdBy" . '</p><p>' . ts('Created Date:') . ' ' . $values['created_date'] . '</p><p>' . ts('Last Modified By:') . ' ' . $modifiedBy . '</p><p>' . ts('Payment Method:') . ' ' . $values['payment_instrument_id'] . '</p>';
$subject = '';
if (!empty($values['total'])) {
$subject .= ts('Total') . '[' . CRM_Utils_Money::format($values['total']) . '],';
}
if (!empty($values['item_count'])) {
$subject .= ' ' . ts('Count') . '[' . $values['item_count'] . '],';
}
// create activity.
$subject .= ' ' . ts('Batch') . '[' . $values['title'] . ']';
$activityTypes = CRM_Core_PseudoConstant::activityType(TRUE, FALSE, FALSE, 'name');
$activityParams = array(
'activity_type_id' => array_search('Export Accounting Batch', $activityTypes),
'subject' => $subject,
'status_id' => 2,
'activity_date_time' => date('YmdHis'),
'source_contact_id' => $session->get('userID'),
'source_record_id' => $values['id'],
'target_contact_id' => $session->get('userID'),
'details' => $details,
'attachFile_1' => array(
'uri' => $fileName,
'type' => 'text/csv',
'location' => $fileName,
'upload_date' => date('YmdHis'),
),
);
CRM_Activity_BAO_Activity::create($activityParams);
}
/**
* @param array $files
* @param null $destination
* @param bool $overwrite
*
* @return bool
*/
public function createZip($files = array(), $destination = NULL, $overwrite = FALSE) {
// if the zip file already exists and overwrite is false, return false
if (file_exists($destination) && !$overwrite) {
return FALSE;
}
$valid_files = array();
if (is_array($files)) {
foreach ($files as $file) {
// make sure the file exists
if (file_exists($file)) {
$validFiles[] = $file;
}
}
}
if (count($validFiles)) {
$zip = new ZipArchive();
if ($zip->open($destination, $overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== TRUE) {
return FALSE;
}
foreach ($validFiles as $file) {
$zip->addFile($file, CRM_Utils_File::cleanFileName(basename($file)));
}
$zip->close();
return file_exists($destination);
}
else {
return FALSE;
}
}
}

View file

@ -0,0 +1,256 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
/**
* @link http://wiki.civicrm.org/confluence/display/CRM/CiviAccounts+Specifications+-++Batches#CiviAccountsSpecifications-Batches-%C2%A0Overviewofimplementation
*/
class CRM_Financial_BAO_ExportFormat_CSV extends CRM_Financial_BAO_ExportFormat {
/**
* For this phase, we always output these records too so that there isn't data
* referenced in the journal entries that isn't defined anywhere.
*
* Possibly in the future this could be selected by the user.
*/
public static $complementaryTables = array(
'ACCNT',
'CUST',
);
/**
* Class constructor.
*/
public function __construct() {
parent::__construct();
}
/**
* @param array $exportParams
*/
public function export($exportParams) {
$export = parent::export($exportParams);
// Save the file in the public directory.
$fileName = self::putFile($export);
foreach (self::$complementaryTables as $rct) {
$func = "export{$rct}";
$this->$func();
}
$this->output($fileName);
}
/**
* @param int $batchId
*
* @return Object
*/
public function generateExportQuery($batchId) {
$sql = "SELECT
ft.id as financial_trxn_id,
ft.trxn_date,
fa_to.accounting_code AS to_account_code,
fa_to.name AS to_account_name,
fa_to.account_type_code AS to_account_type_code,
ft.total_amount AS debit_total_amount,
ft.trxn_id AS trxn_id,
cov.label AS payment_instrument,
ft.check_number,
c.source AS source,
c.id AS contribution_id,
c.contact_id AS contact_id,
eb.batch_id AS batch_id,
ft.currency AS currency,
cov_status.label AS status,
CASE
WHEN efti.entity_id IS NOT NULL
THEN efti.amount
ELSE eftc.amount
END AS amount,
fa_from.account_type_code AS credit_account_type_code,
fa_from.accounting_code AS credit_account,
fa_from.name AS credit_account_name,
fac.account_type_code AS from_credit_account_type_code,
fac.accounting_code AS from_credit_account,
fac.name AS from_credit_account_name,
fi.description AS item_description
FROM civicrm_entity_batch eb
LEFT JOIN civicrm_financial_trxn ft ON (eb.entity_id = ft.id AND eb.entity_table = 'civicrm_financial_trxn')
LEFT JOIN civicrm_financial_account fa_to ON fa_to.id = ft.to_financial_account_id
LEFT JOIN civicrm_financial_account fa_from ON fa_from.id = ft.from_financial_account_id
LEFT JOIN civicrm_option_group cog ON cog.name = 'payment_instrument'
LEFT JOIN civicrm_option_value cov ON (cov.value = ft.payment_instrument_id AND cov.option_group_id = cog.id)
LEFT JOIN civicrm_entity_financial_trxn eftc ON (eftc.financial_trxn_id = ft.id AND eftc.entity_table = 'civicrm_contribution')
LEFT JOIN civicrm_contribution c ON c.id = eftc.entity_id
LEFT JOIN civicrm_option_group cog_status ON cog_status.name = 'contribution_status'
LEFT JOIN civicrm_option_value cov_status ON (cov_status.value = ft.status_id AND cov_status.option_group_id = cog_status.id)
LEFT JOIN civicrm_entity_financial_trxn efti ON (efti.financial_trxn_id = ft.id AND efti.entity_table = 'civicrm_financial_item')
LEFT JOIN civicrm_financial_item fi ON fi.id = efti.entity_id
LEFT JOIN civicrm_financial_account fac ON fac.id = fi.financial_account_id
LEFT JOIN civicrm_financial_account fa ON fa.id = fi.financial_account_id
WHERE eb.batch_id = ( %1 )";
CRM_Utils_Hook::batchQuery($sql);
$params = array(1 => array($batchId, 'String'));
$dao = CRM_Core_DAO::executeQuery($sql, $params);
return $dao;
}
/**
* @param $export
*
* @return string
*/
public function putFile($export) {
$config = CRM_Core_Config::singleton();
$fileName = $config->uploadDir . 'Financial_Transactions_' . $this->_batchIds . '_' . date('YmdHis') . '.' . $this->getFileExtension();
$this->_downloadFile[] = $config->customFileUploadDir . CRM_Utils_File::cleanFileName(basename($fileName));
$out = fopen($fileName, 'w');
if (!empty($export['headers'])) {
fputcsv($out, $export['headers']);
}
unset($export['headers']);
if (!empty($export)) {
foreach ($export as $fields) {
fputcsv($out, $fields);
}
fclose($out);
}
return $fileName;
}
/**
* Format table headers.
*
* @param array $values
* @return array
*/
public function formatHeaders($values) {
$arrayKeys = array_keys($values);
$headers = '';
if (!empty($arrayKeys)) {
foreach ($values[$arrayKeys[0]] as $title => $value) {
$headers[] = $title;
}
}
return $headers;
}
/**
* Generate CSV array for export.
*
* @param array $export
*/
public function makeExport($export) {
// getting data from admin page
$prefixValue = Civi::settings()->get('contribution_invoice_settings');
foreach ($export as $batchId => $dao) {
$financialItems = array();
$this->_batchIds = $batchId;
$batchItems = array();
$queryResults = array();
while ($dao->fetch()) {
$creditAccountName = $creditAccountType = $creditAccount = NULL;
if ($dao->credit_account) {
$creditAccountName = $dao->credit_account_name;
$creditAccountType = $dao->credit_account_type_code;
$creditAccount = $dao->credit_account;
}
else {
$creditAccountName = $dao->from_credit_account_name;
$creditAccountType = $dao->from_credit_account_type_code;
$creditAccount = $dao->from_credit_account;
}
$invoiceNo = CRM_Utils_Array::value('invoice_prefix', $prefixValue) . "" . $dao->contribution_id;
$financialItems[] = array(
'Batch ID' => $dao->batch_id,
'Invoice No' => $invoiceNo,
'Contact ID' => $dao->contact_id,
'Financial Trxn ID/Internal ID' => $dao->financial_trxn_id,
'Transaction Date' => $dao->trxn_date,
'Debit Account' => $dao->to_account_code,
'Debit Account Name' => $dao->to_account_name,
'Debit Account Type' => $dao->to_account_type_code,
'Debit Account Amount (Unsplit)' => $dao->debit_total_amount,
'Transaction ID (Unsplit)' => $dao->trxn_id,
'Debit amount (Split)' => $dao->amount,
'Payment Instrument' => $dao->payment_instrument,
'Check Number' => $dao->check_number,
'Source' => $dao->source,
'Currency' => $dao->currency,
'Transaction Status' => $dao->status,
'Amount' => $dao->amount,
'Credit Account' => $creditAccount,
'Credit Account Name' => $creditAccountName,
'Credit Account Type' => $creditAccountType,
'Item Description' => $dao->item_description,
);
end($financialItems);
$batchItems[] = &$financialItems[key($financialItems)];
$queryResults[] = get_object_vars($dao);
}
CRM_Utils_Hook::batchItems($queryResults, $batchItems);
$financialItems['headers'] = self::formatHeaders($financialItems);
self::export($financialItems);
}
parent::initiateDownload();
}
/**
* @return string
*/
public function getFileExtension() {
return 'csv';
}
public function exportACCNT() {
}
public function exportCUST() {
}
public function exportTRANS() {
}
}

View file

@ -0,0 +1,389 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
/**
* @link http://wiki.civicrm.org/confluence/display/CRM/CiviAccounts+Specifications+-++Batches#CiviAccountsSpecifications-Batches-%C2%A0Overviewofimplementation
*/
class CRM_Financial_BAO_ExportFormat_IIF extends CRM_Financial_BAO_ExportFormat {
/**
* Tab character. Some people's editors replace tabs with spaces so I'm scared to use actual tabs.
* Can't set it here using chr() because static. Same thing if a const. So it's set in constructor.
*/
static $SEPARATOR;
/**
* For this phase, we always output these records too so that there isn't data
* referenced in the journal entries that isn't defined anywhere.
*
* Possibly in the future this could be selected by the user.
*/
public static $complementaryTables = array(
'ACCNT',
'CUST',
);
/**
* Class constructor.
*/
public function __construct() {
parent::__construct();
self::$SEPARATOR = chr(9);
}
/**
* @param array $exportParams
*/
public function export($exportParams) {
parent::export($exportParams);
foreach (self::$complementaryTables as $rct) {
$func = "export{$rct}";
$this->$func();
}
// now do general journal entries
$this->exportTRANS();
$this->output();
}
/**
* @param null $fileName
*/
public function output($fileName = NULL) {
$tplFile = $this->getHookedTemplateFileName();
$out = self::getTemplate()->fetch($tplFile);
$fileName = $this->putFile($out);
self::createActivityExport($this->_batchIds, $fileName);
}
/**
* @param $out
*
* @return string
*/
public function putFile($out) {
$config = CRM_Core_Config::singleton();
$fileName = $config->uploadDir . 'Financial_Transactions_' . $this->_batchIds . '_' . date('YmdHis') . '.' . $this->getFileExtension();
$this->_downloadFile[] = $config->customFileUploadDir . CRM_Utils_File::cleanFileName(basename($fileName));
$buffer = fopen($fileName, 'w');
fwrite($buffer, $out);
fclose($buffer);
return $fileName;
}
/**
* @param int $batchId
*
* @return Object
*/
public function generateExportQuery($batchId) {
$sql = "SELECT
ft.id as financial_trxn_id,
ft.trxn_date,
ft.total_amount AS debit_total_amount,
ft.currency AS currency,
ft.trxn_id AS trxn_id,
cov.label AS payment_instrument,
ft.check_number,
fa_from.id AS from_account_id,
fa_from.name AS from_account_name,
fa_from.accounting_code AS from_account_code,
fa_from.financial_account_type_id AS from_account_type_id,
fa_from.description AS from_account_description,
fa_from.account_type_code AS from_account_type_code,
fa_to.id AS to_account_id,
fa_to.name AS to_account_name,
fa_to.accounting_code AS to_account_code,
fa_to.financial_account_type_id AS to_account_type_id,
fa_to.account_type_code AS to_account_type_code,
fa_to.description AS to_account_description,
fi.description AS item_description,
contact_from.id AS contact_from_id,
contact_from.display_name AS contact_from_name,
contact_from.first_name AS contact_from_first_name,
contact_from.last_name AS contact_from_last_name,
contact_to.id AS contact_to_id,
contact_to.display_name AS contact_to_name,
contact_to.first_name AS contact_to_first_name,
contact_to.last_name AS contact_to_last_name
FROM civicrm_entity_batch eb
LEFT JOIN civicrm_financial_trxn ft ON (eb.entity_id = ft.id AND eb.entity_table = 'civicrm_financial_trxn')
LEFT JOIN civicrm_financial_account fa_from ON fa_from.id = ft.from_financial_account_id
LEFT JOIN civicrm_financial_account fa_to ON fa_to.id = ft.to_financial_account_id
LEFT JOIN civicrm_option_group cog ON cog.name = 'payment_instrument'
LEFT JOIN civicrm_option_value cov ON (cov.value = ft.payment_instrument_id AND cov.option_group_id = cog.id)
LEFT JOIN civicrm_contact contact_from ON contact_from.id = fa_from.contact_id
LEFT JOIN civicrm_contact contact_to ON contact_to.id = fa_to.contact_id
LEFT JOIN civicrm_entity_financial_trxn efti ON (efti.financial_trxn_id = ft.id AND efti.entity_table = 'civicrm_financial_item')
LEFT JOIN civicrm_financial_item fi ON fi.id = efti.entity_id
WHERE eb.batch_id = ( %1 )";
$params = array(1 => array($batchId, 'String'));
$dao = CRM_Core_DAO::executeQuery($sql, $params);
return $dao;
}
/**
* @param $export
*/
public function makeExport($export) {
// Keep running list of accounts and contacts used in this batch, since we need to
// include those in the output. Only want to include ones used in the batch, not everything in the db,
// since would increase the chance of messing up user's existing Quickbooks entries.
foreach ($export as $batchId => $dao) {
$accounts = $contacts = $journalEntries = $exportParams = array();
$this->_batchIds = $batchId;
while ($dao->fetch()) {
// add to running list of accounts
if (!empty($dao->from_account_id) && !isset($accounts[$dao->from_account_id])) {
$accounts[$dao->from_account_id] = array(
'name' => $this->format($dao->from_account_name),
'account_code' => $this->format($dao->from_account_code),
'description' => $this->format($dao->from_account_description),
'type' => $this->format($dao->from_account_type_code),
);
}
if (!empty($dao->to_account_id) && !isset($accounts[$dao->to_account_id])) {
$accounts[$dao->to_account_id] = array(
'name' => $this->format($dao->to_account_name),
'account_code' => $this->format($dao->to_account_code),
'description' => $this->format($dao->to_account_description),
'type' => $this->format($dao->to_account_type_code),
);
}
// add to running list of contacts
if (!empty($dao->contact_from_id) && !isset($contacts[$dao->contact_from_id])) {
$contacts[$dao->contact_from_id] = array(
'name' => $this->format($dao->contact_from_name),
'first_name' => $this->format($dao->contact_from_first_name),
'last_name' => $this->format($dao->contact_from_last_name),
);
}
if (!empty($dao->contact_to_id) && !isset($contacts[$dao->contact_to_id])) {
$contacts[$dao->contact_to_id] = array(
'name' => $this->format($dao->contact_to_name),
'first_name' => $this->format($dao->contact_to_first_name),
'last_name' => $this->format($dao->contact_to_last_name),
);
}
// set up the journal entries for this financial trxn
$journalEntries[$dao->financial_trxn_id] = array(
'to_account' => array(
'trxn_date' => $this->format($dao->trxn_date, 'date'),
'trxn_id' => $this->format($dao->trxn_id),
'account_name' => $this->format($dao->to_account_name),
'amount' => $this->format($dao->debit_total_amount, 'money'),
'contact_name' => $this->format($dao->contact_to_name),
'payment_instrument' => $this->format($dao->payment_instrument),
'check_number' => $this->format($dao->check_number),
),
'splits' => array(),
);
/*
* splits has two possibilities depending on FROM account
*/
if (empty($dao->from_account_id)) {
// In this case, split records need to use the individual financial_item account for each item in the trxn
$item_sql = "SELECT
fa.id AS account_id,
fa.name AS account_name,
fa.accounting_code AS account_code,
fa.description AS account_description,
fi.description AS description,
fi.id AS financial_item_id,
fi.currency AS currency,
cov.label AS payment_instrument,
ft.check_number AS check_number,
fi.transaction_date AS transaction_date,
fi.amount AS amount,
fa.account_type_code AS account_type_code,
contact.id AS contact_id,
contact.display_name AS contact_name,
contact.first_name AS contact_first_name,
contact.last_name AS contact_last_name
FROM civicrm_entity_financial_trxn eft
LEFT JOIN civicrm_financial_item fi ON eft.entity_id = fi.id
LEFT JOIN civicrm_financial_trxn ft ON ft.id = eft.financial_trxn_id
LEFT JOIN civicrm_option_group cog ON cog.name = 'payment_instrument'
LEFT JOIN civicrm_option_value cov ON (cov.value = ft.payment_instrument_id AND cov.option_group_id = cog.id)
LEFT JOIN civicrm_financial_account fa ON fa.id = fi.financial_account_id
LEFT JOIN civicrm_contact contact ON contact.id = fi.contact_id
WHERE eft.entity_table = 'civicrm_financial_item'
AND eft.financial_trxn_id = %1";
$itemParams = array(1 => array($dao->financial_trxn_id, 'Integer'));
$itemDAO = CRM_Core_DAO::executeQuery($item_sql, $itemParams);
while ($itemDAO->fetch()) {
// add to running list of accounts
if (!empty($itemDAO->account_id) && !isset($accounts[$itemDAO->account_id])) {
$accounts[$itemDAO->account_id] = array(
'name' => $this->format($itemDAO->account_name),
'account_code' => $this->format($itemDAO->account_code),
'description' => $this->format($itemDAO->account_description),
'type' => $this->format($itemDAO->account_type_code),
);
}
if (!empty($itemDAO->contact_id) && !isset($contacts[$itemDAO->contact_id])) {
$contacts[$itemDAO->contact_id] = array(
'name' => $this->format($itemDAO->contact_name),
'first_name' => $this->format($itemDAO->contact_first_name),
'last_name' => $this->format($itemDAO->contact_last_name),
);
}
// add split line for this item
$journalEntries[$dao->financial_trxn_id]['splits'][$itemDAO->financial_item_id] = array(
'trxn_date' => $this->format($itemDAO->transaction_date, 'date'),
'spl_id' => $this->format($itemDAO->financial_item_id),
'account_name' => $this->format($itemDAO->account_name),
'amount' => '-' . $this->format($itemDAO->amount, 'money'),
'contact_name' => $this->format($itemDAO->contact_name),
'payment_instrument' => $this->format($itemDAO->payment_instrument),
'description' => $this->format($itemDAO->description),
'check_number' => $this->format($itemDAO->check_number),
'currency' => $this->format($itemDAO->currency),
);
} // end items loop
$itemDAO->free();
}
else {
// In this case, split record just uses the FROM account from the trxn, and there's only one record here
$journalEntries[$dao->financial_trxn_id]['splits'][] = array(
'trxn_date' => $this->format($dao->trxn_date, 'date'),
'spl_id' => $this->format($dao->financial_trxn_id),
'account_name' => $this->format($dao->from_account_name),
'amount' => '-' . $this->format($dao->debit_total_amount, 'money'),
'contact_name' => $this->format($dao->contact_from_name),
'description' => $this->format($dao->item_description),
'payment_instrument' => $this->format($dao->payment_instrument),
'check_number' => $this->format($dao->check_number),
'currency' => $this->format($dao->currency),
);
}
}
$exportParams = array(
'accounts' => $accounts,
'contacts' => $contacts,
'journalEntries' => $journalEntries,
);
self::export($exportParams);
}
parent::initiateDownload();
}
public function exportACCNT() {
self::assign('accounts', $this->_exportParams['accounts']);
}
public function exportCUST() {
self::assign('contacts', $this->_exportParams['contacts']);
}
public function exportTRANS() {
self::assign('journalEntries', $this->_exportParams['journalEntries']);
}
/**
* @return string
*/
public function getMimeType() {
return 'application/octet-stream';
}
/**
* @return string
*/
public function getFileExtension() {
return 'iif';
}
/**
* @return string
*/
public function getHookedTemplateFileName() {
return 'CRM/Financial/ExportFormat/IIF.tpl';
}
/**
* @param string $s
* the input string
* @param string $type
* type can be string, date, or notepad
*
* @return bool|mixed|string
*/
public static function format($s, $type = 'string') {
// If I remember right there's a couple things:
// NOTEPAD field needs to be surrounded by quotes and then get rid of double quotes inside, also newlines should be literal \n, and ditch any ascii 0x0d's.
// Date handling has changed over the years. It used to only understand mm/dd/yy but I think now it might depend on your OS settings. Sometimes mm/dd/yyyy works but sometimes it wants yyyy/mm/dd, at least where I had used it.
// In all cases need to do something with tabs in the input.
$s1 = str_replace(self::$SEPARATOR, '\t', $s);
switch ($type) {
case 'date':
$dateFormat = Civi::settings()->get('dateformatFinancialBatch');
$sout = CRM_Utils_Date::customFormat($s1, $dateFormat);
break;
case 'money':
$sout = CRM_Utils_Money::format($s, NULL, NULL, TRUE);
break;
case 'string':
case 'notepad':
$s2 = str_replace("\n", '\n', $s1);
$s3 = str_replace("\r", '', $s2);
$s4 = str_replace('"', "'", $s3);
if ($type == 'notepad') {
$sout = '"' . $s4 . '"';
}
else {
$sout = $s4;
}
break;
}
return $sout;
}
}

View file

@ -0,0 +1,480 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
class CRM_Financial_BAO_FinancialAccount extends CRM_Financial_DAO_FinancialAccount {
/**
* Static holder for the default LT.
*/
static $_defaultContributionType = NULL;
/**
* Class constructor.
*/
public function __construct() {
parent::__construct();
}
/**
* Fetch object based on array of properties.
*
* @param array $params
* (reference ) an assoc array of name/value pairs.
* @param array $defaults
* (reference ) an assoc array to hold the flattened values.
*
* @return CRM_Financial_BAO_FinancialAccount
*/
public static function retrieve(&$params, &$defaults) {
$financialAccount = new CRM_Financial_DAO_FinancialAccount();
$financialAccount->copyValues($params);
if ($financialAccount->find(TRUE)) {
CRM_Core_DAO::storeValues($financialAccount, $defaults);
return $financialAccount;
}
return NULL;
}
/**
* Update the is_active flag in the db.
*
* @param int $id
* Id of the database record.
* @param bool $is_active
* Value we want to set the is_active field.
*
* @return CRM_Core_DAO|null
* DAO object on success, null otherwise
*/
public static function setIsActive($id, $is_active) {
return CRM_Core_DAO::setFieldValue('CRM_Financial_DAO_FinancialAccount', $id, 'is_active', $is_active);
}
/**
* Add the financial types.
*
* @param array $params
* Reference array contains the values submitted by the form.
*
* @return CRM_Financial_DAO_FinancialAccount
*/
public static function add(&$params) {
if (empty($params['id'])) {
$params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE);
$params['is_deductible'] = CRM_Utils_Array::value('is_deductible', $params, FALSE);
$params['is_tax'] = CRM_Utils_Array::value('is_tax', $params, FALSE);
$params['is_header_account'] = CRM_Utils_Array::value('is_header_account', $params, FALSE);
$params['is_default'] = CRM_Utils_Array::value('is_default', $params, FALSE);
}
if (!empty($params['id'])
&& !empty($params['financial_account_type_id'])
&& CRM_Financial_BAO_FinancialAccount::validateFinancialAccount(
$params['id'],
$params['financial_account_type_id']
)
) {
throw new CRM_Core_Exception(ts('You cannot change the account type since this financial account refers to a financial item having an account type of Revenue/Liability.'));
}
if (!empty($params['is_default'])) {
$query = 'UPDATE civicrm_financial_account SET is_default = 0 WHERE financial_account_type_id = %1';
$queryParams = array(1 => array($params['financial_account_type_id'], 'Integer'));
CRM_Core_DAO::executeQuery($query, $queryParams);
}
// action is taken depending upon the mode
$financialAccount = new CRM_Financial_DAO_FinancialAccount();
// invoke pre hook
$op = 'create';
if (!empty($params['id'])) {
$op = 'edit';
}
CRM_Utils_Hook::pre($op, 'FinancialAccount', CRM_Utils_Array::value('id', $params), $params);
if (!empty($params['id'])) {
$financialAccount->id = $params['id'];
$financialAccount->find(TRUE);
}
$financialAccount->copyValues($params);
$financialAccount->save();
// invoke post hook
$op = 'create';
if (!empty($params['id'])) {
$op = 'edit';
}
CRM_Utils_Hook::post($op, 'FinancialAccount', $financialAccount->id, $financialAccount);
return $financialAccount;
}
/**
* Delete financial Types.
*
* @param int $financialAccountId
*/
public static function del($financialAccountId) {
// checking if financial type is present
$check = FALSE;
//check dependencies
$dependency = array(
array('Core', 'FinancialTrxn', 'to_financial_account_id'),
array('Financial', 'FinancialTypeAccount', 'financial_account_id'),
array('Financial', 'FinancialItem', 'financial_account_id'),
);
foreach ($dependency as $name) {
require_once str_replace('_', DIRECTORY_SEPARATOR, "CRM_" . $name[0] . "_BAO_" . $name[1]) . ".php";
$className = "CRM_{$name[0]}_BAO_{$name[1]}";
$bao = new $className();
$bao->{$name[2]} = $financialAccountId;
if ($bao->find(TRUE)) {
$check = TRUE;
}
}
if ($check) {
CRM_Core_Session::setStatus(ts('This financial account cannot be deleted since it is being used as a header account. Please remove it from being a header account before trying to delete it again.'));
return FALSE;
}
// delete from financial Type table
$financialAccount = new CRM_Financial_DAO_FinancialAccount();
$financialAccount->id = $financialAccountId;
$financialAccount->delete();
return TRUE;
}
/**
* Get accounting code for a financial type with account relation Income Account is.
*
* @param int $financialTypeId
*
* @return int
* accounting code
*/
public static function getAccountingCode($financialTypeId) {
$relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Income Account is' "));
$query = "SELECT cfa.accounting_code
FROM civicrm_financial_type cft
LEFT JOIN civicrm_entity_financial_account cefa ON cefa.entity_id = cft.id AND cefa.entity_table = 'civicrm_financial_type'
LEFT JOIN civicrm_financial_account cfa ON cefa.financial_account_id = cfa.id
WHERE cft.id = %1
AND account_relationship = %2";
$params = array(
1 => array($financialTypeId, 'Integer'),
2 => array($relationTypeId, 'Integer'),
);
return CRM_Core_DAO::singleValueQuery($query, $params);
}
/**
* Get AR account.
*
* @param $financialAccountId
* Financial account id.
*
* @param $financialAccountTypeId
* Financial account type id.
*
* @param string $accountTypeCode
* account type code
*
* @return int
* count
*/
public static function getARAccounts($financialAccountId, $financialAccountTypeId = NULL, $accountTypeCode = 'ar') {
if (!$financialAccountTypeId) {
$financialAccountTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('financial_account_type', NULL, " AND v.name LIKE 'Asset' "));
}
$query = "SELECT count(id) FROM civicrm_financial_account WHERE financial_account_type_id = %1 AND LCASE(account_type_code) = %2
AND id != %3 AND is_active = 1;";
$params = array(
1 => array($financialAccountTypeId, 'Integer'),
2 => array(strtolower($accountTypeCode), 'String'),
3 => array($financialAccountId, 'Integer'),
);
return CRM_Core_DAO::singleValueQuery($query, $params);
}
/**
* Get the Financial Account for a Financial Type Relationship Combo.
*
* Note that some relationships are optionally configured - so far
* Chargeback and Credit / Contra. Since these are the only 2 currently Income
* is an appropriate fallback. In future it might make sense to extend the logic.
*
* Note that we avoid the CRM_Core_PseudoConstant function as it stores one
* account per financial type and is unreliable.
*
* @param int $financialTypeID
*
* @param string $relationshipType
*
* @return int
*/
public static function getFinancialAccountForFinancialTypeByRelationship($financialTypeID, $relationshipType) {
$relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE '{$relationshipType}' "));
if (!isset(Civi::$statics[__CLASS__]['entity_financial_account'][$financialTypeID][$relationTypeId])) {
$accounts = civicrm_api3('EntityFinancialAccount', 'get', array(
'entity_id' => $financialTypeID,
'entity_table' => 'civicrm_financial_type',
));
foreach ($accounts['values'] as $account) {
Civi::$statics[__CLASS__]['entity_financial_account'][$financialTypeID][$account['account_relationship']] = $account['financial_account_id'];
}
$accountRelationships = CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL);
$incomeAccountRelationshipID = array_search('Income Account is', $accountRelationships);
$incomeAccountFinancialAccountID = Civi::$statics[__CLASS__]['entity_financial_account'][$financialTypeID][$incomeAccountRelationshipID];
foreach (array('Chargeback Account is', 'Credit/Contra Revenue Account is') as $optionalAccountRelationship) {
$accountRelationshipID = array_search($optionalAccountRelationship, $accountRelationships);
if (empty(Civi::$statics[__CLASS__]['entity_financial_account'][$financialTypeID][$accountRelationshipID])) {
Civi::$statics[__CLASS__]['entity_financial_account'][$financialTypeID][$accountRelationshipID] = $incomeAccountFinancialAccountID;
}
}
}
return Civi::$statics[__CLASS__]['entity_financial_account'][$financialTypeID][$relationTypeId];
}
/**
* Get Financial Account type relations.
*
* @param $flip bool
*
* @return array
*
*/
public static function getfinancialAccountRelations($flip = FALSE) {
$params = array('labelColumn' => 'name');
$financialAccountType = CRM_Core_PseudoConstant::get('CRM_Financial_DAO_FinancialAccount', 'financial_account_type_id', $params);
$accountRelationships = CRM_Core_PseudoConstant::get('CRM_Financial_DAO_EntityFinancialAccount', 'account_relationship', $params);
$Links = array(
'Expense Account is' => 'Expenses',
'Accounts Receivable Account is' => 'Asset',
'Income Account is' => 'Revenue',
'Asset Account is' => 'Asset',
'Cost of Sales Account is' => 'Cost of Sales',
'Premiums Inventory Account is' => 'Asset',
'Discounts Account is' => 'Revenue',
'Sales Tax Account is' => 'Liability',
'Deferred Revenue Account is' => 'Liability',
);
if (!$flip) {
foreach ($Links as $accountRelation => $accountType) {
$financialAccountLinks[array_search($accountRelation, $accountRelationships)] = array_search($accountType, $financialAccountType);
}
}
else {
foreach ($Links as $accountRelation => $accountType) {
$financialAccountLinks[array_search($accountType, $financialAccountType)][] = array_search($accountRelation, $accountRelationships);
}
}
return $financialAccountLinks;
}
/**
* Get Deferred Financial type.
*
* @return array
*
*/
public static function getDeferredFinancialType() {
$deferredFinancialType = array();
$query = "SELECT ce.entity_id, cft.name FROM civicrm_entity_financial_account ce
INNER JOIN civicrm_financial_type cft ON ce.entity_id = cft.id
WHERE ce.entity_table = 'civicrm_financial_type' AND ce.account_relationship = %1 AND cft.is_active = 1";
$deferredAccountRel = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Deferred Revenue Account is' "));
$queryParams = array(1 => array($deferredAccountRel, 'Integer'));
$dao = CRM_Core_DAO::executeQuery($query, $queryParams);
while ($dao->fetch()) {
$deferredFinancialType[$dao->entity_id] = $dao->name;
}
return $deferredFinancialType;
}
/**
* Check if financial account is referenced by financial item.
*
* @param int $financialAccountId
*
* @param int $financialAccountTypeID
*
* @return bool
*
*/
public static function validateFinancialAccount($financialAccountId, $financialAccountTypeID = NULL) {
$sql = "SELECT f.financial_account_type_id FROM civicrm_financial_account f
INNER JOIN civicrm_financial_item fi ON fi.financial_account_id = f.id
WHERE f.id = %1 AND f.financial_account_type_id IN (%2)
LIMIT 1";
$params = array('labelColumn' => 'name');
$financialAccountType = CRM_Core_PseudoConstant::get('CRM_Financial_DAO_FinancialAccount', 'financial_account_type_id', $params);
$params = array(
1 => array($financialAccountId, 'Integer'),
2 => array(
implode(',',
array(
array_search('Revenue', $financialAccountType),
array_search('Liability', $financialAccountType),
)
),
'Text',
),
);
$result = CRM_Core_DAO::singleValueQuery($sql, $params);
if ($result && $result != $financialAccountTypeID) {
return TRUE;
}
return FALSE;
}
/**
* Validate Financial Type has Deferred Revenue account relationship
* with Financial Account.
*
* @param array $params
* Holds submitted formvalues and params from api for updating/adding contribution.
*
* @param int $contributionID
* Contribution ID
*
* @param array $priceSetFields
* Array of price fields of a price set.
*
* @return bool
*
*/
public static function checkFinancialTypeHasDeferred($params, $contributionID = NULL, $priceSetFields = NULL) {
if (!CRM_Contribute_BAO_Contribution::checkContributeSettings('deferred_revenue_enabled')) {
return FALSE;
}
$recognitionDate = CRM_Utils_Array::value('revenue_recognition_date', $params);
if (!(!CRM_Utils_System::isNull($recognitionDate)
|| ($contributionID && isset($params['prevContribution'])
&& !CRM_Utils_System::isNull($params['prevContribution']->revenue_recognition_date)))
) {
return FALSE;
}
$lineItems = CRM_Utils_Array::value('line_item', $params);
$financialTypeID = CRM_Utils_Array::value('financial_type_id', $params);
if (!$financialTypeID) {
$financialTypeID = $params['prevContribution']->financial_type_id;
}
if (($contributionID || !empty($params['price_set_id'])) && empty($lineItems)) {
if (!$contributionID) {
CRM_Price_BAO_PriceSet::processAmount($priceSetFields,
$params, $items);
}
else {
$items = CRM_Price_BAO_LineItem::getLineItems($contributionID, 'contribution', TRUE, TRUE, TRUE);
}
if (!empty($items)) {
$lineItems[] = $items;
}
}
$deferredFinancialType = self::getDeferredFinancialType();
$isError = FALSE;
if (!empty($lineItems)) {
foreach ($lineItems as $lineItem) {
foreach ($lineItem as $items) {
if (!array_key_exists($items['financial_type_id'], $deferredFinancialType)) {
$isError = TRUE;
}
}
}
}
elseif (!array_key_exists($financialTypeID, $deferredFinancialType)) {
$isError = TRUE;
}
if ($isError) {
$error = ts('Revenue Recognition Date cannot be processed unless there is a Deferred Revenue account setup for the Financial Type. Please remove Revenue Recognition Date, select a different Financial Type with a Deferred Revenue account setup for it, or setup a Deferred Revenue account for this Financial Type.');
throw new CRM_Core_Exception($error);
}
return $isError;
}
/**
* Retrieve all Deferred Financial Accounts.
*
*
* @return array of Deferred Financial Account
*
*/
public static function getAllDeferredFinancialAccount() {
$financialAccount = array();
$result = civicrm_api3('EntityFinancialAccount', 'get', array(
'sequential' => 1,
'return' => array("financial_account_id.id", "financial_account_id.name", "financial_account_id.accounting_code"),
'entity_table' => "civicrm_financial_type",
'account_relationship' => "Deferred Revenue Account is",
));
if ($result['count'] > 0) {
foreach ($result['values'] as $key => $value) {
$financialAccount[$value['financial_account_id.id']] = $value['financial_account_id.name'] . ' (' . $value['financial_account_id.accounting_code'] . ')';
}
}
return $financialAccount;
}
/**
* Get Organization Name associated with Financial Account.
*
* @param bool $checkPermissions
*
* @return array
*
*/
public static function getOrganizationNames($checkPermissions = TRUE) {
$result = civicrm_api3('FinancialAccount', 'get', array(
'return' => array("contact_id.organization_name", "contact_id"),
'contact_id.is_deleted' => 0,
'options' => array('limit' => 0),
'check_permissions' => $checkPermissions,
));
$organizationNames = array();
foreach ($result['values'] as $values) {
$organizationNames[$values['contact_id']] = $values['contact_id.organization_name'];
}
return $organizationNames;
}
}

View file

@ -0,0 +1,304 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
class CRM_Financial_BAO_FinancialItem extends CRM_Financial_DAO_FinancialItem {
/**
* Class constructor.
*/
public function __construct() {
parent::__construct();
}
/**
* Fetch object based on array of properties.
*
* @param array $params
* (reference ) an assoc array of name/value pairs.
* @param array $defaults
* (reference ) an assoc array to hold the flattened values.
*
* @return CRM_Contribute_BAO_FinancialItem
*/
public static function retrieve(&$params, &$defaults) {
$financialItem = new CRM_Financial_DAO_FinancialItem();
$financialItem->copyValues($params);
if ($financialItem->find(TRUE)) {
CRM_Core_DAO::storeValues($financialItem, $defaults);
return $financialItem;
}
return NULL;
}
/**
* Add the financial items and financial trxn.
*
* @param object $lineItem
* Line item object.
* @param object $contribution
* Contribution object.
* @param bool $taxTrxnID
*
* @param int $trxnId
*
* @return CRM_Financial_DAO_FinancialItem
*/
public static function add($lineItem, $contribution, $taxTrxnID = FALSE, $trxnId = NULL) {
$contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
$financialItemStatus = CRM_Core_PseudoConstant::get('CRM_Financial_DAO_FinancialItem', 'status_id');
$itemStatus = NULL;
if ($contribution->contribution_status_id == array_search('Completed', $contributionStatuses)
|| $contribution->contribution_status_id == array_search('Pending refund', $contributionStatuses)
) {
$itemStatus = array_search('Paid', $financialItemStatus);
}
elseif ($contribution->contribution_status_id == array_search('Pending', $contributionStatuses)
|| $contribution->contribution_status_id == array_search('In Progress', $contributionStatuses)
) {
$itemStatus = array_search('Unpaid', $financialItemStatus);
}
elseif ($contribution->contribution_status_id == array_search('Partially paid', $contributionStatuses)) {
$itemStatus = array_search('Partially paid', $financialItemStatus);
}
$params = array(
'transaction_date' => CRM_Utils_Date::isoToMysql($contribution->receive_date),
'contact_id' => $contribution->contact_id,
'amount' => $lineItem->line_total,
'currency' => $contribution->currency,
'entity_table' => 'civicrm_line_item',
'entity_id' => $lineItem->id,
'description' => ($lineItem->qty != 1 ? $lineItem->qty . ' of ' : '') . $lineItem->label,
'status_id' => $itemStatus,
);
if ($taxTrxnID) {
$invoiceSettings = Civi::settings()->get('contribution_invoice_settings');
$taxTerm = CRM_Utils_Array::value('tax_term', $invoiceSettings);
$params['amount'] = $lineItem->tax_amount;
$params['description'] = $taxTerm;
$accountRelName = 'Sales Tax Account is';
}
else {
$accountRelName = 'Income Account is';
if (property_exists($contribution, 'revenue_recognition_date') && !CRM_Utils_System::isNull($contribution->revenue_recognition_date)) {
$accountRelName = 'Deferred Revenue Account is';
}
}
if ($lineItem->financial_type_id) {
$params['financial_account_id'] = CRM_Contribute_PseudoConstant::getRelationalFinancialAccount(
$lineItem->financial_type_id,
$accountRelName
);
}
if (empty($trxnId)) {
$trxnId['id'] = CRM_Contribute_BAO_Contribution::$_trxnIDs;
if (empty($trxnId['id'])) {
$trxn = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($contribution->id, 'ASC', TRUE);
$trxnId['id'] = $trxn['financialTrxnId'];
}
}
$financialItem = self::create($params, NULL, $trxnId);
return $financialItem;
}
/**
* Create the financial Items and financial entity trxn.
*
* @param array $params
* Associated array to create financial items.
* @param array $ids
* Financial item ids.
* @param array $trxnIds
* Financial item ids.
*
* @return CRM_Financial_DAO_FinancialItem
*/
public static function create(&$params, $ids = NULL, $trxnIds = NULL) {
$financialItem = new CRM_Financial_DAO_FinancialItem();
if (!empty($ids['id'])) {
CRM_Utils_Hook::pre('edit', 'FinancialItem', $ids['id'], $params);
}
else {
CRM_Utils_Hook::pre('create', 'FinancialItem', NULL, $params);
}
$financialItem->copyValues($params);
if (!empty($ids['id'])) {
$financialItem->id = $ids['id'];
}
$financialItem->save();
$financialtrxnIDS = CRM_Utils_Array::value('id', $trxnIds);
if (!empty($financialtrxnIDS)) {
if (!is_array($financialtrxnIDS)) {
$financialtrxnIDS = array($financialtrxnIDS);
}
foreach ($financialtrxnIDS as $tID) {
$entity_financial_trxn_params = array(
'entity_table' => "civicrm_financial_item",
'entity_id' => $financialItem->id,
'financial_trxn_id' => $tID,
'amount' => $params['amount'],
);
if (!empty($ids['entityFinancialTrxnId'])) {
$entity_financial_trxn_params['id'] = $ids['entityFinancialTrxnId'];
}
self::createEntityTrxn($entity_financial_trxn_params);
}
}
if (!empty($ids['id'])) {
CRM_Utils_Hook::post('edit', 'FinancialItem', $financialItem->id, $financialItem);
}
else {
CRM_Utils_Hook::post('create', 'FinancialItem', $financialItem->id, $financialItem);
}
return $financialItem;
}
/**
* Takes an associative array and creates a entity financial transaction object.
*
* @param array $params
* (reference ) an assoc array of name/value pairs.
*
* @return CRM_Core_BAO_FinancialTrxn
*/
public static function createEntityTrxn($params) {
$entity_trxn = new CRM_Financial_DAO_EntityFinancialTrxn();
$entity_trxn->copyValues($params);
$entity_trxn->save();
return $entity_trxn;
}
/**
* Retrive entity financial trxn details.
*
* @param array $params
* (reference ) an assoc array of name/value pairs.
* @param bool $maxId
* To retrive max id.
*
* @return array
*/
public static function retrieveEntityFinancialTrxn($params, $maxId = FALSE) {
$financialItem = new CRM_Financial_DAO_EntityFinancialTrxn();
$financialItem->copyValues($params);
// retrieve last entry from civicrm_entity_financial_trxn
if ($maxId) {
$financialItem->orderBy('id DESC');
$financialItem->limit(1);
}
$financialItem->find();
while ($financialItem->fetch()) {
$financialItems[$financialItem->id] = array(
'id' => $financialItem->id,
'entity_table' => $financialItem->entity_table,
'entity_id' => $financialItem->entity_id,
'financial_trxn_id' => $financialItem->financial_trxn_id,
'amount' => $financialItem->amount,
);
}
if (!empty($financialItems)) {
return $financialItems;
}
else {
return NULL;
}
}
/**
* Check if contact is present in financial_item table.
*
* CRM-12929
*
* @param array $contactIds
* An array contact id's.
*
* @param array $error
* Error to display.
*
* @return array
*/
public static function checkContactPresent($contactIds, &$error) {
if (empty($contactIds)) {
return FALSE;
}
$allowPermDelete = Civi::settings()->get('allowPermDeleteFinancial');
if (!$allowPermDelete) {
$sql = 'SELECT DISTINCT(cc.id), cc.display_name FROM civicrm_contact cc
INNER JOIN civicrm_contribution con ON con.contact_id = cc.id
WHERE cc.id IN (' . implode(',', $contactIds) . ') AND con.is_test = 0';
$dao = CRM_Core_DAO::executeQuery($sql);
if ($dao->N) {
while ($dao->fetch()) {
$url = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid=$dao->id");
$not_deleted[$dao->id] = "<a href='$url'>$dao->display_name</a>";
}
$errorStatus = '';
if (is_array($error)) {
$errorStatus = '<ul><li>' . implode('</li><li>', $not_deleted) . '</li></ul>';
}
$error['_qf_default'] = $errorStatus . ts('This contact(s) can not be permanently deleted because the contact record is linked to one or more live financial transactions. Deleting this contact would result in the loss of financial data.');
return $error;
}
}
return FALSE;
}
/**
* Get most relevant previous financial item relating to the line item.
*
* This function specifically excludes sales tax.
*
* @param int $entityId
*
* @return object CRM_Core_DAO
*/
public static function getPreviousFinancialItem($entityId) {
$params = array(
'entity_id' => $entityId,
'entity_table' => 'civicrm_line_item',
'options' => array('limit' => 1, 'sort' => 'id DESC'),
);
$salesTaxFinancialAccounts = civicrm_api3('FinancialAccount', 'get', array('is_tax' => 1));
if ($salesTaxFinancialAccounts['count']) {
$params['financial_account_id'] = array('NOT IN' => array_keys($salesTaxFinancialAccounts['values']));
}
return civicrm_api3('FinancialItem', 'getsingle', $params);
}
}

View file

@ -0,0 +1,473 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
class CRM_Financial_BAO_FinancialType extends CRM_Financial_DAO_FinancialType {
/**
* Static holder for the default LT.
*/
static $_defaultContributionType = NULL;
/**
* Static cache holder of available financial types for this session
*/
static $_availableFinancialTypes = array();
/**
* Static cache holder of status of ACL-FT enabled/disabled for this session
*/
static $_statusACLFt = array();
/**
* Class constructor.
*/
public function __construct() {
parent::__construct();
}
/**
* Fetch object based on array of properties.
*
* @param array $params
* (reference ) an assoc array of name/value pairs.
* @param array $defaults
* (reference ) an assoc array to hold the flattened values.
*
* @return CRM_Contribute_BAO_ContributionType
*/
public static function retrieve(&$params, &$defaults) {
$financialType = new CRM_Financial_DAO_FinancialType();
$financialType->copyValues($params);
if ($financialType->find(TRUE)) {
CRM_Core_DAO::storeValues($financialType, $defaults);
return $financialType;
}
return NULL;
}
/**
* Update the is_active flag in the db.
*
* @param int $id
* Id of the database record.
* @param bool $is_active
* Value we want to set the is_active field.
*
* @return Object
* DAO object on success, null otherwise
*/
public static function setIsActive($id, $is_active) {
return CRM_Core_DAO::setFieldValue('CRM_Financial_DAO_FinancialType', $id, 'is_active', $is_active);
}
/**
* Add the financial types.
*
* @param array $params
* Reference array contains the values submitted by the form.
* @param array $ids
* Reference array contains the id.
*
* @return object
*/
public static function add(&$params, &$ids = array()) {
if (empty($params['id'])) {
$params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE);
$params['is_deductible'] = CRM_Utils_Array::value('is_deductible', $params, FALSE);
$params['is_reserved'] = CRM_Utils_Array::value('is_reserved', $params, FALSE);
}
// action is taken depending upon the mode
$financialType = new CRM_Financial_DAO_FinancialType();
$financialType->copyValues($params);
if (!empty($ids['financialType'])) {
$financialType->id = CRM_Utils_Array::value('financialType', $ids);
if (self::isACLFinancialTypeStatus()) {
$prevName = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType', $financialType->id, 'name');
if ($prevName != $params['name']) {
CRM_Core_Session::setStatus(ts("Changing the name of a Financial Type will result in losing the current permissions associated with that Financial Type.
Before making this change you should likely note the existing permissions at Administer > Users and Permissions > Permissions (Access Control),
then clicking the Access Control link for your Content Management System, then noting down the permissions for 'CiviCRM: {financial type name} view', etc.
Then after making the change of name, reset the permissions to the way they were."), ts('Warning'), 'warning');
}
}
}
$financialType->save();
// CRM-12470
if (empty($ids['financialType']) && empty($params['id'])) {
$titles = CRM_Financial_BAO_FinancialTypeAccount::createDefaultFinancialAccounts($financialType);
$financialType->titles = $titles;
}
return $financialType;
}
/**
* Delete financial Types.
*
* @param int $financialTypeId
*
* @return array|bool
*/
public static function del($financialTypeId) {
$financialType = new CRM_Financial_DAO_FinancialType();
$financialType->id = $financialTypeId;
$financialType->find(TRUE);
// tables to ingore checks for financial_type_id
$ignoreTables = array('CRM_Financial_DAO_EntityFinancialAccount');
// TODO: if (!$financialType->find(true)) {
// ensure that we have no objects that have an FK to this financial type id TODO: that cannot be null
$occurrences = $financialType->findReferences();
if ($occurrences) {
$tables = array();
foreach ($occurrences as $occurrence) {
$className = get_class($occurrence);
if (!in_array($className, $tables) && !in_array($className, $ignoreTables)) {
$tables[] = $className;
}
}
if (!empty($tables)) {
$message = ts('The following tables have an entry for this financial type: %1', array('%1' => implode(', ', $tables)));
$errors = array();
$errors['is_error'] = 1;
$errors['error_message'] = $message;
return $errors;
}
}
// delete from financial Type table
$financialType->delete();
$entityFinancialType = new CRM_Financial_DAO_EntityFinancialAccount();
$entityFinancialType->entity_id = $financialTypeId;
$entityFinancialType->entity_table = 'civicrm_financial_type';
$entityFinancialType->delete();
return FALSE;
}
/**
* fetch financial type having relationship as Income Account is.
*
*
* @return array
* all financial type with income account is relationship
*/
public static function getIncomeFinancialType() {
// Financial Type
$financialType = CRM_Contribute_PseudoConstant::financialType();
$revenueFinancialType = array();
$relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Income Account is' "));
CRM_Core_PseudoConstant::populate(
$revenueFinancialType,
'CRM_Financial_DAO_EntityFinancialAccount',
$all = TRUE,
$retrieve = 'entity_id',
$filter = NULL,
"account_relationship = $relationTypeId AND entity_table = 'civicrm_financial_type' "
);
foreach ($financialType as $key => $financialTypeName) {
if (!in_array($key, $revenueFinancialType)
|| (CRM_Financial_BAO_FinancialType::isACLFinancialTypeStatus()
&& !CRM_Core_Permission::check('add contributions of type ' . $financialTypeName))
) {
unset($financialType[$key]);
}
}
return $financialType;
}
/**
* Add permissions for financial types.
*
* @param array $permissions
* @param array $descriptions
*
* @return bool
*/
public static function permissionedFinancialTypes(&$permissions, $descriptions) {
if (!self::isACLFinancialTypeStatus()) {
return FALSE;
}
$financialTypes = CRM_Contribute_PseudoConstant::financialType();
$prefix = ts('CiviCRM') . ': ';
$actions = array('add', 'view', 'edit', 'delete');
foreach ($financialTypes as $id => $type) {
foreach ($actions as $action) {
if ($descriptions) {
$permissions[$action . ' contributions of type ' . $type] = array(
$prefix . ts($action . ' contributions of type ') . $type,
ts(ucfirst($action) . ' contributions of type ') . $type,
);
}
else {
$permissions[$action . ' contributions of type ' . $type] = $prefix . ts($action . ' contributions of type ') . $type;
}
}
}
if (!$descriptions) {
$permissions['administer CiviCRM Financial Types'] = $prefix . ts('administer CiviCRM Financial Types');
}
else {
$permissions['administer CiviCRM Financial Types'] = array(
$prefix . ts('administer CiviCRM Financial Types'),
ts('Administer access to Financial Types'),
);
}
}
/**
* Wrapper aroung getAvailableFinancialTypes to get all including disabled FinancialTypes
* @param int|string $action
* the type of action, can be add, view, edit, delete
* @param bool $resetCache
* load values from static cache
*
* @return array
*/
public static function getAllAvailableFinancialTypes($action = CRM_Core_Action::VIEW, $resetCache = FALSE) {
// Flush pseudoconstant cache
CRM_Contribute_PseudoConstant::flush('financialType');
$thisIsAUselessVariableButSolvesPHPError = NULL;
$financialTypes = self::getAvailableFinancialTypes($thisIsAUselessVariableButSolvesPHPError, $action, $resetCache, TRUE);
return $financialTypes;
}
/**
* Wrapper aroung getAvailableFinancialTypes to get all FinancialTypes Excluding Disabled ones.
* @param int|string $action
* the type of action, can be add, view, edit, delete
* @param bool $resetCache
* load values from static cache
*
* @return array
*/
public static function getAllEnabledAvailableFinancialTypes($action = CRM_Core_Action::VIEW, $resetCache = FALSE) {
$thisIsAUselessVariableButSolvesPHPError = NULL;
$financialTypes = self::getAvailableFinancialTypes($thisIsAUselessVariableButSolvesPHPError, $action, $resetCache);
return $financialTypes;
}
/**
* Get available Financial Types.
*
* @param array $financialTypes
* (reference ) an array of financial types
* @param int|string $action
* the type of action, can be add, view, edit, delete
* @param bool $resetCache
* load values from static cache
* @param bool $includeDisabled
* Whether we should load in disabled FinancialTypes or Not
*
* @return array
*/
public static function getAvailableFinancialTypes(&$financialTypes = NULL, $action = CRM_Core_Action::VIEW, $resetCache = FALSE, $includeDisabled = FALSE) {
if (empty($financialTypes)) {
$financialTypes = CRM_Contribute_PseudoConstant::financialType(NULL, $includeDisabled);
}
if (!self::isACLFinancialTypeStatus()) {
return $financialTypes;
}
$actions = array(
CRM_Core_Action::VIEW => 'view',
CRM_Core_Action::UPDATE => 'edit',
CRM_Core_Action::ADD => 'add',
CRM_Core_Action::DELETE => 'delete',
);
// check cached value
if (CRM_Utils_Array::value($action, self::$_availableFinancialTypes) && !$resetCache) {
$financialTypes = self::$_availableFinancialTypes[$action];
return self::$_availableFinancialTypes[$action];
}
foreach ($financialTypes as $finTypeId => $type) {
if (!CRM_Core_Permission::check($actions[$action] . ' contributions of type ' . $type)) {
unset($financialTypes[$finTypeId]);
}
}
self::$_availableFinancialTypes[$action] = $financialTypes;
return $financialTypes;
}
/**
* Get available Membership Types.
*
* @param array $membershipTypes
* (reference ) an array of membership types
* @param int|string $action
* the type of action, can be add, view, edit, delete
*
* @return array
*/
public static function getAvailableMembershipTypes(&$membershipTypes = NULL, $action = CRM_Core_Action::VIEW) {
if (empty($membershipTypes)) {
$membershipTypes = CRM_Member_PseudoConstant::membershipType();
}
if (!self::isACLFinancialTypeStatus()) {
return $membershipTypes;
}
$actions = array(
CRM_Core_Action::VIEW => 'view',
CRM_Core_Action::UPDATE => 'edit',
CRM_Core_Action::ADD => 'add',
CRM_Core_Action::DELETE => 'delete',
);
foreach ($membershipTypes as $memTypeId => $type) {
$finTypeId = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $memTypeId, 'financial_type_id');
$finType = CRM_Contribute_PseudoConstant::financialType($finTypeId);
if (!CRM_Core_Permission::check($actions[$action] . ' contributions of type ' . $finType)) {
unset($membershipTypes[$memTypeId]);
}
}
return $membershipTypes;
}
/**
* Function to build a permissioned sql where clause based on available financial types.
*
* @param array $whereClauses
* (reference ) an array of clauses
* @param string $component
* the type of component
* @param string $alias
* the alias to use
*
*/
public static function buildPermissionedClause(&$whereClauses, $component = NULL, $alias = NULL) {
if (!self::isACLFinancialTypeStatus()) {
return FALSE;
}
if (is_array($whereClauses)) {
$types = self::getAllEnabledAvailableFinancialTypes();
if (empty($types)) {
$whereClauses[] = ' ' . $alias . '.financial_type_id IN (0)';
}
else {
$whereClauses[] = ' ' . $alias . '.financial_type_id IN (' . implode(',', array_keys($types)) . ')';
}
}
else {
if ($component == 'contribution') {
$types = self::getAllEnabledAvailableFinancialTypes();
$column = "financial_type_id";
}
if ($component == 'membership') {
self::getAvailableMembershipTypes($types, CRM_Core_Action::VIEW);
$column = "membership_type_id";
}
if (!empty($whereClauses)) {
$whereClauses .= ' AND ';
}
if (empty($types)) {
$whereClauses .= " civicrm_{$component}.{$column} IN (0)";
return;
}
$whereClauses .= " civicrm_{$component}.{$column} IN (" . implode(',', array_keys($types)) . ")";
}
}
/**
* Function to check if lineitems present in a contribution have permissioned FTs.
*
* @param int $id
* contribution id
* @param string $op
* the mode of operation, can be add, view, edit, delete
* @param bool $force
*
* @return bool
*/
public static function checkPermissionedLineItems($id, $op, $force = TRUE) {
if (!self::isACLFinancialTypeStatus()) {
return TRUE;
}
$lineItems = CRM_Price_BAO_LineItem::getLineItemsByContributionID($id);
$flag = FALSE;
foreach ($lineItems as $items) {
if (!CRM_Core_Permission::check($op . ' contributions of type ' . CRM_Contribute_PseudoConstant::financialType($items['financial_type_id']))) {
if ($force) {
CRM_Core_Error::fatal(ts('You do not have permission to access this page.'));
break;
}
$flag = FALSE;
break;
}
else {
$flag = TRUE;
}
}
return $flag;
}
/**
* Check if the logged in user has permission to edit the given financial type.
*
* This is called when determining if they can edit things like option values
* in price sets. At the moment it is not possible to change an option value from
* a type you do not have permission to to a type that you do.
*
* @todo it is currently not possible to edit disabled types if you have ACLs on.
* Do ACLs still apply once disabled? That question should be resolved if tackling
* that gap.
*
* @param int $financialTypeID
*
* @return bool
*/
public static function checkPermissionToEditFinancialType($financialTypeID) {
if (!self::isACLFinancialTypeStatus()) {
return TRUE;
}
$financialTypes = CRM_Financial_BAO_FinancialType::getAllAvailableFinancialTypes(CRM_Core_Action::UPDATE);
return isset($financialTypes[$financialTypeID]);
}
/**
* Check if FT-ACL is turned on or off.
*
* @todo rename this function e.g isFinancialTypeACLsEnabled.
*
* @return bool
*/
public static function isACLFinancialTypeStatus() {
if (array_key_exists('acl_financial_type', self::$_statusACLFt)) {
return self::$_statusACLFt['acl_financial_type'];
}
$contributeSettings = Civi::settings()->get('contribution_invoice_settings');
self::$_statusACLFt['acl_financial_type'] = FALSE;
if (CRM_Utils_Array::value('acl_financial_type', $contributeSettings)) {
self::$_statusACLFt['acl_financial_type'] = TRUE;
}
return self::$_statusACLFt['acl_financial_type'];
}
}

View file

@ -0,0 +1,274 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
class CRM_Financial_BAO_FinancialTypeAccount extends CRM_Financial_DAO_EntityFinancialAccount {
/**
* Class constructor.
*/
public function __construct() {
parent::__construct();
}
/**
* Fetch object based on array of properties.
*
* @param array $params
* (reference ) an assoc array of name/value pairs.
* @param array $defaults
* (reference ) an assoc array to hold the flattened values.
*
* @param array $allValues
*
* @return CRM_Contribute_BAO_ContributionType
*/
public static function retrieve(&$params, &$defaults, &$allValues = array()) {
$financialTypeAccount = new CRM_Financial_DAO_EntityFinancialAccount();
$financialTypeAccount->copyValues($params);
$financialTypeAccount->find();
while ($financialTypeAccount->fetch()) {
CRM_Core_DAO::storeValues($financialTypeAccount, $defaults);
$allValues[] = $defaults;
}
return $defaults;
}
/**
* Add the financial types.
*
* @param array $params
* Reference array contains the values submitted by the form.
* @param array $ids
* Reference array contains the id.
*
* @return object
*/
public static function add(&$params, &$ids = NULL) {
// action is taken depending upon the mode
$financialTypeAccount = new CRM_Financial_DAO_EntityFinancialAccount();
if ($params['entity_table'] != 'civicrm_financial_type') {
$financialTypeAccount->entity_id = $params['entity_id'];
$financialTypeAccount->entity_table = $params['entity_table'];
$financialTypeAccount->find(TRUE);
}
if (!empty($ids['entityFinancialAccount'])) {
$financialTypeAccount->id = $ids['entityFinancialAccount'];
$financialTypeAccount->find(TRUE);
}
$financialTypeAccount->copyValues($params);
self::validateRelationship($financialTypeAccount);
$financialTypeAccount->save();
return $financialTypeAccount;
}
/**
* Delete financial Types.
*
* @param int $financialTypeAccountId
* @param int $accountId
*
*/
public static function del($financialTypeAccountId, $accountId = NULL) {
// check if financial type is present
$check = FALSE;
$relationValues = CRM_Core_PseudoConstant::get('CRM_Financial_DAO_EntityFinancialAccount', 'account_relationship');
$financialTypeId = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_EntityFinancialAccount', $financialTypeAccountId, 'entity_id');
// check dependencies
// FIXME more table containing financial_type_id to come
$dependency = array(
array('Contribute', 'Contribution'),
array('Contribute', 'ContributionPage'),
array('Member', 'MembershipType'),
array('Price', 'PriceFieldValue'),
array('Grant', 'Grant'),
array('Contribute', 'PremiumsProduct'),
array('Contribute', 'Product'),
array('Price', 'LineItem'),
);
foreach ($dependency as $name) {
$daoString = 'CRM_' . $name[0] . '_DAO_' . $name[1];
$dao = new $daoString();
$dao->financial_type_id = $financialTypeId;
if ($dao->find(TRUE)) {
$check = TRUE;
break;
}
}
if ($check) {
if ($name[1] == 'PremiumsProduct' || $name[1] == 'Product') {
CRM_Core_Session::setStatus(ts('You cannot remove an account with a %1 relationship while the Financial Type is used for a Premium.', array(1 => $relationValues[$financialTypeAccountId])));
}
else {
$accountRelationShipId = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_EntityFinancialAccount', $financialTypeAccountId, 'account_relationship');
CRM_Core_Session::setStatus(ts('You cannot remove an account with a %1 relationship because it is being referenced by one or more of the following types of records: Contributions, Contribution Pages, or Membership Types. Consider disabling this type instead if you no longer want it used.', array(1 => $relationValues[$accountRelationShipId])), NULL, 'error');
}
return CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/admin/financial/financialType/accounts', "reset=1&action=browse&aid={$accountId}"));
}
// delete from financial Type table
$financialType = new CRM_Financial_DAO_EntityFinancialAccount();
$financialType->id = $financialTypeAccountId;
$financialType->find(TRUE);
$financialType->delete();
CRM_Core_Session::setStatus(ts('Unbalanced transactions may be created if you delete the account of type: %1.', array(1 => $relationValues[$financialType->account_relationship])));
}
/**
* Financial Account for payment instrument.
*
* @param int $paymentInstrumentValue
* Payment instrument value.
*
* @return null|int
*/
public static function getInstrumentFinancialAccount($paymentInstrumentValue) {
$paymentInstrument = civicrm_api3('OptionValue', 'getsingle', array(
'return' => array("id"),
'value' => $paymentInstrumentValue,
'option_group_id' => "payment_instrument",
));
$financialAccountId = CRM_Contribute_PseudoConstant::getRelationalFinancialAccount(
$paymentInstrument['id'],
NULL,
'civicrm_option_value'
);
return $financialAccountId;
}
/**
* Create default entity financial accounts
* for financial type
* CRM-12470
*
* @param $financialType
*
* @return array
*/
public static function createDefaultFinancialAccounts($financialType) {
$titles = array();
$financialAccountTypeID = CRM_Core_OptionGroup::values('financial_account_type', FALSE, FALSE, FALSE, NULL, 'name');
$accountRelationship = CRM_Core_OptionGroup::values('account_relationship', FALSE, FALSE, FALSE, NULL, 'name');
$relationships = array(
array_search('Accounts Receivable Account is', $accountRelationship) => array_search('Asset', $financialAccountTypeID),
array_search('Expense Account is', $accountRelationship) => array_search('Expenses', $financialAccountTypeID),
array_search('Cost of Sales Account is', $accountRelationship) => array_search('Cost of Sales', $financialAccountTypeID),
array_search('Income Account is', $accountRelationship) => array_search('Revenue', $financialAccountTypeID),
);
$dao = CRM_Core_DAO::executeQuery('SELECT id, financial_account_type_id FROM civicrm_financial_account WHERE name LIKE %1',
array(1 => array($financialType->name, 'String'))
);
$dao->fetch();
$existingFinancialAccount = array();
if (!$dao->N) {
$params = array(
'name' => $financialType->name,
'contact_id' => CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Domain', CRM_Core_Config::domainID(), 'contact_id'),
'financial_account_type_id' => array_search('Revenue', $financialAccountTypeID),
'description' => $financialType->description,
'account_type_code' => 'INC',
'is_active' => 1,
);
$financialAccount = CRM_Financial_BAO_FinancialAccount::add($params);
}
else {
$existingFinancialAccount[$dao->financial_account_type_id] = $dao->id;
}
$params = array(
'entity_table' => 'civicrm_financial_type',
'entity_id' => $financialType->id,
);
foreach ($relationships as $key => $value) {
if (!array_key_exists($value, $existingFinancialAccount)) {
if ($accountRelationship[$key] == 'Accounts Receivable Account is') {
$params['financial_account_id'] = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialAccount', 'Accounts Receivable', 'id', 'name');
if (!empty($params['financial_account_id'])) {
$titles[] = 'Accounts Receivable';
}
else {
$query = "SELECT financial_account_id, name FROM civicrm_entity_financial_account
LEFT JOIN civicrm_financial_account ON civicrm_financial_account.id = civicrm_entity_financial_account.financial_account_id
WHERE account_relationship = {$key} AND entity_table = 'civicrm_financial_type' LIMIT 1";
$dao = CRM_Core_DAO::executeQuery($query);
$dao->fetch();
$params['financial_account_id'] = $dao->financial_account_id;
$titles[] = $dao->name;
}
}
elseif ($accountRelationship[$key] == 'Income Account is' && empty($existingFinancialAccount)) {
$params['financial_account_id'] = $financialAccount->id;
}
else {
$query = "SELECT id, name FROM civicrm_financial_account WHERE is_default = 1 AND financial_account_type_id = {$value}";
$dao = CRM_Core_DAO::executeQuery($query);
$dao->fetch();
$params['financial_account_id'] = $dao->id;
$titles[] = $dao->name;
}
}
else {
$params['financial_account_id'] = $existingFinancialAccount[$value];
$titles[] = $financialType->name;
}
$params['account_relationship'] = $key;
self::add($params);
}
if (!empty($existingFinancialAccount)) {
$titles = array();
}
return $titles;
}
/**
* Validate account relationship with financial account type
*
* @param obj $financialTypeAccount of CRM_Financial_DAO_EntityFinancialAccount
*
* @throws CRM_Core_Exception
*/
public static function validateRelationship($financialTypeAccount) {
$financialAccountLinks = CRM_Financial_BAO_FinancialAccount::getfinancialAccountRelations();
$financialAccountType = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialAccount', $financialTypeAccount->financial_account_id, 'financial_account_type_id');
if (CRM_Utils_Array::value($financialTypeAccount->account_relationship, $financialAccountLinks) != $financialAccountType) {
$accountRelationships = CRM_Core_PseudoConstant::get('CRM_Financial_DAO_EntityFinancialAccount', 'account_relationship');
$params = array(
1 => $accountRelationships[$financialTypeAccount->account_relationship],
);
throw new CRM_Core_Exception(ts("This financial account cannot have '%1' relationship.", $params));
}
}
}

View file

@ -0,0 +1,552 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
/**
* This class contains payment processor related functions.
*/
class CRM_Financial_BAO_PaymentProcessor extends CRM_Financial_DAO_PaymentProcessor {
/**
* Static holder for the default payment processor
*/
static $_defaultPaymentProcessor = NULL;
/**
* Create Payment Processor.
*
* @param array $params
* Parameters for Processor entity.
*
* @return CRM_Financial_DAO_PaymentProcessor
* @throws Exception
*/
public static function create($params) {
$processor = new CRM_Financial_DAO_PaymentProcessor();
$processor->copyValues($params);
if (empty($params['id'])) {
$ppTypeDAO = new CRM_Financial_DAO_PaymentProcessorType();
$ppTypeDAO->id = $params['payment_processor_type_id'];
if (!$ppTypeDAO->find(TRUE)) {
CRM_Core_Error::fatal(ts('Could not find payment processor meta information'));
}
// also copy meta fields from the info DAO
$processor->is_recur = $ppTypeDAO->is_recur;
$processor->billing_mode = $ppTypeDAO->billing_mode;
$processor->class_name = $ppTypeDAO->class_name;
$processor->payment_type = $ppTypeDAO->payment_type;
}
$processor->save();
// CRM-11826, add entry in civicrm_entity_financial_account
// if financial_account_id is not NULL
if (!empty($params['financial_account_id'])) {
$relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Asset Account is' "));
$values = array(
'entity_table' => 'civicrm_payment_processor',
'entity_id' => $processor->id,
'account_relationship' => $relationTypeId,
'financial_account_id' => $params['financial_account_id'],
);
CRM_Financial_BAO_FinancialTypeAccount::add($values);
}
if (isset($params['id']) && isset($params['is_active']) && !isset($params['is_test'])) {
// check if is_active has changed & if so update test instance is_active too.
$test_id = self::getTestProcessorId($params['id']);
$testDAO = new CRM_Financial_DAO_PaymentProcessor();
$testDAO->id = $test_id;
if ($testDAO->find(TRUE)) {
$testDAO->is_active = $params['is_active'];
$testDAO->save();
}
}
Civi\Payment\System::singleton()->flushProcessors();
return $processor;
}
/**
* Class constructor.
*/
public function __construct() {
parent::__construct();
}
/**
* Retrieve array of allowed credit cards for this payment processor.
* @param interger|null $paymentProcessorID id of processor.
* @return array
*/
public static function getCreditCards($paymentProcessorID = NULL) {
if (!empty($paymentProcessorID)) {
$processor = new CRM_Financial_DAO_PaymentProcessor();
$processor->id = $paymentProcessorID;
$processor->find(TRUE);
$cards = json_decode($processor->accepted_credit_cards, TRUE);
return $cards;
}
return array();
}
/**
* Retrieve DB object based on input parameters.
*
* It also stores all the retrieved values in the default array.
*
* @param array $params
* (reference ) an assoc array of name/value pairs.
* @param array $defaults
* (reference ) an assoc array to hold the flattened values.
*
* @return CRM_Financial_DAO_PaymentProcessor|null
* object on success, null otherwise
*/
public static function retrieve(&$params, &$defaults) {
$paymentProcessor = new CRM_Financial_DAO_PaymentProcessor();
$paymentProcessor->copyValues($params);
if ($paymentProcessor->find(TRUE)) {
CRM_Core_DAO::storeValues($paymentProcessor, $defaults);
return $paymentProcessor;
}
return NULL;
}
/**
* Update the is_active flag in the db.
*
* @param int $id
* Id of the database record.
* @param bool $is_active
* Value we want to set the is_active field.
*
* @return CRM_Financial_DAO_PaymentProcessor|null
* DAO object on success, null otherwise
*
*/
public static function setIsActive($id, $is_active) {
return CRM_Core_DAO::setFieldValue('CRM_Financial_DAO_PaymentProcessor', $id, 'is_active', $is_active);
}
/**
* Retrieve the default payment processor.
*
* @return CRM_Financial_DAO_PaymentProcessor|null
* The default payment processor object on success,
* null otherwise
*/
public static function &getDefault() {
if (self::$_defaultPaymentProcessor == NULL) {
$params = array('is_default' => 1);
$defaults = array();
self::$_defaultPaymentProcessor = self::retrieve($params, $defaults);
}
return self::$_defaultPaymentProcessor;
}
/**
* Delete payment processor.
*
* @param int $paymentProcessorID
*
* @return null
*/
public static function del($paymentProcessorID) {
if (!$paymentProcessorID) {
CRM_Core_Error::fatal(ts('Invalid value passed to delete function.'));
}
$dao = new CRM_Financial_DAO_PaymentProcessor();
$dao->id = $paymentProcessorID;
if (!$dao->find(TRUE)) {
return NULL;
}
$testDAO = new CRM_Financial_DAO_PaymentProcessor();
$testDAO->name = $dao->name;
$testDAO->is_test = 1;
$testDAO->delete();
$dao->delete();
Civi\Payment\System::singleton()->flushProcessors();
}
/**
* Get the payment processor details.
*
* This returns an array whereas Civi\Payment\System::singleton->getByID() returns an object.
* The object is a key in the array.
*
* @param int $paymentProcessorID
* Payment processor id.
* @param string $mode
* Payment mode ie test or live.
*
* @return array
* associated array with payment processor related fields
*/
public static function getPayment($paymentProcessorID, $mode = 'based_on_id') {
$capabilities = ($mode == 'test') ? array('TestMode') : array();
$processors = self::getPaymentProcessors($capabilities, array($paymentProcessorID));
$processor = $processors[$paymentProcessorID];
$fields = array(
'id',
'name',
'payment_processor_type_id',
'user_name',
'password',
'signature',
'url_site',
'url_api',
'url_recur',
'url_button',
'subject',
'class_name',
'is_recur',
'billing_mode',
'is_test',
'payment_type',
'is_default',
);
// Just to prevent e-Notices elsewhere we set all fields.
foreach ($fields as $name) {
if (!isset($processor)) {
$processor[$name] = NULL;
}
}
$processor['payment_processor_type'] = CRM_Core_PseudoConstant::paymentProcessorType(FALSE,
$processor['payment_processor_type_id'], 'name');
return $processors[$paymentProcessorID];
}
/**
* Given a live processor ID get the test id.
*
* @param int $id
*
* @return int
* Test payment processor ID.
*/
public static function getTestProcessorId($id) {
$liveProcessorName = civicrm_api3('payment_processor', 'getvalue', array(
'id' => $id,
'return' => 'name',
));
return civicrm_api3('payment_processor', 'getvalue', array(
'return' => 'id',
'name' => $liveProcessorName,
'is_test' => 1,
'domain_id' => CRM_Core_Config::domainID(),
));
}
/**
* Compare 2 payment processors to see which should go first based on is_default
* (sort function for sortDefaultFirst)
* @param array $processor1
* @param array $processor2
*
* @return int
*/
public static function defaultComparison($processor1, $processor2) {
$p1 = CRM_Utils_Array::value('is_default', $processor1);
$p2 = CRM_Utils_Array::value('is_default', $processor2);
if ($p1 == $p2) {
return 0;
}
return ($p1 > $p2) ? -1 : 1;
}
/**
* Get all payment processors as an array of objects.
*
* @param string|NULL $mode
* only return this mode - test|live or NULL for all
* @param bool $reset
* @param bool $isCurrentDomainOnly
* Do we only want to load payment processors associated with the current domain.
*
* @throws CiviCRM_API3_Exception
* @return array
*/
public static function getAllPaymentProcessors($mode = 'all', $reset = FALSE, $isCurrentDomainOnly = TRUE) {
$cacheKey = 'CRM_Financial_BAO_Payment_Processor_' . $mode . '_' . CRM_Core_Config::domainID();
if (!$reset) {
$processors = CRM_Utils_Cache::singleton()->get($cacheKey);
if (!empty($processors)) {
return $processors;
}
}
$retrievalParameters = array(
'is_active' => TRUE,
'options' => array('sort' => 'is_default DESC, name', 'limit' => 0),
'api.payment_processor_type.getsingle' => 1,
);
if ($isCurrentDomainOnly) {
$retrievalParameters['domain_id'] = CRM_Core_Config::domainID();
}
if ($mode == 'test') {
$retrievalParameters['is_test'] = 1;
}
elseif ($mode == 'live') {
$retrievalParameters['is_test'] = 0;
}
$processors = civicrm_api3('payment_processor', 'get', $retrievalParameters);
foreach ($processors['values'] as $processor) {
$fieldsToProvide = array('user_name', 'password', 'signature', 'subject', 'is_recur');
foreach ($fieldsToProvide as $field) {
// Prevent e-notices in processor classes when not configured.
if (!isset($processor[$field])) {
$processors['values'][$processor['id']][$field] = NULL;
}
}
$processors['values'][$processor['id']]['payment_processor_type'] = $processor['payment_processor_type'] = $processors['values'][$processor['id']]['api.payment_processor_type.getsingle']['name'];
$processors['values'][$processor['id']]['object'] = Civi\Payment\System::singleton()->getByProcessor($processor);
}
// Add the pay-later pseudo-processor.
$processors['values'][0] = array(
'object' => new CRM_Core_Payment_Manual(),
'id' => 0,
'payment_processor_type_id' => 0,
// This shouldn't be required but there are still some processors hacked into core with nasty 'if's.
'payment_processor_type' => 'Manual',
'class_name' => 'Payment_Manual',
'name' => 'pay_later',
'billing_mode' => '',
'is_default' => 0,
'payment_instrument_id' => key(CRM_Core_OptionGroup::values('payment_instrument', FALSE, FALSE, FALSE, 'AND is_default = 1')),
// Making this optionally recur would give lots of options -but it should
// be a row in the payment processor table before we do that.
'is_recur' => FALSE,
'is_test' => FALSE,
);
CRM_Utils_Cache::singleton()->set($cacheKey, $processors['values']);
return $processors['values'];
}
/**
* Get Payment processors with specified capabilities.
* Note that both the singleton & the pseudoconstant function have caching so we don't add
* arguably this could go on the pseudoconstant class
*
* @param array $capabilities
* capabilities of processor e.g
* - BackOffice
* - TestMode
* - LiveMode
* - FutureStartDate
*
* @param array|bool $ids
*
* @return array
* available processors
*/
public static function getPaymentProcessors($capabilities = array(), $ids = FALSE) {
$testProcessors = in_array('TestMode', $capabilities) ? self::getAllPaymentProcessors('test') : array();
if (is_array($ids)) {
$processors = self::getAllPaymentProcessors('all', TRUE, FALSE);
}
else {
$processors = self::getAllPaymentProcessors('all', TRUE);
}
if (in_array('TestMode', $capabilities) && is_array($ids)) {
$possibleLiveIDs = array_diff($ids, array_keys($testProcessors));
foreach ($possibleLiveIDs as $possibleLiveID) {
if (isset($processors[$possibleLiveID]) && ($liveProcessorName = $processors[$possibleLiveID]['name']) != FALSE) {
foreach ($testProcessors as $index => $testProcessor) {
if ($testProcessor['name'] == $liveProcessorName) {
$ids[] = $testProcessor['id'];
}
}
}
}
$processors = $testProcessors;
}
foreach ($processors as $index => $processor) {
if (is_array($ids) && !in_array($processor['id'], $ids)) {
unset($processors[$index]);
continue;
}
// Invalid processors will store a null value in 'object' (e.g. if not all required config fields are present).
// This is determined by calling when loading the processor via the $processorObject->checkConfig() function.
if (!is_a($processor['object'], 'CRM_Core_Payment')) {
unset($processors[$index]);
continue;
}
foreach ($capabilities as $capability) {
if (($processor['object']->supports($capability)) == FALSE) {
unset($processors[$index]);
continue 1;
}
}
}
return $processors;
}
/**
* Is there a processor on this site with the specified capability.
*
* The capabilities are defined on CRM_Core_Payment and can be extended by
* processors.
*
* examples are
* - supportsBackOffice
* - supportsLiveMode
* - supportsFutureRecurDate
* - supportsCancelRecurring
* - supportsRecurContributionsForPledges
*
* They are passed as array('BackOffice');
*
* Details of specific functions are in the docblocks on the CRM_Core_Payment class.
*
* @param array $capabilities
*
* @return bool
*/
public static function hasPaymentProcessorSupporting($capabilities = array()) {
$result = self::getPaymentProcessors($capabilities);
return (!empty($result)) ? TRUE : FALSE;
}
/**
* Retrieve payment processor id / info/ object based on component-id.
*
* @todo function needs revisiting. The whole 'info / obj' thing is an overload. Recommend creating new functions
* that are entity specific as there is little shared code specific to obj or info
*
* Also, it does not accurately derive the processor - for a completed contribution the best place to look is in the
* relevant financial_trxn record. For a recurring contribution it is in the contribution_recur table.
*
* For a membership the relevant contribution_recur should be derived & then resolved as above. The contribution page
* is never a reliable place to look as there can be more than one configured. For a pending contribution there is
* no way to derive the processor - but hey - what processor? it didn't go through!
*
* Query for membership might look something like:
* SELECT fte.payment_processor_id
* FROM civicrm_membership mem
* INNER JOIN civicrm_line_item li ON ( mem.id = li.entity_id AND li.entity_table = 'civicrm_membership')
* INNER JOIN civicrm_contribution con ON ( li.contribution_id = con.id )
* LEFT JOIN civicrm_entity_financial_trxn ft ON ft.entity_id = con.id AND ft.entity_table =
* 'civicrm_contribution'
* LEFT JOIN civicrm_financial_trxn fte ON fte.id = ft.financial_trxn_id
*
* @param int $entityID
* @param string $component
* Component.
* @param string $type
* Type of payment information to be retrieved.
*
* @return int|array|object
*/
public static function getProcessorForEntity($entityID, $component = 'contribute', $type = 'id') {
$result = NULL;
if (!in_array($component, array(
'membership',
'contribute',
'recur',
))
) {
return $result;
}
if ($component == 'membership') {
$sql = "
SELECT cr.payment_processor_id as ppID1, cp.payment_processor as ppID2, con.is_test
FROM civicrm_membership mem
INNER JOIN civicrm_membership_payment mp ON ( mem.id = mp.membership_id )
INNER JOIN civicrm_contribution con ON ( mp.contribution_id = con.id )
LEFT JOIN civicrm_contribution_recur cr ON ( mem.contribution_recur_id = cr.id )
LEFT JOIN civicrm_contribution_page cp ON ( con.contribution_page_id = cp.id )
WHERE mp.membership_id = %1";
}
elseif ($component == 'contribute') {
$sql = "
SELECT cr.payment_processor_id as ppID1, cp.payment_processor as ppID2, con.is_test
FROM civicrm_contribution con
LEFT JOIN civicrm_contribution_recur cr ON ( con.contribution_recur_id = cr.id )
LEFT JOIN civicrm_contribution_page cp ON ( con.contribution_page_id = cp.id )
WHERE con.id = %1";
}
elseif ($component == 'recur') {
$sql = "
SELECT cr.payment_processor_id as ppID1, NULL as ppID2, cr.is_test
FROM civicrm_contribution_recur cr
WHERE cr.id = %1";
}
// We are interested in a single record.
$sql .= ' LIMIT 1';
$params = array(1 => array($entityID, 'Integer'));
$dao = CRM_Core_DAO::executeQuery($sql, $params);
if (!$dao->fetch()) {
return $result;
}
$ppID = (isset($dao->ppID1) && $dao->ppID1) ? $dao->ppID1 : (isset($dao->ppID2) ? $dao->ppID2 : NULL);
$mode = (isset($dao->is_test) && $dao->is_test) ? 'test' : 'live';
if (!$ppID || $type == 'id') {
$result = $ppID;
}
elseif ($type == 'info') {
$result = self::getPayment($ppID, $mode);
}
elseif ($type == 'obj' && is_numeric($ppID)) {
try {
$paymentProcessor = civicrm_api3('PaymentProcessor', 'getsingle', array('id' => $ppID));
}
catch (API_Exception $e) {
// Unable to load the processor because this function uses an unreliable method to derive it.
// The function looks to load the payment processor ID from the contribution page, which
// can support multiple processors.
}
$paymentProcessor['payment_processor_type'] = CRM_Core_PseudoConstant::paymentProcessorType(FALSE, $paymentProcessor['payment_processor_type_id'], 'name');
$result = Civi\Payment\System::singleton()->getByProcessor($paymentProcessor);
}
return $result;
}
}

View file

@ -0,0 +1,213 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
class CRM_Financial_BAO_PaymentProcessorType extends CRM_Financial_DAO_PaymentProcessorType {
/**
* Static holder for the default payment processor.
*/
static $_defaultPaymentProcessorType = NULL;
/**
* Class constructor.
*/
public function __construct() {
parent::__construct();
}
/**
* Fetch object based on array of properties.
*
* @param array $params
* (reference ) an assoc array of name/value pairs.
* @param array $defaults
* (reference ) an assoc array to hold the flattened values.
*
* @return CRM_Core_BAO_LocationType|null
* object on success, null otherwise
*/
public static function retrieve(&$params, &$defaults) {
$paymentProcessorType = new CRM_Financial_DAO_PaymentProcessorType();
$paymentProcessorType->copyValues($params);
if ($paymentProcessorType->find(TRUE)) {
CRM_Core_DAO::storeValues($paymentProcessorType, $defaults);
return $paymentProcessorType;
}
return NULL;
}
/**
* Update the is_active flag in the db.
*
* @param int $id
* Id of the database record.
* @param bool $is_active
* Value we want to set the is_active field.
*
* @return Object
* DAO object on success, null otherwise
*
*/
public static function setIsActive($id, $is_active) {
return CRM_Core_DAO::setFieldValue('CRM_Financial_DAO_PaymentProcessorType', $id, 'is_active', $is_active);
}
/**
* Retrieve the default payment processor.
*
* @return object
* The default payment processor object on success,
* null otherwise
*/
public static function &getDefault() {
if (self::$_defaultPaymentProcessorType == NULL) {
$params = array('is_default' => 1);
$defaults = array();
self::$_defaultPaymentProcessorType = self::retrieve($params, $defaults);
}
return self::$_defaultPaymentProcessorType;
}
/**
* Add the payment-processor type in the db
*
* @param array $params
* (reference ) an assoc array of name/value pairs.
*
* @throws Exception
* @return CRM_Financial_DAO_PaymentProcessorType
*/
public static function create(&$params) {
$paymentProcessorType = new CRM_Financial_DAO_PaymentProcessorType();
$paymentProcessorType->copyValues($params);
/* @codingStandardsIgnoreStart
// adapted from CRM_Core_Extensions_Payment::install
foreach (array(
'class_name',
'title',
'name',
'description',
'user_name_label',
'password_label',
'signature_label',
'subject_label',
'url_site_default',
'url_api_default',
'url_recur_default',
'url_site_test_default',
'url_api_test_default',
'url_recur_test_default',
'url_button_default',
'url_button_test_default',
'billing_mode',
'is_recur',
'payment_type'
) as $trimmable) {
if (isset($paymentProcessorType->{$trimmable})) {
$paymentProcessorType->{$trimmable} = trim($paymentProcessorType->{$trimmable});
}
}
@codingStandardsIgnoreEnd */
if (isset($paymentProcessorType->billing_mode)) {
// ugh unidirectional manipulation
if (!is_numeric($paymentProcessorType->billing_mode)) {
$billingModes = array_flip(self::buildOptions('billing_mode'));
if (array_key_exists($paymentProcessorType->billing_mode, $billingModes)) {
$paymentProcessorType->billing_mode = $billingModes[$paymentProcessorType->billing_mode];
}
}
if (!array_key_exists($paymentProcessorType->billing_mode, self::buildOptions('billing_mode'))) {
throw new Exception("Unrecognized billing_mode");
}
}
// FIXME handle is_default
if (!empty($paymentProcessorType->id)) {
$ppByName = self::getAllPaymentProcessorTypes('name');
if (array_key_exists($paymentProcessorType->name, $ppByName)) {
if ($ppByName[$paymentProcessorType->name] != $paymentProcessorType->id) {
CRM_Core_Error::fatal('This payment processor type already exists.');
}
}
}
return $paymentProcessorType->save();
}
/**
* Delete payment processor.
*
* @param int $paymentProcessorTypeId
* ID of the processor to be deleted.
*
* @return bool|NULL
*/
public static function del($paymentProcessorTypeId) {
$query = "
SELECT pp.id processor_id
FROM civicrm_payment_processor pp, civicrm_payment_processor_type ppt
WHERE pp.payment_processor_type_id = ppt.id AND ppt.id = %1";
$params = array(1 => array($paymentProcessorTypeId, 'Integer'));
$dao = CRM_Core_DAO::executeQuery($query, $params);
if ($dao->fetch()) {
CRM_Core_Session::setStatus(ts('There is a Payment Processor associated with selected Payment Processor type, hence it can not be deleted.'), ts('Deletion Error'), 'error');
return NULL;
}
$paymentProcessorType = new CRM_Financial_DAO_PaymentProcessorType();
$paymentProcessorType->id = $paymentProcessorTypeId;
if ($paymentProcessorType->delete()) {
CRM_Core_Session::setStatus(ts('Selected Payment Processor type has been deleted.<br/>'), '', 'success');
return TRUE;
}
}
/**
* @param $attr
*
* @return array
*/
static private function getAllPaymentProcessorTypes($attr) {
$ppt = array();
$dao = new CRM_Financial_DAO_PaymentProcessorType();
$dao->find();
while ($dao->fetch()) {
$ppt[$dao->$attr] = $dao->id;
}
return $ppt;
}
}