4 +--------------------------------------------------------------------+
5 | CiviCRM version 4.5 |
6 +--------------------------------------------------------------------+
7 | Copyright CiviCRM LLC (c) 2004-2014 |
8 +--------------------------------------------------------------------+
9 | This file is a part of CiviCRM. |
11 | CiviCRM is free software; you can copy, modify, and distribute it |
12 | under the terms of the GNU Affero General Public License |
13 | Version 3, 19 November 2007. |
15 | CiviCRM is distributed in the hope that it will be useful, but |
16 | WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
18 | See the GNU Affero General Public License for more details. |
20 | You should have received a copy of the GNU Affero General Public |
21 | License along with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2014
35 class CRM_Upgrade_Incremental_php_FourThree
{
36 const BATCH_SIZE
= 5000;
43 function verifyPreDBstate(&$errors) {
48 * Compute any messages which should be displayed beforeupgrade
50 * Note: This function is called iteratively for each upcoming
51 * revision to the database.
53 * @param $preUpgradeMessage
54 * @param $rev string, a version number, e.g. '4.3.alpha1', '4.3.beta3', '4.3.0'
55 * @param null $currentVer
57 * @internal param string $postUpgradeMessage , alterable
60 function setPreUpgradeMessage(&$preUpgradeMessage, $rev, $currentVer = NULL) {
61 if ($rev == '4.3.beta3') {
63 //sql for checking orphaned contribution records
64 $sql = "SELECT COUNT(ct.id) FROM civicrm_contribution ct LEFT JOIN civicrm_contact c ON ct.contact_id = c.id WHERE c.id IS NULL";
65 $count = CRM_Core_DAO
::singleValueQuery($sql, array(), TRUE, FALSE);
68 $error = ts("There is a data integrity issue with this CiviCRM database. It contains %1 contribution records which are linked to contact records that have been deleted. You will need to correct this manually before you can run the upgrade. Use the following MySQL query to identify the problem records: %2 These records will need to be deleted or linked to an existing contact record.", array(1 => $count, 2 => '<em>SELECT ct.* FROM civicrm_contribution ct LEFT JOIN civicrm_contact c ON ct.contact_id = c.id WHERE c.id IS NULL;</em>'));
69 CRM_Core_Error
::fatal($error);
73 if ($rev == '4.3.beta4' && CRM_Utils_Constant
::value('CIVICRM_UF', FALSE) == 'Drupal6') {
74 // CRM-11823 - Make sure the D6 HTML HEAD technique will work on
75 // upgrade pages ... except when we're in Drush.
76 if (!function_exists('drush_main')) {
77 theme('item_list', array()); // force-load theme registry
78 $theme_registry = theme_get_registry();
79 if (!isset($theme_registry['page']['preprocess functions']) ||
FALSE === array_search('civicrm_preprocess_page_inject', $theme_registry['page']['preprocess functions'])) {
80 CRM_Core_Error
::fatal('Please reset the Drupal cache (Administer => Site Configuration => Performance => Clear cached data))');
85 if ($rev == '4.3.6') {
86 $constraintArray = array(
87 'civicrm_contact' => 'contact_id',
88 'civicrm_payment_processor' => 'payment_processor_id',
91 if (version_compare('4.1alpha1', $currentVer) <= 0) {
92 $constraintArray['civicrm_campaign'] = 'campaign_id';
95 if (version_compare('4.3alpha1', $currentVer) <= 0) {
96 $constraintArray['civicrm_financial_type'] = 'financial_type_id';
99 foreach ($constraintArray as $key => $value) {
100 $query = "SELECT contri_recur.id FROM civicrm_contribution_recur contri_recur LEFT JOIN {$key} ON contri_recur.{$value} = {$key}.id
101 WHERE {$key}.id IS NULL";
102 if ($value != 'contact_id') {
103 $query .= " AND contri_recur.{$value} IS NOT NULL ";
105 $dao = CRM_Core_DAO
::executeQuery($query);
107 $invalidDataMessage = '<strong>Oops, it looks like you have orphaned recurring contribution records in your database. Before this upgrade can complete they will need to be fixed or deleted. <a href="http://wiki.civicrm.org/confluence/display/CRMDOC/Fixing+Orphaned+Contribution+Recur+Records" target="_blank">You can review steps to correct this situation on the documentation wiki.</a></strong>';
108 CRM_Core_Error
::fatal($invalidDataMessage);
116 * Compute any messages which should be displayed after upgrade
118 * @param $postUpgradeMessage string, alterable
119 * @param $rev string, an intermediate version; note that setPostUpgradeMessage is called repeatedly with different $revs
122 function setPostUpgradeMessage(&$postUpgradeMessage, $rev) {
123 if ($rev == '4.3.alpha1') {
124 // check if CiviMember component is enabled
125 $config = CRM_Core_Config
::singleton();
126 if (in_array('CiviMember', $config->enableComponents
)) {
127 $postUpgradeMessage .= '<br />' . ts('Membership renewal reminders must now be configured using the Schedule Reminders feature, which supports multiple renewal reminders (Administer > Communications > Schedule Reminders). The Update Membership Statuses scheduled job will no longer send membershp renewal reminders. You can use your existing renewal reminder message template(s) with the Schedule Reminders feature.');
128 $postUpgradeMessage .= '<br />' . ts('The Set Membership Reminder Dates scheduled job has been deleted since membership reminder dates stored in the membership table are no longer in use.');
132 //here we do the financial type check and migration
133 $isDefaultsModified = self
::_checkAndMigrateDefaultFinancialTypes();
134 if($isDefaultsModified) {
135 $postUpgradeMessage .= '<br />' . ts('Please review all price set financial type assignments.');
137 list($context, $orgName) = self
::createDomainContacts();
138 if ($context == 'added') {
139 $postUpgradeMessage .= '<br />' . ts("A new organization contact has been added as the default domain contact using the information from your Organization Address and Contact Info settings: '%1'.", array(1 => $orgName));
141 elseif ($context == 'merged') {
142 $postUpgradeMessage .= '<br />' . ts("The existing organization contact record for '%1' has been marked as the default domain contact, and has been updated with information from your Organization Address and Contact Info settings.", array(1 => $orgName));
145 $providerExists = CRM_Core_DAO
::singleValueQuery("SELECT id FROM civicrm_sms_provider LIMIT 1");
146 if ($providerExists) {
147 $postUpgradeMessage .= '<br />' . ts('SMS providers were found to setup. Please note Clickatell / Twilio are now shipped as extensions and will require installing them to continue working. Extension could be downloaded and installed from <a href="%1">github</a>.', array(1 => 'https://github.com/civicrm/civicrm-core/tree/master/tools/extensions'));
151 if ($rev == '4.3.alpha2') {
154 FROM civicrm_action_schedule
155 WHERE entity_value = '' OR entity_value IS NULL
158 $dao = CRM_Core_DAO
::executeQuery($sql);
161 while ($dao->fetch()) {
162 $reminder[$dao->id
] = $dao->title
;
163 $list .= "<li>{$dao->title}</li>";
165 if (!empty($reminder)) {
166 $list = "<br /><ul>" . $list . "</ul>";
167 $postUpgradeMessage .= '<br />' .ts("Scheduled Reminders must be linked to one or more 'entities' (Events, Event Templates, Activity Types, Membership Types). The following reminders are not configured properly and will not be run. Please review them and update or delete them: %1", array(1 => $list));
170 if ($rev == '4.3.beta2') {
171 $postUpgradeMessage .= '<br />' . ts('Default versions of the following System Workflow Message Templates have been modified to handle new functionality: <ul><li>Events - Registration Confirmation and Receipt (on-line)</li><li>Events - Registration Confirmation and Receipt (off-line)</li><li>Pledges - Acknowledgement</li><li>Pledges - Payment Reminder</li><li>Contributions - Receipt (off-line)</li><li>Contributions - Receipt (on-line)</li><li>Memberships - Signup and Renewal Receipts (off-line)</li><li>Memberships - Receipt (on-line)</li><li>Personal Campaign Pages - Admin Notification</li></ul> If you have modified these templates, please review the new default versions and implement updates as needed to your copies (Administer > Communications > Message Templates > System Workflow Messages).');
174 if ($rev == '4.3.beta5') {
175 $postUpgradeMessage .= '<br />' . ts("If you are interested in trying out the new Accounting Integration features, please review user permissions and assign the new 'manual batch' permissions as appropriate.");
179 SELECT ceft.id FROM `civicrm_financial_trxn` cft
180 LEFT JOIN civicrm_entity_financial_trxn ceft
181 ON ceft.financial_trxn_id = cft.id AND ceft.entity_table = 'civicrm_contribution'
182 LEFT JOIN civicrm_contribution cc
183 ON cc.id = ceft.entity_id AND ceft.entity_table = 'civicrm_contribution'
187 $dao = CRM_Core_DAO
::executeQuery($query);
188 $isOrphanData = TRUE;
191 SELECT cli.id FROM civicrm_line_item cli
192 LEFT JOIN civicrm_contribution cc ON cli.entity_id = cc.id AND cli.entity_table = 'civicrm_contribution'
193 LEFT JOIN civicrm_participant cp ON cli.entity_id = cp.id AND cli.entity_table = 'civicrm_participant'
194 WHERE CASE WHEN cli.entity_table = 'civicrm_contribution'
199 $dao = CRM_Core_DAO
::executeQuery($query);
201 $revPattern = '/^((\d{1,2})\.\d{1,2})\.(\d{1,2}|\w{4,7})?$/i';
202 preg_match($revPattern, $currentVer, $version);
203 if ($version[1] >= 4.3) {
206 FROM civicrm_financial_item cfi
207 LEFT JOIN civicrm_entity_financial_trxn ceft ON ceft.entity_table = 'civicrm_financial_item' and cfi.id = ceft.entity_id
208 WHERE ceft.entity_id IS NULL;
210 $dao = CRM_Core_DAO
::executeQuery($query);
212 $isOrphanData = FALSE;
216 $isOrphanData = FALSE;
222 $postUpgradeMessage .= "</br> <strong>" . ts('Your database contains extraneous financial records related to deleted contacts and contributions. These records should not affect the site and will not appear in reports, search results or exports. However you may wish to clean them up. Refer to <a href="%1" target="_blank">this wiki page for details</a>.
223 ', array( 1 => 'http://wiki.civicrm.org/confluence/display/CRMDOC/Clean+up+extraneous+financial+data+-+4.3+upgrades')) . "</strong>";
226 if ($rev == '4.3.4') {
227 $postUpgradeMessage .= '<br />' . ts('System Administrator Alert: If you are running scheduled jobs using CLI.php, you will need to reconfigure cron tasks to include a password. Scheduled jobs will no longer run if the password is not provided (<a href="%1" target="_blank">learn more</a>).',
228 array( 1 => 'http://wiki.civicrm.org/confluence/display/CRMDOC/Managing+Scheduled+Jobs'));
230 if ($rev == '4.3.5') {
231 $postUpgradeMessage .= '<br />' . ts('Default versions of the following System Workflow Message Templates have been modified to handle new functionality: <ul><li>Events - Registration Confirmation and Receipt (on-line)</li><li>Events - Registration Confirmation and Receipt (off-line)</li></ul> If you have modified these templates, please review the new default versions and implement updates as needed to your copies (Administer > Communications > Message Templates > System Workflow Messages).');
233 if ($rev == '4.3.6') {
234 $flag = CRM_Core_DAO
::singleValueQuery('SELECT count(ccp.id) FROM civicrm_contribution_product ccp
235 INNER JOIN civicrm_product cp ON ccp.product_id = cp.id
236 WHERE ccp.financial_type_id IS NULL and cp.cost > 0');
238 $postUpgradeMessage .= '<br />' . ts('Your database contains one or more premiums which have a cost but are not linked to a financial type. If you are exporting transations to an accounting package, this will result in unbalanced transactions. <a href="%1" target="_blank">You can review steps to correct this situation on the wiki.</a>',
239 array( 1 => 'http://wiki.civicrm.org/confluence/display/CRMDOC/Fixing+Issues+Caused+by+Missing+Cost+of+Goods+Account+-+4.3+Upgrades'));
249 function upgrade_4_3_alpha1($rev) {
250 self
::task_4_3_alpha1_checkDBConstraints();
252 // add indexes for civicrm_entity_financial_trxn
254 $this->addTask('Check/Add indexes for civicrm_entity_financial_trxn', 'task_4_3_x_checkIndexes', $rev);
255 // task to process sql
256 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.3.alpha1')), 'task_4_3_x_runSql', $rev);
259 $this->addTask('Populate financial type values for price records', 'assignFinancialTypeToPriceRecords');
260 //CRM-11514 create financial records for contributions
261 $this->addTask('Create financial records for contributions', 'createFinancialRecords');
263 $minId = CRM_Core_DAO
::singleValueQuery('SELECT coalesce(min(id),0) FROM civicrm_contact');
264 $maxId = CRM_Core_DAO
::singleValueQuery('SELECT coalesce(max(id),0) FROM civicrm_contact');
265 for ($startId = $minId; $startId <= $maxId; $startId +
= self
::BATCH_SIZE
) {
266 $endId = $startId + self
::BATCH_SIZE
- 1;
267 $title = ts('Upgrade timestamps (%1 => %2)', array(1 => $startId, 2 => $endId));
268 $this->addTask($title, 'convertTimestamps', $startId, $endId);
272 // fix WP access control
273 $config = CRM_Core_Config
::singleton( );
274 if ($config->userFramework
== 'WordPress') {
275 civicrm_wp_set_capabilities( );
278 // Update phones CRM-11292.
279 $this->addTask('Upgrade Phone Numbers', 'phoneNumeric');
287 function upgrade_4_3_alpha2($rev) {
289 $isColumnPresent = CRM_Core_DAO
::checkFieldExists('civicrm_dedupe_rule_group', 'is_default');
290 if ($isColumnPresent) {
291 CRM_Core_DAO
::executeQuery('ALTER TABLE civicrm_dedupe_rule_group DROP COLUMN is_default');
293 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.3.alpha2')), 'task_4_3_x_runSql', $rev);
299 function upgrade_4_3_alpha3($rev) {
300 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.3.alpha3')), 'task_4_3_x_runSql', $rev);
306 function upgrade_4_3_beta2($rev) {
307 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.3.beta2')), 'task_4_3_x_runSql', $rev);
311 CRM_Core_DAO
::checkTableExists('log_civicrm_line_item') &&
312 CRM_Core_DAO
::checkFieldExists('log_civicrm_line_item', 'label')
314 CRM_Core_DAO
::executeQuery('ALTER TABLE `log_civicrm_line_item` CHANGE `label` `label` VARCHAR(255) NULL DEFAULT NULL');
321 function upgrade_4_3_beta3($rev) {
322 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.3.beta3')), 'task_4_3_x_runSql', $rev);
324 $query = "SELECT id, form_values FROM civicrm_report_instance WHERE form_values LIKE '%contribution_type%'";
325 $this->addTask('Replace contribution_type to financial_type in table civicrm_report_instance', 'replaceContributionTypeId', $query, 'reportInstance');
326 $query = "SELECT * FROM civicrm_saved_search WHERE form_values LIKE '%contribution_type%'";
327 $this->addTask('Replace contribution_type to financial_type in table civicrm_saved_search', 'replaceContributionTypeId', $query, 'savedSearch');
333 function upgrade_4_3_beta4($rev) {
334 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.3.beta4')), 'task_4_3_x_runSql', $rev);
335 // add indexes for civicrm_entity_financial_trxn
337 $this->addTask('Check/Add indexes for civicrm_entity_financial_trxn', 'task_4_3_x_checkIndexes', $rev);
343 function upgrade_4_3_beta5($rev) {
346 CRM_Core_DAO
::checkTableExists('log_civicrm_financial_trxn') &&
347 CRM_Core_DAO
::checkFieldExists('log_civicrm_financial_trxn', 'trxn_id')
349 CRM_Core_DAO
::executeQuery('ALTER TABLE `log_civicrm_financial_trxn` CHANGE `trxn_id` `trxn_id` VARCHAR(255) NULL DEFAULT NULL');
351 // CRM-12142 - some sites didn't get this column added yet, and sites which installed 4.3 from scratch will already have it
352 // CRM-12367 - add this column to single lingual sites only
353 $upgrade = new CRM_Upgrade_Form();
354 if (!$upgrade->multilingual
&&
355 !CRM_Core_DAO
::checkFieldExists('civicrm_premiums', 'premiums_nothankyou_label')
358 ALTER TABLE civicrm_premiums
359 ADD COLUMN premiums_nothankyou_label varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL
360 COMMENT 'Label displayed for No Thank-you option in premiums block (e.g. No thank you)'
362 CRM_Core_DAO
::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
364 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.3.beta5')), 'task_4_3_x_runSql', $rev);
370 function upgrade_4_3_4($rev) {
371 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.3.4')), 'task_4_3_x_runSql', $rev);
377 function upgrade_4_3_5($rev) {
379 $config = CRM_Core_Config
::singleton();
380 $dbname = DB
::parseDSN($config->dsn
);
381 $sql = "SELECT DELETE_RULE
382 FROM information_schema.REFERENTIAL_CONSTRAINTS
383 WHERE CONSTRAINT_NAME = 'FK_civicrm_financial_item_contact_id'
384 AND CONSTRAINT_SCHEMA = %1";
385 $params = array(1 => array($dbname['database'], 'String'));
386 $onDelete = CRM_Core_DAO
::singleValueQuery($sql, $params, TRUE, FALSE);
388 if ($onDelete != 'CASCADE') {
389 $query = "ALTER TABLE `civicrm_financial_item`
390 DROP FOREIGN KEY FK_civicrm_financial_item_contact_id,
391 DROP INDEX FK_civicrm_financial_item_contact_id;";
392 CRM_Core_DAO
::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
394 ALTER TABLE `civicrm_financial_item`
395 ADD CONSTRAINT `FK_civicrm_financial_item_contact_id` FOREIGN KEY (`contact_id`) REFERENCES `civicrm_contact` (`id`) ON DELETE CASCADE;
397 CRM_Core_DAO
::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
399 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.3.5')), 'task_4_3_x_runSql', $rev);
405 function upgrade_4_3_6($rev) {
407 $this->addTask(ts('Add missing constraints'), 'addMissingConstraints', $rev);
409 $this->addTask('Add ON DELETE Options for constraints', 'task_4_3_x_checkConstraints', $rev);
410 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.3.6')), 'task_4_3_x_runSql', $rev);
412 // update line_item, financial_trxn and financial_item table for recurring contributions
413 $this->addTask('Update financial_account_id in financial_trxn table', 'updateFinancialTrxnData', $rev);
414 $this->addTask('Update Line Item Data', 'updateLineItemData', $rev);
421 function assignFinancialTypeToPriceRecords() {
422 $upgrade = new CRM_Upgrade_Form();
423 //here we update price set entries
425 SELECT id, LCASE(name) name
426 FROM civicrm_financial_type
427 WHERE name IN ('Donation', 'Event Fee', 'Member Dues');
429 $daoFinancialIds = CRM_Core_DAO
::executeQuery($sqlFinancialIds);
430 while($daoFinancialIds->fetch()) {
431 $financialIds[$daoFinancialIds->name
] = $daoFinancialIds->id
;
433 $sqlPriceSetUpdate = "
434 UPDATE civicrm_price_set ps
435 SET ps.financial_type_id =
437 WHEN ps.extends LIKE '%1%' THEN {$financialIds['event fee']}
438 WHEN ps.extends LIKE '2' THEN {$financialIds['donation']}
439 WHEN ps.extends LIKE '3' THEN {$financialIds['member dues']}
441 WHERE financial_type_id IS NULL
443 CRM_Core_DAO
::executeQuery($sqlPriceSetUpdate);
445 //here we update price field value rows
446 $sqlPriceFieldValueUpdate = "
447 UPDATE civicrm_price_field_value pfv
448 LEFT JOIN civicrm_membership_type mt ON (pfv.membership_type_id = mt.id)
449 INNER JOIN civicrm_price_field pf ON (pfv.price_field_id = pf.id)
450 INNER JOIN civicrm_price_set ps ON (pf.price_set_id = ps.id)
451 SET pfv.financial_type_id =
453 WHEN pfv.membership_type_id IS NOT NULL THEN mt.financial_type_id
454 WHEN pfv.membership_type_id IS NULL THEN ps.financial_type_id
457 CRM_Core_DAO
::executeQuery($sqlPriceFieldValueUpdate);
465 static function _checkAndMigrateDefaultFinancialTypes() {
466 $modifiedDefaults = FALSE;
467 //insert types if not exists
470 FROM civicrm_contribution_type
471 WHERE name IN ('Donation', 'Event Fee', 'Member Dues') AND is_active =1
473 $daoFetchTypes = CRM_Core_DAO
::executeQuery($sqlFetchTypes);
475 if ($daoFetchTypes->N
< 3) {
476 $modifiedDefaults = TRUE;
477 $insertStatments = array (
478 'Donation' => "('Donation', 0, 1, 1)",
479 'Member' => "('Member Dues', 0, 1, 1)",
480 'Event Fee' => "('Event Fee', 0, 1, 0)",
482 foreach ($insertStatments as $values) {
484 INSERT INTO civicrm_contribution_type (name, is_reserved, is_active, is_deductible)
486 ON DUPLICATE KEY UPDATE is_active = 1
488 CRM_Core_DAO
::executeQuery($query);
491 return $modifiedDefaults;
497 function createFinancialRecords() {
498 $upgrade = new CRM_Upgrade_Form();
500 // update civicrm_entity_financial_trxn.amount = civicrm_financial_trxn.total_amount
502 UPDATE civicrm_entity_financial_trxn ceft
503 LEFT JOIN civicrm_financial_trxn cft ON cft.id = ceft.financial_trxn_id
504 SET ceft.amount = total_amount
505 WHERE cft.net_amount IS NOT NULL
506 AND ceft.entity_table = 'civicrm_contribution'
508 CRM_Core_DAO
::executeQuery($query);
510 $contributionStatus = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
511 $completedStatus = array_search('Completed', $contributionStatus);
512 $pendingStatus = array_search('Pending', $contributionStatus);
513 $cancelledStatus = array_search('Cancelled', $contributionStatus);
514 $queryParams = array(
515 1 => array($completedStatus, 'Integer'),
516 2 => array($pendingStatus, 'Integer'),
517 3 => array($cancelledStatus, 'Integer')
520 $accountType = key(CRM_Core_PseudoConstant
::accountOptionValues('financial_account_type', NULL, " AND v.name = 'Asset' "));
523 FROM civicrm_financial_account
525 AND financial_account_type_id = {$accountType}
527 $financialAccountId = CRM_Core_DAO
::singleValueQuery($query);
529 $accountRelationsips = CRM_Core_PseudoConstant
::get('CRM_Financial_DAO_EntityFinancialAccount',
530 'account_relationship', CRM_Core_DAO
::$_nullArray, 'validate');
532 $accountsReceivableAccount = array_search('Accounts Receivable Account is', $accountRelationsips);
533 $incomeAccountIs = array_search('Income Account is', $accountRelationsips);
534 $assetAccountIs = array_search('Asset Account is', $accountRelationsips);
535 $expenseAccountIs = array_search('Expense Account is', $accountRelationsips);
537 $financialItemStatus = CRM_Core_PseudoConstant
::get('CRM_Financial_DAO_FinancialItem', 'status_id',
538 CRM_Core_DAO
::$_nullArray, 'validate');
539 $unpaidStatus = array_search('Unpaid', $financialItemStatus);
540 $paidStatus = array_search('Paid', $financialItemStatus);
542 $validCurrencyCodes = CRM_Core_PseudoConstant
::currencyCode();
543 $validCurrencyCodes = implode("','", $validCurrencyCodes);
544 $config = CRM_Core_Config
::singleton();
545 $defaultCurrency = $config->defaultCurrency
;
546 $now = date( 'YmdHis' );
548 //adding financial_trxn records and entity_financial_trxn records related to contribution
549 //Add temp column for easy entry in entity_financial_trxn
550 $sql = "ALTER TABLE civicrm_financial_trxn ADD COLUMN contribution_id INT DEFAULT NULL";
551 CRM_Core_DAO
::executeQuery($sql);
553 //pending pay later status handling
555 INSERT INTO civicrm_financial_trxn
556 (contribution_id, payment_instrument_id, currency, total_amount, net_amount, fee_amount, trxn_id, status_id,
557 check_number, to_financial_account_id, from_financial_account_id, trxn_date)
558 SELECT con.id as contribution_id, con.payment_instrument_id,
559 IF(con.currency IN ('{$validCurrencyCodes}'), con.currency, '{$defaultCurrency}') as currency,
560 con.total_amount, con.net_amount, con.fee_amount, con.trxn_id, con.contribution_status_id,
561 con.check_number, efa.financial_account_id as to_financial_account_id, NULL as from_financial_account_id,
562 REPLACE(REPLACE(REPLACE(
564 WHEN con.receive_date IS NOT NULL THEN
566 WHEN con.receipt_date IS NOT NULL THEN
571 , '-', ''), ':', ''), ' ', '') as trxn_date
572 FROM civicrm_contribution con
573 LEFT JOIN civicrm_entity_financial_account efa
574 ON (con.financial_type_id = efa.entity_id AND efa.entity_table = 'civicrm_financial_type'
575 AND efa.account_relationship = {$accountsReceivableAccount})
576 WHERE con.is_pay_later = 1
577 AND con.contribution_status_id = {$pendingStatus}
579 CRM_Core_DAO
::executeQuery($sql);
581 //create a temp table to hold financial account id related to payment instruments
582 $tempTableName1 = CRM_Core_DAO
::createTempTableName();
585 CREATE TEMPORARY TABLE {$tempTableName1}
586 SELECT ceft.financial_account_id financial_account_id, cov.value as instrument_id
587 FROM civicrm_entity_financial_account ceft
588 INNER JOIN civicrm_option_value cov ON cov.id = ceft.entity_id AND ceft.entity_table = 'civicrm_option_value'
589 INNER JOIN civicrm_option_group cog ON cog.id = cov.option_group_id
590 WHERE cog.name = 'payment_instrument'
592 CRM_Core_DAO
::executeQuery($sql);
595 $sql = "ALTER TABLE {$tempTableName1} ADD INDEX index_instrument_id (instrument_id(200));";
596 CRM_Core_DAO
::executeQuery($sql);
598 //create temp table to process completed / cancelled contribution
599 $tempTableName2 = CRM_Core_DAO
::createTempTableName();
601 CREATE TEMPORARY TABLE {$tempTableName2}
602 SELECT con.id as contribution_id, con.payment_instrument_id,
603 IF(con.currency IN ('{$validCurrencyCodes}'), con.currency, '{$defaultCurrency}') as currency,
604 con.total_amount, con.net_amount, con.fee_amount, con.trxn_id, con.contribution_status_id,
605 con.check_number, NULL as from_financial_account_id,
606 REPLACE(REPLACE(REPLACE(
608 WHEN con.receive_date IS NOT NULL THEN
610 WHEN con.receipt_date IS NOT NULL THEN
615 , '-', ''), ':', ''), ' ', '') as trxn_date,
617 WHEN con.payment_instrument_id IS NULL THEN
618 {$financialAccountId}
619 WHEN con.payment_instrument_id IS NOT NULL THEN
620 tpi.financial_account_id
621 END as to_financial_account_id,
622 IF(eft.financial_trxn_id IS NULL, 'insert', eft.financial_trxn_id) as action
623 FROM civicrm_contribution con
624 LEFT JOIN civicrm_entity_financial_trxn eft
625 ON (eft.entity_table = 'civicrm_contribution' AND eft.entity_id = con.id)
626 LEFT JOIN {$tempTableName1} tpi
627 ON con.payment_instrument_id = tpi.instrument_id
628 WHERE con.contribution_status_id IN ({$completedStatus}, {$cancelledStatus})
630 CRM_Core_DAO
::executeQuery($sql);
633 $sql = "ALTER TABLE {$tempTableName2} ADD INDEX index_action (action);";
634 CRM_Core_DAO
::executeQuery($sql);
636 //handling for completed contribution and cancelled contribution
637 //insertion of new records
639 INSERT INTO civicrm_financial_trxn
640 (contribution_id, payment_instrument_id, currency, total_amount, net_amount, fee_amount, trxn_id, status_id, check_number,
641 to_financial_account_id, from_financial_account_id, trxn_date)
642 SELECT tempI.contribution_id, tempI.payment_instrument_id, tempI.currency, tempI.total_amount, tempI.net_amount,
643 tempI.fee_amount, tempI.trxn_id, tempI.contribution_status_id, tempI.check_number,
644 tempI.to_financial_account_id, tempI.from_financial_account_id, tempI.trxn_date
645 FROM {$tempTableName2} tempI
646 WHERE tempI.action = 'insert'
648 CRM_Core_DAO
::executeQuery($sql);
650 //update of existing records
652 UPDATE civicrm_financial_trxn ft
653 INNER JOIN {$tempTableName2} tempU
654 ON (tempU.action != 'insert' AND ft.id = tempU.action)
655 SET ft.from_financial_account_id = NULL,
656 ft.to_financial_account_id = tempU.to_financial_account_id,
657 ft.status_id = tempU.contribution_status_id,
658 ft.payment_instrument_id = tempU.payment_instrument_id,
659 ft.check_number = tempU.check_number,
660 ft.contribution_id = tempU.contribution_id;";
661 CRM_Core_DAO
::executeQuery($sql);
663 //insert the -ve transaction rows for cancelled contributions
665 INSERT INTO civicrm_financial_trxn
666 (contribution_id, payment_instrument_id, currency, total_amount, net_amount, fee_amount, trxn_id, status_id,
667 check_number, to_financial_account_id, from_financial_account_id, trxn_date)
668 SELECT ft.contribution_id, ft.payment_instrument_id, ft.currency, -ft.total_amount, ft.net_amount, ft.fee_amount, ft.trxn_id,
669 ft.status_id, ft.check_number, ft.to_financial_account_id, ft.from_financial_account_id, ft.trxn_date
670 FROM civicrm_financial_trxn ft
671 WHERE ft.status_id = {$cancelledStatus};";
672 CRM_Core_DAO
::executeQuery($sql);
674 //inserting entity financial trxn entries if its not present in entity_financial_trxn for completed and pending contribution statuses
675 //this also handles +ve and -ve both transaction entries for a cancelled contribution
677 INSERT INTO civicrm_entity_financial_trxn (entity_table, entity_id, financial_trxn_id, amount)
678 SELECT 'civicrm_contribution', ft.contribution_id, ft.id, ft.total_amount as amount
679 FROM civicrm_financial_trxn ft
680 WHERE contribution_id IS NOT NULL AND
681 ft.id NOT IN (SELECT financial_trxn_id
682 FROM civicrm_entity_financial_trxn
683 WHERE entity_table = 'civicrm_contribution'
684 AND entity_id = ft.contribution_id)";
685 CRM_Core_DAO
::executeQuery($sql);
686 //end of adding financial_trxn records and entity_financial_trxn records related to contribution
688 //update all linked line_item rows
689 // set line_item.financial_type_id = contribution.financial_type_id if contribution page id is null and not participant line item
690 // set line_item.financial_type_id = price_field_value.financial_type_id if contribution page id is set and not participant line item
691 // set line_item.financial_type_id = event.financial_type_id if its participant line item and line_item.price_field_value_id is null
692 // set line_item.financial_type_id = price_field_value.financial_type_id if its participant line item and line_item.price_field_value_id is set
693 $updateLineItemSql = "
694 UPDATE civicrm_line_item li
695 LEFT JOIN civicrm_contribution con
696 ON (li.entity_id = con.id AND li.entity_table = 'civicrm_contribution')
697 LEFT JOIN civicrm_price_field_value cpfv
698 ON li.price_field_value_id = cpfv.id
699 LEFT JOIN civicrm_participant cp
700 ON (li.entity_id = cp.id AND li.entity_table = 'civicrm_participant')
701 LEFT JOIN civicrm_event ce
702 ON ce.id = cp.event_id
703 SET li.financial_type_id = CASE
704 WHEN (con.contribution_page_id IS NULL || li.price_field_value_id IS NULL) AND cp.id IS NULL THEN
705 con.financial_type_id
706 WHEN (con.contribution_page_id IS NOT NULL AND cp.id IS NULL) || (cp.id IS NOT NULL AND li.price_field_value_id IS NOT NULL) THEN
707 cpfv.financial_type_id
708 WHEN cp.id IS NOT NULL AND li.price_field_value_id IS NULL THEN
711 CRM_Core_DAO
::executeQuery($updateLineItemSql, $queryParams);
713 //add the financial_item entries
714 //add a temp column so that inserting entity_financial_trxn entries gets easy
715 $sql = "ALTER TABLE civicrm_financial_item ADD COLUMN f_trxn_id INT DEFAULT NULL";
716 CRM_Core_DAO
::executeQuery($sql);
718 //add financial_item entries for contribution completed / pending pay later / cancelled
719 $contributionlineItemSql = "
720 INSERT INTO civicrm_financial_item
721 (transaction_date, contact_id, amount, currency, entity_table, entity_id, description, status_id, financial_account_id, f_trxn_id)
723 SELECT REPLACE(REPLACE(REPLACE(ft.trxn_date, '-', ''), ':', ''), ' ', ''), con.contact_id,
724 IF(ft.total_amount < 0 AND con.contribution_status_id = %3, -li.line_total, li.line_total) as line_total, con.currency, 'civicrm_line_item',
725 li.id as line_item_id, li.label as line_item_label,
726 IF(con.contribution_status_id = {$pendingStatus}, {$unpaidStatus}, {$paidStatus}) as status_id, efa.financial_account_id as financial_account_id,
728 FROM civicrm_line_item li
729 INNER JOIN civicrm_contribution con
730 ON (li.entity_id = con.id AND li.entity_table = 'civicrm_contribution')
731 INNER JOIN civicrm_financial_trxn ft
732 ON (con.id = ft.contribution_id)
733 LEFT JOIN civicrm_entity_financial_account efa
734 ON (li.financial_type_id = efa.entity_id AND efa.entity_table = 'civicrm_financial_type'
735 AND efa.account_relationship = {$incomeAccountIs})
736 WHERE con.contribution_status_id IN (%1, %3) OR (con.is_pay_later = 1 AND con.contribution_status_id = %2)";
737 CRM_Core_DAO
::executeQuery($contributionlineItemSql, $queryParams);
739 //add financial_item entries for event
740 $participantLineItemSql = "
741 INSERT INTO civicrm_financial_item
742 (transaction_date, contact_id, amount, currency, entity_table, entity_id, description, status_id, financial_account_id, f_trxn_id)
744 SELECT REPLACE(REPLACE(REPLACE(ft.trxn_date, '-', ''), ':', ''), ' ', ''), con.contact_id,
745 IF(ft.total_amount < 0 AND con.contribution_status_id = %3, -li.line_total, li.line_total) as line_total,
746 con.currency, 'civicrm_line_item', li.id as line_item_id, li.label as line_item_label,
747 IF(con.contribution_status_id = {$pendingStatus}, {$unpaidStatus}, {$paidStatus}) as status_id,
748 efa.financial_account_id as financial_account_id, ft.id as f_trxn_id
749 FROM civicrm_line_item li
750 INNER JOIN civicrm_participant par
751 ON (li.entity_id = par.id AND li.entity_table = 'civicrm_participant')
752 INNER JOIN civicrm_participant_payment pp
753 ON (pp.participant_id = par.id)
754 INNER JOIN civicrm_contribution con
755 ON (pp.contribution_id = con.id)
756 INNER JOIN civicrm_financial_trxn ft
757 ON (con.id = ft.contribution_id)
758 LEFT JOIN civicrm_entity_financial_account efa
759 ON (li.financial_type_id = efa.entity_id AND
760 efa.entity_table = 'civicrm_financial_type' AND efa.account_relationship = {$incomeAccountIs})
761 WHERE con.contribution_status_id IN (%1, %3) OR (con.is_pay_later = 1 AND con.contribution_status_id = %2)";
762 CRM_Core_DAO
::executeQuery($participantLineItemSql, $queryParams);
764 //fee handling for contributions
765 //insert fee entries in financial_trxn for contributions
766 $sql = "ALTER TABLE civicrm_financial_trxn ADD COLUMN is_fee TINYINT DEFAULT NULL";
767 CRM_Core_DAO
::executeQuery($sql);
770 INSERT INTO civicrm_financial_trxn
771 (contribution_id, payment_instrument_id, currency, total_amount, net_amount, fee_amount, trxn_id, status_id, check_number,
772 to_financial_account_id, from_financial_account_id, trxn_date, payment_processor_id, is_fee)
774 SELECT con.id, ft.payment_instrument_id, ft.currency, ft.fee_amount, NULL, NULL, ft.trxn_id, %1 as status_id,
775 ft.check_number, efaFT.financial_account_id as to_financial_account_id, CASE
776 WHEN efaPP.financial_account_id IS NOT NULL THEN
777 efaPP.financial_account_id
778 WHEN tpi.financial_account_id IS NOT NULL THEN
779 tpi.financial_account_id
781 {$financialAccountId}
782 END as from_financial_account_id, ft.trxn_date, ft.payment_processor_id, 1 as is_fee
783 FROM civicrm_contribution con
784 INNER JOIN civicrm_financial_trxn ft
785 ON (ft.contribution_id = con.id)
786 LEFT JOIN civicrm_entity_financial_account efaFT
787 ON (con.financial_type_id = efaFT.entity_id AND efaFT.entity_table = 'civicrm_financial_type'
788 AND efaFT.account_relationship = {$expenseAccountIs})
789 LEFT JOIN civicrm_entity_financial_account efaPP
790 ON (ft.payment_processor_id = efaPP.entity_id AND efaPP.entity_table = 'civicrm_payment_processor'
791 AND efaPP.account_relationship = {$assetAccountIs})
792 LEFT JOIN {$tempTableName1} tpi
793 ON ft.payment_instrument_id = tpi.instrument_id
794 WHERE ft.fee_amount IS NOT NULL AND ft.fee_amount != 0 AND (con.contribution_status_id IN (%1, %3) OR (con.contribution_status_id =%2 AND con.is_pay_later = 1))
796 CRM_Core_DAO
::executeQuery($sql, $queryParams);
798 //link financial_trxn to contribution
800 INSERT INTO civicrm_entity_financial_trxn
801 (entity_table, entity_id, financial_trxn_id, amount)
802 SELECT 'civicrm_contribution', ft.contribution_id, ft.id, ft.total_amount
803 FROM civicrm_financial_trxn ft
804 WHERE ft.is_fee = 1";
805 CRM_Core_DAO
::executeQuery($sql);
807 //add fee related entries to financial item table
808 $domainId = CRM_Core_Config
::domainID();
809 $domainContactId = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_Domain', $domainId, 'contact_id');
811 INSERT INTO civicrm_financial_item
812 (transaction_date, contact_id, amount, currency, entity_table, entity_id, description, status_id, financial_account_id, f_trxn_id)
813 SELECT ft.trxn_date, {$domainContactId} as contact_id, ft.total_amount, ft.currency, 'civicrm_financial_trxn', ft.id,
814 'Fee', {$paidStatus} as status_id, ft.to_financial_account_id as financial_account_id, ft.id as f_trxn_id
815 FROM civicrm_financial_trxn ft
816 WHERE ft.is_fee = 1;";
817 CRM_Core_DAO
::executeQuery($sql);
819 //add entries to entity_financial_trxn table
821 INSERT INTO civicrm_entity_financial_trxn (entity_table, entity_id, financial_trxn_id, amount)
822 SELECT 'civicrm_financial_item' as entity_table, fi.id as entity_id, fi.f_trxn_id as financial_trxn_id, fi.amount
823 FROM civicrm_financial_item fi";
824 CRM_Core_DAO
::executeQuery($sql);
826 //drop the temparory columns
827 $sql = "ALTER TABLE civicrm_financial_trxn
828 DROP COLUMN contribution_id,
829 DROP COLUMN is_fee;";
830 CRM_Core_DAO
::executeQuery($sql);
832 $sql = "ALTER TABLE civicrm_financial_item DROP f_trxn_id";
833 CRM_Core_DAO
::executeQuery($sql);
841 function createDomainContacts() {
842 $domainParams = $context = array();
844 ALTER TABLE civicrm_domain ADD contact_id INT( 10 ) UNSIGNED NULL DEFAULT NULL COMMENT 'FK to Contact ID. This is specifically not an FK to avoid circular constraints',
845 ADD CONSTRAINT FK_civicrm_domain_contact_id FOREIGN KEY (contact_id) REFERENCES civicrm_contact(id);";
846 CRM_Core_DAO
::executeQuery($query, CRM_Core_DAO
::$_nullArray, TRUE, NULL, FALSE, FALSE);
849 SELECT cd.id, cd.name, ce.email FROM civicrm_domain cd
850 LEFT JOIN civicrm_loc_block clb ON clb.id = cd. loc_block_id
851 LEFT JOIN civicrm_email ce ON ce.id = clb.email_id ;
853 $dao = CRM_Core_DAO
::executeQuery($query);
854 while($dao->fetch()) {
856 SELECT cc.id FROM civicrm_contact cc
857 LEFT JOIN civicrm_email ce ON ce.contact_id = cc.id
858 WHERE cc.contact_type = 'Organization' AND cc.organization_name = %1
860 $params = array(1 => array($dao->name
, 'String'));
862 $query .= " AND ce.email = %2 ";
863 $params[2] = array($dao->email
, 'String');
865 $contactID = CRM_Core_DAO
::singleValueQuery($query, $params);
866 $context[1] = $dao->name
;
867 if (empty($contactID)) {
869 'sort_name' => $dao->name
,
870 'display_name' => $dao->name
,
871 'legal_name' => $dao->name
,
872 'organization_name' => $dao->name
,
873 'contact_type' => 'Organization'
875 $contact = CRM_Contact_BAO_Contact
::add($params);
876 $contactID = $contact->id
;
877 $context[0] = 'added';
880 $context[0] = 'merged';
882 $domainParams['contact_id'] = $contactID;
883 CRM_Core_BAO_Domain
::edit($domainParams, $dao->id
);
888 function task_4_3_alpha1_checkDBConstraints() {
889 //checking whether the foreign key exists before dropping it CRM-11260
890 $config = CRM_Core_Config
::singleton();
891 $dbUf = DB
::parseDSN($config->dsn
);
893 'autorenewal_msg_id' => array('tableName' => 'civicrm_membership_type', 'fkey' => 'FK_civicrm_membership_autorenewal_msg_id'),
894 'to_account_id' => array('tableName' => 'civicrm_financial_trxn', 'constraintName' => 'civicrm_financial_trxn_ibfk_2'),
895 'from_account_id' => array('tableName' => 'civicrm_financial_trxn', 'constraintName' => 'civicrm_financial_trxn_ibfk_1'),
896 'contribution_type_id' => array('tableName' => 'civicrm_contribution_recur', 'fkey' => 'FK_civicrm_contribution_recur_contribution_type_id'),
899 SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
900 WHERE table_name = 'civicrm_contribution_recur'
901 AND constraint_name = 'FK_civicrm_contribution_recur_contribution_type_id'
902 AND TABLE_SCHEMA = %1
904 $params = array(1 => array($dbUf['database'], 'String'));
905 $dao = CRM_Core_DAO
::executeQuery($query, $params, TRUE, NULL, FALSE, FALSE);
906 foreach($tables as $columnName => $value){
907 if ($value['tableName'] == 'civicrm_membership_type' ||
$value['tableName'] == 'civicrm_contribution_recur') {
908 $foreignKeyExists = CRM_Core_DAO
::checkConstraintExists($value['tableName'], $value['fkey']);
909 $fKey = $value['fkey'];
911 $foreignKeyExists = CRM_Core_DAO
::checkFKConstraintInFormat($value['tableName'], $columnName);
912 $fKey = "`FK_{$value['tableName']}_{$columnName}`";
914 if ($foreignKeyExists ||
$value['tableName'] == 'civicrm_financial_trxn') {
915 if ($value['tableName'] != 'civicrm_contribution_recur' ||
($value['tableName'] == 'civicrm_contribution_recur' && $dao->N
)) {
916 $constraintName = $foreignKeyExists ?
$fKey : $value['constraintName'];
917 $query = "ALTER TABLE {$value['tableName']} DROP FOREIGN KEY {$constraintName}";
918 CRM_Core_DAO
::executeQuery($query, $params, TRUE, NULL, FALSE, FALSE);
920 $query = "ALTER TABLE {$value['tableName']} DROP INDEX {$fKey}";
921 CRM_Core_DAO
::executeQuery($query, $params, TRUE, NULL, FALSE, FALSE);
924 // check if column contact_id is present or not in civicrm_financial_account
925 $fieldExists = CRM_Core_DAO
::checkFieldExists('civicrm_financial_account', 'contact_id', FALSE);
928 ALTER TABLE civicrm_financial_account
929 ADD contact_id int(10) unsigned DEFAULT NULL COMMENT 'Version identifier of financial_type' AFTER name,
930 ADD CONSTRAINT FK_civicrm_financial_account_contact_id FOREIGN KEY (contact_id) REFERENCES civicrm_contact(id);
932 CRM_Core_DAO
::executeQuery($query, $params, TRUE, NULL, FALSE, FALSE);
937 * Read creation and modification times from civicrm_log; add
938 * them to civicrm_contact.
940 function convertTimestamps(CRM_Queue_TaskContext
$ctx, $startId, $endId) {
942 SELECT entity_id, min(modified_date) AS created, max(modified_date) AS modified
944 WHERE entity_table = 'civicrm_contact'
945 AND entity_id BETWEEN %1 AND %2
949 1 => array($startId, 'Integer'),
950 2 => array($endId, 'Integer'),
952 $dao = CRM_Core_DAO
::executeQuery($sql, $params);
953 while ($dao->fetch()) {
954 // FIXME civicrm_log.modified_date is DATETIME; civicrm_contact.modified_date is TIMESTAMP
955 CRM_Core_DAO
::executeQuery(
956 'UPDATE civicrm_contact SET created_date = FROM_UNIXTIME(UNIX_TIMESTAMP(%1)), modified_date = FROM_UNIXTIME(UNIX_TIMESTAMP(%2)) WHERE id = %3',
958 1 => array($dao->created
, 'String'),
959 2 => array($dao->modified
, 'String'),
960 3 => array($dao->entity_id
, 'Integer'),
969 * change index and add missing constraints for civicrm_contribution_recur
971 function addMissingConstraints(CRM_Queue_TaskContext
$ctx) {
972 $query = "SHOW KEYS FROM `civicrm_contribution_recur` WHERE key_name = 'UI_contrib_payment_instrument_id'";
973 $dao = CRM_Core_DAO
::executeQuery($query);
975 CRM_Core_DAO
::executeQuery('ALTER TABLE civicrm_contribution_recur DROP INDEX UI_contrib_payment_instrument_id');
976 CRM_Core_DAO
::executeQuery('ALTER TABLE civicrm_contribution_recur ADD INDEX UI_contribution_recur_payment_instrument_id (payment_instrument_id)');
978 $constraintArray = array(
979 'contact_id' => " ADD CONSTRAINT `FK_civicrm_contribution_recur_contact_id` FOREIGN KEY (`contact_id`) REFERENCES `civicrm_contact` (`id`) ON DELETE CASCADE ",
980 'payment_processor_id' => " ADD CONSTRAINT `FK_civicrm_contribution_recur_payment_processor_id` FOREIGN KEY (`payment_processor_id`) REFERENCES `civicrm_payment_processor` (`id`) ON DELETE SET NULL ",
981 'financial_type_id' => " ADD CONSTRAINT `FK_civicrm_contribution_recur_financial_type_id` FOREIGN KEY (`financial_type_id`) REFERENCES `civicrm_financial_type` (`id`) ON DELETE SET NULL ",
982 'campaign_id' => " ADD CONSTRAINT `FK_civicrm_contribution_recur_campaign_id` FOREIGN KEY (`campaign_id`) REFERENCES `civicrm_campaign` (`id`) ON DELETE SET NULL ",
984 $constraint = array();
985 foreach ($constraintArray as $constraintKey => $value) {
986 $foreignKeyExists = CRM_Core_DAO
::checkFKConstraintInFormat('civicrm_contribution_recur', $constraintKey);
987 if (!$foreignKeyExists) {
988 $constraint[] = $value;
991 if (!empty($constraint)) {
992 $query = "ALTER TABLE civicrm_contribution_recur " . implode(' , ', $constraint);
993 CRM_Core_DAO
::executeQuery($query);
999 * Update financial_account_id for bad data in financial_trxn table
1003 function updateFinancialTrxnData(CRM_Queue_TaskContext
$ctx) {
1004 $upgrade = new CRM_Upgrade_Form();
1005 $sql = "SELECT cc.id contribution_id, cc.contribution_recur_id, cft.payment_processor_id,
1006 cft.id financial_trxn_id, cfi.entity_table, cft.from_financial_account_id, cft.to_financial_account_id
1008 FROM `civicrm_contribution` cc
1009 LEFT JOIN civicrm_entity_financial_trxn ceft ON ceft.entity_id = cc.id
1010 LEFT JOIN civicrm_financial_trxn cft ON cft.id = ceft.financial_trxn_id
1011 LEFT JOIN civicrm_entity_financial_trxn ceft1 ON ceft1.financial_trxn_id = ceft.financial_trxn_id
1012 LEFT JOIN civicrm_financial_item cfi ON cfi.id = ceft1.entity_id
1013 WHERE ceft.entity_table = 'civicrm_contribution' AND cc.contribution_recur_id IS NOT NULL
1014 AND ceft1.entity_table = 'civicrm_financial_item' AND cft.id IS NOT NULL AND cft.payment_instrument_id = %1
1017 $paymentInstrument = CRM_Contribute_PseudoConstant
::paymentInstrument('name');
1018 $param = array(1 => array(array_search('Credit Card', $paymentInstrument), 'Integer'));
1019 $dao = CRM_Core_DAO
::executeQuery($sql, $param);
1020 $financialTrxn = array();
1021 $subsequentPayments = array();
1022 while ($dao->fetch()) {
1023 if (!array_key_exists($dao->contribution_recur_id
, $financialTrxn)) {
1024 $financialTrxn[$dao->contribution_recur_id
] = array(
1025 'from_financial_account_id' => $dao->to_financial_account_id
,
1026 'payment_processor_id' => $dao->payment_processor_id
,
1027 $dao->contribution_id
=> 1,
1029 if (!is_null($dao->from_financial_account_id
)) {
1030 $sql = 'UPDATE civicrm_financial_trxn SET from_financial_account_id = NULL WHERE id = %1';
1031 $params = array(1 => array($dao->financial_trxn_id
, 'Integer'));
1032 CRM_Core_DAO
::executeQuery($sql, $params);
1035 elseif (!array_key_exists($dao->contribution_id
, $financialTrxn[$dao->contribution_recur_id
])) {
1036 if (($dao->entity_table
== 'civicrm_line_item' && $dao->to_financial_account_id
== $financialTrxn[$dao->contribution_recur_id
]['from_financial_account_id'])
1037 ||
($dao->entity_table
== 'civicrm_financial_trxn' && $dao->from_financial_account_id
== $financialTrxn[$dao->contribution_recur_id
]['from_financial_account_id'])) {
1040 $subsequentPayments[$dao->contribution_recur_id
][$dao->entity_table
][] = $dao->financial_trxn_id
;
1043 foreach ($subsequentPayments as $key => $value) {
1044 foreach ($value as $table => $val) {
1045 if ($table == 'civicrm_financial_trxn') {
1046 $field = 'from_financial_account_id';
1049 $field = 'to_financial_account_id';
1051 $sql = "UPDATE civicrm_financial_trxn SET $field = " . $financialTrxn[$dao->contribution_recur_id
]['from_financial_account_id'] . ',
1052 payment_processor_id = ' . $financialTrxn[$dao->contribution_recur_id
]['payment_processor_id'] . ' WHERE
1053 id IN (' . implode(',', $val) . ')';
1054 CRM_Core_DAO
::executeQuery($sql);
1061 * Update financial_account_id for bad data in financial_trxn table
1065 function updateLineItemData(CRM_Queue_TaskContext
$ctx) {
1066 $sql = "SELECT cc.id contribution_id, cc.contribution_recur_id,
1067 cc.financial_type_id contribution_financial_type,
1068 cli.financial_type_id line_financial_type_id,
1069 cli.price_field_id, cli.price_field_value_id, cli.label, cli.id line_item_id,
1070 cfi.financial_account_id
1071 FROM `civicrm_line_item` cli
1072 LEFT JOIN civicrm_contribution cc ON cc.id = cli.entity_id
1073 LEFT JOIN civicrm_financial_item cfi ON cfi.entity_id = cli.id
1074 LEFT JOIN civicrm_price_field cpf ON cpf.id = cli.price_field_id
1075 LEFT JOIN civicrm_price_set cps ON cps.id = cpf.price_set_id
1076 LEFT JOIN civicrm_price_field_value cpfv ON cpfv.id = cli.price_field_value_id
1077 WHERE cfi.entity_table = 'civicrm_line_item'
1078 AND cli.entity_table = 'civicrm_contribution'
1079 AND cps.is_quick_config = 1 AND cc.contribution_recur_id IS NOT NULL
1081 $dao = CRM_Core_DAO
::executeQuery($sql);
1082 $financialTrxn = $subsequentPayments = array();
1083 while ($dao->fetch()) {
1084 if (!array_key_exists($dao->contribution_recur_id
, $financialTrxn)) {
1085 $financialTrxn[$dao->contribution_recur_id
] = array(
1086 'price_field_id' => $dao->price_field_id
,
1087 'price_field_value_id' => $dao->price_field_value_id
,
1088 'label' => strval($dao->label
),
1089 'financial_account_id' => $dao->financial_account_id
,
1090 $dao->contribution_id
=> 1,
1094 if ($dao->price_field_value_id
== $financialTrxn[$dao->contribution_recur_id
]['price_field_value_id']) {
1097 $subsequentPayments[$dao->contribution_recur_id
][] = $dao->line_item_id
;
1100 foreach ($subsequentPayments as $key => $value) {
1101 $sql = "UPDATE civicrm_line_item cli
1102 LEFT JOIN civicrm_financial_item cfi ON cli.id = cfi.entity_id
1105 cli.price_field_id = %2,
1106 cli.price_field_value_id = %3,
1107 cfi.financial_account_id = %4,
1108 cfi.description = %5,
1109 cli.financial_type_id = %6
1110 WHERE cfi.entity_table = 'civicrm_line_item'
1111 AND cli.entity_table = 'civicrm_contribution' AND cli.id IN (" . implode(',', $value). ');';
1113 1 => array($financialTrxn[$key]['label'], 'String'),
1114 2 => array($financialTrxn[$key]['price_field_id'], 'Integer'),
1115 3 => array($financialTrxn[$key]['price_field_value_id'], 'Integer'),
1116 4 => array($financialTrxn[$key]['financial_account_id'], 'Integer'),
1117 5 => array($financialTrxn[$key]['label'], 'String'),
1118 6 => array($dao->contribution_financial_type
, 'Integer'),
1120 CRM_Core_DAO
::executeQuery($sql, $params);
1126 * replace contribution_type to financial_type in table
1127 * civicrm_saved_search and Structure civicrm_report_instance
1129 function replaceContributionTypeId(CRM_Queue_TaskContext
$ctx, $query, $table) {
1130 $dao = CRM_Core_DAO
::executeQuery($query);
1131 while ($dao->fetch()) {
1132 $formValues = unserialize($dao->form_values
);
1133 foreach (array('contribution_type_id_op', 'contribution_type_id_value', 'contribution_type_id') as $value) {
1134 if (array_key_exists($value, $formValues)) {
1135 $key = preg_replace('/contribution/', 'financial', $value);
1136 $formValues[$key] = $formValues[$value];
1137 unset($formValues[$value]);
1140 if ($table != 'savedSearch') {
1141 foreach (array('fields', 'group_bys') as $value) {
1142 if (array_key_exists($value, $formValues)) {
1143 if (array_key_exists('contribution_type_id', $formValues[$value])) {
1144 $formValues[$value]['financial_type_id'] = $formValues[$value]['contribution_type_id'];
1145 unset($formValues[$value]['contribution_type_id']);
1147 else if (array_key_exists('contribution_type', $formValues[$value])) {
1148 $formValues[$value]['financial_type'] = $formValues[$value]['contribution_type'];
1149 unset($formValues[$value]['contribution_type']);
1153 if (array_key_exists('order_bys', $formValues)) {
1154 foreach ($formValues['order_bys'] as $key => $values) {
1155 if (preg_grep('/contribution_type/', $values)) {
1156 $formValues['order_bys'][$key]['column'] = preg_replace('/contribution_type/', 'financial_type', $values['column']);
1162 if ($table == 'savedSearch') {
1163 $saveDao = new CRM_Contact_DAO_SavedSearch();
1166 $saveDao = new CRM_Report_DAO_ReportInstance();
1168 $saveDao->id
= $dao->id
;
1170 if ($table == 'savedSearch') {
1171 if (array_key_exists('mapper', $formValues)) {
1172 foreach ($formValues['mapper'] as $key => $values) {
1173 foreach ($values as $k => $v) {
1174 if (preg_grep('/contribution_/', $v)) {
1175 $formValues['mapper'][$key][$k] = preg_replace('/contribution_type/', 'financial_type', $v);
1180 foreach (array('select_tables', 'where_tables') as $value) {
1181 if (preg_match('/contribution_type/', $dao->$value)) {
1182 $tempValue = unserialize($dao->$value);
1183 if (array_key_exists('civicrm_contribution_type', $tempValue)) {
1184 $tempValue['civicrm_financial_type'] = $tempValue['civicrm_contribution_type'];
1185 unset($tempValue['civicrm_contribution_type']);
1187 $saveDao->$value = serialize($tempValue);
1190 if (preg_match('/contribution_type/', $dao->where_clause
)) {
1191 $saveDao->where_clause
= preg_replace('/contribution_type/', 'financial_type', $dao->where_clause
);
1194 $saveDao->form_values
= serialize($formValues);
1202 * Add ON DELETE options for constraint if not present
1203 * CRM-13088 && CRM-12156
1205 * @param CRM_Queue_TaskContext $ctx
1207 * @return bool TRUE for success
1209 function task_4_3_x_checkConstraints(CRM_Queue_TaskContext
$ctx) {
1210 CRM_Core_DAO
::executeQuery('ALTER TABLE `civicrm_financial_account` CHANGE `contact_id` `contact_id` INT( 10 ) UNSIGNED NULL DEFAULT NULL');
1211 $config = CRM_Core_Config
::singleton();
1212 $dbname = DB
::parseDSN($config->dsn
);
1213 $constraintArray = array(
1214 "'FK_civicrm_financial_account_contact_id'",
1215 "'FK_civicrm_financial_item_contact_id'",
1216 "'FK_civicrm_contribution_recur_financial_type_id'",
1217 "'FK_civicrm_line_item_financial_type_id'",
1218 "'FK_civicrm_product_financial_type_id'",
1219 "'FK_civicrm_premiums_product_financial_type_id'",
1220 "'FK_civicrm_price_field_value_financial_type_id'",
1221 "'FK_civicrm_contribution_product_financial_type_id'",
1222 "'FK_civicrm_price_set_financial_type_id'",
1223 "'FK_civicrm_grant_financial_type_id'",
1226 $sql = "SELECT DELETE_RULE, TABLE_NAME, CONSTRAINT_NAME
1227 FROM information_schema.REFERENTIAL_CONSTRAINTS
1228 WHERE CONSTRAINT_NAME IN (" . implode(',', $constraintArray) . ")
1229 AND CONSTRAINT_SCHEMA = %1";
1230 $params = array(1 => array($dbname['database'], 'String'));
1231 $onDelete = CRM_Core_DAO
::executeQuery($sql, $params, TRUE, FALSE);
1232 while ($onDelete->fetch()) {
1233 if (($onDelete->TABLE_NAME
!= 'civicrm_financial_item' && $onDelete->DELETE_RULE
!= 'SET NULL') ||
1234 ($onDelete->TABLE_NAME
== 'civicrm_financial_item' && $onDelete->DELETE_RULE
!= 'CASCADE')) {
1235 $tableName = 'civicrm_financial_type';
1236 $onDeleteOption = ' SET NULL ';
1237 $columnName = 'financial_type_id';
1238 if (preg_match('/contact_id/', $onDelete->CONSTRAINT_NAME
)) {
1239 $tableName = 'civicrm_contact';
1240 $columnName = 'contact_id';
1241 if ($onDelete->TABLE_NAME
== 'civicrm_financial_item') {
1242 $onDeleteOption = 'CASCADE';
1249 $query = "ALTER TABLE {$onDelete->TABLE_NAME}
1250 DROP FOREIGN KEY {$onDelete->CONSTRAINT_NAME},
1251 DROP INDEX {$onDelete->CONSTRAINT_NAME};";
1252 CRM_Core_DAO
::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
1253 $query = " ALTER TABLE {$onDelete->TABLE_NAME}
1254 ADD CONSTRAINT {$onDelete->CONSTRAINT_NAME} FOREIGN KEY (`" . $columnName . "`) REFERENCES {$tableName} (`id`) ON DELETE {$onDeleteOption};
1256 CRM_Core_DAO
::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
1262 * Check/Add INDEX CRM-12141
1264 * @param CRM_Queue_TaskContext $ctx
1266 * @return bool TRUE for success
1268 function task_4_3_x_checkIndexes(CRM_Queue_TaskContext
$ctx) {
1271 FROM civicrm_entity_financial_trxn
1272 WHERE key_name IN ('UI_entity_financial_trxn_entity_table', 'UI_entity_financial_trxn_entity_id')
1274 $dao = CRM_Core_DAO
::executeQuery($query);
1277 ALTER TABLE civicrm_entity_financial_trxn
1278 ADD INDEX UI_entity_financial_trxn_entity_table (entity_table),
1279 ADD INDEX UI_entity_financial_trxn_entity_id (entity_id);
1281 CRM_Core_DAO
::executeQuery($query);
1287 * Update phones CRM-11292
1289 * @param CRM_Queue_TaskContext $ctx
1291 * @return bool TRUE for success
1293 static function phoneNumeric(CRM_Queue_TaskContext
$ctx) {
1294 CRM_Core_DAO
::executeQuery(CRM_Contact_BAO_Contact
::DROP_STRIP_FUNCTION_43
);
1295 CRM_Core_DAO
::executeQuery(CRM_Contact_BAO_Contact
::CREATE_STRIP_FUNCTION_43
);
1296 CRM_Core_DAO
::executeQuery("UPDATE civicrm_phone SET phone_numeric = civicrm_strip_non_numeric(phone)");
1301 * (Queue Task Callback)
1303 static function task_4_3_x_runSql(CRM_Queue_TaskContext
$ctx, $rev) {
1304 $upgrade = new CRM_Upgrade_Form();
1305 $upgrade->processSQL($rev);
1311 * Syntatic sugar for adding a task which (a) is in this class and (b) has
1314 * After passing the $funcName, you can also pass parameters that will go to
1315 * the function. Note that all params must be serializable.
1317 protected function addTask($title, $funcName) {
1318 $queue = CRM_Queue_Service
::singleton()->load(array(
1320 'name' => CRM_Upgrade_Form
::QUEUE_NAME
,
1323 $args = func_get_args();
1324 $title = array_shift($args);
1325 $funcName = array_shift($args);
1326 $task = new CRM_Queue_Task(
1327 array(get_class($this), $funcName),
1331 $queue->createItem($task, array('weight' => -1));