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);
194 CRM_Core_DAO
::checkTableExists('log_civicrm_line_item') &&
195 CRM_Core_DAO
::checkFieldExists('log_civicrm_line_item', 'label')
197 CRM_Core_DAO
::executeQuery('ALTER TABLE `log_civicrm_line_item` CHANGE `label` `label` VARCHAR(255) NULL DEFAULT NULL');
201 function upgrade_4_3_beta3($rev) {
202 $this->addTask(ts('Upgrade DB to 4.3.beta3: SQL'), 'task_4_3_x_runSql', $rev);
204 $query = "SELECT id, form_values FROM civicrm_report_instance WHERE form_values LIKE '%contribution_type%'";
205 $this->addTask('Replace contribution_type to financial_type in table civicrm_report_instance', 'replaceContributionTypeId', $query, 'reportInstance');
206 $query = "SELECT * FROM civicrm_saved_search WHERE form_values LIKE '%contribution_type%'";
207 $this->addTask('Replace contribution_type to financial_type in table civicrm_saved_search', 'replaceContributionTypeId', $query, 'savedSearch');
210 function upgrade_4_3_beta4($rev) {
211 $this->addTask(ts('Upgrade DB to 4.3.beta4: SQL'), 'task_4_3_x_runSql', $rev);
212 // add indexes for civicrm_entity_financial_trxn
214 $this->addTask(ts('Check/Add indexes for civicrm_entity_financial_trxn'), 'task_4_3_x_checkIndexes', $rev);
218 function assignFinancialTypeToPriceRecords() {
219 $upgrade = new CRM_Upgrade_Form();
220 //here we update price set entries
221 $sqlFinancialIds = "SELECT id, name FROM civicrm_financial_type
222 WHERE name IN ('Donation', 'Event Fee', 'Member Dues');";
223 $daoFinancialIds = CRM_Core_DAO
::executeQuery($sqlFinancialIds);
224 while($daoFinancialIds->fetch()) {
225 $financialIds[$daoFinancialIds->name
] = $daoFinancialIds->id
;
227 $sqlPriceSetUpdate = "UPDATE civicrm_price_set ps
228 SET ps.financial_type_id = CASE
229 WHEN ps.extends LIKE '%1%' THEN {$financialIds['Event Fee']}
230 WHEN ps.extends LIKE '2' THEN {$financialIds['Donation']}
231 WHEN ps.extends LIKE '3' THEN {$financialIds['Member Dues']}
233 WHERE financial_type_id IS NULL";
234 CRM_Core_DAO
::executeQuery($sqlPriceSetUpdate);
236 //here we update price field value rows
237 $sqlPriceFieldValueUpdate = "UPDATE civicrm_price_field_value pfv
238 LEFT JOIN civicrm_membership_type mt ON (pfv.membership_type_id = mt.id)
239 INNER JOIN civicrm_price_field pf ON (pfv.price_field_id = pf.id)
240 INNER JOIN civicrm_price_set ps ON (pf.price_set_id = ps.id)
241 SET pfv.financial_type_id = CASE
242 WHEN pfv.membership_type_id IS NOT NULL THEN mt.financial_type_id
243 WHEN pfv.membership_type_id IS NULL THEN ps.financial_type_id
245 CRM_Core_DAO
::executeQuery($sqlPriceFieldValueUpdate);
250 static function _checkAndMigrateDefaultFinancialTypes() {
251 $modifiedDefaults = FALSE;
252 //insert types if not exists
253 $sqlFetchTypes = "SELECT id, name FROM civicrm_contribution_type
254 WHERE name IN ('Donation', 'Event Fee', 'Member Dues') AND is_active =1;";
255 $daoFetchTypes = CRM_Core_DAO
::executeQuery($sqlFetchTypes);
257 if ($daoFetchTypes->N
< 3) {
258 $modifiedDefaults = TRUE;
259 $insertStatments = array (
260 'Donation' => "('Donation', 0, 1, 1)",
261 'Member' => "('Member Dues', 0, 1, 1)",
262 'Event Fee' => "('Event Fee', 0, 1, 0)",
264 foreach ($insertStatments as $values) {
265 $query = "INSERT INTO civicrm_contribution_type (name, is_reserved, is_active, is_deductible)
267 ON DUPLICATE KEY UPDATE is_active = 1;";
268 CRM_Core_DAO
::executeQuery($query);
271 return $modifiedDefaults;
274 function createFinancialRecords() {
275 $upgrade = new CRM_Upgrade_Form();
277 // update civicrm_entity_financial_trxn.amount = civicrm_financial_trxn.total_amount
278 $query = "UPDATE civicrm_entity_financial_trxn ceft
279 LEFT JOIN civicrm_financial_trxn cft ON cft.id = ceft.financial_trxn_id
280 SET ceft.amount = total_amount
281 WHERE cft.net_amount IS NOT NULL AND ceft.entity_table = 'civicrm_contribution';";
282 CRM_Core_DAO
::executeQuery($query);
284 $contributionStatus = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
285 $completedStatus = array_search('Completed', $contributionStatus);
286 $pendingStatus = array_search('Pending', $contributionStatus);
287 $cancelledStatus = array_search('Cancelled', $contributionStatus);
288 $queryParams = array(
289 1 => array($completedStatus, 'Integer'),
290 2 => array($pendingStatus, 'Integer'),
291 3 => array($cancelledStatus, 'Integer')
294 $accountType = key(CRM_Core_PseudoConstant
::accountOptionValues('financial_account_type', NULL, " AND v.name = 'Asset' "));
295 $financialAccountId =
296 CRM_Core_DAO
::singleValueQuery("SELECT id FROM civicrm_financial_account WHERE is_default = 1 AND financial_account_type_id = {$accountType}");
298 $accountRelationsips = CRM_Core_PseudoConstant
::accountOptionValues('account_relationship', NULL);
300 $accountsReceivableAccount = array_search('Accounts Receivable Account is', $accountRelationsips);
301 $incomeAccountIs = array_search('Income Account is', $accountRelationsips);
302 $assetAccountIs = array_search('Asset Account is', $accountRelationsips);
303 $expenseAccountIs = array_search('Expense Account is', $accountRelationsips);
305 $financialItemStatus = CRM_Core_PseudoConstant
::accountOptionValues('financial_item_status');
306 $unpaidStatus = array_search('Unpaid', $financialItemStatus);
307 $paidStatus = array_search('Paid', $financialItemStatus);
309 $validCurrencyCodes = CRM_Core_PseudoConstant
::currencyCode();
310 $validCurrencyCodes = implode("','", $validCurrencyCodes);
311 $config = CRM_Core_Config
::singleton();
312 $defaultCurrency = $config->defaultCurrency
;
313 $now = date( 'YmdHis' );
315 //adding financial_trxn records and entity_financial_trxn records related to contribution
316 //Add temp column for easy entry in entity_financial_trxn
317 $sql = "ALTER TABLE civicrm_financial_trxn ADD COLUMN contribution_id INT DEFAULT NULL";
318 CRM_Core_DAO
::executeQuery($sql);
320 //pending pay later status handling
322 INSERT INTO civicrm_financial_trxn
323 (contribution_id, payment_instrument_id, currency, total_amount, net_amount, fee_amount, trxn_id, status_id,
324 check_number, to_financial_account_id, from_financial_account_id, trxn_date)
326 SELECT con.id as contribution_id, con.payment_instrument_id, IF(con.currency IN ('{$validCurrencyCodes}'), con.currency, '{$defaultCurrency}')
327 as currency, con.total_amount, con.net_amount, con.fee_amount, con.trxn_id, con.contribution_status_id,
328 con.check_number, efa.financial_account_id as to_financial_account_id, NULL as from_financial_account_id,
329 REPLACE(REPLACE(REPLACE(
331 WHEN con.receive_date IS NOT NULL THEN
333 WHEN con.receipt_date IS NOT NULL THEN
338 , '-', ''), ':', ''), ' ', '') as trxn_date
339 FROM civicrm_contribution con
340 LEFT JOIN civicrm_entity_financial_account efa
341 ON (con.financial_type_id = efa.entity_id AND efa.entity_table = 'civicrm_financial_type'
342 AND efa.account_relationship = {$accountsReceivableAccount})
343 WHERE con.is_pay_later = 1 AND con.contribution_status_id = {$pendingStatus}";
344 CRM_Core_DAO
::executeQuery($sql);
346 //create a temp table to hold financial account id related to payment instruments
347 $tempTableName1 = CRM_Core_DAO
::createTempTableName();
349 $sql = "CREATE TEMPORARY TABLE {$tempTableName1}
351 SELECT ceft.financial_account_id financial_account_id, cov.value as instrument_id
352 FROM civicrm_entity_financial_account ceft
353 INNER JOIN civicrm_option_value cov ON cov.id = ceft.entity_id AND ceft.entity_table = 'civicrm_option_value'
354 INNER JOIN civicrm_option_group cog ON cog.id = cov.option_group_id
355 WHERE cog.name = 'payment_instrument'";
356 CRM_Core_DAO
::executeQuery($sql);
358 $sql = "ALTER TABLE {$tempTableName1} ADD INDEX index_instrument_id (instrument_id);";
359 CRM_Core_DAO
::executeQuery($sql);
361 //create temp table to process completed / cancelled contribution
362 $tempTableName2 = CRM_Core_DAO
::createTempTableName();
363 $sql = "CREATE TEMPORARY TABLE {$tempTableName2}
365 SELECT con.id as contribution_id, con.payment_instrument_id, IF(con.currency IN ('{$validCurrencyCodes}'), con.currency, '{$defaultCurrency}') as currency,
366 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,
367 REPLACE(REPLACE(REPLACE(
369 WHEN con.receive_date IS NOT NULL THEN
371 WHEN con.receipt_date IS NOT NULL THEN
376 , '-', ''), ':', ''), ' ', '') as trxn_date,
378 WHEN con.payment_instrument_id IS NULL THEN
379 {$financialAccountId}
380 WHEN con.payment_instrument_id IS NOT NULL THEN
381 tpi.financial_account_id
382 END as to_financial_account_id,
383 IF(eft.financial_trxn_id IS NULL, 'insert', eft.financial_trxn_id) as action
384 FROM civicrm_contribution con
385 LEFT JOIN civicrm_entity_financial_trxn eft
386 ON (eft.entity_table = 'civicrm_contribution' AND eft.entity_id = con.id)
387 LEFT JOIN {$tempTableName1} tpi
388 ON con.payment_instrument_id = tpi.instrument_id
389 WHERE con.contribution_status_id IN ({$completedStatus}, {$cancelledStatus})";
390 CRM_Core_DAO
::executeQuery($sql);
392 $sql = "ALTER TABLE {$tempTableName2} ADD INDEX index_action (action);";
393 CRM_Core_DAO
::executeQuery($sql);
395 //handling for completed contribution and cancelled contribution
396 //insertion of new records
398 INSERT INTO civicrm_financial_trxn
399 (contribution_id, payment_instrument_id, currency, total_amount, net_amount, fee_amount, trxn_id, status_id, check_number,
400 to_financial_account_id, from_financial_account_id, trxn_date)
401 SELECT tempI.contribution_id, tempI.payment_instrument_id, tempI.currency, tempI.total_amount, tempI.net_amount,
402 tempI.fee_amount, tempI.trxn_id, tempI.contribution_status_id, tempI.check_number,
403 tempI.to_financial_account_id, tempI.from_financial_account_id, tempI.trxn_date
404 FROM {$tempTableName2} tempI
405 WHERE tempI.action = 'insert';";
406 CRM_Core_DAO
::executeQuery($sql);
408 //update of existing records
410 UPDATE civicrm_financial_trxn ft
411 INNER JOIN {$tempTableName2} tempU
412 ON (tempU.action != 'insert' AND ft.id = tempU.action)
413 SET ft.from_financial_account_id = NULL,
414 ft.to_financial_account_id = tempU.to_financial_account_id,
415 ft.status_id = tempU.contribution_status_id,
416 ft.payment_instrument_id = tempU.payment_instrument_id,
417 ft.check_number = tempU.check_number,
418 ft.contribution_id = tempU.contribution_id;";
419 CRM_Core_DAO
::executeQuery($sql);
421 //insert the -ve transaction rows for cancelled contributions
423 INSERT INTO civicrm_financial_trxn
424 (contribution_id, payment_instrument_id, currency, total_amount, net_amount, fee_amount, trxn_id, status_id,
425 check_number, to_financial_account_id, from_financial_account_id, trxn_date)
426 SELECT ft.contribution_id, ft.payment_instrument_id, ft.currency, -ft.total_amount, ft.net_amount, ft.fee_amount, ft.trxn_id,
427 ft.status_id, ft.check_number, ft.to_financial_account_id, ft.from_financial_account_id, ft.trxn_date
428 FROM civicrm_financial_trxn ft
429 WHERE ft.status_id = {$cancelledStatus};";
430 CRM_Core_DAO
::executeQuery($sql);
432 //inserting entity financial trxn entries if its not present in entity_financial_trxn for completed and pending contribution statuses
433 //this also handles +ve and -ve both transaction entries for a cancelled contribution
435 INSERT INTO civicrm_entity_financial_trxn (entity_table, entity_id, financial_trxn_id, amount)
436 SELECT 'civicrm_contribution', ft.contribution_id, ft.id, ft.total_amount as amount
437 FROM civicrm_financial_trxn ft
438 WHERE contribution_id IS NOT NULL AND
439 ft.id NOT IN (SELECT financial_trxn_id
440 FROM civicrm_entity_financial_trxn
441 WHERE entity_table = 'civicrm_contribution'
442 AND entity_id = ft.contribution_id)";
443 CRM_Core_DAO
::executeQuery($sql);
444 //end of adding financial_trxn records and entity_financial_trxn records related to contribution
446 //update all linked line_item rows
447 // set line_item.financial_type_id = contribution.financial_type_id if contribution page id is null and not participant line item
448 // set line_item.financial_type_id = price_field_value.financial_type_id if contribution page id is set and not participant line item
449 // set line_item.financial_type_id = event.financial_type_id if its participant line item and line_item.price_field_value_id is null
450 // 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
451 $updateLineItemSql = "
452 UPDATE civicrm_line_item li
453 LEFT JOIN civicrm_contribution con
454 ON (li.entity_id = con.id AND li.entity_table = 'civicrm_contribution')
455 LEFT JOIN civicrm_price_field_value cpfv
456 ON li.price_field_value_id = cpfv.id
457 LEFT JOIN civicrm_participant cp
458 ON (li.entity_id = cp.id AND li.entity_table = 'civicrm_participant')
459 LEFT JOIN civicrm_event ce
460 ON ce.id = cp.event_id
461 SET li.financial_type_id = CASE
462 WHEN (con.contribution_page_id IS NULL || li.price_field_value_id IS NULL) AND cp.id IS NULL THEN
463 con.financial_type_id
464 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
465 cpfv.financial_type_id
466 WHEN cp.id IS NOT NULL AND li.price_field_value_id IS NULL THEN
469 CRM_Core_DAO
::executeQuery($updateLineItemSql, $queryParams);
471 //add the financial_item entries
472 //add a temp column so that inserting entity_financial_trxn entries gets easy
473 $sql = "ALTER TABLE civicrm_financial_item ADD COLUMN f_trxn_id INT DEFAULT NULL";
474 CRM_Core_DAO
::executeQuery($sql);
476 //add financial_item entries for contribution completed / pending pay later / cancelled
477 $contributionlineItemSql = "
478 INSERT INTO civicrm_financial_item
479 (transaction_date, contact_id, amount, currency, entity_table, entity_id, description, status_id, financial_account_id, f_trxn_id)
481 SELECT REPLACE(REPLACE(REPLACE(ft.trxn_date, '-', ''), ':', ''), ' ', ''), con.contact_id,
482 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',
483 li.id as line_item_id, li.label as line_item_label,
484 IF(con.contribution_status_id = {$pendingStatus}, {$unpaidStatus}, {$paidStatus}) as status_id, efa.financial_account_id as financial_account_id,
486 FROM civicrm_line_item li
487 INNER JOIN civicrm_contribution con
488 ON (li.entity_id = con.id AND li.entity_table = 'civicrm_contribution')
489 INNER JOIN civicrm_financial_trxn ft
490 ON (con.id = ft.contribution_id)
491 LEFT JOIN civicrm_entity_financial_account efa
492 ON (li.financial_type_id = efa.entity_id AND efa.entity_table = 'civicrm_financial_type'
493 AND efa.account_relationship = {$incomeAccountIs})
494 WHERE con.contribution_status_id IN (%1, %3) OR (con.is_pay_later = 1 AND con.contribution_status_id = %2)";
495 CRM_Core_DAO
::executeQuery($contributionlineItemSql, $queryParams);
497 //add financial_item entries for event
498 $participantLineItemSql = "
499 INSERT INTO civicrm_financial_item
500 (transaction_date, contact_id, amount, currency, entity_table, entity_id, description, status_id, financial_account_id, f_trxn_id)
502 SELECT REPLACE(REPLACE(REPLACE(ft.trxn_date, '-', ''), ':', ''), ' ', ''), con.contact_id,
503 IF(ft.total_amount < 0 AND con.contribution_status_id = %3, -li.line_total, li.line_total) as line_total,
504 con.currency, 'civicrm_line_item', li.id as line_item_id, li.label as line_item_label,
505 IF(con.contribution_status_id = {$pendingStatus}, {$unpaidStatus}, {$paidStatus}) as status_id,
506 efa.financial_account_id as financial_account_id, ft.id as f_trxn_id
507 FROM civicrm_line_item li
508 INNER JOIN civicrm_participant par
509 ON (li.entity_id = par.id AND li.entity_table = 'civicrm_participant')
510 INNER JOIN civicrm_participant_payment pp
511 ON (pp.participant_id = par.id)
512 INNER JOIN civicrm_contribution con
513 ON (pp.contribution_id = con.id)
514 INNER JOIN civicrm_financial_trxn ft
515 ON (con.id = ft.contribution_id)
516 LEFT JOIN civicrm_entity_financial_account efa
517 ON (li.financial_type_id = efa.entity_id AND
518 efa.entity_table = 'civicrm_financial_type' AND efa.account_relationship = {$incomeAccountIs})
519 WHERE con.contribution_status_id IN (%1, %3) OR (con.is_pay_later = 1 AND con.contribution_status_id = %2)";
520 CRM_Core_DAO
::executeQuery($participantLineItemSql, $queryParams);
522 //fee handling for contributions
523 //insert fee entries in financial_trxn for contributions
524 $sql = "ALTER TABLE civicrm_financial_trxn ADD COLUMN is_fee TINYINT DEFAULT NULL";
525 CRM_Core_DAO
::executeQuery($sql);
528 INSERT INTO civicrm_financial_trxn
529 (contribution_id, payment_instrument_id, currency, total_amount, net_amount, fee_amount, trxn_id, status_id, check_number,
530 to_financial_account_id, from_financial_account_id, trxn_date, payment_processor_id, is_fee)
532 SELECT con.id, ft.payment_instrument_id, ft.currency, ft.fee_amount, NULL, NULL, ft.trxn_id, %1 as status_id,
533 ft.check_number, efaFT.financial_account_id as to_financial_account_id, CASE
534 WHEN efaPP.financial_account_id IS NOT NULL THEN
535 efaPP.financial_account_id
536 WHEN tpi.financial_account_id IS NOT NULL THEN
537 tpi.financial_account_id
539 {$financialAccountId}
540 END as from_financial_account_id, ft.trxn_date, ft.payment_processor_id, 1 as is_fee
541 FROM civicrm_contribution con
542 INNER JOIN civicrm_financial_trxn ft
543 ON (ft.contribution_id = con.id)
544 LEFT JOIN civicrm_entity_financial_account efaFT
545 ON (con.financial_type_id = efaFT.entity_id AND efaFT.entity_table = 'civicrm_financial_type'
546 AND efaFT.account_relationship = {$expenseAccountIs})
547 LEFT JOIN civicrm_entity_financial_account efaPP
548 ON (ft.payment_processor_id = efaPP.entity_id AND efaPP.entity_table = 'civicrm_payment_processor'
549 AND efaPP.account_relationship = {$assetAccountIs})
550 LEFT JOIN {$tempTableName1} tpi
551 ON ft.payment_instrument_id = tpi.instrument_id
552 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))
554 CRM_Core_DAO
::executeQuery($sql, $queryParams);
556 //link financial_trxn to contribution
558 INSERT INTO civicrm_entity_financial_trxn
559 (entity_table, entity_id, financial_trxn_id, amount)
560 SELECT 'civicrm_contribution', ft.contribution_id, ft.id, ft.total_amount
561 FROM civicrm_financial_trxn ft
562 WHERE ft.is_fee = 1";
563 CRM_Core_DAO
::executeQuery($sql);
565 //add fee related entries to financial item table
566 $domainId = CRM_Core_Config
::domainID();
567 $domainContactId = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_Domain', $domainId, 'contact_id');
569 INSERT INTO civicrm_financial_item
570 (transaction_date, contact_id, amount, currency, entity_table, entity_id, description, status_id, financial_account_id, f_trxn_id)
571 SELECT ft.trxn_date, {$domainContactId} as contact_id, ft.total_amount, ft.currency, 'civicrm_financial_trxn', ft.id,
572 'Fee', {$paidStatus} as status_id, ft.to_financial_account_id as financial_account_id, ft.id as f_trxn_id
573 FROM civicrm_financial_trxn ft
574 WHERE ft.is_fee = 1;";
575 CRM_Core_DAO
::executeQuery($sql);
577 //add entries to entity_financial_trxn table
579 INSERT INTO civicrm_entity_financial_trxn (entity_table, entity_id, financial_trxn_id, amount)
580 SELECT 'civicrm_financial_item' as entity_table, fi.id as entity_id, fi.f_trxn_id as financial_trxn_id, fi.amount
581 FROM civicrm_financial_item fi";
582 CRM_Core_DAO
::executeQuery($sql);
584 //drop the temparory columns
585 $sql = "ALTER TABLE civicrm_financial_trxn
586 DROP COLUMN contribution_id,
587 DROP COLUMN is_fee;";
588 CRM_Core_DAO
::executeQuery($sql);
590 $sql = "ALTER TABLE civicrm_financial_item DROP f_trxn_id";
591 CRM_Core_DAO
::executeQuery($sql);
596 function createDomainContacts() {
597 $domainParams = $context = array();
599 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',
600 ADD CONSTRAINT `FK_civicrm_domain_contact_id` FOREIGN KEY (`contact_id`) REFERENCES `civicrm_contact` (`id`);";
601 CRM_Core_DAO
::executeQuery($query, CRM_Core_DAO
::$_nullArray, TRUE, NULL, FALSE, FALSE);
603 $query = 'SELECT cd.id, cd.name, ce.email FROM `civicrm_domain` cd
604 LEFT JOIN civicrm_loc_block clb ON clb.id = cd. loc_block_id
605 LEFT JOIN civicrm_email ce ON ce.id = clb.email_id ;' ;
606 $dao = CRM_Core_DAO
::executeQuery($query);
607 while($dao->fetch()) {
609 'sort_name' => $dao->name
,
610 'display_name' => $dao->name
,
611 'legal_name' => $dao->name
,
612 'organization_name' => $dao->name
,
613 'contact_type' => 'Organization'
615 $query = "SELECT cc.id FROM `civicrm_contact` cc
616 LEFT JOIN civicrm_email ce ON ce.contact_id = cc.id
617 WHERE cc.contact_type = 'Organization' AND cc.organization_name = '{$dao->name}' ";
619 $query .= " AND ce.email = '{$dao->email}' ";
621 $contactID = CRM_Core_DAO
::singleValueQuery($query);
622 $context[1] = $dao->name
;
623 if (empty($contactID)) {
624 $contact = CRM_Contact_BAO_Contact
::add($params);
625 $contactID = $contact->id
;
626 $context[0] = 'added';
629 $context[0] = 'merged';
631 $domainParams['contact_id'] = $contactID;
632 CRM_Core_BAO_Domain
::edit($domainParams, $dao->id
);
637 function task_4_3_alpha1_checkDBConstraints() {
638 //checking whether the foreign key exists before dropping it CRM-11260
639 $config = CRM_Core_Config
::singleton();
640 $dbUf = DB
::parseDSN($config->dsn
);
643 'autorenewal_msg_id' => array('tableName' => 'civicrm_membership_type', 'fkey' => 'FK_civicrm_membership_autorenewal_msg_id'),
644 'to_account_id' => array('tableName' => 'civicrm_financial_trxn', 'constraintName' => 'civicrm_financial_trxn_ibfk_2'),
645 'from_account_id' => array('tableName' => 'civicrm_financial_trxn', 'constraintName' => 'civicrm_financial_trxn_ibfk_1'),
646 'contribution_type_id' => array('tableName' => 'civicrm_contribution_recur', 'fkey' => 'FK_civicrm_contribution_recur_contribution_type_id'),
648 $query = "SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
649 WHERE table_name = 'civicrm_contribution_recur'
650 AND constraint_name = 'FK_civicrm_contribution_recur_contribution_type_id'
651 AND TABLE_SCHEMA = '{$dbUf['database']}'";
653 $dao = CRM_Core_DAO
::executeQuery($query, $params, TRUE, NULL, FALSE, FALSE);
654 foreach($tables as $columnName => $value){
655 if ($value['tableName'] == 'civicrm_membership_type' ||
$value['tableName'] == 'civicrm_contribution_recur') {
656 $foreignKeyExists = CRM_Core_DAO
::checkConstraintExists($value['tableName'], $value['fkey']);
657 $fKey = $value['fkey'];
659 $foreignKeyExists = CRM_Core_DAO
::checkFKConstraintInFormat($value['tableName'], $columnName);
660 $fKey = "`FK_{$value['tableName']}_{$columnName}`";
662 if ($foreignKeyExists ||
$value['tableName'] == 'civicrm_financial_trxn') {
663 if ($value['tableName'] != 'civicrm_contribution_recur' ||
($value['tableName'] == 'civicrm_contribution_recur' && $dao->N
)) {
664 $constraintName = $foreignKeyExists ?
$fKey : $value['constraintName'];
665 CRM_Core_DAO
::executeQuery("ALTER TABLE {$value['tableName']} DROP FOREIGN KEY {$constraintName}", $params, TRUE, NULL, FALSE, FALSE);
667 CRM_Core_DAO
::executeQuery("ALTER TABLE {$value['tableName']} DROP INDEX {$fKey}", $params, TRUE, NULL, FALSE, FALSE);
670 // check if column contact_id is present or not in civicrm_financial_account
671 $fieldExists = CRM_Core_DAO
::checkFieldExists('civicrm_financial_account', 'contact_id', FALSE);
673 $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);";
674 CRM_Core_DAO
::executeQuery($query, $params, TRUE, NULL, FALSE, FALSE);
679 * Read creation and modification times from civicrm_log; add
680 * them to civicrm_contact.
682 function convertTimestamps(CRM_Queue_TaskContext
$ctx, $startId, $endId) {
684 SELECT entity_id, min(modified_date) AS created, max(modified_date) AS modified
686 WHERE entity_table = 'civicrm_contact'
687 AND entity_id BETWEEN %1 AND %2
691 1 => array($startId, 'Integer'),
692 2 => array($endId, 'Integer'),
694 $dao = CRM_Core_DAO
::executeQuery($sql, $params);
695 while ($dao->fetch()) {
696 // FIXME civicrm_log.modified_date is DATETIME; civicrm_contact.modified_date is TIMESTAMP
697 CRM_Core_DAO
::executeQuery(
698 'UPDATE civicrm_contact SET created_date = %1, modified_date = %2 WHERE id = %3',
700 1 => array($dao->created
, 'String'),
701 2 => array($dao->modified
, 'String'),
702 3 => array($dao->entity_id
, 'Integer'),
711 * replace contribution_type to financial_type in table
712 * civicrm_saved_search and Structure civicrm_report_instance
714 function replaceContributionTypeId(CRM_Queue_TaskContext
$ctx, $query, $table) {
715 $dao = CRM_Core_DAO
::executeQuery($query);
716 while ($dao->fetch()) {
717 $formValues = unserialize($dao->form_values
);
718 foreach (array('contribution_type_id_op', 'contribution_type_id_value', 'contribution_type_id') as $value) {
719 if (array_key_exists($value, $formValues)) {
720 $key = preg_replace('/contribution/', 'financial', $value);
721 $formValues[$key] = $formValues[$value];
722 unset($formValues[$value]);
725 if ($table != 'savedSearch') {
726 foreach (array('fields', 'group_bys') as $value) {
727 if (array_key_exists($value, $formValues)) {
728 if (array_key_exists('contribution_type_id', $formValues[$value])) {
729 $formValues[$value]['financial_type_id'] = $formValues[$value]['contribution_type_id'];
730 unset($formValues[$value]['contribution_type_id']);
732 else if (array_key_exists('contribution_type', $formValues[$value])) {
733 $formValues[$value]['financial_type'] = $formValues[$value]['contribution_type'];
734 unset($formValues[$value]['contribution_type']);
738 if (array_key_exists('order_bys', $formValues)) {
739 foreach ($formValues['order_bys'] as $key => $values) {
740 if (preg_grep('/contribution_type/', $values)) {
741 $formValues['order_bys'][$key]['column'] = preg_replace('/contribution_type/', 'financial_type', $values['column']);
747 if ($table == 'savedSearch') {
748 $saveDao = new CRM_Contact_DAO_SavedSearch();
751 $saveDao = new CRM_Report_DAO_Instance();
753 $saveDao->id
= $dao->id
;
755 if ($table == 'savedSearch') {
756 if (array_key_exists('mapper', $formValues)) {
757 foreach ($formValues['mapper'] as $key => $values) {
758 foreach ($values as $k => $v) {
759 if (preg_grep('/contribution_/', $v)) {
760 $formValues['mapper'][$key][$k] = preg_replace('/contribution_type/', 'financial_type', $v);
765 foreach (array('select_tables', 'where_tables') as $value) {
766 if (preg_match('/contribution_type/', $dao->$value)) {
767 $tempValue = unserialize($dao->$value);
768 if (array_key_exists('civicrm_contribution_type', $tempValue)) {
769 $tempValue['civicrm_financial_type'] = $tempValue['civicrm_contribution_type'];
770 unset($tempValue['civicrm_contribution_type']);
772 $saveDao->$value = serialize($tempValue);
775 if (preg_match('/contribution_type/', $dao->where_clause
)) {
776 $saveDao->where_clause
= preg_replace('/contribution_type/', 'financial_type', $dao->where_clause
);
779 $saveDao->form_values
= serialize($formValues);
787 * Check/Add INDEX CRM-12141
789 * @return bool TRUE for success
791 function task_4_3_x_checkIndexes(CRM_Queue_TaskContext
$ctx) {
792 $query = "SHOW KEYS FROM `civicrm_entity_financial_trxn`
793 WHERE key_name IN ('UI_entity_financial_trxn_entity_table', 'UI_entity_financial_trxn_entity_id');";
794 $dao = CRM_Core_DAO
::executeQuery($query);
796 CRM_Core_DAO
::executeQuery("ALTER TABLE civicrm_entity_financial_trxn
797 ADD INDEX UI_entity_financial_trxn_entity_table (entity_table),
798 ADD INDEX UI_entity_financial_trxn_entity_id (entity_id);");
804 * Update phones CRM-11292
806 * @return bool TRUE for success
808 static function phoneNumeric(CRM_Queue_TaskContext
$ctx) {
809 CRM_Core_DAO
::executeQuery(CRM_Contact_BAO_Contact
::DROP_STRIP_FUNCTION_43
);
810 CRM_Core_DAO
::executeQuery(CRM_Contact_BAO_Contact
::CREATE_STRIP_FUNCTION_43
);
811 CRM_Core_DAO
::executeQuery("UPDATE civicrm_phone SET phone_numeric = civicrm_strip_non_numeric(phone)");
816 * (Queue Task Callback)
818 static function task_4_3_x_runSql(CRM_Queue_TaskContext
$ctx, $rev) {
819 $upgrade = new CRM_Upgrade_Form();
820 $upgrade->processSQL($rev);
826 * Syntatic sugar for adding a task which (a) is in this class and (b) has
829 * After passing the $funcName, you can also pass parameters that will go to
830 * the function. Note that all params must be serializable.
832 protected function addTask($title, $funcName) {
833 $queue = CRM_Queue_Service
::singleton()->load(array(
835 'name' => CRM_Upgrade_Form
::QUEUE_NAME
,
838 $args = func_get_args();
839 $title = array_shift($args);
840 $funcName = array_shift($args);
841 $task = new CRM_Queue_Task(
842 array(get_class($this), $funcName),
846 $queue->createItem($task, array('weight' => -1));