Merge pull request #248 from pradpnayak/CRM-12155
[civicrm-core.git] / CRM / Upgrade / Incremental / php / FourThree.php
1 <?php
2
3 /*
4 +--------------------------------------------------------------------+
5 | CiviCRM version 4.3 |
6 +--------------------------------------------------------------------+
7 | Copyright CiviCRM LLC (c) 2004-2013 |
8 +--------------------------------------------------------------------+
9 | This file is a part of CiviCRM. |
10 | |
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. |
14 | |
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. |
19 | |
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 +--------------------------------------------------------------------+
26 */
27
28 /**
29 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2013
32 * $Id$
33 *
34 */
35 class CRM_Upgrade_Incremental_php_FourThree {
36 const BATCH_SIZE = 5000;
37
38 function verifyPreDBstate(&$errors) {
39 return TRUE;
40 }
41
42 /**
43 * Compute any messages which should be displayed beforeupgrade
44 *
45 * Note: This function is called iteratively for each upcoming
46 * revision to the database.
47 *
48 * @param $postUpgradeMessage string, alterable
49 * @param $rev string, a version number, e.g. '4.3.alpha1', '4.3.beta3', '4.3.0'
50 * @return void
51 */
52 function setPreUpgradeMessage(&$preUpgradeMessage, $rev, $currentVer = NULL) {
53 if ($rev == '4.3.beta3') {
54 //CRM-12084
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);
58
59 if ($count > 0) {
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);
62 return FALSE;
63 }
64 }
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();
69 if (
70 !isset($theme_registry['page']['preprocess functions']) ||
71 FALSE === array_search('civicrm_preprocess_page_inject', $theme_registry['page']['preprocess functions'])
72 ) {
73 CRM_Core_Error::fatal('Please reset the Drupal cache (Administer => Site Configuration => Performance => Clear cached data))');
74 }
75 }
76 // CRM-12155
77 if ($rev == '4.3.beta5') {
78 $query = "SELECT ceft.id FROM `civicrm_financial_trxn` cft
79 LEFT JOIN civicrm_entity_financial_trxn ceft
80 ON ceft.financial_trxn_id = cft.id AND ceft.entity_table = 'civicrm_contribution'
81 LEFT JOIN civicrm_contribution cc ON cc.id = ceft.entity_id AND ceft.entity_table = 'civicrm_contribution'
82 WHERE cc.id IS NULL";
83
84 $dao = CRM_Core_DAO::executeQuery($query);
85 $isOrphanData = TRUE;
86 if (!$dao->N) {
87 $query = "SELECT cli.id FROM civicrm_line_item cli
88 LEFT JOIN civicrm_contribution cc ON cli.entity_id = cc.id AND cli.entity_table = 'civicrm_contribution'
89 LEFT JOIN civicrm_participant cp ON cli.entity_id = cp.id AND cli.entity_table = 'civicrm_participant'
90 WHERE CASE WHEN cli.entity_table = 'civicrm_contribution'
91 THEN cc.id IS NULL
92 ELSE cp.id IS NULL
93 END";
94 $dao = CRM_Core_DAO::executeQuery($query);
95 if (!$dao->N) {
96 $revPattern = '/^((\d{1,2})\.\d{1,2})\.(\d{1,2}|\w{4,7})?$/i';
97 preg_match($revPattern, $currentVer, $version);
98 if ($version[1] >= 4.3) {
99 $query = "SELECT cfi.id FROM civicrm_financial_item cfi
100 LEFT JOIN civicrm_entity_financial_trxn ceft ON ceft.entity_table = 'civicrm_financial_item' and cfi.id = ceft.entity_id
101 WHERE ceft.entity_id IS NULL;";
102 $dao = CRM_Core_DAO::executeQuery($query);
103 if (!$dao->N) {
104 $isOrphanData = FALSE;
105 }
106 }
107 else {
108 $isOrphanData = FALSE;
109 }
110 }
111 }
112
113 if ($isOrphanData) {
114 $preUpgradeMessage = "</br> <strong>" . ts('Your database contains orphaned financial records related to deleted contributions. Refer to <a href="%1">this wiki page for instructions on repairing your database</a> so that you can run the upgrade successfully.
115 ', array( 1 => 'http://wiki.civicrm.org/confluence/display/CRMDOC43/Database+repair+for+4.3+upgrades')) . "</strong>";
116 }
117 }
118 }
119
120 /**
121 * Compute any messages which should be displayed after upgrade
122 *
123 * @param $postUpgradeMessage string, alterable
124 * @param $rev string, an intermediate version; note that setPostUpgradeMessage is called repeatedly with different $revs
125 * @return void
126 */
127 function setPostUpgradeMessage(&$postUpgradeMessage, $rev) {
128 if ($rev == '4.3.alpha1') {
129 // check if CiviMember component is enabled
130 $config = CRM_Core_Config::singleton();
131 if (in_array('CiviMember', $config->enableComponents)) {
132 $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.');
133 $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 }
135
136 //CRM-11636
137 //here we do the financial type check and migration
138 $isDefaultsModified = self::_checkAndMigrateDefaultFinancialTypes();
139 if($isDefaultsModified) {
140 $postUpgradeMessage .= '<br />' . ts('Please review all price set financial type assignments.');
141 }
142 list($context, $orgName) = self::createDomainContacts();
143 if ($context == 'added') {
144 $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}'.");
145 }
146 elseif ($context == 'merged') {
147 $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.");
148 }
149
150 $providerExists = CRM_Core_DAO::singleValueQuery("SELECT id FROM civicrm_sms_provider LIMIT 1");
151 if ($providerExists) {
152 $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 }
154 }
155
156 if ($rev == '4.3.alpha2') {
157 $sql = "
158 SELECT title, id
159 FROM civicrm_action_schedule
160 WHERE entity_value = '' OR entity_value IS NULL
161 ";
162
163 $dao = CRM_Core_DAO::executeQuery($sql);
164 $reminder = array();
165 $list = '';
166 while ($dao->fetch()) {
167 $reminder[$dao->id] = $dao->title;
168 $list .= "<li>{$dao->title}</li>";
169 }
170 if (!empty($reminder)) {
171 $list = "<br /><ul>" . $list . "</ul>";
172 $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));
173 }
174 }
175
176 if ($rev == '4.3.beta2') {
177 $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).');
178 }
179 }
180
181 function upgrade_4_3_alpha1($rev) {
182 self::task_4_3_alpha1_checkDBConstraints();
183
184 // add indexes for civicrm_entity_financial_trxn
185 // CRM-12141
186 $this->addTask(ts('Check/Add indexes for civicrm_entity_financial_trxn'), 'task_4_3_x_checkIndexes', $rev);
187 // task to process sql
188 $this->addTask(ts('Upgrade DB to 4.3.alpha1: SQL'), 'task_4_3_x_runSql', $rev);
189
190 //CRM-11636
191 $this->addTask(ts('Populate financial type values for price records'), 'assignFinancialTypeToPriceRecords');
192 //CRM-11514 create financial records for contributions
193 $this->addTask(ts('Create financial records for contributions'), 'createFinancialRecords');
194
195 $minId = CRM_Core_DAO::singleValueQuery('SELECT coalesce(min(id),0) FROM civicrm_contact');
196 $maxId = CRM_Core_DAO::singleValueQuery('SELECT coalesce(max(id),0) FROM civicrm_contact');
197 for ($startId = $minId; $startId <= $maxId; $startId += self::BATCH_SIZE) {
198 $endId = $startId + self::BATCH_SIZE - 1;
199 $title = ts('Upgrade timestamps (%1 => %2)', array(
200 1 => $startId,
201 2 => $endId,
202 ));
203 $this->addTask($title, 'convertTimestamps', $startId, $endId);
204 }
205
206 // CRM-10893
207 // fix WP access control
208 $config = CRM_Core_Config::singleton( );
209 if ($config->userFramework == 'WordPress') {
210 civicrm_wp_set_capabilities( );
211 }
212
213 // Update phones CRM-11292.
214 $this->addTask(ts('Upgrade Phone Numbers'), 'phoneNumeric');
215
216 return TRUE;
217 }
218
219 function upgrade_4_3_alpha2($rev) {
220 //CRM-11847
221 $isColumnPresent = CRM_Core_DAO::checkFieldExists('civicrm_dedupe_rule_group', 'is_default');
222 if ($isColumnPresent) {
223 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_dedupe_rule_group DROP COLUMN is_default');
224 }
225 $this->addTask(ts('Upgrade DB to 4.3.alpha2: SQL'), 'task_4_3_x_runSql', $rev);
226 }
227
228 function upgrade_4_3_alpha3($rev) {
229 $this->addTask(ts('Upgrade DB to 4.3.alpha3: SQL'), 'task_4_3_x_runSql', $rev);
230 }
231
232 function upgrade_4_3_beta2($rev) {
233 $this->addTask(ts('Upgrade DB to 4.3.beta2: SQL'), 'task_4_3_x_runSql', $rev);
234
235 // CRM-12002
236 if (
237 CRM_Core_DAO::checkTableExists('log_civicrm_line_item') &&
238 CRM_Core_DAO::checkFieldExists('log_civicrm_line_item', 'label')
239 ) {
240 CRM_Core_DAO::executeQuery('ALTER TABLE `log_civicrm_line_item` CHANGE `label` `label` VARCHAR(255) NULL DEFAULT NULL');
241 }
242 }
243
244 function upgrade_4_3_beta3($rev) {
245 $this->addTask(ts('Upgrade DB to 4.3.beta3: SQL'), 'task_4_3_x_runSql', $rev);
246 // CRM-12065
247 $query = "SELECT id, form_values FROM civicrm_report_instance WHERE form_values LIKE '%contribution_type%'";
248 $this->addTask('Replace contribution_type to financial_type in table civicrm_report_instance', 'replaceContributionTypeId', $query, 'reportInstance');
249 $query = "SELECT * FROM civicrm_saved_search WHERE form_values LIKE '%contribution_type%'";
250 $this->addTask('Replace contribution_type to financial_type in table civicrm_saved_search', 'replaceContributionTypeId', $query, 'savedSearch');
251 }
252
253 function upgrade_4_3_beta4($rev) {
254 $this->addTask(ts('Upgrade DB to 4.3.beta4: SQL'), 'task_4_3_x_runSql', $rev);
255 // add indexes for civicrm_entity_financial_trxn
256 // CRM-12141
257 $this->addTask(ts('Check/Add indexes for civicrm_entity_financial_trxn'), 'task_4_3_x_checkIndexes', $rev);
258 }
259
260 function upgrade_4_3_beta5($rev) {
261 $this->addTask(ts('Upgrade DB to 4.3.beta5: SQL'), 'task_4_3_x_runSql', $rev);
262 // CRM-12205
263 if (
264 CRM_Core_DAO::checkTableExists('log_civicrm_financial_trxn') &&
265 CRM_Core_DAO::checkFieldExists('log_civicrm_financial_trxn', 'trxn_id')
266 ) {
267 CRM_Core_DAO::executeQuery('ALTER TABLE `log_civicrm_financial_trxn` CHANGE `trxn_id` `trxn_id` VARCHAR(255) NULL DEFAULT NULL');
268 }
269 }
270
271 //CRM-11636
272 function assignFinancialTypeToPriceRecords() {
273 $upgrade = new CRM_Upgrade_Form();
274 //here we update price set entries
275 $sqlFinancialIds = "SELECT id, name FROM civicrm_financial_type
276 WHERE name IN ('Donation', 'Event Fee', 'Member Dues');";
277 $daoFinancialIds = CRM_Core_DAO::executeQuery($sqlFinancialIds);
278 while($daoFinancialIds->fetch()) {
279 $financialIds[$daoFinancialIds->name] = $daoFinancialIds->id;
280 }
281 $sqlPriceSetUpdate = "UPDATE civicrm_price_set ps
282 SET ps.financial_type_id = CASE
283 WHEN ps.extends LIKE '%1%' THEN {$financialIds['Event Fee']}
284 WHEN ps.extends LIKE '2' THEN {$financialIds['Donation']}
285 WHEN ps.extends LIKE '3' THEN {$financialIds['Member Dues']}
286 END
287 WHERE financial_type_id IS NULL";
288 CRM_Core_DAO::executeQuery($sqlPriceSetUpdate);
289
290 //here we update price field value rows
291 $sqlPriceFieldValueUpdate = "UPDATE civicrm_price_field_value pfv
292 LEFT JOIN civicrm_membership_type mt ON (pfv.membership_type_id = mt.id)
293 INNER JOIN civicrm_price_field pf ON (pfv.price_field_id = pf.id)
294 INNER JOIN civicrm_price_set ps ON (pf.price_set_id = ps.id)
295 SET pfv.financial_type_id = CASE
296 WHEN pfv.membership_type_id IS NOT NULL THEN mt.financial_type_id
297 WHEN pfv.membership_type_id IS NULL THEN ps.financial_type_id
298 END";
299 CRM_Core_DAO::executeQuery($sqlPriceFieldValueUpdate);
300
301 return TRUE;
302 }
303
304 static function _checkAndMigrateDefaultFinancialTypes() {
305 $modifiedDefaults = FALSE;
306 //insert types if not exists
307 $sqlFetchTypes = "SELECT id, name FROM civicrm_contribution_type
308 WHERE name IN ('Donation', 'Event Fee', 'Member Dues') AND is_active =1;";
309 $daoFetchTypes = CRM_Core_DAO::executeQuery($sqlFetchTypes);
310
311 if ($daoFetchTypes->N < 3) {
312 $modifiedDefaults = TRUE;
313 $insertStatments = array (
314 'Donation' => "('Donation', 0, 1, 1)",
315 'Member' => "('Member Dues', 0, 1, 1)",
316 'Event Fee' => "('Event Fee', 0, 1, 0)",
317 );
318 foreach ($insertStatments as $values) {
319 $query = "INSERT INTO civicrm_contribution_type (name, is_reserved, is_active, is_deductible)
320 VALUES $values
321 ON DUPLICATE KEY UPDATE is_active = 1;";
322 CRM_Core_DAO::executeQuery($query);
323 }
324 }
325 return $modifiedDefaults;
326 }
327
328 function createFinancialRecords() {
329 $upgrade = new CRM_Upgrade_Form();
330
331 // update civicrm_entity_financial_trxn.amount = civicrm_financial_trxn.total_amount
332 $query = "UPDATE civicrm_entity_financial_trxn ceft
333 LEFT JOIN civicrm_financial_trxn cft ON cft.id = ceft.financial_trxn_id
334 SET ceft.amount = total_amount
335 WHERE cft.net_amount IS NOT NULL AND ceft.entity_table = 'civicrm_contribution';";
336 CRM_Core_DAO::executeQuery($query);
337
338 $contributionStatus = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
339 $completedStatus = array_search('Completed', $contributionStatus);
340 $pendingStatus = array_search('Pending', $contributionStatus);
341 $cancelledStatus = array_search('Cancelled', $contributionStatus);
342 $queryParams = array(
343 1 => array($completedStatus, 'Integer'),
344 2 => array($pendingStatus, 'Integer'),
345 3 => array($cancelledStatus, 'Integer')
346 );
347
348 $accountType = key(CRM_Core_PseudoConstant::accountOptionValues('financial_account_type', NULL, " AND v.name = 'Asset' "));
349 $financialAccountId =
350 CRM_Core_DAO::singleValueQuery("SELECT id FROM civicrm_financial_account WHERE is_default = 1 AND financial_account_type_id = {$accountType}");
351
352 $accountRelationsips = CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL);
353
354 $accountsReceivableAccount = array_search('Accounts Receivable Account is', $accountRelationsips);
355 $incomeAccountIs = array_search('Income Account is', $accountRelationsips);
356 $assetAccountIs = array_search('Asset Account is', $accountRelationsips);
357 $expenseAccountIs = array_search('Expense Account is', $accountRelationsips);
358
359 $financialItemStatus = CRM_Core_PseudoConstant::accountOptionValues('financial_item_status');
360 $unpaidStatus = array_search('Unpaid', $financialItemStatus);
361 $paidStatus = array_search('Paid', $financialItemStatus);
362
363 $validCurrencyCodes = CRM_Core_PseudoConstant::currencyCode();
364 $validCurrencyCodes = implode("','", $validCurrencyCodes);
365 $config = CRM_Core_Config::singleton();
366 $defaultCurrency = $config->defaultCurrency;
367 $now = date( 'YmdHis' );
368
369 //adding financial_trxn records and entity_financial_trxn records related to contribution
370 //Add temp column for easy entry in entity_financial_trxn
371 $sql = "ALTER TABLE civicrm_financial_trxn ADD COLUMN contribution_id INT DEFAULT NULL";
372 CRM_Core_DAO::executeQuery($sql);
373
374 //pending pay later status handling
375 $sql = "
376 INSERT INTO civicrm_financial_trxn
377 (contribution_id, payment_instrument_id, currency, total_amount, net_amount, fee_amount, trxn_id, status_id,
378 check_number, to_financial_account_id, from_financial_account_id, trxn_date)
379
380 SELECT con.id as contribution_id, con.payment_instrument_id, IF(con.currency IN ('{$validCurrencyCodes}'), con.currency, '{$defaultCurrency}')
381 as currency, con.total_amount, con.net_amount, con.fee_amount, con.trxn_id, con.contribution_status_id,
382 con.check_number, efa.financial_account_id as to_financial_account_id, NULL as from_financial_account_id,
383 REPLACE(REPLACE(REPLACE(
384 CASE
385 WHEN con.receive_date IS NOT NULL THEN
386 con.receive_date
387 WHEN con.receipt_date IS NOT NULL THEN
388 con.receipt_date
389 ELSE
390 {$now}
391 END
392 , '-', ''), ':', ''), ' ', '') as trxn_date
393 FROM civicrm_contribution con
394 LEFT JOIN civicrm_entity_financial_account efa
395 ON (con.financial_type_id = efa.entity_id AND efa.entity_table = 'civicrm_financial_type'
396 AND efa.account_relationship = {$accountsReceivableAccount})
397 WHERE con.is_pay_later = 1 AND con.contribution_status_id = {$pendingStatus}";
398 CRM_Core_DAO::executeQuery($sql);
399
400 //create a temp table to hold financial account id related to payment instruments
401 $tempTableName1 = CRM_Core_DAO::createTempTableName();
402
403 $sql = "CREATE TEMPORARY TABLE {$tempTableName1}
404
405 SELECT ceft.financial_account_id financial_account_id, cov.value as instrument_id
406 FROM civicrm_entity_financial_account ceft
407 INNER JOIN civicrm_option_value cov ON cov.id = ceft.entity_id AND ceft.entity_table = 'civicrm_option_value'
408 INNER JOIN civicrm_option_group cog ON cog.id = cov.option_group_id
409 WHERE cog.name = 'payment_instrument'";
410 CRM_Core_DAO::executeQuery($sql);
411 //CRM-12141
412 $sql = "ALTER TABLE {$tempTableName1} ADD INDEX index_instrument_id (instrument_id);";
413 CRM_Core_DAO::executeQuery($sql);
414
415 //create temp table to process completed / cancelled contribution
416 $tempTableName2 = CRM_Core_DAO::createTempTableName();
417 $sql = "CREATE TEMPORARY TABLE {$tempTableName2}
418
419 SELECT con.id as contribution_id, con.payment_instrument_id, IF(con.currency IN ('{$validCurrencyCodes}'), con.currency, '{$defaultCurrency}') as currency,
420 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,
421 REPLACE(REPLACE(REPLACE(
422 CASE
423 WHEN con.receive_date IS NOT NULL THEN
424 con.receive_date
425 WHEN con.receipt_date IS NOT NULL THEN
426 con.receipt_date
427 ELSE
428 {$now}
429 END
430 , '-', ''), ':', ''), ' ', '') as trxn_date,
431 CASE
432 WHEN con.payment_instrument_id IS NULL THEN
433 {$financialAccountId}
434 WHEN con.payment_instrument_id IS NOT NULL THEN
435 tpi.financial_account_id
436 END as to_financial_account_id,
437 IF(eft.financial_trxn_id IS NULL, 'insert', eft.financial_trxn_id) as action
438 FROM civicrm_contribution con
439 LEFT JOIN civicrm_entity_financial_trxn eft
440 ON (eft.entity_table = 'civicrm_contribution' AND eft.entity_id = con.id)
441 LEFT JOIN {$tempTableName1} tpi
442 ON con.payment_instrument_id = tpi.instrument_id
443 WHERE con.contribution_status_id IN ({$completedStatus}, {$cancelledStatus})";
444 CRM_Core_DAO::executeQuery($sql);
445 // CRM-12141
446 $sql = "ALTER TABLE {$tempTableName2} ADD INDEX index_action (action);";
447 CRM_Core_DAO::executeQuery($sql);
448
449 //handling for completed contribution and cancelled contribution
450 //insertion of new records
451 $sql = "
452 INSERT INTO civicrm_financial_trxn
453 (contribution_id, payment_instrument_id, currency, total_amount, net_amount, fee_amount, trxn_id, status_id, check_number,
454 to_financial_account_id, from_financial_account_id, trxn_date)
455 SELECT tempI.contribution_id, tempI.payment_instrument_id, tempI.currency, tempI.total_amount, tempI.net_amount,
456 tempI.fee_amount, tempI.trxn_id, tempI.contribution_status_id, tempI.check_number,
457 tempI.to_financial_account_id, tempI.from_financial_account_id, tempI.trxn_date
458 FROM {$tempTableName2} tempI
459 WHERE tempI.action = 'insert';";
460 CRM_Core_DAO::executeQuery($sql);
461
462 //update of existing records
463 $sql = "
464 UPDATE civicrm_financial_trxn ft
465 INNER JOIN {$tempTableName2} tempU
466 ON (tempU.action != 'insert' AND ft.id = tempU.action)
467 SET ft.from_financial_account_id = NULL,
468 ft.to_financial_account_id = tempU.to_financial_account_id,
469 ft.status_id = tempU.contribution_status_id,
470 ft.payment_instrument_id = tempU.payment_instrument_id,
471 ft.check_number = tempU.check_number,
472 ft.contribution_id = tempU.contribution_id;";
473 CRM_Core_DAO::executeQuery($sql);
474
475 //insert the -ve transaction rows for cancelled contributions
476 $sql = "
477 INSERT INTO civicrm_financial_trxn
478 (contribution_id, payment_instrument_id, currency, total_amount, net_amount, fee_amount, trxn_id, status_id,
479 check_number, to_financial_account_id, from_financial_account_id, trxn_date)
480 SELECT ft.contribution_id, ft.payment_instrument_id, ft.currency, -ft.total_amount, ft.net_amount, ft.fee_amount, ft.trxn_id,
481 ft.status_id, ft.check_number, ft.to_financial_account_id, ft.from_financial_account_id, ft.trxn_date
482 FROM civicrm_financial_trxn ft
483 WHERE ft.status_id = {$cancelledStatus};";
484 CRM_Core_DAO::executeQuery($sql);
485
486 //inserting entity financial trxn entries if its not present in entity_financial_trxn for completed and pending contribution statuses
487 //this also handles +ve and -ve both transaction entries for a cancelled contribution
488 $sql = "
489 INSERT INTO civicrm_entity_financial_trxn (entity_table, entity_id, financial_trxn_id, amount)
490 SELECT 'civicrm_contribution', ft.contribution_id, ft.id, ft.total_amount as amount
491 FROM civicrm_financial_trxn ft
492 WHERE contribution_id IS NOT NULL AND
493 ft.id NOT IN (SELECT financial_trxn_id
494 FROM civicrm_entity_financial_trxn
495 WHERE entity_table = 'civicrm_contribution'
496 AND entity_id = ft.contribution_id)";
497 CRM_Core_DAO::executeQuery($sql);
498 //end of adding financial_trxn records and entity_financial_trxn records related to contribution
499
500 //update all linked line_item rows
501 // set line_item.financial_type_id = contribution.financial_type_id if contribution page id is null and not participant line item
502 // set line_item.financial_type_id = price_field_value.financial_type_id if contribution page id is set and not participant line item
503 // set line_item.financial_type_id = event.financial_type_id if its participant line item and line_item.price_field_value_id is null
504 // 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
505 $updateLineItemSql = "
506 UPDATE civicrm_line_item li
507 LEFT JOIN civicrm_contribution con
508 ON (li.entity_id = con.id AND li.entity_table = 'civicrm_contribution')
509 LEFT JOIN civicrm_price_field_value cpfv
510 ON li.price_field_value_id = cpfv.id
511 LEFT JOIN civicrm_participant cp
512 ON (li.entity_id = cp.id AND li.entity_table = 'civicrm_participant')
513 LEFT JOIN civicrm_event ce
514 ON ce.id = cp.event_id
515 SET li.financial_type_id = CASE
516 WHEN (con.contribution_page_id IS NULL || li.price_field_value_id IS NULL) AND cp.id IS NULL THEN
517 con.financial_type_id
518 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
519 cpfv.financial_type_id
520 WHEN cp.id IS NOT NULL AND li.price_field_value_id IS NULL THEN
521 ce.financial_type_id
522 END";
523 CRM_Core_DAO::executeQuery($updateLineItemSql, $queryParams);
524
525 //add the financial_item entries
526 //add a temp column so that inserting entity_financial_trxn entries gets easy
527 $sql = "ALTER TABLE civicrm_financial_item ADD COLUMN f_trxn_id INT DEFAULT NULL";
528 CRM_Core_DAO::executeQuery($sql);
529
530 //add financial_item entries for contribution completed / pending pay later / cancelled
531 $contributionlineItemSql = "
532 INSERT INTO civicrm_financial_item
533 (transaction_date, contact_id, amount, currency, entity_table, entity_id, description, status_id, financial_account_id, f_trxn_id)
534
535 SELECT REPLACE(REPLACE(REPLACE(ft.trxn_date, '-', ''), ':', ''), ' ', ''), con.contact_id,
536 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',
537 li.id as line_item_id, li.label as line_item_label,
538 IF(con.contribution_status_id = {$pendingStatus}, {$unpaidStatus}, {$paidStatus}) as status_id, efa.financial_account_id as financial_account_id,
539 ft.id as f_trxn_id
540 FROM civicrm_line_item li
541 INNER JOIN civicrm_contribution con
542 ON (li.entity_id = con.id AND li.entity_table = 'civicrm_contribution')
543 INNER JOIN civicrm_financial_trxn ft
544 ON (con.id = ft.contribution_id)
545 LEFT JOIN civicrm_entity_financial_account efa
546 ON (li.financial_type_id = efa.entity_id AND efa.entity_table = 'civicrm_financial_type'
547 AND efa.account_relationship = {$incomeAccountIs})
548 WHERE con.contribution_status_id IN (%1, %3) OR (con.is_pay_later = 1 AND con.contribution_status_id = %2)";
549 CRM_Core_DAO::executeQuery($contributionlineItemSql, $queryParams);
550
551 //add financial_item entries for event
552 $participantLineItemSql = "
553 INSERT INTO civicrm_financial_item
554 (transaction_date, contact_id, amount, currency, entity_table, entity_id, description, status_id, financial_account_id, f_trxn_id)
555
556 SELECT REPLACE(REPLACE(REPLACE(ft.trxn_date, '-', ''), ':', ''), ' ', ''), con.contact_id,
557 IF(ft.total_amount < 0 AND con.contribution_status_id = %3, -li.line_total, li.line_total) as line_total,
558 con.currency, 'civicrm_line_item', li.id as line_item_id, li.label as line_item_label,
559 IF(con.contribution_status_id = {$pendingStatus}, {$unpaidStatus}, {$paidStatus}) as status_id,
560 efa.financial_account_id as financial_account_id, ft.id as f_trxn_id
561 FROM civicrm_line_item li
562 INNER JOIN civicrm_participant par
563 ON (li.entity_id = par.id AND li.entity_table = 'civicrm_participant')
564 INNER JOIN civicrm_participant_payment pp
565 ON (pp.participant_id = par.id)
566 INNER JOIN civicrm_contribution con
567 ON (pp.contribution_id = con.id)
568 INNER JOIN civicrm_financial_trxn ft
569 ON (con.id = ft.contribution_id)
570 LEFT JOIN civicrm_entity_financial_account efa
571 ON (li.financial_type_id = efa.entity_id AND
572 efa.entity_table = 'civicrm_financial_type' AND efa.account_relationship = {$incomeAccountIs})
573 WHERE con.contribution_status_id IN (%1, %3) OR (con.is_pay_later = 1 AND con.contribution_status_id = %2)";
574 CRM_Core_DAO::executeQuery($participantLineItemSql, $queryParams);
575
576 //fee handling for contributions
577 //insert fee entries in financial_trxn for contributions
578 $sql = "ALTER TABLE civicrm_financial_trxn ADD COLUMN is_fee TINYINT DEFAULT NULL";
579 CRM_Core_DAO::executeQuery($sql);
580
581 $sql = "
582 INSERT INTO civicrm_financial_trxn
583 (contribution_id, payment_instrument_id, currency, total_amount, net_amount, fee_amount, trxn_id, status_id, check_number,
584 to_financial_account_id, from_financial_account_id, trxn_date, payment_processor_id, is_fee)
585
586 SELECT con.id, ft.payment_instrument_id, ft.currency, ft.fee_amount, NULL, NULL, ft.trxn_id, %1 as status_id,
587 ft.check_number, efaFT.financial_account_id as to_financial_account_id, CASE
588 WHEN efaPP.financial_account_id IS NOT NULL THEN
589 efaPP.financial_account_id
590 WHEN tpi.financial_account_id IS NOT NULL THEN
591 tpi.financial_account_id
592 ELSE
593 {$financialAccountId}
594 END as from_financial_account_id, ft.trxn_date, ft.payment_processor_id, 1 as is_fee
595 FROM civicrm_contribution con
596 INNER JOIN civicrm_financial_trxn ft
597 ON (ft.contribution_id = con.id)
598 LEFT JOIN civicrm_entity_financial_account efaFT
599 ON (con.financial_type_id = efaFT.entity_id AND efaFT.entity_table = 'civicrm_financial_type'
600 AND efaFT.account_relationship = {$expenseAccountIs})
601 LEFT JOIN civicrm_entity_financial_account efaPP
602 ON (ft.payment_processor_id = efaPP.entity_id AND efaPP.entity_table = 'civicrm_payment_processor'
603 AND efaPP.account_relationship = {$assetAccountIs})
604 LEFT JOIN {$tempTableName1} tpi
605 ON ft.payment_instrument_id = tpi.instrument_id
606 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))
607 GROUP BY con.id";
608 CRM_Core_DAO::executeQuery($sql, $queryParams);
609
610 //link financial_trxn to contribution
611 $sql = "
612 INSERT INTO civicrm_entity_financial_trxn
613 (entity_table, entity_id, financial_trxn_id, amount)
614 SELECT 'civicrm_contribution', ft.contribution_id, ft.id, ft.total_amount
615 FROM civicrm_financial_trxn ft
616 WHERE ft.is_fee = 1";
617 CRM_Core_DAO::executeQuery($sql);
618
619 //add fee related entries to financial item table
620 $domainId = CRM_Core_Config::domainID();
621 $domainContactId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Domain', $domainId, 'contact_id');
622 $sql = "
623 INSERT INTO civicrm_financial_item
624 (transaction_date, contact_id, amount, currency, entity_table, entity_id, description, status_id, financial_account_id, f_trxn_id)
625 SELECT ft.trxn_date, {$domainContactId} as contact_id, ft.total_amount, ft.currency, 'civicrm_financial_trxn', ft.id,
626 'Fee', {$paidStatus} as status_id, ft.to_financial_account_id as financial_account_id, ft.id as f_trxn_id
627 FROM civicrm_financial_trxn ft
628 WHERE ft.is_fee = 1;";
629 CRM_Core_DAO::executeQuery($sql);
630
631 //add entries to entity_financial_trxn table
632 $sql = "
633 INSERT INTO civicrm_entity_financial_trxn (entity_table, entity_id, financial_trxn_id, amount)
634 SELECT 'civicrm_financial_item' as entity_table, fi.id as entity_id, fi.f_trxn_id as financial_trxn_id, fi.amount
635 FROM civicrm_financial_item fi";
636 CRM_Core_DAO::executeQuery($sql);
637
638 //drop the temparory columns
639 $sql = "ALTER TABLE civicrm_financial_trxn
640 DROP COLUMN contribution_id,
641 DROP COLUMN is_fee;";
642 CRM_Core_DAO::executeQuery($sql);
643
644 $sql = "ALTER TABLE civicrm_financial_item DROP f_trxn_id";
645 CRM_Core_DAO::executeQuery($sql);
646
647 return TRUE;
648 }
649
650 function createDomainContacts() {
651 $domainParams = $context = array();
652 $query = "
653 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',
654 ADD CONSTRAINT `FK_civicrm_domain_contact_id` FOREIGN KEY (`contact_id`) REFERENCES `civicrm_contact` (`id`);";
655 CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray, TRUE, NULL, FALSE, FALSE);
656
657 $query = 'SELECT cd.id, cd.name, ce.email FROM `civicrm_domain` cd
658 LEFT JOIN civicrm_loc_block clb ON clb.id = cd. loc_block_id
659 LEFT JOIN civicrm_email ce ON ce.id = clb.email_id ;' ;
660 $dao = CRM_Core_DAO::executeQuery($query);
661 while($dao->fetch()) {
662 $params = array(
663 'sort_name' => $dao->name,
664 'display_name' => $dao->name,
665 'legal_name' => $dao->name,
666 'organization_name' => $dao->name,
667 'contact_type' => 'Organization'
668 );
669 $query = "SELECT cc.id FROM `civicrm_contact` cc
670 LEFT JOIN civicrm_email ce ON ce.contact_id = cc.id
671 WHERE cc.contact_type = 'Organization' AND cc.organization_name = '{$dao->name}' ";
672 if ($dao->email) {
673 $query .= " AND ce.email = '{$dao->email}' ";
674 }
675 $contactID = CRM_Core_DAO::singleValueQuery($query);
676 $context[1] = $dao->name;
677 if (empty($contactID)) {
678 $contact = CRM_Contact_BAO_Contact::add($params);
679 $contactID = $contact->id;
680 $context[0] = 'added';
681 }
682 else {
683 $context[0] = 'merged';
684 }
685 $domainParams['contact_id'] = $contactID;
686 CRM_Core_BAO_Domain::edit($domainParams, $dao->id);
687 }
688 return $context;
689 }
690
691 function task_4_3_alpha1_checkDBConstraints() {
692 //checking whether the foreign key exists before dropping it CRM-11260
693 $config = CRM_Core_Config::singleton();
694 $dbUf = DB::parseDSN($config->dsn);
695 $params = array();
696 $tables = array(
697 'autorenewal_msg_id' => array('tableName' => 'civicrm_membership_type', 'fkey' => 'FK_civicrm_membership_autorenewal_msg_id'),
698 'to_account_id' => array('tableName' => 'civicrm_financial_trxn', 'constraintName' => 'civicrm_financial_trxn_ibfk_2'),
699 'from_account_id' => array('tableName' => 'civicrm_financial_trxn', 'constraintName' => 'civicrm_financial_trxn_ibfk_1'),
700 'contribution_type_id' => array('tableName' => 'civicrm_contribution_recur', 'fkey' => 'FK_civicrm_contribution_recur_contribution_type_id'),
701 );
702 $query = "SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
703 WHERE table_name = 'civicrm_contribution_recur'
704 AND constraint_name = 'FK_civicrm_contribution_recur_contribution_type_id'
705 AND TABLE_SCHEMA = '{$dbUf['database']}'";
706
707 $dao = CRM_Core_DAO::executeQuery($query, $params, TRUE, NULL, FALSE, FALSE);
708 foreach($tables as $columnName => $value){
709 if ($value['tableName'] == 'civicrm_membership_type' || $value['tableName'] == 'civicrm_contribution_recur') {
710 $foreignKeyExists = CRM_Core_DAO::checkConstraintExists($value['tableName'], $value['fkey']);
711 $fKey = $value['fkey'];
712 } else {
713 $foreignKeyExists = CRM_Core_DAO::checkFKConstraintInFormat($value['tableName'], $columnName);
714 $fKey = "`FK_{$value['tableName']}_{$columnName}`";
715 }
716 if ($foreignKeyExists || $value['tableName'] == 'civicrm_financial_trxn') {
717 if ($value['tableName'] != 'civicrm_contribution_recur' || ($value['tableName'] == 'civicrm_contribution_recur' && $dao->N)) {
718 $constraintName = $foreignKeyExists ? $fKey : $value['constraintName'];
719 CRM_Core_DAO::executeQuery("ALTER TABLE {$value['tableName']} DROP FOREIGN KEY {$constraintName}", $params, TRUE, NULL, FALSE, FALSE);
720 }
721 CRM_Core_DAO::executeQuery("ALTER TABLE {$value['tableName']} DROP INDEX {$fKey}", $params, TRUE, NULL, FALSE, FALSE);
722 }
723 }
724 // check if column contact_id is present or not in civicrm_financial_account
725 $fieldExists = CRM_Core_DAO::checkFieldExists('civicrm_financial_account', 'contact_id', FALSE);
726 if (!$fieldExists) {
727 $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);";
728 CRM_Core_DAO::executeQuery($query, $params, TRUE, NULL, FALSE, FALSE);
729 }
730 }
731
732 /**
733 * Read creation and modification times from civicrm_log; add
734 * them to civicrm_contact.
735 */
736 function convertTimestamps(CRM_Queue_TaskContext $ctx, $startId, $endId) {
737 $sql = "
738 SELECT entity_id, min(modified_date) AS created, max(modified_date) AS modified
739 FROM civicrm_log
740 WHERE entity_table = 'civicrm_contact'
741 AND entity_id BETWEEN %1 AND %2
742 GROUP BY entity_id
743 ";
744 $params = array(
745 1 => array($startId, 'Integer'),
746 2 => array($endId, 'Integer'),
747 );
748 $dao = CRM_Core_DAO::executeQuery($sql, $params);
749 while ($dao->fetch()) {
750 // FIXME civicrm_log.modified_date is DATETIME; civicrm_contact.modified_date is TIMESTAMP
751 CRM_Core_DAO::executeQuery(
752 'UPDATE civicrm_contact SET created_date = %1, modified_date = %2 WHERE id = %3',
753 array(
754 1 => array($dao->created, 'String'),
755 2 => array($dao->modified, 'String'),
756 3 => array($dao->entity_id, 'Integer'),
757 )
758 );
759 }
760
761 return TRUE;
762 }
763
764 /**
765 * replace contribution_type to financial_type in table
766 * civicrm_saved_search and Structure civicrm_report_instance
767 */
768 function replaceContributionTypeId(CRM_Queue_TaskContext $ctx, $query, $table) {
769 $dao = CRM_Core_DAO::executeQuery($query);
770 while ($dao->fetch()) {
771 $formValues = unserialize($dao->form_values);
772 foreach (array('contribution_type_id_op', 'contribution_type_id_value', 'contribution_type_id') as $value) {
773 if (array_key_exists($value, $formValues)) {
774 $key = preg_replace('/contribution/', 'financial', $value);
775 $formValues[$key] = $formValues[$value];
776 unset($formValues[$value]);
777 }
778 }
779 if ($table != 'savedSearch') {
780 foreach (array('fields', 'group_bys') as $value) {
781 if (array_key_exists($value, $formValues)) {
782 if (array_key_exists('contribution_type_id', $formValues[$value])) {
783 $formValues[$value]['financial_type_id'] = $formValues[$value]['contribution_type_id'];
784 unset($formValues[$value]['contribution_type_id']);
785 }
786 else if (array_key_exists('contribution_type', $formValues[$value])) {
787 $formValues[$value]['financial_type'] = $formValues[$value]['contribution_type'];
788 unset($formValues[$value]['contribution_type']);
789 }
790 }
791 }
792 if (array_key_exists('order_bys', $formValues)) {
793 foreach ($formValues['order_bys'] as $key => $values) {
794 if (preg_grep('/contribution_type/', $values)) {
795 $formValues['order_bys'][$key]['column'] = preg_replace('/contribution_type/', 'financial_type', $values['column']);
796 }
797 }
798 }
799 }
800
801 if ($table == 'savedSearch') {
802 $saveDao = new CRM_Contact_DAO_SavedSearch();
803 }
804 else {
805 $saveDao = new CRM_Report_DAO_Instance();
806 }
807 $saveDao->id = $dao->id;
808
809 if ($table == 'savedSearch') {
810 if (array_key_exists('mapper', $formValues)) {
811 foreach ($formValues['mapper'] as $key => $values) {
812 foreach ($values as $k => $v) {
813 if (preg_grep('/contribution_/', $v)) {
814 $formValues['mapper'][$key][$k] = preg_replace('/contribution_type/', 'financial_type', $v);
815 }
816 }
817 }
818 }
819 foreach (array('select_tables', 'where_tables') as $value) {
820 if (preg_match('/contribution_type/', $dao->$value)) {
821 $tempValue = unserialize($dao->$value);
822 if (array_key_exists('civicrm_contribution_type', $tempValue)) {
823 $tempValue['civicrm_financial_type'] = $tempValue['civicrm_contribution_type'];
824 unset($tempValue['civicrm_contribution_type']);
825 }
826 $saveDao->$value = serialize($tempValue);
827 }
828 }
829 if (preg_match('/contribution_type/', $dao->where_clause)) {
830 $saveDao->where_clause = preg_replace('/contribution_type/', 'financial_type', $dao->where_clause);
831 }
832 }
833 $saveDao->form_values = serialize($formValues);
834
835 $saveDao->save();
836 }
837 return TRUE;
838 }
839
840 /**
841 * Check/Add INDEX CRM-12141
842 *
843 * @return bool TRUE for success
844 */
845 function task_4_3_x_checkIndexes(CRM_Queue_TaskContext $ctx) {
846 $query = "SHOW KEYS FROM `civicrm_entity_financial_trxn`
847 WHERE key_name IN ('UI_entity_financial_trxn_entity_table', 'UI_entity_financial_trxn_entity_id');";
848 $dao = CRM_Core_DAO::executeQuery($query);
849 if (!$dao->N) {
850 CRM_Core_DAO::executeQuery("ALTER TABLE civicrm_entity_financial_trxn
851 ADD INDEX UI_entity_financial_trxn_entity_table (entity_table),
852 ADD INDEX UI_entity_financial_trxn_entity_id (entity_id);");
853 }
854 return TRUE;
855 }
856
857 /**
858 * Update phones CRM-11292
859 *
860 * @return bool TRUE for success
861 */
862 static function phoneNumeric(CRM_Queue_TaskContext $ctx) {
863 CRM_Core_DAO::executeQuery(CRM_Contact_BAO_Contact::DROP_STRIP_FUNCTION_43);
864 CRM_Core_DAO::executeQuery(CRM_Contact_BAO_Contact::CREATE_STRIP_FUNCTION_43);
865 CRM_Core_DAO::executeQuery("UPDATE civicrm_phone SET phone_numeric = civicrm_strip_non_numeric(phone)");
866 return TRUE;
867 }
868
869 /**
870 * (Queue Task Callback)
871 */
872 static function task_4_3_x_runSql(CRM_Queue_TaskContext $ctx, $rev) {
873 $upgrade = new CRM_Upgrade_Form();
874 $upgrade->processSQL($rev);
875
876 return TRUE;
877 }
878
879 /**
880 * Syntatic sugar for adding a task which (a) is in this class and (b) has
881 * a high priority.
882 *
883 * After passing the $funcName, you can also pass parameters that will go to
884 * the function. Note that all params must be serializable.
885 */
886 protected function addTask($title, $funcName) {
887 $queue = CRM_Queue_Service::singleton()->load(array(
888 'type' => 'Sql',
889 'name' => CRM_Upgrade_Form::QUEUE_NAME,
890 ));
891
892 $args = func_get_args();
893 $title = array_shift($args);
894 $funcName = array_shift($args);
895 $task = new CRM_Queue_Task(
896 array(get_class($this), $funcName),
897 $args,
898 $title
899 );
900 $queue->createItem($task, array('weight' => -1));
901 }
902 }