4 +--------------------------------------------------------------------+
5 | CiviCRM version 4.6 |
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 public 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
55 * String, a version number, e.g. '4.3.alpha1', '4.3.beta3', '4.3.0'.
56 * @param null $currentVer
60 public 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
121 * String, an intermediate version; note that setPostUpgradeMessage is called repeatedly with different $revs.
124 public function setPostUpgradeMessage(&$postUpgradeMessage, $rev) {
125 if ($rev == '4.3.alpha1') {
126 // check if CiviMember component is enabled
127 $config = CRM_Core_Config
::singleton();
128 if (in_array('CiviMember', $config->enableComponents
)) {
129 $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.');
130 $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.');
134 //here we do the financial type check and migration
135 $isDefaultsModified = self
::_checkAndMigrateDefaultFinancialTypes();
136 if($isDefaultsModified) {
137 $postUpgradeMessage .= '<br />' . ts('Please review all price set financial type assignments.');
139 list($context, $orgName) = self
::createDomainContacts();
140 if ($context == 'added') {
141 $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));
143 elseif ($context == 'merged') {
144 $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));
147 $providerExists = CRM_Core_DAO
::singleValueQuery("SELECT id FROM civicrm_sms_provider LIMIT 1");
148 if ($providerExists) {
149 $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'));
153 if ($rev == '4.3.alpha2') {
156 FROM civicrm_action_schedule
157 WHERE entity_value = '' OR entity_value IS NULL
160 $dao = CRM_Core_DAO
::executeQuery($sql);
163 while ($dao->fetch()) {
164 $reminder[$dao->id
] = $dao->title
;
165 $list .= "<li>{$dao->title}</li>";
167 if (!empty($reminder)) {
168 $list = "<br /><ul>" . $list . "</ul>";
169 $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));
172 if ($rev == '4.3.beta2') {
173 $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).');
176 if ($rev == '4.3.beta5') {
177 $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.");
181 SELECT ceft.id FROM `civicrm_financial_trxn` cft
182 LEFT JOIN civicrm_entity_financial_trxn ceft
183 ON ceft.financial_trxn_id = cft.id AND ceft.entity_table = 'civicrm_contribution'
184 LEFT JOIN civicrm_contribution cc
185 ON cc.id = ceft.entity_id AND ceft.entity_table = 'civicrm_contribution'
189 $dao = CRM_Core_DAO
::executeQuery($query);
190 $isOrphanData = TRUE;
193 SELECT cli.id FROM civicrm_line_item cli
194 LEFT JOIN civicrm_contribution cc ON cli.entity_id = cc.id AND cli.entity_table = 'civicrm_contribution'
195 LEFT JOIN civicrm_participant cp ON cli.entity_id = cp.id AND cli.entity_table = 'civicrm_participant'
196 WHERE CASE WHEN cli.entity_table = 'civicrm_contribution'
201 $dao = CRM_Core_DAO
::executeQuery($query);
203 $revPattern = '/^((\d{1,2})\.\d{1,2})\.(\d{1,2}|\w{4,7})?$/i';
204 preg_match($revPattern, $currentVer, $version);
205 if ($version[1] >= 4.3) {
208 FROM civicrm_financial_item cfi
209 LEFT JOIN civicrm_entity_financial_trxn ceft ON ceft.entity_table = 'civicrm_financial_item' and cfi.id = ceft.entity_id
210 WHERE ceft.entity_id IS NULL;
212 $dao = CRM_Core_DAO
::executeQuery($query);
214 $isOrphanData = FALSE;
218 $isOrphanData = FALSE;
224 $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>.
225 ', array( 1 => 'http://wiki.civicrm.org/confluence/display/CRMDOC/Clean+up+extraneous+financial+data+-+4.3+upgrades')) . "</strong>";
228 if ($rev == '4.3.4') {
229 $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>).',
230 array( 1 => 'http://wiki.civicrm.org/confluence/display/CRMDOC/Managing+Scheduled+Jobs'));
232 if ($rev == '4.3.5') {
233 $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).');
235 if ($rev == '4.3.6') {
236 $flag = CRM_Core_DAO
::singleValueQuery('SELECT count(ccp.id) FROM civicrm_contribution_product ccp
237 INNER JOIN civicrm_product cp ON ccp.product_id = cp.id
238 WHERE ccp.financial_type_id IS NULL and cp.cost > 0');
240 $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>',
241 array( 1 => 'http://wiki.civicrm.org/confluence/display/CRMDOC/Fixing+Issues+Caused+by+Missing+Cost+of+Goods+Account+-+4.3+Upgrades'));
251 public function upgrade_4_3_alpha1($rev) {
252 self
::task_4_3_alpha1_checkDBConstraints();
254 // add indexes for civicrm_entity_financial_trxn
256 $this->addTask('Check/Add indexes for civicrm_entity_financial_trxn', 'task_4_3_x_checkIndexes', $rev);
257 // task to process sql
258 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.3.alpha1')), 'task_4_3_x_runSql', $rev);
261 $this->addTask('Populate financial type values for price records', 'assignFinancialTypeToPriceRecords');
262 //CRM-11514 create financial records for contributions
263 $this->addTask('Create financial records for contributions', 'createFinancialRecords');
265 $minId = CRM_Core_DAO
::singleValueQuery('SELECT coalesce(min(id),0) FROM civicrm_contact');
266 $maxId = CRM_Core_DAO
::singleValueQuery('SELECT coalesce(max(id),0) FROM civicrm_contact');
267 for ($startId = $minId; $startId <= $maxId; $startId +
= self
::BATCH_SIZE
) {
268 $endId = $startId + self
::BATCH_SIZE
- 1;
269 $title = ts('Upgrade timestamps (%1 => %2)', array(1 => $startId, 2 => $endId));
270 $this->addTask($title, 'convertTimestamps', $startId, $endId);
274 // fix WP access control
275 $config = CRM_Core_Config
::singleton( );
276 if ($config->userFramework
== 'WordPress') {
277 civicrm_wp_set_capabilities( );
280 // Update phones CRM-11292.
281 $this->addTask('Upgrade Phone Numbers', 'phoneNumeric');
289 public function upgrade_4_3_alpha2($rev) {
291 $isColumnPresent = CRM_Core_DAO
::checkFieldExists('civicrm_dedupe_rule_group', 'is_default');
292 if ($isColumnPresent) {
293 CRM_Core_DAO
::executeQuery('ALTER TABLE civicrm_dedupe_rule_group DROP COLUMN is_default');
295 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.3.alpha2')), 'task_4_3_x_runSql', $rev);
301 public function upgrade_4_3_alpha3($rev) {
302 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.3.alpha3')), 'task_4_3_x_runSql', $rev);
308 public function upgrade_4_3_beta2($rev) {
309 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.3.beta2')), 'task_4_3_x_runSql', $rev);
313 CRM_Core_DAO
::checkTableExists('log_civicrm_line_item') &&
314 CRM_Core_DAO
::checkFieldExists('log_civicrm_line_item', 'label')
316 CRM_Core_DAO
::executeQuery('ALTER TABLE `log_civicrm_line_item` CHANGE `label` `label` VARCHAR(255) NULL DEFAULT NULL');
323 public function upgrade_4_3_beta3($rev) {
324 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.3.beta3')), 'task_4_3_x_runSql', $rev);
326 $query = "SELECT id, form_values FROM civicrm_report_instance WHERE form_values LIKE '%contribution_type%'";
327 $this->addTask('Replace contribution_type to financial_type in table civicrm_report_instance', 'replaceContributionTypeId', $query, 'reportInstance');
328 $query = "SELECT * FROM civicrm_saved_search WHERE form_values LIKE '%contribution_type%'";
329 $this->addTask('Replace contribution_type to financial_type in table civicrm_saved_search', 'replaceContributionTypeId', $query, 'savedSearch');
335 public function upgrade_4_3_beta4($rev) {
336 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.3.beta4')), 'task_4_3_x_runSql', $rev);
337 // add indexes for civicrm_entity_financial_trxn
339 $this->addTask('Check/Add indexes for civicrm_entity_financial_trxn', 'task_4_3_x_checkIndexes', $rev);
345 public function upgrade_4_3_beta5($rev) {
348 CRM_Core_DAO
::checkTableExists('log_civicrm_financial_trxn') &&
349 CRM_Core_DAO
::checkFieldExists('log_civicrm_financial_trxn', 'trxn_id')
351 CRM_Core_DAO
::executeQuery('ALTER TABLE `log_civicrm_financial_trxn` CHANGE `trxn_id` `trxn_id` VARCHAR(255) NULL DEFAULT NULL');
353 // CRM-12142 - some sites didn't get this column added yet, and sites which installed 4.3 from scratch will already have it
354 // CRM-12367 - add this column to single lingual sites only
355 $upgrade = new CRM_Upgrade_Form();
356 if (!$upgrade->multilingual
&&
357 !CRM_Core_DAO
::checkFieldExists('civicrm_premiums', 'premiums_nothankyou_label')
360 ALTER TABLE civicrm_premiums
361 ADD COLUMN premiums_nothankyou_label varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL
362 COMMENT 'Label displayed for No Thank-you option in premiums block (e.g. No thank you)'
364 CRM_Core_DAO
::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
366 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.3.beta5')), 'task_4_3_x_runSql', $rev);
372 public function upgrade_4_3_4($rev) {
373 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.3.4')), 'task_4_3_x_runSql', $rev);
379 public function upgrade_4_3_5($rev) {
381 $config = CRM_Core_Config
::singleton();
382 $dbname = DB
::parseDSN($config->dsn
);
383 $sql = "SELECT DELETE_RULE
384 FROM information_schema.REFERENTIAL_CONSTRAINTS
385 WHERE CONSTRAINT_NAME = 'FK_civicrm_financial_item_contact_id'
386 AND CONSTRAINT_SCHEMA = %1";
387 $params = array(1 => array($dbname['database'], 'String'));
388 $onDelete = CRM_Core_DAO
::singleValueQuery($sql, $params, TRUE, FALSE);
390 if ($onDelete != 'CASCADE') {
391 $query = "ALTER TABLE `civicrm_financial_item`
392 DROP FOREIGN KEY FK_civicrm_financial_item_contact_id,
393 DROP INDEX FK_civicrm_financial_item_contact_id;";
394 CRM_Core_DAO
::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
396 ALTER TABLE `civicrm_financial_item`
397 ADD CONSTRAINT `FK_civicrm_financial_item_contact_id` FOREIGN KEY (`contact_id`) REFERENCES `civicrm_contact` (`id`) ON DELETE CASCADE;
399 CRM_Core_DAO
::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
401 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.3.5')), 'task_4_3_x_runSql', $rev);
407 public function upgrade_4_3_6($rev) {
409 $this->addTask(ts('Add missing constraints'), 'addMissingConstraints', $rev);
411 $this->addTask('Add ON DELETE Options for constraints', 'task_4_3_x_checkConstraints', $rev);
412 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.3.6')), 'task_4_3_x_runSql', $rev);
414 // update line_item, financial_trxn and financial_item table for recurring contributions
415 $this->addTask('Update financial_account_id in financial_trxn table', 'updateFinancialTrxnData', $rev);
416 $this->addTask('Update Line Item Data', 'updateLineItemData', $rev);
423 public function assignFinancialTypeToPriceRecords() {
424 $upgrade = new CRM_Upgrade_Form();
425 //here we update price set entries
427 SELECT id, LCASE(name) name
428 FROM civicrm_financial_type
429 WHERE name IN ('Donation', 'Event Fee', 'Member Dues');
431 $daoFinancialIds = CRM_Core_DAO
::executeQuery($sqlFinancialIds);
432 while($daoFinancialIds->fetch()) {
433 $financialIds[$daoFinancialIds->name
] = $daoFinancialIds->id
;
435 $sqlPriceSetUpdate = "
436 UPDATE civicrm_price_set ps
437 SET ps.financial_type_id =
439 WHEN ps.extends LIKE '%1%' THEN {$financialIds['event fee']}
440 WHEN ps.extends LIKE '2' THEN {$financialIds['donation']}
441 WHEN ps.extends LIKE '3' THEN {$financialIds['member dues']}
443 WHERE financial_type_id IS NULL
445 CRM_Core_DAO
::executeQuery($sqlPriceSetUpdate);
447 //here we update price field value rows
448 $sqlPriceFieldValueUpdate = "
449 UPDATE civicrm_price_field_value pfv
450 LEFT JOIN civicrm_membership_type mt ON (pfv.membership_type_id = mt.id)
451 INNER JOIN civicrm_price_field pf ON (pfv.price_field_id = pf.id)
452 INNER JOIN civicrm_price_set ps ON (pf.price_set_id = ps.id)
453 SET pfv.financial_type_id =
455 WHEN pfv.membership_type_id IS NOT NULL THEN mt.financial_type_id
456 WHEN pfv.membership_type_id IS NULL THEN ps.financial_type_id
459 CRM_Core_DAO
::executeQuery($sqlPriceFieldValueUpdate);
467 public static function _checkAndMigrateDefaultFinancialTypes() {
468 $modifiedDefaults = FALSE;
469 //insert types if not exists
472 FROM civicrm_contribution_type
473 WHERE name IN ('Donation', 'Event Fee', 'Member Dues') AND is_active =1
475 $daoFetchTypes = CRM_Core_DAO
::executeQuery($sqlFetchTypes);
477 if ($daoFetchTypes->N
< 3) {
478 $modifiedDefaults = TRUE;
479 $insertStatments = array (
480 'Donation' => "('Donation', 0, 1, 1)",
481 'Member' => "('Member Dues', 0, 1, 1)",
482 'Event Fee' => "('Event Fee', 0, 1, 0)",
484 foreach ($insertStatments as $values) {
486 INSERT INTO civicrm_contribution_type (name, is_reserved, is_active, is_deductible)
488 ON DUPLICATE KEY UPDATE is_active = 1
490 CRM_Core_DAO
::executeQuery($query);
493 return $modifiedDefaults;
499 public function createFinancialRecords() {
500 $upgrade = new CRM_Upgrade_Form();
502 // update civicrm_entity_financial_trxn.amount = civicrm_financial_trxn.total_amount
504 UPDATE civicrm_entity_financial_trxn ceft
505 LEFT JOIN civicrm_financial_trxn cft ON cft.id = ceft.financial_trxn_id
506 SET ceft.amount = total_amount
507 WHERE cft.net_amount IS NOT NULL
508 AND ceft.entity_table = 'civicrm_contribution'
510 CRM_Core_DAO
::executeQuery($query);
512 $contributionStatus = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
513 $completedStatus = array_search('Completed', $contributionStatus);
514 $pendingStatus = array_search('Pending', $contributionStatus);
515 $cancelledStatus = array_search('Cancelled', $contributionStatus);
516 $queryParams = array(
517 1 => array($completedStatus, 'Integer'),
518 2 => array($pendingStatus, 'Integer'),
519 3 => array($cancelledStatus, 'Integer')
522 $accountType = key(CRM_Core_PseudoConstant
::accountOptionValues('financial_account_type', NULL, " AND v.name = 'Asset' "));
525 FROM civicrm_financial_account
527 AND financial_account_type_id = {$accountType}
529 $financialAccountId = CRM_Core_DAO
::singleValueQuery($query);
531 $accountRelationsips = CRM_Core_PseudoConstant
::get('CRM_Financial_DAO_EntityFinancialAccount',
532 'account_relationship', CRM_Core_DAO
::$_nullArray, 'validate');
534 $accountsReceivableAccount = array_search('Accounts Receivable Account is', $accountRelationsips);
535 $incomeAccountIs = array_search('Income Account is', $accountRelationsips);
536 $assetAccountIs = array_search('Asset Account is', $accountRelationsips);
537 $expenseAccountIs = array_search('Expense Account is', $accountRelationsips);
539 $financialItemStatus = CRM_Core_PseudoConstant
::get('CRM_Financial_DAO_FinancialItem', 'status_id',
540 CRM_Core_DAO
::$_nullArray, 'validate');
541 $unpaidStatus = array_search('Unpaid', $financialItemStatus);
542 $paidStatus = array_search('Paid', $financialItemStatus);
544 $validCurrencyCodes = CRM_Core_PseudoConstant
::currencyCode();
545 $validCurrencyCodes = implode("','", $validCurrencyCodes);
546 $config = CRM_Core_Config
::singleton();
547 $defaultCurrency = $config->defaultCurrency
;
548 $now = date( 'YmdHis' );
550 //adding financial_trxn records and entity_financial_trxn records related to contribution
551 //Add temp column for easy entry in entity_financial_trxn
552 $sql = "ALTER TABLE civicrm_financial_trxn ADD COLUMN contribution_id INT DEFAULT NULL";
553 CRM_Core_DAO
::executeQuery($sql);
555 //pending pay later status handling
557 INSERT INTO civicrm_financial_trxn
558 (contribution_id, payment_instrument_id, currency, total_amount, net_amount, fee_amount, trxn_id, status_id,
559 check_number, to_financial_account_id, from_financial_account_id, trxn_date)
560 SELECT con.id as contribution_id, con.payment_instrument_id,
561 IF(con.currency IN ('{$validCurrencyCodes}'), con.currency, '{$defaultCurrency}') as currency,
562 con.total_amount, con.net_amount, con.fee_amount, con.trxn_id, con.contribution_status_id,
563 con.check_number, efa.financial_account_id as to_financial_account_id, NULL as from_financial_account_id,
564 REPLACE(REPLACE(REPLACE(
566 WHEN con.receive_date IS NOT NULL THEN
568 WHEN con.receipt_date IS NOT NULL THEN
573 , '-', ''), ':', ''), ' ', '') as trxn_date
574 FROM civicrm_contribution con
575 LEFT JOIN civicrm_entity_financial_account efa
576 ON (con.financial_type_id = efa.entity_id AND efa.entity_table = 'civicrm_financial_type'
577 AND efa.account_relationship = {$accountsReceivableAccount})
578 WHERE con.is_pay_later = 1
579 AND con.contribution_status_id = {$pendingStatus}
581 CRM_Core_DAO
::executeQuery($sql);
583 //create a temp table to hold financial account id related to payment instruments
584 $tempTableName1 = CRM_Core_DAO
::createTempTableName();
587 CREATE TEMPORARY TABLE {$tempTableName1}
588 SELECT ceft.financial_account_id financial_account_id, cov.value as instrument_id
589 FROM civicrm_entity_financial_account ceft
590 INNER JOIN civicrm_option_value cov ON cov.id = ceft.entity_id AND ceft.entity_table = 'civicrm_option_value'
591 INNER JOIN civicrm_option_group cog ON cog.id = cov.option_group_id
592 WHERE cog.name = 'payment_instrument'
594 CRM_Core_DAO
::executeQuery($sql);
597 $sql = "ALTER TABLE {$tempTableName1} ADD INDEX index_instrument_id (instrument_id(200));";
598 CRM_Core_DAO
::executeQuery($sql);
600 //create temp table to process completed / cancelled contribution
601 $tempTableName2 = CRM_Core_DAO
::createTempTableName();
603 CREATE TEMPORARY TABLE {$tempTableName2}
604 SELECT con.id as contribution_id, con.payment_instrument_id,
605 IF(con.currency IN ('{$validCurrencyCodes}'), con.currency, '{$defaultCurrency}') as currency,
606 con.total_amount, con.net_amount, con.fee_amount, con.trxn_id, con.contribution_status_id,
607 con.check_number, NULL as from_financial_account_id,
608 REPLACE(REPLACE(REPLACE(
610 WHEN con.receive_date IS NOT NULL THEN
612 WHEN con.receipt_date IS NOT NULL THEN
617 , '-', ''), ':', ''), ' ', '') as trxn_date,
619 WHEN con.payment_instrument_id IS NULL THEN
620 {$financialAccountId}
621 WHEN con.payment_instrument_id IS NOT NULL THEN
622 tpi.financial_account_id
623 END as to_financial_account_id,
624 IF(eft.financial_trxn_id IS NULL, 'insert', eft.financial_trxn_id) as action
625 FROM civicrm_contribution con
626 LEFT JOIN civicrm_entity_financial_trxn eft
627 ON (eft.entity_table = 'civicrm_contribution' AND eft.entity_id = con.id)
628 LEFT JOIN {$tempTableName1} tpi
629 ON con.payment_instrument_id = tpi.instrument_id
630 WHERE con.contribution_status_id IN ({$completedStatus}, {$cancelledStatus})
632 CRM_Core_DAO
::executeQuery($sql);
635 $sql = "ALTER TABLE {$tempTableName2} ADD INDEX index_action (action);";
636 CRM_Core_DAO
::executeQuery($sql);
638 //handling for completed contribution and cancelled contribution
639 //insertion of new records
641 INSERT INTO civicrm_financial_trxn
642 (contribution_id, payment_instrument_id, currency, total_amount, net_amount, fee_amount, trxn_id, status_id, check_number,
643 to_financial_account_id, from_financial_account_id, trxn_date)
644 SELECT tempI.contribution_id, tempI.payment_instrument_id, tempI.currency, tempI.total_amount, tempI.net_amount,
645 tempI.fee_amount, tempI.trxn_id, tempI.contribution_status_id, tempI.check_number,
646 tempI.to_financial_account_id, tempI.from_financial_account_id, tempI.trxn_date
647 FROM {$tempTableName2} tempI
648 WHERE tempI.action = 'insert'
650 CRM_Core_DAO
::executeQuery($sql);
652 //update of existing records
654 UPDATE civicrm_financial_trxn ft
655 INNER JOIN {$tempTableName2} tempU
656 ON (tempU.action != 'insert' AND ft.id = tempU.action)
657 SET ft.from_financial_account_id = NULL,
658 ft.to_financial_account_id = tempU.to_financial_account_id,
659 ft.status_id = tempU.contribution_status_id,
660 ft.payment_instrument_id = tempU.payment_instrument_id,
661 ft.check_number = tempU.check_number,
662 ft.contribution_id = tempU.contribution_id;";
663 CRM_Core_DAO
::executeQuery($sql);
665 //insert the -ve transaction rows for cancelled contributions
667 INSERT INTO civicrm_financial_trxn
668 (contribution_id, payment_instrument_id, currency, total_amount, net_amount, fee_amount, trxn_id, status_id,
669 check_number, to_financial_account_id, from_financial_account_id, trxn_date)
670 SELECT ft.contribution_id, ft.payment_instrument_id, ft.currency, -ft.total_amount, ft.net_amount, ft.fee_amount, ft.trxn_id,
671 ft.status_id, ft.check_number, ft.to_financial_account_id, ft.from_financial_account_id, ft.trxn_date
672 FROM civicrm_financial_trxn ft
673 WHERE ft.status_id = {$cancelledStatus};";
674 CRM_Core_DAO
::executeQuery($sql);
676 //inserting entity financial trxn entries if its not present in entity_financial_trxn for completed and pending contribution statuses
677 //this also handles +ve and -ve both transaction entries for a cancelled contribution
679 INSERT INTO civicrm_entity_financial_trxn (entity_table, entity_id, financial_trxn_id, amount)
680 SELECT 'civicrm_contribution', ft.contribution_id, ft.id, ft.total_amount as amount
681 FROM civicrm_financial_trxn ft
682 WHERE contribution_id IS NOT NULL AND
683 ft.id NOT IN (SELECT financial_trxn_id
684 FROM civicrm_entity_financial_trxn
685 WHERE entity_table = 'civicrm_contribution'
686 AND entity_id = ft.contribution_id)";
687 CRM_Core_DAO
::executeQuery($sql);
688 //end of adding financial_trxn records and entity_financial_trxn records related to contribution
690 //update all linked line_item rows
691 // set line_item.financial_type_id = contribution.financial_type_id if contribution page id is null and not participant line item
692 // set line_item.financial_type_id = price_field_value.financial_type_id if contribution page id is set and not participant line item
693 // set line_item.financial_type_id = event.financial_type_id if its participant line item and line_item.price_field_value_id is null
694 // 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
695 $updateLineItemSql = "
696 UPDATE civicrm_line_item li
697 LEFT JOIN civicrm_contribution con
698 ON (li.entity_id = con.id AND li.entity_table = 'civicrm_contribution')
699 LEFT JOIN civicrm_price_field_value cpfv
700 ON li.price_field_value_id = cpfv.id
701 LEFT JOIN civicrm_participant cp
702 ON (li.entity_id = cp.id AND li.entity_table = 'civicrm_participant')
703 LEFT JOIN civicrm_event ce
704 ON ce.id = cp.event_id
705 SET li.financial_type_id = CASE
706 WHEN (con.contribution_page_id IS NULL || li.price_field_value_id IS NULL) AND cp.id IS NULL THEN
707 con.financial_type_id
708 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
709 cpfv.financial_type_id
710 WHEN cp.id IS NOT NULL AND li.price_field_value_id IS NULL THEN
713 CRM_Core_DAO
::executeQuery($updateLineItemSql, $queryParams);
715 //add the financial_item entries
716 //add a temp column so that inserting entity_financial_trxn entries gets easy
717 $sql = "ALTER TABLE civicrm_financial_item ADD COLUMN f_trxn_id INT DEFAULT NULL";
718 CRM_Core_DAO
::executeQuery($sql);
720 //add financial_item entries for contribution completed / pending pay later / cancelled
721 $contributionlineItemSql = "
722 INSERT INTO civicrm_financial_item
723 (transaction_date, contact_id, amount, currency, entity_table, entity_id, description, status_id, financial_account_id, f_trxn_id)
725 SELECT REPLACE(REPLACE(REPLACE(ft.trxn_date, '-', ''), ':', ''), ' ', ''), con.contact_id,
726 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',
727 li.id as line_item_id, li.label as line_item_label,
728 IF(con.contribution_status_id = {$pendingStatus}, {$unpaidStatus}, {$paidStatus}) as status_id, efa.financial_account_id as financial_account_id,
730 FROM civicrm_line_item li
731 INNER JOIN civicrm_contribution con
732 ON (li.entity_id = con.id AND li.entity_table = 'civicrm_contribution')
733 INNER JOIN civicrm_financial_trxn ft
734 ON (con.id = ft.contribution_id)
735 LEFT JOIN civicrm_entity_financial_account efa
736 ON (li.financial_type_id = efa.entity_id AND efa.entity_table = 'civicrm_financial_type'
737 AND efa.account_relationship = {$incomeAccountIs})
738 WHERE con.contribution_status_id IN (%1, %3) OR (con.is_pay_later = 1 AND con.contribution_status_id = %2)";
739 CRM_Core_DAO
::executeQuery($contributionlineItemSql, $queryParams);
741 //add financial_item entries for event
742 $participantLineItemSql = "
743 INSERT INTO civicrm_financial_item
744 (transaction_date, contact_id, amount, currency, entity_table, entity_id, description, status_id, financial_account_id, f_trxn_id)
746 SELECT REPLACE(REPLACE(REPLACE(ft.trxn_date, '-', ''), ':', ''), ' ', ''), con.contact_id,
747 IF(ft.total_amount < 0 AND con.contribution_status_id = %3, -li.line_total, li.line_total) as line_total,
748 con.currency, 'civicrm_line_item', li.id as line_item_id, li.label as line_item_label,
749 IF(con.contribution_status_id = {$pendingStatus}, {$unpaidStatus}, {$paidStatus}) as status_id,
750 efa.financial_account_id as financial_account_id, ft.id as f_trxn_id
751 FROM civicrm_line_item li
752 INNER JOIN civicrm_participant par
753 ON (li.entity_id = par.id AND li.entity_table = 'civicrm_participant')
754 INNER JOIN civicrm_participant_payment pp
755 ON (pp.participant_id = par.id)
756 INNER JOIN civicrm_contribution con
757 ON (pp.contribution_id = con.id)
758 INNER JOIN civicrm_financial_trxn ft
759 ON (con.id = ft.contribution_id)
760 LEFT JOIN civicrm_entity_financial_account efa
761 ON (li.financial_type_id = efa.entity_id AND
762 efa.entity_table = 'civicrm_financial_type' AND efa.account_relationship = {$incomeAccountIs})
763 WHERE con.contribution_status_id IN (%1, %3) OR (con.is_pay_later = 1 AND con.contribution_status_id = %2)";
764 CRM_Core_DAO
::executeQuery($participantLineItemSql, $queryParams);
766 //fee handling for contributions
767 //insert fee entries in financial_trxn for contributions
768 $sql = "ALTER TABLE civicrm_financial_trxn ADD COLUMN is_fee TINYINT DEFAULT NULL";
769 CRM_Core_DAO
::executeQuery($sql);
772 INSERT INTO civicrm_financial_trxn
773 (contribution_id, payment_instrument_id, currency, total_amount, net_amount, fee_amount, trxn_id, status_id, check_number,
774 to_financial_account_id, from_financial_account_id, trxn_date, payment_processor_id, is_fee)
776 SELECT con.id, ft.payment_instrument_id, ft.currency, ft.fee_amount, NULL, NULL, ft.trxn_id, %1 as status_id,
777 ft.check_number, efaFT.financial_account_id as to_financial_account_id, CASE
778 WHEN efaPP.financial_account_id IS NOT NULL THEN
779 efaPP.financial_account_id
780 WHEN tpi.financial_account_id IS NOT NULL THEN
781 tpi.financial_account_id
783 {$financialAccountId}
784 END as from_financial_account_id, ft.trxn_date, ft.payment_processor_id, 1 as is_fee
785 FROM civicrm_contribution con
786 INNER JOIN civicrm_financial_trxn ft
787 ON (ft.contribution_id = con.id)
788 LEFT JOIN civicrm_entity_financial_account efaFT
789 ON (con.financial_type_id = efaFT.entity_id AND efaFT.entity_table = 'civicrm_financial_type'
790 AND efaFT.account_relationship = {$expenseAccountIs})
791 LEFT JOIN civicrm_entity_financial_account efaPP
792 ON (ft.payment_processor_id = efaPP.entity_id AND efaPP.entity_table = 'civicrm_payment_processor'
793 AND efaPP.account_relationship = {$assetAccountIs})
794 LEFT JOIN {$tempTableName1} tpi
795 ON ft.payment_instrument_id = tpi.instrument_id
796 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))
798 CRM_Core_DAO
::executeQuery($sql, $queryParams);
800 //link financial_trxn to contribution
802 INSERT INTO civicrm_entity_financial_trxn
803 (entity_table, entity_id, financial_trxn_id, amount)
804 SELECT 'civicrm_contribution', ft.contribution_id, ft.id, ft.total_amount
805 FROM civicrm_financial_trxn ft
806 WHERE ft.is_fee = 1";
807 CRM_Core_DAO
::executeQuery($sql);
809 //add fee related entries to financial item table
810 $domainId = CRM_Core_Config
::domainID();
811 $domainContactId = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_Domain', $domainId, 'contact_id');
813 INSERT INTO civicrm_financial_item
814 (transaction_date, contact_id, amount, currency, entity_table, entity_id, description, status_id, financial_account_id, f_trxn_id)
815 SELECT ft.trxn_date, {$domainContactId} as contact_id, ft.total_amount, ft.currency, 'civicrm_financial_trxn', ft.id,
816 'Fee', {$paidStatus} as status_id, ft.to_financial_account_id as financial_account_id, ft.id as f_trxn_id
817 FROM civicrm_financial_trxn ft
818 WHERE ft.is_fee = 1;";
819 CRM_Core_DAO
::executeQuery($sql);
821 //add entries to entity_financial_trxn table
823 INSERT INTO civicrm_entity_financial_trxn (entity_table, entity_id, financial_trxn_id, amount)
824 SELECT 'civicrm_financial_item' as entity_table, fi.id as entity_id, fi.f_trxn_id as financial_trxn_id, fi.amount
825 FROM civicrm_financial_item fi";
826 CRM_Core_DAO
::executeQuery($sql);
828 //drop the temparory columns
829 $sql = "ALTER TABLE civicrm_financial_trxn
830 DROP COLUMN contribution_id,
831 DROP COLUMN is_fee;";
832 CRM_Core_DAO
::executeQuery($sql);
834 $sql = "ALTER TABLE civicrm_financial_item DROP f_trxn_id";
835 CRM_Core_DAO
::executeQuery($sql);
843 public function createDomainContacts() {
844 $domainParams = $context = array();
846 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',
847 ADD CONSTRAINT FK_civicrm_domain_contact_id FOREIGN KEY (contact_id) REFERENCES civicrm_contact(id);";
848 CRM_Core_DAO
::executeQuery($query, CRM_Core_DAO
::$_nullArray, TRUE, NULL, FALSE, FALSE);
851 SELECT cd.id, cd.name, ce.email FROM civicrm_domain cd
852 LEFT JOIN civicrm_loc_block clb ON clb.id = cd. loc_block_id
853 LEFT JOIN civicrm_email ce ON ce.id = clb.email_id ;
855 $dao = CRM_Core_DAO
::executeQuery($query);
856 while($dao->fetch()) {
858 SELECT cc.id FROM civicrm_contact cc
859 LEFT JOIN civicrm_email ce ON ce.contact_id = cc.id
860 WHERE cc.contact_type = 'Organization' AND cc.organization_name = %1
862 $params = array(1 => array($dao->name
, 'String'));
864 $query .= " AND ce.email = %2 ";
865 $params[2] = array($dao->email
, 'String');
867 $contactID = CRM_Core_DAO
::singleValueQuery($query, $params);
868 $context[1] = $dao->name
;
869 if (empty($contactID)) {
871 'sort_name' => $dao->name
,
872 'display_name' => $dao->name
,
873 'legal_name' => $dao->name
,
874 'organization_name' => $dao->name
,
875 'contact_type' => 'Organization'
877 $contact = CRM_Contact_BAO_Contact
::add($params);
878 $contactID = $contact->id
;
879 $context[0] = 'added';
882 $context[0] = 'merged';
884 $domainParams['contact_id'] = $contactID;
885 CRM_Core_BAO_Domain
::edit($domainParams, $dao->id
);
890 public function task_4_3_alpha1_checkDBConstraints() {
891 //checking whether the foreign key exists before dropping it CRM-11260
892 $config = CRM_Core_Config
::singleton();
893 $dbUf = DB
::parseDSN($config->dsn
);
895 'autorenewal_msg_id' => array('tableName' => 'civicrm_membership_type', 'fkey' => 'FK_civicrm_membership_autorenewal_msg_id'),
896 'to_account_id' => array('tableName' => 'civicrm_financial_trxn', 'constraintName' => 'civicrm_financial_trxn_ibfk_2'),
897 'from_account_id' => array('tableName' => 'civicrm_financial_trxn', 'constraintName' => 'civicrm_financial_trxn_ibfk_1'),
898 'contribution_type_id' => array('tableName' => 'civicrm_contribution_recur', 'fkey' => 'FK_civicrm_contribution_recur_contribution_type_id'),
901 SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
902 WHERE table_name = 'civicrm_contribution_recur'
903 AND constraint_name = 'FK_civicrm_contribution_recur_contribution_type_id'
904 AND TABLE_SCHEMA = %1
906 $params = array(1 => array($dbUf['database'], 'String'));
907 $dao = CRM_Core_DAO
::executeQuery($query, $params, TRUE, NULL, FALSE, FALSE);
908 foreach($tables as $columnName => $value){
909 if ($value['tableName'] == 'civicrm_membership_type' ||
$value['tableName'] == 'civicrm_contribution_recur') {
910 $foreignKeyExists = CRM_Core_DAO
::checkConstraintExists($value['tableName'], $value['fkey']);
911 $fKey = $value['fkey'];
913 $foreignKeyExists = CRM_Core_DAO
::checkFKConstraintInFormat($value['tableName'], $columnName);
914 $fKey = "`FK_{$value['tableName']}_{$columnName}`";
916 if ($foreignKeyExists ||
$value['tableName'] == 'civicrm_financial_trxn') {
917 if ($value['tableName'] != 'civicrm_contribution_recur' ||
($value['tableName'] == 'civicrm_contribution_recur' && $dao->N
)) {
918 $constraintName = $foreignKeyExists ?
$fKey : $value['constraintName'];
919 $query = "ALTER TABLE {$value['tableName']} DROP FOREIGN KEY {$constraintName}";
920 CRM_Core_DAO
::executeQuery($query, $params, TRUE, NULL, FALSE, FALSE);
922 $query = "ALTER TABLE {$value['tableName']} DROP INDEX {$fKey}";
923 CRM_Core_DAO
::executeQuery($query, $params, TRUE, NULL, FALSE, FALSE);
926 // check if column contact_id is present or not in civicrm_financial_account
927 $fieldExists = CRM_Core_DAO
::checkFieldExists('civicrm_financial_account', 'contact_id', FALSE);
930 ALTER TABLE civicrm_financial_account
931 ADD contact_id int(10) unsigned DEFAULT NULL COMMENT 'Version identifier of financial_type' AFTER name,
932 ADD CONSTRAINT FK_civicrm_financial_account_contact_id FOREIGN KEY (contact_id) REFERENCES civicrm_contact(id);
934 CRM_Core_DAO
::executeQuery($query, $params, TRUE, NULL, FALSE, FALSE);
939 * Read creation and modification times from civicrm_log; add
940 * them to civicrm_contact.
942 public function convertTimestamps(CRM_Queue_TaskContext
$ctx, $startId, $endId) {
944 SELECT entity_id, min(modified_date) AS created, max(modified_date) AS modified
946 WHERE entity_table = 'civicrm_contact'
947 AND entity_id BETWEEN %1 AND %2
951 1 => array($startId, 'Integer'),
952 2 => array($endId, 'Integer'),
954 $dao = CRM_Core_DAO
::executeQuery($sql, $params);
955 while ($dao->fetch()) {
956 // FIXME civicrm_log.modified_date is DATETIME; civicrm_contact.modified_date is TIMESTAMP
957 CRM_Core_DAO
::executeQuery(
958 'UPDATE civicrm_contact SET created_date = FROM_UNIXTIME(UNIX_TIMESTAMP(%1)), modified_date = FROM_UNIXTIME(UNIX_TIMESTAMP(%2)) WHERE id = %3',
960 1 => array($dao->created
, 'String'),
961 2 => array($dao->modified
, 'String'),
962 3 => array($dao->entity_id
, 'Integer'),
971 * Change index and add missing constraints for civicrm_contribution_recur
973 public function addMissingConstraints(CRM_Queue_TaskContext
$ctx) {
974 $query = "SHOW KEYS FROM `civicrm_contribution_recur` WHERE key_name = 'UI_contrib_payment_instrument_id'";
975 $dao = CRM_Core_DAO
::executeQuery($query);
977 CRM_Core_DAO
::executeQuery('ALTER TABLE civicrm_contribution_recur DROP INDEX UI_contrib_payment_instrument_id');
978 CRM_Core_DAO
::executeQuery('ALTER TABLE civicrm_contribution_recur ADD INDEX UI_contribution_recur_payment_instrument_id (payment_instrument_id)');
980 $constraintArray = array(
981 'contact_id' => " ADD CONSTRAINT `FK_civicrm_contribution_recur_contact_id` FOREIGN KEY (`contact_id`) REFERENCES `civicrm_contact` (`id`) ON DELETE CASCADE ",
982 '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 ",
983 '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 ",
984 'campaign_id' => " ADD CONSTRAINT `FK_civicrm_contribution_recur_campaign_id` FOREIGN KEY (`campaign_id`) REFERENCES `civicrm_campaign` (`id`) ON DELETE SET NULL ",
986 $constraint = array();
987 foreach ($constraintArray as $constraintKey => $value) {
988 $foreignKeyExists = CRM_Core_DAO
::checkFKConstraintInFormat('civicrm_contribution_recur', $constraintKey);
989 if (!$foreignKeyExists) {
990 $constraint[] = $value;
993 if (!empty($constraint)) {
994 $query = "ALTER TABLE civicrm_contribution_recur " . implode(' , ', $constraint);
995 CRM_Core_DAO
::executeQuery($query);
1001 * Update financial_account_id for bad data in financial_trxn table
1005 public function updateFinancialTrxnData(CRM_Queue_TaskContext
$ctx) {
1006 $upgrade = new CRM_Upgrade_Form();
1007 $sql = "SELECT cc.id contribution_id, cc.contribution_recur_id, cft.payment_processor_id,
1008 cft.id financial_trxn_id, cfi.entity_table, cft.from_financial_account_id, cft.to_financial_account_id
1010 FROM `civicrm_contribution` cc
1011 LEFT JOIN civicrm_entity_financial_trxn ceft ON ceft.entity_id = cc.id
1012 LEFT JOIN civicrm_financial_trxn cft ON cft.id = ceft.financial_trxn_id
1013 LEFT JOIN civicrm_entity_financial_trxn ceft1 ON ceft1.financial_trxn_id = ceft.financial_trxn_id
1014 LEFT JOIN civicrm_financial_item cfi ON cfi.id = ceft1.entity_id
1015 WHERE ceft.entity_table = 'civicrm_contribution' AND cc.contribution_recur_id IS NOT NULL
1016 AND ceft1.entity_table = 'civicrm_financial_item' AND cft.id IS NOT NULL AND cft.payment_instrument_id = %1
1019 $paymentInstrument = CRM_Contribute_PseudoConstant
::paymentInstrument('name');
1020 $param = array(1 => array(array_search('Credit Card', $paymentInstrument), 'Integer'));
1021 $dao = CRM_Core_DAO
::executeQuery($sql, $param);
1022 $financialTrxn = array();
1023 $subsequentPayments = array();
1024 while ($dao->fetch()) {
1025 if (!array_key_exists($dao->contribution_recur_id
, $financialTrxn)) {
1026 $financialTrxn[$dao->contribution_recur_id
] = array(
1027 'from_financial_account_id' => $dao->to_financial_account_id
,
1028 'payment_processor_id' => $dao->payment_processor_id
,
1029 $dao->contribution_id
=> 1,
1031 if (!is_null($dao->from_financial_account_id
)) {
1032 $sql = 'UPDATE civicrm_financial_trxn SET from_financial_account_id = NULL WHERE id = %1';
1033 $params = array(1 => array($dao->financial_trxn_id
, 'Integer'));
1034 CRM_Core_DAO
::executeQuery($sql, $params);
1037 elseif (!array_key_exists($dao->contribution_id
, $financialTrxn[$dao->contribution_recur_id
])) {
1038 if (($dao->entity_table
== 'civicrm_line_item' && $dao->to_financial_account_id
== $financialTrxn[$dao->contribution_recur_id
]['from_financial_account_id'])
1039 ||
($dao->entity_table
== 'civicrm_financial_trxn' && $dao->from_financial_account_id
== $financialTrxn[$dao->contribution_recur_id
]['from_financial_account_id'])) {
1042 $subsequentPayments[$dao->contribution_recur_id
][$dao->entity_table
][] = $dao->financial_trxn_id
;
1045 foreach ($subsequentPayments as $key => $value) {
1046 foreach ($value as $table => $val) {
1047 if ($table == 'civicrm_financial_trxn') {
1048 $field = 'from_financial_account_id';
1051 $field = 'to_financial_account_id';
1053 $sql = "UPDATE civicrm_financial_trxn SET $field = " . $financialTrxn[$dao->contribution_recur_id
]['from_financial_account_id'] . ',
1054 payment_processor_id = ' . $financialTrxn[$dao->contribution_recur_id
]['payment_processor_id'] . ' WHERE
1055 id IN (' . implode(',', $val) . ')';
1056 CRM_Core_DAO
::executeQuery($sql);
1063 * Update financial_account_id for bad data in financial_trxn table
1067 public function updateLineItemData(CRM_Queue_TaskContext
$ctx) {
1068 $sql = "SELECT cc.id contribution_id, cc.contribution_recur_id,
1069 cc.financial_type_id contribution_financial_type,
1070 cli.financial_type_id line_financial_type_id,
1071 cli.price_field_id, cli.price_field_value_id, cli.label, cli.id line_item_id,
1072 cfi.financial_account_id
1073 FROM `civicrm_line_item` cli
1074 LEFT JOIN civicrm_contribution cc ON cc.id = cli.entity_id
1075 LEFT JOIN civicrm_financial_item cfi ON cfi.entity_id = cli.id
1076 LEFT JOIN civicrm_price_field cpf ON cpf.id = cli.price_field_id
1077 LEFT JOIN civicrm_price_set cps ON cps.id = cpf.price_set_id
1078 LEFT JOIN civicrm_price_field_value cpfv ON cpfv.id = cli.price_field_value_id
1079 WHERE cfi.entity_table = 'civicrm_line_item'
1080 AND cli.entity_table = 'civicrm_contribution'
1081 AND cps.is_quick_config = 1 AND cc.contribution_recur_id IS NOT NULL
1083 $dao = CRM_Core_DAO
::executeQuery($sql);
1084 $financialTrxn = $subsequentPayments = array();
1085 while ($dao->fetch()) {
1086 if (!array_key_exists($dao->contribution_recur_id
, $financialTrxn)) {
1087 $financialTrxn[$dao->contribution_recur_id
] = array(
1088 'price_field_id' => $dao->price_field_id
,
1089 'price_field_value_id' => $dao->price_field_value_id
,
1090 'label' => strval($dao->label
),
1091 'financial_account_id' => $dao->financial_account_id
,
1092 $dao->contribution_id
=> 1,
1096 if ($dao->price_field_value_id
== $financialTrxn[$dao->contribution_recur_id
]['price_field_value_id']) {
1099 $subsequentPayments[$dao->contribution_recur_id
][] = $dao->line_item_id
;
1102 foreach ($subsequentPayments as $key => $value) {
1103 $sql = "UPDATE civicrm_line_item cli
1104 LEFT JOIN civicrm_financial_item cfi ON cli.id = cfi.entity_id
1107 cli.price_field_id = %2,
1108 cli.price_field_value_id = %3,
1109 cfi.financial_account_id = %4,
1110 cfi.description = %5,
1111 cli.financial_type_id = %6
1112 WHERE cfi.entity_table = 'civicrm_line_item'
1113 AND cli.entity_table = 'civicrm_contribution' AND cli.id IN (" . implode(',', $value). ');';
1115 1 => array($financialTrxn[$key]['label'], 'String'),
1116 2 => array($financialTrxn[$key]['price_field_id'], 'Integer'),
1117 3 => array($financialTrxn[$key]['price_field_value_id'], 'Integer'),
1118 4 => array($financialTrxn[$key]['financial_account_id'], 'Integer'),
1119 5 => array($financialTrxn[$key]['label'], 'String'),
1120 6 => array($dao->contribution_financial_type
, 'Integer'),
1122 CRM_Core_DAO
::executeQuery($sql, $params);
1128 * Replace contribution_type to financial_type in table
1129 * civicrm_saved_search and Structure civicrm_report_instance
1131 public function replaceContributionTypeId(CRM_Queue_TaskContext
$ctx, $query, $table) {
1132 $dao = CRM_Core_DAO
::executeQuery($query);
1133 while ($dao->fetch()) {
1134 $formValues = unserialize($dao->form_values
);
1135 foreach (array('contribution_type_id_op', 'contribution_type_id_value', 'contribution_type_id') as $value) {
1136 if (array_key_exists($value, $formValues)) {
1137 $key = preg_replace('/contribution/', 'financial', $value);
1138 $formValues[$key] = $formValues[$value];
1139 unset($formValues[$value]);
1142 if ($table != 'savedSearch') {
1143 foreach (array('fields', 'group_bys') as $value) {
1144 if (array_key_exists($value, $formValues)) {
1145 if (array_key_exists('contribution_type_id', $formValues[$value])) {
1146 $formValues[$value]['financial_type_id'] = $formValues[$value]['contribution_type_id'];
1147 unset($formValues[$value]['contribution_type_id']);
1149 else if (array_key_exists('contribution_type', $formValues[$value])) {
1150 $formValues[$value]['financial_type'] = $formValues[$value]['contribution_type'];
1151 unset($formValues[$value]['contribution_type']);
1155 if (array_key_exists('order_bys', $formValues)) {
1156 foreach ($formValues['order_bys'] as $key => $values) {
1157 if (preg_grep('/contribution_type/', $values)) {
1158 $formValues['order_bys'][$key]['column'] = preg_replace('/contribution_type/', 'financial_type', $values['column']);
1164 if ($table == 'savedSearch') {
1165 $saveDao = new CRM_Contact_DAO_SavedSearch();
1168 $saveDao = new CRM_Report_DAO_ReportInstance();
1170 $saveDao->id
= $dao->id
;
1172 if ($table == 'savedSearch') {
1173 if (array_key_exists('mapper', $formValues)) {
1174 foreach ($formValues['mapper'] as $key => $values) {
1175 foreach ($values as $k => $v) {
1176 if (preg_grep('/contribution_/', $v)) {
1177 $formValues['mapper'][$key][$k] = preg_replace('/contribution_type/', 'financial_type', $v);
1182 foreach (array('select_tables', 'where_tables') as $value) {
1183 if (preg_match('/contribution_type/', $dao->$value)) {
1184 $tempValue = unserialize($dao->$value);
1185 if (array_key_exists('civicrm_contribution_type', $tempValue)) {
1186 $tempValue['civicrm_financial_type'] = $tempValue['civicrm_contribution_type'];
1187 unset($tempValue['civicrm_contribution_type']);
1189 $saveDao->$value = serialize($tempValue);
1192 if (preg_match('/contribution_type/', $dao->where_clause
)) {
1193 $saveDao->where_clause
= preg_replace('/contribution_type/', 'financial_type', $dao->where_clause
);
1196 $saveDao->form_values
= serialize($formValues);
1204 * Add ON DELETE options for constraint if not present
1205 * CRM-13088 && CRM-12156
1207 * @param CRM_Queue_TaskContext $ctx
1209 * @return bool TRUE for success
1211 public function task_4_3_x_checkConstraints(CRM_Queue_TaskContext
$ctx) {
1212 CRM_Core_DAO
::executeQuery('ALTER TABLE `civicrm_financial_account` CHANGE `contact_id` `contact_id` INT( 10 ) UNSIGNED NULL DEFAULT NULL');
1213 $config = CRM_Core_Config
::singleton();
1214 $dbname = DB
::parseDSN($config->dsn
);
1215 $constraintArray = array(
1216 "'FK_civicrm_financial_account_contact_id'",
1217 "'FK_civicrm_financial_item_contact_id'",
1218 "'FK_civicrm_contribution_recur_financial_type_id'",
1219 "'FK_civicrm_line_item_financial_type_id'",
1220 "'FK_civicrm_product_financial_type_id'",
1221 "'FK_civicrm_premiums_product_financial_type_id'",
1222 "'FK_civicrm_price_field_value_financial_type_id'",
1223 "'FK_civicrm_contribution_product_financial_type_id'",
1224 "'FK_civicrm_price_set_financial_type_id'",
1225 "'FK_civicrm_grant_financial_type_id'",
1228 $sql = "SELECT DELETE_RULE, TABLE_NAME, CONSTRAINT_NAME
1229 FROM information_schema.REFERENTIAL_CONSTRAINTS
1230 WHERE CONSTRAINT_NAME IN (" . implode(',', $constraintArray) . ")
1231 AND CONSTRAINT_SCHEMA = %1";
1232 $params = array(1 => array($dbname['database'], 'String'));
1233 $onDelete = CRM_Core_DAO
::executeQuery($sql, $params, TRUE, FALSE);
1234 while ($onDelete->fetch()) {
1235 if (($onDelete->TABLE_NAME
!= 'civicrm_financial_item' && $onDelete->DELETE_RULE
!= 'SET NULL') ||
1236 ($onDelete->TABLE_NAME
== 'civicrm_financial_item' && $onDelete->DELETE_RULE
!= 'CASCADE')) {
1237 $tableName = 'civicrm_financial_type';
1238 $onDeleteOption = ' SET NULL ';
1239 $columnName = 'financial_type_id';
1240 if (preg_match('/contact_id/', $onDelete->CONSTRAINT_NAME
)) {
1241 $tableName = 'civicrm_contact';
1242 $columnName = 'contact_id';
1243 if ($onDelete->TABLE_NAME
== 'civicrm_financial_item') {
1244 $onDeleteOption = 'CASCADE';
1251 $query = "ALTER TABLE {$onDelete->TABLE_NAME}
1252 DROP FOREIGN KEY {$onDelete->CONSTRAINT_NAME},
1253 DROP INDEX {$onDelete->CONSTRAINT_NAME};";
1254 CRM_Core_DAO
::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
1255 $query = " ALTER TABLE {$onDelete->TABLE_NAME}
1256 ADD CONSTRAINT {$onDelete->CONSTRAINT_NAME} FOREIGN KEY (`" . $columnName . "`) REFERENCES {$tableName} (`id`) ON DELETE {$onDeleteOption};
1258 CRM_Core_DAO
::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
1264 * Check/Add INDEX CRM-12141
1266 * @param CRM_Queue_TaskContext $ctx
1268 * @return bool TRUE for success
1270 public function task_4_3_x_checkIndexes(CRM_Queue_TaskContext
$ctx) {
1273 FROM civicrm_entity_financial_trxn
1274 WHERE key_name IN ('UI_entity_financial_trxn_entity_table', 'UI_entity_financial_trxn_entity_id')
1276 $dao = CRM_Core_DAO
::executeQuery($query);
1279 ALTER TABLE civicrm_entity_financial_trxn
1280 ADD INDEX UI_entity_financial_trxn_entity_table (entity_table),
1281 ADD INDEX UI_entity_financial_trxn_entity_id (entity_id);
1283 CRM_Core_DAO
::executeQuery($query);
1289 * Update phones CRM-11292
1291 * @param CRM_Queue_TaskContext $ctx
1293 * @return bool TRUE for success
1295 public static function phoneNumeric(CRM_Queue_TaskContext
$ctx) {
1296 CRM_Core_DAO
::executeQuery(CRM_Contact_BAO_Contact
::DROP_STRIP_FUNCTION_43
);
1297 CRM_Core_DAO
::executeQuery(CRM_Contact_BAO_Contact
::CREATE_STRIP_FUNCTION_43
);
1298 CRM_Core_DAO
::executeQuery("UPDATE civicrm_phone SET phone_numeric = civicrm_strip_non_numeric(phone)");
1303 * (Queue Task Callback)
1305 public static function task_4_3_x_runSql(CRM_Queue_TaskContext
$ctx, $rev) {
1306 $upgrade = new CRM_Upgrade_Form();
1307 $upgrade->processSQL($rev);
1313 * Syntatic sugar for adding a task which (a) is in this class and (b) has
1316 * After passing the $funcName, you can also pass parameters that will go to
1317 * the function. Note that all params must be serializable.
1319 protected function addTask($title, $funcName) {
1320 $queue = CRM_Queue_Service
::singleton()->load(array(
1322 'name' => CRM_Upgrade_Form
::QUEUE_NAME
,
1325 $args = func_get_args();
1326 $title = array_shift($args);
1327 $funcName = array_shift($args);
1328 $task = new CRM_Queue_Task(
1329 array(get_class($this), $funcName),
1333 $queue->createItem($task, array('weight' => -1));