4 +--------------------------------------------------------------------+
5 | CiviCRM version 4.3 |
6 +--------------------------------------------------------------------+
7 | Copyright CiviCRM LLC (c) 2004-2013 |
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-2013
35 class CRM_Upgrade_Incremental_php_FourThree
{
36 const BATCH_SIZE
= 5000;
38 function verifyPreDBstate(&$errors) {
43 * Compute any messages which should be displayed beforeupgrade
45 * Note: This function is called iteratively for each upcoming
46 * revision to the database.
48 * @param $postUpgradeMessage string, alterable
49 * @param $rev string, a version number, e.g. '4.3.alpha1', '4.3.beta3', '4.3.0'
52 function setPreUpgradeMessage(&$preUpgradeMessage, $rev, $currentVer = NULL) {
53 if ($rev == '4.3.beta3') {
55 //sql for checking orphaned contribution records
56 $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";
57 $count = CRM_Core_DAO
::singleValueQuery($sql, array(), TRUE, FALSE);
60 $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>'));
61 CRM_Core_Error
::fatal($error);
65 if ($rev == '4.3.beta4' && CRM_Utils_Constant
::value('CIVICRM_UF', FALSE) == 'Drupal6') {
66 // CRM-11823 - Make sure the D6 HTML HEAD technique will work on upgrade pages
67 theme('item_list', array()); // force-load theme registry
68 $theme_registry = theme_get_registry();
70 !isset($theme_registry['page']['preprocess functions']) ||
71 FALSE === array_search('civicrm_preprocess_page_inject', $theme_registry['page']['preprocess functions'])
73 CRM_Core_Error
::fatal('Please reset the Drupal cache (Administer => Site Configuration => Performance => Clear cached data))');
79 * Compute any messages which should be displayed after upgrade
81 * @param $postUpgradeMessage string, alterable
82 * @param $rev string, an intermediate version; note that setPostUpgradeMessage is called repeatedly with different $revs
85 function setPostUpgradeMessage(&$postUpgradeMessage, $rev) {
86 if ($rev == '4.3.alpha1') {
87 // check if CiviMember component is enabled
88 $config = CRM_Core_Config
::singleton();
89 if (in_array('CiviMember', $config->enableComponents
)) {
90 $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.');
91 $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.');
95 //here we do the financial type check and migration
96 $isDefaultsModified = self
::_checkAndMigrateDefaultFinancialTypes();
97 if($isDefaultsModified) {
98 $postUpgradeMessage .= '<br />' . ts('Please review all price set financial type assignments.');
100 list($context, $orgName) = self
::createDomainContacts();
101 if ($context == 'added') {
102 $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: '{$orgName}'.");
104 elseif ($context == 'merged') {
105 $postUpgradeMessage .= '<br />' . ts("The existing organization contact record for '{$orgName}' has been marked as the default domain contact, and has been updated with information from your Organization Address and Contact Info settings.");
108 $providerExists = CRM_Core_DAO
::singleValueQuery("SELECT id FROM civicrm_sms_provider LIMIT 1");
109 if ($providerExists) {
110 $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'));
114 if ($rev == '4.3.alpha2') {
117 FROM civicrm_action_schedule
118 WHERE entity_value = '' OR entity_value IS NULL
121 $dao = CRM_Core_DAO
::executeQuery($sql);
124 while ($dao->fetch()) {
125 $reminder[$dao->id
] = $dao->title
;
126 $list .= "<li>{$dao->title}</li>";
128 if (!empty($reminder)) {
129 $list = "<br /><ul>" . $list . "</ul>";
130 $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));
134 if ($rev == '4.3.beta2') {
135 $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).');
139 function upgrade_4_3_alpha1($rev) {
140 self
::task_4_3_alpha1_checkDBConstraints();
142 // add indexes for civicrm_entity_financial_trxn
144 $this->addTask(ts('Check/Add indexes for civicrm_entity_financial_trxn'), 'task_4_3_x_checkIndexes', $rev);
145 // task to process sql
146 $this->addTask(ts('Upgrade DB to 4.3.alpha1: SQL'), 'task_4_3_x_runSql', $rev);
149 $this->addTask(ts('Populate financial type values for price records'), 'assignFinancialTypeToPriceRecords');
150 //CRM-11514 create financial records for contributions
151 $this->addTask(ts('Create financial records for contributions'), 'createFinancialRecords');
153 $minId = CRM_Core_DAO
::singleValueQuery('SELECT coalesce(min(id),0) FROM civicrm_contact');
154 $maxId = CRM_Core_DAO
::singleValueQuery('SELECT coalesce(max(id),0) FROM civicrm_contact');
155 for ($startId = $minId; $startId <= $maxId; $startId +
= self
::BATCH_SIZE
) {
156 $endId = $startId + self
::BATCH_SIZE
- 1;
157 $title = ts('Upgrade timestamps (%1 => %2)', array(
161 $this->addTask($title, 'convertTimestamps', $startId, $endId);
165 // fix WP access control
166 $config = CRM_Core_Config
::singleton( );
167 if ($config->userFramework
== 'WordPress') {
168 civicrm_wp_set_capabilities( );
171 // Update phones CRM-11292.
172 $this->addTask(ts('Upgrade Phone Numbers'), 'phoneNumeric');
177 function upgrade_4_3_alpha2($rev) {
179 $isColumnPresent = CRM_Core_DAO
::checkFieldExists('civicrm_dedupe_rule_group', 'is_default');
180 if ($isColumnPresent) {
181 CRM_Core_DAO
::executeQuery('ALTER TABLE civicrm_dedupe_rule_group DROP COLUMN is_default');
183 $this->addTask(ts('Upgrade DB to 4.3.alpha2: SQL'), 'task_4_3_x_runSql', $rev);
186 function upgrade_4_3_alpha3($rev) {
187 $this->addTask(ts('Upgrade DB to 4.3.alpha3: SQL'), 'task_4_3_x_runSql', $rev);
190 function upgrade_4_3_beta2($rev) {
191 $this->addTask(ts('Upgrade DB to 4.3.beta2: SQL'), 'task_4_3_x_runSql', $rev);
195 CRM_Core_DAO
::checkTableExists('log_civicrm_line_item') &&
196 CRM_Core_DAO
::checkFieldExists('log_civicrm_line_item', 'label')
198 CRM_Core_DAO
::executeQuery('ALTER TABLE `log_civicrm_line_item` CHANGE `label` `label` VARCHAR(255) NULL DEFAULT NULL');
202 function upgrade_4_3_beta3($rev) {
203 $this->addTask(ts('Upgrade DB to 4.3.beta3: SQL'), 'task_4_3_x_runSql', $rev);
205 $query = "SELECT id, form_values FROM civicrm_report_instance WHERE form_values LIKE '%contribution_type%'";
206 $this->addTask('Replace contribution_type to financial_type in table civicrm_report_instance', 'replaceContributionTypeId', $query, 'reportInstance');
207 $query = "SELECT * FROM civicrm_saved_search WHERE form_values LIKE '%contribution_type%'";
208 $this->addTask('Replace contribution_type to financial_type in table civicrm_saved_search', 'replaceContributionTypeId', $query, 'savedSearch');
211 function upgrade_4_3_beta4($rev) {
212 $this->addTask(ts('Upgrade DB to 4.3.beta4: SQL'), 'task_4_3_x_runSql', $rev);
213 // add indexes for civicrm_entity_financial_trxn
215 $this->addTask(ts('Check/Add indexes for civicrm_entity_financial_trxn'), 'task_4_3_x_checkIndexes', $rev);
218 function upgrade_4_3_beta5($rev) {
219 $this->addTask(ts('Upgrade DB to 4.3.beta5: SQL'), 'task_4_3_x_runSql', $rev);
222 CRM_Core_DAO
::checkTableExists('log_civicrm_financial_trxn') &&
223 CRM_Core_DAO
::checkFieldExists('log_civicrm_financial_trxn', 'trxn_id')
225 CRM_Core_DAO
::executeQuery('ALTER TABLE `log_civicrm_financial_trxn` CHANGE `trxn_id` `trxn_id` VARCHAR(255) NULL DEFAULT NULL');
230 function assignFinancialTypeToPriceRecords() {
231 $upgrade = new CRM_Upgrade_Form();
232 //here we update price set entries
233 $sqlFinancialIds = "SELECT id, name FROM civicrm_financial_type
234 WHERE name IN ('Donation', 'Event Fee', 'Member Dues');";
235 $daoFinancialIds = CRM_Core_DAO
::executeQuery($sqlFinancialIds);
236 while($daoFinancialIds->fetch()) {
237 $financialIds[$daoFinancialIds->name
] = $daoFinancialIds->id
;
239 $sqlPriceSetUpdate = "UPDATE civicrm_price_set ps
240 SET ps.financial_type_id = CASE
241 WHEN ps.extends LIKE '%1%' THEN {$financialIds['Event Fee']}
242 WHEN ps.extends LIKE '2' THEN {$financialIds['Donation']}
243 WHEN ps.extends LIKE '3' THEN {$financialIds['Member Dues']}
245 WHERE financial_type_id IS NULL";
246 CRM_Core_DAO
::executeQuery($sqlPriceSetUpdate);
248 //here we update price field value rows
249 $sqlPriceFieldValueUpdate = "UPDATE civicrm_price_field_value pfv
250 LEFT JOIN civicrm_membership_type mt ON (pfv.membership_type_id = mt.id)
251 INNER JOIN civicrm_price_field pf ON (pfv.price_field_id = pf.id)
252 INNER JOIN civicrm_price_set ps ON (pf.price_set_id = ps.id)
253 SET pfv.financial_type_id = CASE
254 WHEN pfv.membership_type_id IS NOT NULL THEN mt.financial_type_id
255 WHEN pfv.membership_type_id IS NULL THEN ps.financial_type_id
257 CRM_Core_DAO
::executeQuery($sqlPriceFieldValueUpdate);
262 static function _checkAndMigrateDefaultFinancialTypes() {
263 $modifiedDefaults = FALSE;
264 //insert types if not exists
265 $sqlFetchTypes = "SELECT id, name FROM civicrm_contribution_type
266 WHERE name IN ('Donation', 'Event Fee', 'Member Dues') AND is_active =1;";
267 $daoFetchTypes = CRM_Core_DAO
::executeQuery($sqlFetchTypes);
269 if ($daoFetchTypes->N
< 3) {
270 $modifiedDefaults = TRUE;
271 $insertStatments = array (
272 'Donation' => "('Donation', 0, 1, 1)",
273 'Member' => "('Member Dues', 0, 1, 1)",
274 'Event Fee' => "('Event Fee', 0, 1, 0)",
276 foreach ($insertStatments as $values) {
277 $query = "INSERT INTO civicrm_contribution_type (name, is_reserved, is_active, is_deductible)
279 ON DUPLICATE KEY UPDATE is_active = 1;";
280 CRM_Core_DAO
::executeQuery($query);
283 return $modifiedDefaults;
286 function createFinancialRecords() {
287 $upgrade = new CRM_Upgrade_Form();
289 // update civicrm_entity_financial_trxn.amount = civicrm_financial_trxn.total_amount
290 $query = "UPDATE civicrm_entity_financial_trxn ceft
291 LEFT JOIN civicrm_financial_trxn cft ON cft.id = ceft.financial_trxn_id
292 SET ceft.amount = total_amount
293 WHERE cft.net_amount IS NOT NULL AND ceft.entity_table = 'civicrm_contribution';";
294 CRM_Core_DAO
::executeQuery($query);
296 $contributionStatus = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
297 $completedStatus = array_search('Completed', $contributionStatus);
298 $pendingStatus = array_search('Pending', $contributionStatus);
299 $cancelledStatus = array_search('Cancelled', $contributionStatus);
300 $queryParams = array(
301 1 => array($completedStatus, 'Integer'),
302 2 => array($pendingStatus, 'Integer'),
303 3 => array($cancelledStatus, 'Integer')
306 $accountType = key(CRM_Core_PseudoConstant
::accountOptionValues('financial_account_type', NULL, " AND v.name = 'Asset' "));
307 $financialAccountId =
308 CRM_Core_DAO
::singleValueQuery("SELECT id FROM civicrm_financial_account WHERE is_default = 1 AND financial_account_type_id = {$accountType}");
310 $accountRelationsips = CRM_Core_PseudoConstant
::accountOptionValues('account_relationship', NULL);
312 $accountsReceivableAccount = array_search('Accounts Receivable Account is', $accountRelationsips);
313 $incomeAccountIs = array_search('Income Account is', $accountRelationsips);
314 $assetAccountIs = array_search('Asset Account is', $accountRelationsips);
315 $expenseAccountIs = array_search('Expense Account is', $accountRelationsips);
317 $financialItemStatus = CRM_Core_PseudoConstant
::accountOptionValues('financial_item_status');
318 $unpaidStatus = array_search('Unpaid', $financialItemStatus);
319 $paidStatus = array_search('Paid', $financialItemStatus);
321 $validCurrencyCodes = CRM_Core_PseudoConstant
::currencyCode();
322 $validCurrencyCodes = implode("','", $validCurrencyCodes);
323 $config = CRM_Core_Config
::singleton();
324 $defaultCurrency = $config->defaultCurrency
;
325 $now = date( 'YmdHis' );
327 //adding financial_trxn records and entity_financial_trxn records related to contribution
328 //Add temp column for easy entry in entity_financial_trxn
329 $sql = "ALTER TABLE civicrm_financial_trxn ADD COLUMN contribution_id INT DEFAULT NULL";
330 CRM_Core_DAO
::executeQuery($sql);
332 //pending pay later status handling
334 INSERT INTO civicrm_financial_trxn
335 (contribution_id, payment_instrument_id, currency, total_amount, net_amount, fee_amount, trxn_id, status_id,
336 check_number, to_financial_account_id, from_financial_account_id, trxn_date)
338 SELECT con.id as contribution_id, con.payment_instrument_id, IF(con.currency IN ('{$validCurrencyCodes}'), con.currency, '{$defaultCurrency}')
339 as currency, con.total_amount, con.net_amount, con.fee_amount, con.trxn_id, con.contribution_status_id,
340 con.check_number, efa.financial_account_id as to_financial_account_id, NULL as from_financial_account_id,
341 REPLACE(REPLACE(REPLACE(
343 WHEN con.receive_date IS NOT NULL THEN
345 WHEN con.receipt_date IS NOT NULL THEN
350 , '-', ''), ':', ''), ' ', '') as trxn_date
351 FROM civicrm_contribution con
352 LEFT JOIN civicrm_entity_financial_account efa
353 ON (con.financial_type_id = efa.entity_id AND efa.entity_table = 'civicrm_financial_type'
354 AND efa.account_relationship = {$accountsReceivableAccount})
355 WHERE con.is_pay_later = 1 AND con.contribution_status_id = {$pendingStatus}";
356 CRM_Core_DAO
::executeQuery($sql);
358 //create a temp table to hold financial account id related to payment instruments
359 $tempTableName1 = CRM_Core_DAO
::createTempTableName();
361 $sql = "CREATE TEMPORARY TABLE {$tempTableName1}
363 SELECT ceft.financial_account_id financial_account_id, cov.value as instrument_id
364 FROM civicrm_entity_financial_account ceft
365 INNER JOIN civicrm_option_value cov ON cov.id = ceft.entity_id AND ceft.entity_table = 'civicrm_option_value'
366 INNER JOIN civicrm_option_group cog ON cog.id = cov.option_group_id
367 WHERE cog.name = 'payment_instrument'";
368 CRM_Core_DAO
::executeQuery($sql);
370 $sql = "ALTER TABLE {$tempTableName1} ADD INDEX index_instrument_id (instrument_id);";
371 CRM_Core_DAO
::executeQuery($sql);
373 //create temp table to process completed / cancelled contribution
374 $tempTableName2 = CRM_Core_DAO
::createTempTableName();
375 $sql = "CREATE TEMPORARY TABLE {$tempTableName2}
377 SELECT con.id as contribution_id, con.payment_instrument_id, IF(con.currency IN ('{$validCurrencyCodes}'), con.currency, '{$defaultCurrency}') as currency,
378 con.total_amount, con.net_amount, con.fee_amount, con.trxn_id, con.contribution_status_id, con.check_number, NULL as from_financial_account_id,
379 REPLACE(REPLACE(REPLACE(
381 WHEN con.receive_date IS NOT NULL THEN
383 WHEN con.receipt_date IS NOT NULL THEN
388 , '-', ''), ':', ''), ' ', '') as trxn_date,
390 WHEN con.payment_instrument_id IS NULL THEN
391 {$financialAccountId}
392 WHEN con.payment_instrument_id IS NOT NULL THEN
393 tpi.financial_account_id
394 END as to_financial_account_id,
395 IF(eft.financial_trxn_id IS NULL, 'insert', eft.financial_trxn_id) as action
396 FROM civicrm_contribution con
397 LEFT JOIN civicrm_entity_financial_trxn eft
398 ON (eft.entity_table = 'civicrm_contribution' AND eft.entity_id = con.id)
399 LEFT JOIN {$tempTableName1} tpi
400 ON con.payment_instrument_id = tpi.instrument_id
401 WHERE con.contribution_status_id IN ({$completedStatus}, {$cancelledStatus})";
402 CRM_Core_DAO
::executeQuery($sql);
404 $sql = "ALTER TABLE {$tempTableName2} ADD INDEX index_action (action);";
405 CRM_Core_DAO
::executeQuery($sql);
407 //handling for completed contribution and cancelled contribution
408 //insertion of new records
410 INSERT INTO civicrm_financial_trxn
411 (contribution_id, payment_instrument_id, currency, total_amount, net_amount, fee_amount, trxn_id, status_id, check_number,
412 to_financial_account_id, from_financial_account_id, trxn_date)
413 SELECT tempI.contribution_id, tempI.payment_instrument_id, tempI.currency, tempI.total_amount, tempI.net_amount,
414 tempI.fee_amount, tempI.trxn_id, tempI.contribution_status_id, tempI.check_number,
415 tempI.to_financial_account_id, tempI.from_financial_account_id, tempI.trxn_date
416 FROM {$tempTableName2} tempI
417 WHERE tempI.action = 'insert';";
418 CRM_Core_DAO
::executeQuery($sql);
420 //update of existing records
422 UPDATE civicrm_financial_trxn ft
423 INNER JOIN {$tempTableName2} tempU
424 ON (tempU.action != 'insert' AND ft.id = tempU.action)
425 SET ft.from_financial_account_id = NULL,
426 ft.to_financial_account_id = tempU.to_financial_account_id,
427 ft.status_id = tempU.contribution_status_id,
428 ft.payment_instrument_id = tempU.payment_instrument_id,
429 ft.check_number = tempU.check_number,
430 ft.contribution_id = tempU.contribution_id;";
431 CRM_Core_DAO
::executeQuery($sql);
433 //insert the -ve transaction rows for cancelled contributions
435 INSERT INTO civicrm_financial_trxn
436 (contribution_id, payment_instrument_id, currency, total_amount, net_amount, fee_amount, trxn_id, status_id,
437 check_number, to_financial_account_id, from_financial_account_id, trxn_date)
438 SELECT ft.contribution_id, ft.payment_instrument_id, ft.currency, -ft.total_amount, ft.net_amount, ft.fee_amount, ft.trxn_id,
439 ft.status_id, ft.check_number, ft.to_financial_account_id, ft.from_financial_account_id, ft.trxn_date
440 FROM civicrm_financial_trxn ft
441 WHERE ft.status_id = {$cancelledStatus};";
442 CRM_Core_DAO
::executeQuery($sql);
444 //inserting entity financial trxn entries if its not present in entity_financial_trxn for completed and pending contribution statuses
445 //this also handles +ve and -ve both transaction entries for a cancelled contribution
447 INSERT INTO civicrm_entity_financial_trxn (entity_table, entity_id, financial_trxn_id, amount)
448 SELECT 'civicrm_contribution', ft.contribution_id, ft.id, ft.total_amount as amount
449 FROM civicrm_financial_trxn ft
450 WHERE contribution_id IS NOT NULL AND
451 ft.id NOT IN (SELECT financial_trxn_id
452 FROM civicrm_entity_financial_trxn
453 WHERE entity_table = 'civicrm_contribution'
454 AND entity_id = ft.contribution_id)";
455 CRM_Core_DAO
::executeQuery($sql);
456 //end of adding financial_trxn records and entity_financial_trxn records related to contribution
458 //update all linked line_item rows
459 // set line_item.financial_type_id = contribution.financial_type_id if contribution page id is null and not participant line item
460 // set line_item.financial_type_id = price_field_value.financial_type_id if contribution page id is set and not participant line item
461 // set line_item.financial_type_id = event.financial_type_id if its participant line item and line_item.price_field_value_id is null
462 // 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
463 $updateLineItemSql = "
464 UPDATE civicrm_line_item li
465 LEFT JOIN civicrm_contribution con
466 ON (li.entity_id = con.id AND li.entity_table = 'civicrm_contribution')
467 LEFT JOIN civicrm_price_field_value cpfv
468 ON li.price_field_value_id = cpfv.id
469 LEFT JOIN civicrm_participant cp
470 ON (li.entity_id = cp.id AND li.entity_table = 'civicrm_participant')
471 LEFT JOIN civicrm_event ce
472 ON ce.id = cp.event_id
473 SET li.financial_type_id = CASE
474 WHEN (con.contribution_page_id IS NULL || li.price_field_value_id IS NULL) AND cp.id IS NULL THEN
475 con.financial_type_id
476 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
477 cpfv.financial_type_id
478 WHEN cp.id IS NOT NULL AND li.price_field_value_id IS NULL THEN
481 CRM_Core_DAO
::executeQuery($updateLineItemSql, $queryParams);
483 //add the financial_item entries
484 //add a temp column so that inserting entity_financial_trxn entries gets easy
485 $sql = "ALTER TABLE civicrm_financial_item ADD COLUMN f_trxn_id INT DEFAULT NULL";
486 CRM_Core_DAO
::executeQuery($sql);
488 //add financial_item entries for contribution completed / pending pay later / cancelled
489 $contributionlineItemSql = "
490 INSERT INTO civicrm_financial_item
491 (transaction_date, contact_id, amount, currency, entity_table, entity_id, description, status_id, financial_account_id, f_trxn_id)
493 SELECT REPLACE(REPLACE(REPLACE(ft.trxn_date, '-', ''), ':', ''), ' ', ''), con.contact_id,
494 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',
495 li.id as line_item_id, li.label as line_item_label,
496 IF(con.contribution_status_id = {$pendingStatus}, {$unpaidStatus}, {$paidStatus}) as status_id, efa.financial_account_id as financial_account_id,
498 FROM civicrm_line_item li
499 INNER JOIN civicrm_contribution con
500 ON (li.entity_id = con.id AND li.entity_table = 'civicrm_contribution')
501 INNER JOIN civicrm_financial_trxn ft
502 ON (con.id = ft.contribution_id)
503 LEFT JOIN civicrm_entity_financial_account efa
504 ON (li.financial_type_id = efa.entity_id AND efa.entity_table = 'civicrm_financial_type'
505 AND efa.account_relationship = {$incomeAccountIs})
506 WHERE con.contribution_status_id IN (%1, %3) OR (con.is_pay_later = 1 AND con.contribution_status_id = %2)";
507 CRM_Core_DAO
::executeQuery($contributionlineItemSql, $queryParams);
509 //add financial_item entries for event
510 $participantLineItemSql = "
511 INSERT INTO civicrm_financial_item
512 (transaction_date, contact_id, amount, currency, entity_table, entity_id, description, status_id, financial_account_id, f_trxn_id)
514 SELECT REPLACE(REPLACE(REPLACE(ft.trxn_date, '-', ''), ':', ''), ' ', ''), con.contact_id,
515 IF(ft.total_amount < 0 AND con.contribution_status_id = %3, -li.line_total, li.line_total) as line_total,
516 con.currency, 'civicrm_line_item', li.id as line_item_id, li.label as line_item_label,
517 IF(con.contribution_status_id = {$pendingStatus}, {$unpaidStatus}, {$paidStatus}) as status_id,
518 efa.financial_account_id as financial_account_id, ft.id as f_trxn_id
519 FROM civicrm_line_item li
520 INNER JOIN civicrm_participant par
521 ON (li.entity_id = par.id AND li.entity_table = 'civicrm_participant')
522 INNER JOIN civicrm_participant_payment pp
523 ON (pp.participant_id = par.id)
524 INNER JOIN civicrm_contribution con
525 ON (pp.contribution_id = con.id)
526 INNER JOIN civicrm_financial_trxn ft
527 ON (con.id = ft.contribution_id)
528 LEFT JOIN civicrm_entity_financial_account efa
529 ON (li.financial_type_id = efa.entity_id AND
530 efa.entity_table = 'civicrm_financial_type' AND efa.account_relationship = {$incomeAccountIs})
531 WHERE con.contribution_status_id IN (%1, %3) OR (con.is_pay_later = 1 AND con.contribution_status_id = %2)";
532 CRM_Core_DAO
::executeQuery($participantLineItemSql, $queryParams);
534 //fee handling for contributions
535 //insert fee entries in financial_trxn for contributions
536 $sql = "ALTER TABLE civicrm_financial_trxn ADD COLUMN is_fee TINYINT DEFAULT NULL";
537 CRM_Core_DAO
::executeQuery($sql);
540 INSERT INTO civicrm_financial_trxn
541 (contribution_id, payment_instrument_id, currency, total_amount, net_amount, fee_amount, trxn_id, status_id, check_number,
542 to_financial_account_id, from_financial_account_id, trxn_date, payment_processor_id, is_fee)
544 SELECT con.id, ft.payment_instrument_id, ft.currency, ft.fee_amount, NULL, NULL, ft.trxn_id, %1 as status_id,
545 ft.check_number, efaFT.financial_account_id as to_financial_account_id, CASE
546 WHEN efaPP.financial_account_id IS NOT NULL THEN
547 efaPP.financial_account_id
548 WHEN tpi.financial_account_id IS NOT NULL THEN
549 tpi.financial_account_id
551 {$financialAccountId}
552 END as from_financial_account_id, ft.trxn_date, ft.payment_processor_id, 1 as is_fee
553 FROM civicrm_contribution con
554 INNER JOIN civicrm_financial_trxn ft
555 ON (ft.contribution_id = con.id)
556 LEFT JOIN civicrm_entity_financial_account efaFT
557 ON (con.financial_type_id = efaFT.entity_id AND efaFT.entity_table = 'civicrm_financial_type'
558 AND efaFT.account_relationship = {$expenseAccountIs})
559 LEFT JOIN civicrm_entity_financial_account efaPP
560 ON (ft.payment_processor_id = efaPP.entity_id AND efaPP.entity_table = 'civicrm_payment_processor'
561 AND efaPP.account_relationship = {$assetAccountIs})
562 LEFT JOIN {$tempTableName1} tpi
563 ON ft.payment_instrument_id = tpi.instrument_id
564 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))
566 CRM_Core_DAO
::executeQuery($sql, $queryParams);
568 //link financial_trxn to contribution
570 INSERT INTO civicrm_entity_financial_trxn
571 (entity_table, entity_id, financial_trxn_id, amount)
572 SELECT 'civicrm_contribution', ft.contribution_id, ft.id, ft.total_amount
573 FROM civicrm_financial_trxn ft
574 WHERE ft.is_fee = 1";
575 CRM_Core_DAO
::executeQuery($sql);
577 //add fee related entries to financial item table
578 $domainId = CRM_Core_Config
::domainID();
579 $domainContactId = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_Domain', $domainId, 'contact_id');
581 INSERT INTO civicrm_financial_item
582 (transaction_date, contact_id, amount, currency, entity_table, entity_id, description, status_id, financial_account_id, f_trxn_id)
583 SELECT ft.trxn_date, {$domainContactId} as contact_id, ft.total_amount, ft.currency, 'civicrm_financial_trxn', ft.id,
584 'Fee', {$paidStatus} as status_id, ft.to_financial_account_id as financial_account_id, ft.id as f_trxn_id
585 FROM civicrm_financial_trxn ft
586 WHERE ft.is_fee = 1;";
587 CRM_Core_DAO
::executeQuery($sql);
589 //add entries to entity_financial_trxn table
591 INSERT INTO civicrm_entity_financial_trxn (entity_table, entity_id, financial_trxn_id, amount)
592 SELECT 'civicrm_financial_item' as entity_table, fi.id as entity_id, fi.f_trxn_id as financial_trxn_id, fi.amount
593 FROM civicrm_financial_item fi";
594 CRM_Core_DAO
::executeQuery($sql);
596 //drop the temparory columns
597 $sql = "ALTER TABLE civicrm_financial_trxn
598 DROP COLUMN contribution_id,
599 DROP COLUMN is_fee;";
600 CRM_Core_DAO
::executeQuery($sql);
602 $sql = "ALTER TABLE civicrm_financial_item DROP f_trxn_id";
603 CRM_Core_DAO
::executeQuery($sql);
608 function createDomainContacts() {
609 $domainParams = $context = array();
611 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',
612 ADD CONSTRAINT `FK_civicrm_domain_contact_id` FOREIGN KEY (`contact_id`) REFERENCES `civicrm_contact` (`id`);";
613 CRM_Core_DAO
::executeQuery($query, CRM_Core_DAO
::$_nullArray, TRUE, NULL, FALSE, FALSE);
615 $query = 'SELECT cd.id, cd.name, ce.email FROM `civicrm_domain` cd
616 LEFT JOIN civicrm_loc_block clb ON clb.id = cd. loc_block_id
617 LEFT JOIN civicrm_email ce ON ce.id = clb.email_id ;' ;
618 $dao = CRM_Core_DAO
::executeQuery($query);
619 while($dao->fetch()) {
621 'sort_name' => $dao->name
,
622 'display_name' => $dao->name
,
623 'legal_name' => $dao->name
,
624 'organization_name' => $dao->name
,
625 'contact_type' => 'Organization'
627 $query = "SELECT cc.id FROM `civicrm_contact` cc
628 LEFT JOIN civicrm_email ce ON ce.contact_id = cc.id
629 WHERE cc.contact_type = 'Organization' AND cc.organization_name = '{$dao->name}' ";
631 $query .= " AND ce.email = '{$dao->email}' ";
633 $contactID = CRM_Core_DAO
::singleValueQuery($query);
634 $context[1] = $dao->name
;
635 if (empty($contactID)) {
636 $contact = CRM_Contact_BAO_Contact
::add($params);
637 $contactID = $contact->id
;
638 $context[0] = 'added';
641 $context[0] = 'merged';
643 $domainParams['contact_id'] = $contactID;
644 CRM_Core_BAO_Domain
::edit($domainParams, $dao->id
);
649 function task_4_3_alpha1_checkDBConstraints() {
650 //checking whether the foreign key exists before dropping it CRM-11260
651 $config = CRM_Core_Config
::singleton();
652 $dbUf = DB
::parseDSN($config->dsn
);
655 'autorenewal_msg_id' => array('tableName' => 'civicrm_membership_type', 'fkey' => 'FK_civicrm_membership_autorenewal_msg_id'),
656 'to_account_id' => array('tableName' => 'civicrm_financial_trxn', 'constraintName' => 'civicrm_financial_trxn_ibfk_2'),
657 'from_account_id' => array('tableName' => 'civicrm_financial_trxn', 'constraintName' => 'civicrm_financial_trxn_ibfk_1'),
658 'contribution_type_id' => array('tableName' => 'civicrm_contribution_recur', 'fkey' => 'FK_civicrm_contribution_recur_contribution_type_id'),
660 $query = "SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
661 WHERE table_name = 'civicrm_contribution_recur'
662 AND constraint_name = 'FK_civicrm_contribution_recur_contribution_type_id'
663 AND TABLE_SCHEMA = '{$dbUf['database']}'";
665 $dao = CRM_Core_DAO
::executeQuery($query, $params, TRUE, NULL, FALSE, FALSE);
666 foreach($tables as $columnName => $value){
667 if ($value['tableName'] == 'civicrm_membership_type' ||
$value['tableName'] == 'civicrm_contribution_recur') {
668 $foreignKeyExists = CRM_Core_DAO
::checkConstraintExists($value['tableName'], $value['fkey']);
669 $fKey = $value['fkey'];
671 $foreignKeyExists = CRM_Core_DAO
::checkFKConstraintInFormat($value['tableName'], $columnName);
672 $fKey = "`FK_{$value['tableName']}_{$columnName}`";
674 if ($foreignKeyExists ||
$value['tableName'] == 'civicrm_financial_trxn') {
675 if ($value['tableName'] != 'civicrm_contribution_recur' ||
($value['tableName'] == 'civicrm_contribution_recur' && $dao->N
)) {
676 $constraintName = $foreignKeyExists ?
$fKey : $value['constraintName'];
677 CRM_Core_DAO
::executeQuery("ALTER TABLE {$value['tableName']} DROP FOREIGN KEY {$constraintName}", $params, TRUE, NULL, FALSE, FALSE);
679 CRM_Core_DAO
::executeQuery("ALTER TABLE {$value['tableName']} DROP INDEX {$fKey}", $params, TRUE, NULL, FALSE, FALSE);
682 // check if column contact_id is present or not in civicrm_financial_account
683 $fieldExists = CRM_Core_DAO
::checkFieldExists('civicrm_financial_account', 'contact_id', FALSE);
685 $query = "ALTER TABLE civicrm_financial_account ADD `contact_id` int(10) unsigned DEFAULT NULL COMMENT 'Version identifier of financial_type' AFTER `name`, ADD CONSTRAINT `FK_civicrm_financial_account_contact_id` FOREIGN KEY (`contact_id`) REFERENCES `civicrm_contact`(id);";
686 CRM_Core_DAO
::executeQuery($query, $params, TRUE, NULL, FALSE, FALSE);
691 * Read creation and modification times from civicrm_log; add
692 * them to civicrm_contact.
694 function convertTimestamps(CRM_Queue_TaskContext
$ctx, $startId, $endId) {
696 SELECT entity_id, min(modified_date) AS created, max(modified_date) AS modified
698 WHERE entity_table = 'civicrm_contact'
699 AND entity_id BETWEEN %1 AND %2
703 1 => array($startId, 'Integer'),
704 2 => array($endId, 'Integer'),
706 $dao = CRM_Core_DAO
::executeQuery($sql, $params);
707 while ($dao->fetch()) {
708 // FIXME civicrm_log.modified_date is DATETIME; civicrm_contact.modified_date is TIMESTAMP
709 CRM_Core_DAO
::executeQuery(
710 'UPDATE civicrm_contact SET created_date = %1, modified_date = %2 WHERE id = %3',
712 1 => array($dao->created
, 'String'),
713 2 => array($dao->modified
, 'String'),
714 3 => array($dao->entity_id
, 'Integer'),
723 * replace contribution_type to financial_type in table
724 * civicrm_saved_search and Structure civicrm_report_instance
726 function replaceContributionTypeId(CRM_Queue_TaskContext
$ctx, $query, $table) {
727 $dao = CRM_Core_DAO
::executeQuery($query);
728 while ($dao->fetch()) {
729 $formValues = unserialize($dao->form_values
);
730 foreach (array('contribution_type_id_op', 'contribution_type_id_value', 'contribution_type_id') as $value) {
731 if (array_key_exists($value, $formValues)) {
732 $key = preg_replace('/contribution/', 'financial', $value);
733 $formValues[$key] = $formValues[$value];
734 unset($formValues[$value]);
737 if ($table != 'savedSearch') {
738 foreach (array('fields', 'group_bys') as $value) {
739 if (array_key_exists($value, $formValues)) {
740 if (array_key_exists('contribution_type_id', $formValues[$value])) {
741 $formValues[$value]['financial_type_id'] = $formValues[$value]['contribution_type_id'];
742 unset($formValues[$value]['contribution_type_id']);
744 else if (array_key_exists('contribution_type', $formValues[$value])) {
745 $formValues[$value]['financial_type'] = $formValues[$value]['contribution_type'];
746 unset($formValues[$value]['contribution_type']);
750 if (array_key_exists('order_bys', $formValues)) {
751 foreach ($formValues['order_bys'] as $key => $values) {
752 if (preg_grep('/contribution_type/', $values)) {
753 $formValues['order_bys'][$key]['column'] = preg_replace('/contribution_type/', 'financial_type', $values['column']);
759 if ($table == 'savedSearch') {
760 $saveDao = new CRM_Contact_DAO_SavedSearch();
763 $saveDao = new CRM_Report_DAO_Instance();
765 $saveDao->id
= $dao->id
;
767 if ($table == 'savedSearch') {
768 if (array_key_exists('mapper', $formValues)) {
769 foreach ($formValues['mapper'] as $key => $values) {
770 foreach ($values as $k => $v) {
771 if (preg_grep('/contribution_/', $v)) {
772 $formValues['mapper'][$key][$k] = preg_replace('/contribution_type/', 'financial_type', $v);
777 foreach (array('select_tables', 'where_tables') as $value) {
778 if (preg_match('/contribution_type/', $dao->$value)) {
779 $tempValue = unserialize($dao->$value);
780 if (array_key_exists('civicrm_contribution_type', $tempValue)) {
781 $tempValue['civicrm_financial_type'] = $tempValue['civicrm_contribution_type'];
782 unset($tempValue['civicrm_contribution_type']);
784 $saveDao->$value = serialize($tempValue);
787 if (preg_match('/contribution_type/', $dao->where_clause
)) {
788 $saveDao->where_clause
= preg_replace('/contribution_type/', 'financial_type', $dao->where_clause
);
791 $saveDao->form_values
= serialize($formValues);
799 * Check/Add INDEX CRM-12141
801 * @return bool TRUE for success
803 function task_4_3_x_checkIndexes(CRM_Queue_TaskContext
$ctx) {
804 $query = "SHOW KEYS FROM `civicrm_entity_financial_trxn`
805 WHERE key_name IN ('UI_entity_financial_trxn_entity_table', 'UI_entity_financial_trxn_entity_id');";
806 $dao = CRM_Core_DAO
::executeQuery($query);
808 CRM_Core_DAO
::executeQuery("ALTER TABLE civicrm_entity_financial_trxn
809 ADD INDEX UI_entity_financial_trxn_entity_table (entity_table),
810 ADD INDEX UI_entity_financial_trxn_entity_id (entity_id);");
816 * Update phones CRM-11292
818 * @return bool TRUE for success
820 static function phoneNumeric(CRM_Queue_TaskContext
$ctx) {
821 CRM_Core_DAO
::executeQuery(CRM_Contact_BAO_Contact
::DROP_STRIP_FUNCTION_43
);
822 CRM_Core_DAO
::executeQuery(CRM_Contact_BAO_Contact
::CREATE_STRIP_FUNCTION_43
);
823 CRM_Core_DAO
::executeQuery("UPDATE civicrm_phone SET phone_numeric = civicrm_strip_non_numeric(phone)");
828 * (Queue Task Callback)
830 static function task_4_3_x_runSql(CRM_Queue_TaskContext
$ctx, $rev) {
831 $upgrade = new CRM_Upgrade_Form();
832 $upgrade->processSQL($rev);
838 * Syntatic sugar for adding a task which (a) is in this class and (b) has
841 * After passing the $funcName, you can also pass parameters that will go to
842 * the function. Note that all params must be serializable.
844 protected function addTask($title, $funcName) {
845 $queue = CRM_Queue_Service
::singleton()->load(array(
847 'name' => CRM_Upgrade_Form
::QUEUE_NAME
,
850 $args = func_get_args();
851 $title = array_shift($args);
852 $funcName = array_shift($args);
853 $task = new CRM_Queue_Task(
854 array(get_class($this), $funcName),
858 $queue->createItem($task, array('weight' => -1));