Merge pull request #13264 from civicrm/5.9
[civicrm-core.git] / tests / phpunit / CiviTest / CiviUnitTestCase.php
CommitLineData
6a488035
TO
1<?php
2/**
3 * File for the CiviUnitTestCase class
4 *
5 * (PHP 5)
6 *
7 * @copyright Copyright CiviCRM LLC (C) 2009
8 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html
9 * GNU Affero General Public License version 3
10 * @package CiviCRM
11 *
12 * This file is part of CiviCRM
13 *
14 * CiviCRM is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Affero General Public License
16 * as published by the Free Software Foundation; either version 3 of
17 * the License, or (at your option) any later version.
18 *
19 * CiviCRM is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Affero General Public License for more details.
23 *
24 * You should have received a copy of the GNU Affero General Public
25 * License along with this program. If not, see
26 * <http://www.gnu.org/licenses/>.
27 */
28
1fee3ad2
EM
29use Civi\Payment\System;
30
6a488035
TO
31/**
32 * Include class definitions
33 */
6a488035 34require_once 'api/api.php';
6a488035
TO
35define('API_LATEST_VERSION', 3);
36
37/**
38 * Base class for CiviCRM unit tests
39 *
d67f1f28
TO
40 * This class supports two (mutually-exclusive) techniques for cleaning up test data. Subclasses
41 * may opt for one or neither:
42 *
43 * 1. quickCleanup() is a helper which truncates a series of tables. Call quickCleanup()
44 * as part of setUp() and/or tearDown(). quickCleanup() is thorough - but it can
45 * be cumbersome to use (b/c you must identify the tables to cleanup) and slow to execute.
46 * 2. useTransaction() executes the test inside a transaction. It's easier to use
47 * (because you don't need to identify specific tables), but it doesn't work for tests
48 * which manipulate schema or truncate data -- and could behave inconsistently
49 * for tests which specifically examine DB transactions.
50 *
6a488035
TO
51 * Common functions for unit tests
52 * @package CiviCRM
53 */
54class CiviUnitTestCase extends PHPUnit_Extensions_Database_TestCase {
55
195557d5 56 use \Civi\Test\Api3DocTrait;
30f5345c 57
6a488035 58 /**
eceb18cc 59 * Database has been initialized.
6a488035
TO
60 *
61 * @var boolean
62 */
63 private static $dbInit = FALSE;
64
65 /**
eceb18cc 66 * Database connection.
6a488035
TO
67 *
68 * @var PHPUnit_Extensions_Database_DB_IDatabaseConnection
69 */
70 protected $_dbconn;
71
72 /**
eceb18cc 73 * The database name.
6a488035
TO
74 *
75 * @var string
76 */
77 static protected $_dbName;
78
0b6f58fa 79 /**
eceb18cc 80 * Track tables we have modified during a test.
0b6f58fa
ARW
81 */
82 protected $_tablesToTruncate = array();
83
6a488035
TO
84 /**
85 * @var array of temporary directory names
86 */
87 protected $tempDirs;
88
6a488035
TO
89 /**
90 * @var boolean populateOnce allows to skip db resets in setUp
91 *
92 * WARNING! USE WITH CAUTION - IT'LL RENDER DATA DEPENDENCIES
93 * BETWEEN TESTS WHEN RUN IN SUITE. SUITABLE FOR LOCAL, LIMITED
94 * "CHECK RUNS" ONLY!
95 *
96 * IF POSSIBLE, USE $this->DBResetRequired = FALSE IN YOUR TEST CASE!
97 *
98 * see also: http://forum.civicrm.org/index.php/topic,18065.0.html
99 */
100 public static $populateOnce = FALSE;
101
6a488035
TO
102 /**
103 * @var boolean DBResetRequired allows skipping DB reset
104 * in specific test case. If you still need
105 * to reset single test (method) of such case, call
106 * $this->cleanDB() in the first line of this
107 * test (method).
108 */
109 public $DBResetRequired = TRUE;
110
d67f1f28
TO
111 /**
112 * @var CRM_Core_Transaction|NULL
113 */
114 private $tx = NULL;
115
6c466b51
EM
116 /**
117 * @var CRM_Utils_Hook_UnitTests hookClass
118 * example of setting a method for a hook
119 * $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults'));
120 */
121 public $hookClass = NULL;
122
123 /**
124 * @var array common values to be re-used multiple times within a class - usually to create the relevant entity
125 */
126 protected $_params = array();
127
128 /**
129 * @var CRM_Extension_System
130 */
131 protected $origExtensionSystem;
132
204beda3 133 /**
134 * Array of IDs created during test setup routine.
135 *
136 * The cleanUpSetUpIds method can be used to clear these at the end of the test.
137 *
138 * @var array
139 */
140 public $setupIDs = array();
141
dcadbba4 142 /**
8d475ce9 143 * PHPUnit Mock Method to use.
dcadbba4
SL
144 *
145 * @var string
146 */
147 public $mockMethod = 'getMock';
148
6a488035 149 /**
eceb18cc 150 * Constructor.
6a488035
TO
151 *
152 * Because we are overriding the parent class constructor, we
153 * need to show the same arguments as exist in the constructor of
154 * PHPUnit_Framework_TestCase, since
155 * PHPUnit_Framework_TestSuite::createTest() creates a
156 * ReflectionClass of the Test class and checks the constructor
157 * of that class to decide how to set up the test.
158 *
e16033b4
TO
159 * @param string $name
160 * @param array $data
161 * @param string $dataName
6a488035 162 */
00be9182 163 public function __construct($name = NULL, array$data = array(), $dataName = '') {
6a488035
TO
164 parent::__construct($name, $data, $dataName);
165
166 // we need full error reporting
167 error_reporting(E_ALL & ~E_NOTICE);
168
f3e16511 169 self::$_dbName = self::getDBName();
6a488035 170
6a488035
TO
171 // also load the class loader
172 require_once 'CRM/Core/ClassLoader.php';
173 CRM_Core_ClassLoader::singleton()->register();
a130e045
DG
174 if (function_exists('_civix_phpunit_setUp')) {
175 // FIXME: loosen coupling
6a488035
TO
176 _civix_phpunit_setUp();
177 }
dcadbba4
SL
178 if (version_compare(PHPUnit_Runner_Version::id(), '5', '>=')) {
179 $this->mockMethod = 'createMock';
180 }
6a488035
TO
181 }
182
f0be539a
EM
183 /**
184 * Override to run the test and assert its state.
185 * @return mixed
186 * @throws \Exception
187 * @throws \PHPUnit_Framework_IncompleteTest
188 * @throws \PHPUnit_Framework_SkippedTest
189 */
2e90bf37
TO
190 protected function runTest() {
191 try {
192 return parent::runTest();
5896d037
TO
193 }
194 catch (PEAR_Exception $e) {
2e90bf37
TO
195 // PEAR_Exception has metadata in funny places, and PHPUnit won't log it nicely
196 throw new Exception(\CRM_Core_Error::formatTextException($e), $e->getCode());
197 }
198 }
199
4cbe18b8
EM
200 /**
201 * @return bool
202 */
00be9182 203 public function requireDBReset() {
6a488035
TO
204 return $this->DBResetRequired;
205 }
206
4cbe18b8
EM
207 /**
208 * @return string
209 */
00be9182 210 public static function getDBName() {
f3e16511 211 static $dbName = NULL;
649d6dd0 212 if ($dbName === NULL) {
f3e16511
TO
213 require_once "DB.php";
214 $dsninfo = DB::parseDSN(CIVICRM_DSN);
215 $dbName = $dsninfo['database'];
216 }
6a488035
TO
217 return $dbName;
218 }
219
220 /**
eceb18cc 221 * Create database connection for this instance.
6a488035
TO
222 *
223 * Initialize the test database if it hasn't been initialized
224 *
225 * @return PHPUnit_Extensions_Database_DB_IDatabaseConnection connection
226 */
227 protected function getConnection() {
228 $dbName = self::$_dbName;
229 if (!self::$dbInit) {
230 $dbName = self::getDBName();
231
232 // install test database
233 echo PHP_EOL . "Installing {$dbName} database" . PHP_EOL;
234
99117745 235 static::_populateDB(FALSE, $this);
6a488035
TO
236
237 self::$dbInit = TRUE;
238 }
bc560b0a 239
728bbd5b 240 return $this->createDefaultDBConnection(Civi\Test::pdo(), $dbName);
6a488035
TO
241 }
242
243 /**
eceb18cc 244 * Required implementation of abstract method.
6a488035
TO
245 */
246 protected function getDataSet() {
247 }
248
99117745
TO
249 /**
250 * @param bool $perClass
251 * @param null $object
a6c01b45
CW
252 * @return bool
253 * TRUE if the populate logic runs; FALSE if it is skipped
99117745
TO
254 */
255 protected static function _populateDB($perClass = FALSE, &$object = NULL) {
8582a9fc 256 if (CIVICRM_UF !== 'UnitTests') {
cdc44255 257 throw new \RuntimeException("_populateDB requires CIVICRM_UF=UnitTests");
8582a9fc 258 }
6a488035
TO
259
260 if ($perClass || $object == NULL) {
261 $dbreset = TRUE;
262 }
263 else {
264 $dbreset = $object->requireDBReset();
265 }
266
267 if (self::$populateOnce || !$dbreset) {
99117745 268 return FALSE;
6a488035
TO
269 }
270 self::$populateOnce = NULL;
271
728bbd5b 272 Civi\Test::data()->populate();
be709432
TO
273
274 return TRUE;
6a488035
TO
275 }
276
277 public static function setUpBeforeClass() {
99117745 278 static::_populateDB(TRUE);
6a488035
TO
279
280 // also set this global hack
281 $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
282 }
283
284 /**
eceb18cc 285 * Common setup functions for all unit tests.
6a488035
TO
286 */
287 protected function setUp() {
4db17da0
TO
288 $session = CRM_Core_Session::singleton();
289 $session->set('userID', NULL);
290
6a488035
TO
291 $this->errorScope = CRM_Core_TemporaryErrorScope::useException(); // REVERT
292 // Use a temporary file for STDIN
293 $GLOBALS['stdin'] = tmpfile();
294 if ($GLOBALS['stdin'] === FALSE) {
295 echo "Couldn't open temporary file\n";
296 exit(1);
297 }
298
299 // Get and save a connection to the database
300 $this->_dbconn = $this->getConnection();
301
302 // reload database before each test
303 // $this->_populateDB();
304
305 // "initialize" CiviCRM to avoid problems when running single tests
306 // FIXME: look at it closer in second stage
307
c0a1f187
TO
308 $GLOBALS['civicrm_setting']['domain']['fatalErrorHandler'] = 'CiviUnitTestCase_fatalErrorHandler';
309 $GLOBALS['civicrm_setting']['domain']['backtrace'] = 1;
6a488035
TO
310
311 // disable any left-over test extensions
312 CRM_Core_DAO::executeQuery('DELETE FROM civicrm_extension WHERE full_name LIKE "test.%"');
313
314 // reset all the caches
315 CRM_Utils_System::flushCache();
316
c0a1f187
TO
317 // initialize the object once db is loaded
318 \Civi::reset();
319 $config = CRM_Core_Config::singleton(TRUE, TRUE); // ugh, performance
320
321 // when running unit tests, use mockup user framework
edbcbd96 322 $this->hookClass = CRM_Utils_Hook::singleton();
c0a1f187 323
26684821
TO
324 // Make sure the DB connection is setup properly
325 $config->userSystem->setMySQLTimeZone();
a8de1c22 326 $env = new CRM_Utils_Check_Component_Env();
26684821
TO
327 CRM_Utils_Check::singleton()->assertValid($env->checkMysqlTime());
328
6a488035 329 // clear permissions stub to not check permissions
6a488035
TO
330 $config->userPermissionClass->permissions = NULL;
331
332 //flush component settings
333 CRM_Core_Component::getEnabledComponents(TRUE);
334
c3d574fc
EM
335 error_reporting(E_ALL);
336
d58b453e 337 $this->_sethtmlGlobals();
6a488035
TO
338 }
339
0b6f58fa 340 /**
eceb18cc 341 * Read everything from the datasets directory and insert into the db.
0b6f58fa
ARW
342 */
343 public function loadAllFixtures() {
344 $fixturesDir = __DIR__ . '/../../fixtures';
345
346 $this->getConnection()->getConnection()->query("SET FOREIGN_KEY_CHECKS = 0;");
347
348 $xmlFiles = glob($fixturesDir . '/*.xml');
349 foreach ($xmlFiles as $xmlFixture) {
350 $op = new PHPUnit_Extensions_Database_Operation_Insert();
bbfd46a5 351 $dataset = $this->createXMLDataSet($xmlFixture);
0b6f58fa
ARW
352 $this->_tablesToTruncate = array_merge($this->_tablesToTruncate, $dataset->getTableNames());
353 $op->execute($this->_dbconn, $dataset);
354 }
355
356 $yamlFiles = glob($fixturesDir . '/*.yaml');
357 foreach ($yamlFiles as $yamlFixture) {
358 $op = new PHPUnit_Extensions_Database_Operation_Insert();
359 $dataset = new PHPUnit_Extensions_Database_DataSet_YamlDataSet($yamlFixture);
360 $this->_tablesToTruncate = array_merge($this->_tablesToTruncate, $dataset->getTableNames());
361 $op->execute($this->_dbconn, $dataset);
362 }
363
364 $this->getConnection()->getConnection()->query("SET FOREIGN_KEY_CHECKS = 1;");
365 }
366
6a488035 367 /**
eceb18cc 368 * Emulate a logged in user since certain functions use that.
6a488035
TO
369 * value to store a record in the DB (like activity)
370 * CRM-8180
5fc991dd
EM
371 *
372 * @return int
373 * Contact ID of the created user.
6a488035
TO
374 */
375 public function createLoggedInUser() {
376 $params = array(
377 'first_name' => 'Logged In',
378 'last_name' => 'User ' . rand(),
379 'contact_type' => 'Individual',
380 );
381 $contactID = $this->individualCreate($params);
5fc991dd
EM
382 $this->callAPISuccess('UFMatch', 'create', array(
383 'contact_id' => $contactID,
384 'uf_name' => 'superman',
385 'uf_id' => 6,
386 ));
6a488035
TO
387
388 $session = CRM_Core_Session::singleton();
389 $session->set('userID', $contactID);
5fc991dd 390 return $contactID;
6a488035
TO
391 }
392
5767aa07 393 /**
eceb18cc 394 * Create default domain contacts for the two domains added during test class.
5767aa07
AN
395 * database population.
396 */
397 public function createDomainContacts() {
1ca22999 398 $this->organizationCreate();
399 $this->organizationCreate(array('organization_name' => 'Second Domain'));
5767aa07
AN
400 }
401
6a488035 402 /**
eceb18cc 403 * Common teardown functions for all unit tests.
6a488035
TO
404 */
405 protected function tearDown() {
406 error_reporting(E_ALL & ~E_NOTICE);
6c466b51 407 CRM_Utils_Hook::singleton()->reset();
36a29dc0
TO
408 if ($this->hookClass) {
409 $this->hookClass->reset();
410 }
9ce07588
TO
411 $session = CRM_Core_Session::singleton();
412 $session->set('userID', NULL);
d67f1f28
TO
413
414 if ($this->tx) {
415 $this->tx->rollback()->commit();
416 $this->tx = NULL;
417
418 CRM_Core_Transaction::forceRollbackIfEnabled();
419 \Civi\Core\Transaction\Manager::singleton(TRUE);
5896d037
TO
420 }
421 else {
d67f1f28
TO
422 CRM_Core_Transaction::forceRollbackIfEnabled();
423 \Civi\Core\Transaction\Manager::singleton(TRUE);
424
225d474b 425 $tablesToTruncate = array('civicrm_contact', 'civicrm_uf_match');
d67f1f28 426 $this->quickCleanup($tablesToTruncate);
a335f6b2 427 $this->createDomainContacts();
d67f1f28
TO
428 }
429
6a488035
TO
430 $this->cleanTempDirs();
431 $this->unsetExtensionSystem();
432 }
433
6a488035 434 /**
eceb18cc 435 * Generic function to compare expected values after an api call to retrieved.
6a488035
TO
436 * DB values.
437 *
438 * @daoName string DAO Name of object we're evaluating.
439 * @id int Id of object
440 * @match array Associative array of field name => expected value. Empty if asserting
441 * that a DELETE occurred
442 * @delete boolean True if we're checking that a DELETE action occurred.
1e1fdcf6
EM
443 * @param $daoName
444 * @param $id
445 * @param $match
446 * @param bool $delete
447 * @throws \PHPUnit_Framework_AssertionFailedError
6a488035 448 */
00be9182 449 public function assertDBState($daoName, $id, $match, $delete = FALSE) {
6a488035
TO
450 if (empty($id)) {
451 // adding this here since developers forget to check for an id
452 // and hence we get the first value in the db
453 $this->fail('ID not populated. Please fix your assertDBState usage!!!');
454 }
455
4d5c2eb5 456 $object = new $daoName();
6a488035
TO
457 $object->id = $id;
458 $verifiedCount = 0;
459
460 // If we're asserting successful record deletion, make sure object is NOT found.
461 if ($delete) {
462 if ($object->find(TRUE)) {
463 $this->fail("Object not deleted by delete operation: $daoName, $id");
464 }
465 return;
466 }
467
468 // Otherwise check matches of DAO field values against expected values in $match.
469 if ($object->find(TRUE)) {
5896d037 470 $fields = &$object->fields();
6a488035
TO
471 foreach ($fields as $name => $value) {
472 $dbName = $value['name'];
473 if (isset($match[$name])) {
474 $verifiedCount++;
475 $this->assertEquals($object->$dbName, $match[$name]);
476 }
477 elseif (isset($match[$dbName])) {
478 $verifiedCount++;
479 $this->assertEquals($object->$dbName, $match[$dbName]);
480 }
481 }
482 }
483 else {
484 $this->fail("Could not retrieve object: $daoName, $id");
485 }
486 $object->free();
487 $matchSize = count($match);
488 if ($verifiedCount != $matchSize) {
489 $this->fail("Did not verify all fields in match array: $daoName, $id. Verified count = $verifiedCount. Match array size = $matchSize");
490 }
491 }
492
4cbe18b8 493 /**
4f1f1f2a 494 * Request a record from the DB by seachColumn+searchValue. Success if a record is found.
c490a46a 495 * @param string $daoName
4cbe18b8
EM
496 * @param $searchValue
497 * @param $returnColumn
498 * @param $searchColumn
499 * @param $message
500 *
501 * @return null|string
502 * @throws PHPUnit_Framework_AssertionFailedError
503 */
00be9182 504 public function assertDBNotNull($daoName, $searchValue, $returnColumn, $searchColumn, $message) {
6a488035
TO
505 if (empty($searchValue)) {
506 $this->fail("empty value passed to assertDBNotNull");
507 }
508 $value = CRM_Core_DAO::getFieldValue($daoName, $searchValue, $returnColumn, $searchColumn, TRUE);
509 $this->assertNotNull($value, $message);
510
511 return $value;
512 }
513
4cbe18b8 514 /**
4f1f1f2a 515 * Request a record from the DB by seachColumn+searchValue. Success if returnColumn value is NULL.
c490a46a 516 * @param string $daoName
4cbe18b8
EM
517 * @param $searchValue
518 * @param $returnColumn
519 * @param $searchColumn
520 * @param $message
521 */
00be9182 522 public function assertDBNull($daoName, $searchValue, $returnColumn, $searchColumn, $message) {
6a488035
TO
523 $value = CRM_Core_DAO::getFieldValue($daoName, $searchValue, $returnColumn, $searchColumn, TRUE);
524 $this->assertNull($value, $message);
525 }
526
4cbe18b8 527 /**
4f1f1f2a 528 * Request a record from the DB by id. Success if row not found.
c490a46a 529 * @param string $daoName
100fef9d 530 * @param int $id
4cbe18b8
EM
531 * @param null $message
532 */
00be9182 533 public function assertDBRowNotExist($daoName, $id, $message = NULL) {
6a488035
TO
534 $message = $message ? $message : "$daoName (#$id) should not exist";
535 $value = CRM_Core_DAO::getFieldValue($daoName, $id, 'id', 'id', TRUE);
536 $this->assertNull($value, $message);
537 }
538
4cbe18b8 539 /**
4f1f1f2a 540 * Request a record from the DB by id. Success if row not found.
c490a46a 541 * @param string $daoName
100fef9d 542 * @param int $id
4cbe18b8
EM
543 * @param null $message
544 */
00be9182 545 public function assertDBRowExist($daoName, $id, $message = NULL) {
6a488035
TO
546 $message = $message ? $message : "$daoName (#$id) should exist";
547 $value = CRM_Core_DAO::getFieldValue($daoName, $id, 'id', 'id', TRUE);
548 $this->assertEquals($id, $value, $message);
549 }
550
4cbe18b8 551 /**
eceb18cc 552 * Compare a single column value in a retrieved DB record to an expected value.
c490a46a 553 * @param string $daoName
4cbe18b8
EM
554 * @param $searchValue
555 * @param $returnColumn
556 * @param $searchColumn
557 * @param $expectedValue
558 * @param $message
559 */
a130e045 560 public function assertDBCompareValue(
5896d037
TO
561 $daoName, $searchValue, $returnColumn, $searchColumn,
562 $expectedValue, $message
6a488035
TO
563 ) {
564 $value = CRM_Core_DAO::getFieldValue($daoName, $searchValue, $returnColumn, $searchColumn, TRUE);
6dde7f04 565 $this->assertEquals($expectedValue, $value, $message);
6a488035
TO
566 }
567
4cbe18b8 568 /**
eceb18cc 569 * Compare all values in a single retrieved DB record to an array of expected values.
c490a46a 570 * @param string $daoName
100fef9d 571 * @param array $searchParams
4cbe18b8
EM
572 * @param $expectedValues
573 */
00be9182 574 public function assertDBCompareValues($daoName, $searchParams, $expectedValues) {
6a488035
TO
575 //get the values from db
576 $dbValues = array();
577 CRM_Core_DAO::commonRetrieve($daoName, $searchParams, $dbValues);
578
579 // compare db values with expected values
580 self::assertAttributesEquals($expectedValues, $dbValues);
581 }
582
583 /**
eceb18cc 584 * Assert that a SQL query returns a given value.
6a488035
TO
585 *
586 * The first argument is an expected value. The remaining arguments are passed
587 * to CRM_Core_DAO::singleValueQuery
588 *
589 * Example: $this->assertSql(2, 'select count(*) from foo where foo.bar like "%1"',
590 * array(1 => array("Whiz", "String")));
1e1fdcf6
EM
591 * @param $expected
592 * @param $query
593 * @param array $params
594 * @param string $message
6a488035 595 */
00be9182 596 public function assertDBQuery($expected, $query, $params = array(), $message = '') {
5896d037
TO
597 if ($message) {
598 $message .= ': ';
6c6e6187 599 }
6a488035
TO
600 $actual = CRM_Core_DAO::singleValueQuery($query, $params);
601 $this->assertEquals($expected, $actual,
5bb8417a
TO
602 sprintf('%sexpected=[%s] actual=[%s] query=[%s]',
603 $message, $expected, $actual, CRM_Core_DAO::composeQuery($query, $params, FALSE)
6a488035
TO
604 )
605 );
606 }
607
608 /**
609 * Assert that two array-trees are exactly equal, notwithstanding
610 * the sorting of keys
611 *
612 * @param array $expected
613 * @param array $actual
614 */
00be9182 615 public function assertTreeEquals($expected, $actual) {
6a488035
TO
616 $e = array();
617 $a = array();
618 CRM_Utils_Array::flatten($expected, $e, '', ':::');
619 CRM_Utils_Array::flatten($actual, $a, '', ':::');
620 ksort($e);
621 ksort($a);
622
623 $this->assertEquals($e, $a);
624 }
625
dc92f2f8 626 /**
78373706 627 * Assert that two numbers are approximately equal.
dc92f2f8
TO
628 *
629 * @param int|float $expected
630 * @param int|float $actual
631 * @param int|float $tolerance
632 * @param string $message
633 */
00be9182 634 public function assertApproxEquals($expected, $actual, $tolerance, $message = NULL) {
dc92f2f8
TO
635 if ($message === NULL) {
636 $message = sprintf("approx-equals: expected=[%.3f] actual=[%.3f] tolerance=[%.3f]", $expected, $actual, $tolerance);
637 }
638 $this->assertTrue(abs($actual - $expected) < $tolerance, $message);
639 }
640
4cbe18b8 641 /**
78373706
EM
642 * Assert attributes are equal.
643 *
4cbe18b8
EM
644 * @param $expectedValues
645 * @param $actualValues
78373706 646 * @param string $message
4cbe18b8
EM
647 *
648 * @throws PHPUnit_Framework_AssertionFailedError
649 */
00be9182 650 public function assertAttributesEquals($expectedValues, $actualValues, $message = NULL) {
6a488035
TO
651 foreach ($expectedValues as $paramName => $paramValue) {
652 if (isset($actualValues[$paramName])) {
5896d037 653 $this->assertEquals($paramValue, $actualValues[$paramName], "Value Mismatch On $paramName - value 1 is " . print_r($paramValue, TRUE) . " value 2 is " . print_r($actualValues[$paramName], TRUE));
6a488035
TO
654 }
655 else {
797d4c52 656 $this->assertNull($expectedValues[$paramName], "Attribute '$paramName' not present in actual array and we expected it to be " . $expectedValues[$paramName]);
6a488035
TO
657 }
658 }
659 }
660
4cbe18b8
EM
661 /**
662 * @param $key
663 * @param $list
664 */
00be9182 665 public function assertArrayKeyExists($key, &$list) {
6a488035
TO
666 $result = isset($list[$key]) ? TRUE : FALSE;
667 $this->assertTrue($result, ts("%1 element exists?",
668 array(1 => $key)
669 ));
670 }
671
4cbe18b8
EM
672 /**
673 * @param $key
674 * @param $list
675 */
00be9182 676 public function assertArrayValueNotNull($key, &$list) {
6a488035
TO
677 $this->assertArrayKeyExists($key, $list);
678
679 $value = isset($list[$key]) ? $list[$key] : NULL;
680 $this->assertTrue($value,
681 ts("%1 element not null?",
682 array(1 => $key)
683 )
684 );
685 }
686
9fd3215e
AS
687 /**
688 * @param $expected
689 * @param $actual
690 */
691 public function assertArrayValuesEqual($array1, $array2) {
692 $array1 = array_values($array1);
693 $array2 = array_values($array2);
694 sort($array1);
695 sort($array2);
696 $this->assertEquals($array1, $array2);
697 }
698
4cbe18b8
EM
699 /**
700 * @param $expected
701 * @param $actual
702 * @param string $message
703 */
00be9182 704 public function assertType($expected, $actual, $message = '') {
6a488035
TO
705 return $this->assertInternalType($expected, $actual, $message);
706 }
54bd1003 707
888dab1e
TO
708 /**
709 * Create a batch of external API calls which can
710 * be executed concurrently.
711 *
712 * @code
713 * $calls = $this->createExternalAPI()
714 * ->addCall('Contact', 'get', ...)
715 * ->addCall('Contact', 'get', ...)
716 * ...
717 * ->run()
718 * ->getResults();
719 * @endcode
720 *
721 * @return \Civi\API\ExternalBatch
722 * @throws PHPUnit_Framework_SkippedTestError
723 */
724 public function createExternalAPI() {
725 global $civicrm_root;
726 $defaultParams = array(
727 'version' => $this->_apiversion,
728 'debug' => 1,
729 );
730
731 $calls = new \Civi\API\ExternalBatch($defaultParams);
888dab1e
TO
732
733 if (!$calls->isSupported()) {
734 $this->markTestSkipped('The test relies on Civi\API\ExternalBatch. This is unsupported in the local environment.');
735 }
736
737 return $calls;
738 }
739
fbda92d3 740 /**
741 * Create required data based on $this->entity & $this->params
742 * This is just a way to set up the test data for delete & get functions
743 * so the distinction between set
744 * up & tested functions is clearer
745 *
a6c01b45
CW
746 * @return array
747 * api Result
fbda92d3 748 */
5896d037 749 public function createTestEntity() {
fbda92d3 750 return $entity = $this->callAPISuccess($this->entity, 'create', $this->params);
751 }
752
6a488035
TO
753 /**
754 * Generic function to create Organisation, to be used in test cases
755 *
16b10e64
CW
756 * @param array $params
757 * parameters for civicrm_contact_add api function call
758 * @param int $seq
759 * sequence number if creating multiple organizations
6a488035 760 *
a6c01b45
CW
761 * @return int
762 * id of Organisation created
6a488035 763 */
00be9182 764 public function organizationCreate($params = array(), $seq = 0) {
6a488035
TO
765 if (!$params) {
766 $params = array();
767 }
4cc99d00 768 $params = array_merge($this->sampleContact('Organization', $seq), $params);
769 return $this->_contactCreate($params);
6a488035
TO
770 }
771
772 /**
773 * Generic function to create Individual, to be used in test cases
774 *
16b10e64
CW
775 * @param array $params
776 * parameters for civicrm_contact_add api function call
777 * @param int $seq
778 * sequence number if creating multiple individuals
6ec61f19 779 * @param bool $random
6a488035 780 *
a6c01b45
CW
781 * @return int
782 * id of Individual created
6a488035 783 */
6ec61f19 784 public function individualCreate($params = array(), $seq = 0, $random = FALSE) {
785 $params = array_merge($this->sampleContact('Individual', $seq, $random), $params);
6a488035
TO
786 return $this->_contactCreate($params);
787 }
788
789 /**
790 * Generic function to create Household, to be used in test cases
791 *
16b10e64
CW
792 * @param array $params
793 * parameters for civicrm_contact_add api function call
794 * @param int $seq
795 * sequence number if creating multiple households
6a488035 796 *
a6c01b45
CW
797 * @return int
798 * id of Household created
6a488035 799 */
00be9182 800 public function householdCreate($params = array(), $seq = 0) {
dc8624c6 801 $params = array_merge($this->sampleContact('Household', $seq), $params);
6a488035
TO
802 return $this->_contactCreate($params);
803 }
804
4cc99d00 805 /**
eceb18cc 806 * Helper function for getting sample contact properties.
4cc99d00 807 *
16b10e64
CW
808 * @param string $contact_type
809 * enum contact type: Individual, Organization
810 * @param int $seq
811 * sequence number for the values of this type
4cc99d00 812 *
a6c01b45
CW
813 * @return array
814 * properties of sample contact (ie. $params for API call)
4cc99d00 815 */
6ec61f19 816 public function sampleContact($contact_type, $seq = 0, $random = FALSE) {
4cc99d00 817 $samples = array(
818 'Individual' => array(
819 // The number of values in each list need to be coprime numbers to not have duplicates
820 'first_name' => array('Anthony', 'Joe', 'Terrence', 'Lucie', 'Albert', 'Bill', 'Kim'),
821 'middle_name' => array('J.', 'M.', 'P', 'L.', 'K.', 'A.', 'B.', 'C.', 'D', 'E.', 'Z.'),
822 'last_name' => array('Anderson', 'Miller', 'Smith', 'Collins', 'Peterson'),
823 ),
824 'Organization' => array(
5896d037
TO
825 'organization_name' => array(
826 'Unit Test Organization',
827 'Acme',
828 'Roberts and Sons',
829 'Cryo Space Labs',
21dfd5f5 830 'Sharper Pens',
5896d037 831 ),
4cc99d00 832 ),
833 'Household' => array(
834 'household_name' => array('Unit Test household'),
835 ),
836 );
837 $params = array('contact_type' => $contact_type);
838 foreach ($samples[$contact_type] as $key => $values) {
a130e045 839 $params[$key] = $values[$seq % count($values)];
6ec61f19 840 if ($random) {
841 $params[$key] .= substr(sha1(rand()), 0, 5);
842 }
4cc99d00 843 }
5896d037 844 if ($contact_type == 'Individual') {
6c6e6187 845 $params['email'] = strtolower(
5896d037
TO
846 $params['first_name'] . '_' . $params['last_name'] . '@civicrm.org'
847 );
6c6e6187
TO
848 $params['prefix_id'] = 3;
849 $params['suffix_id'] = 3;
4cc99d00 850 }
851 return $params;
852 }
853
6a488035 854 /**
fe482240 855 * Private helper function for calling civicrm_contact_add.
6a488035 856 *
e16033b4
TO
857 * @param array $params
858 * For civicrm_contact_add api function call.
9da2e77c
E
859 *
860 * @throws Exception
6a488035 861 *
a6c01b45
CW
862 * @return int
863 * id of Household created
6a488035
TO
864 */
865 private function _contactCreate($params) {
4732bb2f 866 $result = $this->callAPISuccess('contact', 'create', $params);
8cc574cf 867 if (!empty($result['is_error']) || empty($result['id'])) {
ace01fda 868 throw new Exception('Could not create test contact, with message: ' . CRM_Utils_Array::value('error_message', $result) . "\nBacktrace:" . CRM_Utils_Array::value('trace', $result));
6a488035
TO
869 }
870 return $result['id'];
871 }
872
4cbe18b8 873 /**
507d3b64 874 * Delete contact, ensuring it is not the domain contact
4cbe18b8 875 *
507d3b64
EM
876 * @param int $contactID
877 * Contact ID to delete
4cbe18b8 878 */
00be9182 879 public function contactDelete($contactID) {
a130e045 880 $domain = new CRM_Core_BAO_Domain();
6a488035 881 $domain->contact_id = $contactID;
507d3b64
EM
882 if (!$domain->find(TRUE)) {
883 $this->callAPISuccess('contact', 'delete', array(
884 'id' => $contactID,
885 'skip_undelete' => 1,
886 ));
6a488035 887 }
6a488035
TO
888 }
889
4cbe18b8 890 /**
100fef9d 891 * @param int $contactTypeId
4cbe18b8
EM
892 *
893 * @throws Exception
894 */
00be9182 895 public function contactTypeDelete($contactTypeId) {
6a488035
TO
896 $result = CRM_Contact_BAO_ContactType::del($contactTypeId);
897 if (!$result) {
898 throw new Exception('Could not delete contact type');
899 }
900 }
901
4cbe18b8
EM
902 /**
903 * @param array $params
904 *
905 * @return mixed
906 */
00be9182 907 public function membershipTypeCreate($params = array()) {
6a488035
TO
908 CRM_Member_PseudoConstant::flush('membershipType');
909 CRM_Core_Config::clearDBCache();
204beda3 910 $this->setupIDs['contact'] = $memberOfOrganization = $this->organizationCreate();
75638074 911 $params = array_merge(array(
6a488035
TO
912 'name' => 'General',
913 'duration_unit' => 'year',
914 'duration_interval' => 1,
915 'period_type' => 'rolling',
0090e3d2 916 'member_of_contact_id' => $memberOfOrganization,
6a488035 917 'domain_id' => 1,
4303ea89 918 'financial_type_id' => 2,
6a488035 919 'is_active' => 1,
6a488035 920 'sequential' => 1,
eacf220c 921 'visibility' => 'Public',
75638074 922 ), $params);
923
924 $result = $this->callAPISuccess('MembershipType', 'Create', $params);
6a488035 925
6a488035
TO
926 CRM_Member_PseudoConstant::flush('membershipType');
927 CRM_Utils_Cache::singleton()->flush();
6a488035
TO
928
929 return $result['id'];
930 }
931
4cbe18b8 932 /**
c490a46a 933 * @param array $params
4cbe18b8
EM
934 *
935 * @return mixed
936 */
00be9182 937 public function contactMembershipCreate($params) {
5d8b37be 938 $params = array_merge(array(
6a488035
TO
939 'join_date' => '2007-01-21',
940 'start_date' => '2007-01-21',
941 'end_date' => '2007-12-21',
942 'source' => 'Payment',
5d8b37be 943 'membership_type_id' => 'General',
944 ), $params);
945 if (!is_numeric($params['membership_type_id'])) {
946 $membershipTypes = $this->callAPISuccess('Membership', 'getoptions', array('action' => 'create', 'field' => 'membership_type_id'));
947 if (!in_array($params['membership_type_id'], $membershipTypes['values'])) {
948 $this->membershipTypeCreate(array('name' => $params['membership_type_id']));
6a488035
TO
949 }
950 }
951
f6722559 952 $result = $this->callAPISuccess('Membership', 'create', $params);
6a488035
TO
953 return $result['id'];
954 }
955
956 /**
eceb18cc 957 * Delete Membership Type.
6a488035 958 *
c490a46a 959 * @param array $params
6a488035 960 */
00be9182 961 public function membershipTypeDelete($params) {
cab024d4 962 $this->callAPISuccess('MembershipType', 'Delete', $params);
6a488035
TO
963 }
964
4cbe18b8 965 /**
100fef9d 966 * @param int $membershipID
4cbe18b8 967 */
00be9182 968 public function membershipDelete($membershipID) {
f6722559 969 $deleteParams = array('id' => $membershipID);
970 $result = $this->callAPISuccess('Membership', 'Delete', $deleteParams);
6a488035
TO
971 }
972
4cbe18b8
EM
973 /**
974 * @param string $name
975 *
976 * @return mixed
977 */
00be9182 978 public function membershipStatusCreate($name = 'test member status') {
6a488035
TO
979 $params['name'] = $name;
980 $params['start_event'] = 'start_date';
981 $params['end_event'] = 'end_date';
982 $params['is_current_member'] = 1;
983 $params['is_active'] = 1;
6a488035 984
f6722559 985 $result = $this->callAPISuccess('MembershipStatus', 'Create', $params);
6a488035 986 CRM_Member_PseudoConstant::flush('membershipStatus');
6a488035
TO
987 return $result['id'];
988 }
989
4cbe18b8 990 /**
100fef9d 991 * @param int $membershipStatusID
4cbe18b8 992 */
00be9182 993 public function membershipStatusDelete($membershipStatusID) {
6a488035
TO
994 if (!$membershipStatusID) {
995 return;
996 }
4732bb2f 997 $result = $this->callAPISuccess('MembershipStatus', 'Delete', array('id' => $membershipStatusID));
6a488035
TO
998 }
999
17e615c7
MW
1000 public function membershipRenewalDate($durationUnit, $membershipEndDate) {
1001 // We only have an end_date if frequency units match, otherwise membership won't be autorenewed and dates won't be calculated.
1002 $renewedMembershipEndDate = new DateTime($membershipEndDate);
1003 switch ($durationUnit) {
1004 case 'year':
1005 $renewedMembershipEndDate->add(new DateInterval('P1Y'));
1006 break;
1007
1008 case 'month':
1009 // We have to add 1 day first in case it's the end of the month, then subtract afterwards
1010 // eg. 2018-02-28 should renew to 2018-03-31, if we just added 1 month we'd get 2018-03-28
1011 $renewedMembershipEndDate->add(new DateInterval('P1D'));
1012 $renewedMembershipEndDate->add(new DateInterval('P1M'));
1013 $renewedMembershipEndDate->sub(new DateInterval('P1D'));
1014 break;
1015 }
1016 return $renewedMembershipEndDate->format('Y-m-d');
1017 }
1018
4cbe18b8
EM
1019 /**
1020 * @param array $params
1021 *
1022 * @return mixed
1023 */
00be9182 1024 public function relationshipTypeCreate($params = array()) {
75638074 1025 $params = array_merge(array(
6a488035
TO
1026 'name_a_b' => 'Relation 1 for relationship type create',
1027 'name_b_a' => 'Relation 2 for relationship type create',
1028 'contact_type_a' => 'Individual',
1029 'contact_type_b' => 'Organization',
1030 'is_reserved' => 1,
1031 'is_active' => 1,
75638074 1032 ),
5896d037 1033 $params
75638074 1034 );
6a488035 1035
f6722559 1036 $result = $this->callAPISuccess('relationship_type', 'create', $params);
6a488035
TO
1037 CRM_Core_PseudoConstant::flush('relationshipType');
1038
1039 return $result['id'];
1040 }
1041
1042 /**
eceb18cc 1043 * Delete Relatinship Type.
6a488035
TO
1044 *
1045 * @param int $relationshipTypeID
1046 */
00be9182 1047 public function relationshipTypeDelete($relationshipTypeID) {
6a488035 1048 $params['id'] = $relationshipTypeID;
a60c0bc8
SL
1049 $check = $this->callAPISuccess('relationship_type', 'get', $params);
1050 if (!empty($check['count'])) {
1051 $this->callAPISuccess('relationship_type', 'delete', $params);
1052 }
6a488035
TO
1053 }
1054
4cbe18b8 1055 /**
100fef9d 1056 * @param array $params
4cbe18b8
EM
1057 *
1058 * @return mixed
1059 */
00be9182 1060 public function paymentProcessorTypeCreate($params = NULL) {
6a488035
TO
1061 if (is_null($params)) {
1062 $params = array(
1063 'name' => 'API_Test_PP',
1064 'title' => 'API Test Payment Processor',
1065 'class_name' => 'CRM_Core_Payment_APITest',
1066 'billing_mode' => 'form',
1067 'is_recur' => 0,
1068 'is_reserved' => 1,
1069 'is_active' => 1,
1070 );
1071 }
f6722559 1072 $result = $this->callAPISuccess('payment_processor_type', 'create', $params);
6a488035 1073
6a488035
TO
1074 CRM_Core_PseudoConstant::flush('paymentProcessorType');
1075
1076 return $result['id'];
1077 }
1078
d6944518
EM
1079 /**
1080 * Create test Authorize.net instance.
1081 *
1082 * @param array $params
1083 *
1084 * @return mixed
1085 */
1086 public function paymentProcessorAuthorizeNetCreate($params = array()) {
1087 $params = array_merge(array(
1088 'name' => 'Authorize',
1089 'domain_id' => CRM_Core_Config::domainID(),
1090 'payment_processor_type_id' => 'AuthNet',
1091 'title' => 'AuthNet',
1092 'is_active' => 1,
1093 'is_default' => 0,
1094 'is_test' => 1,
1095 'is_recur' => 1,
1096 'user_name' => '4y5BfuW7jm',
1097 'password' => '4cAmW927n8uLf5J8',
1098 'url_site' => 'https://test.authorize.net/gateway/transact.dll',
1099 'url_recur' => 'https://apitest.authorize.net/xml/v1/request.api',
1100 'class_name' => 'Payment_AuthorizeNet',
1101 'billing_mode' => 1,
1102 ), $params);
1103
4ecbf127 1104 $result = $this->callAPISuccess('PaymentProcessor', 'create', $params);
d6944518
EM
1105 return $result['id'];
1106 }
1107
6a488035 1108 /**
eceb18cc 1109 * Create Participant.
6a488035 1110 *
e16033b4
TO
1111 * @param array $params
1112 * Array of contact id and event id values.
6a488035 1113 *
a6c01b45
CW
1114 * @return int
1115 * $id of participant created
6a488035 1116 */
0f57ba7a 1117 public function participantCreate($params = []) {
5896d037 1118 if (empty($params['contact_id'])) {
94692f2d 1119 $params['contact_id'] = $this->individualCreate();
1120 }
5896d037 1121 if (empty($params['event_id'])) {
94692f2d 1122 $event = $this->eventCreate();
1123 $params['event_id'] = $event['id'];
1124 }
6a488035 1125 $defaults = array(
6a488035
TO
1126 'status_id' => 2,
1127 'role_id' => 1,
1128 'register_date' => 20070219,
1129 'source' => 'Wimbeldon',
1130 'event_level' => 'Payment',
94692f2d 1131 'debug' => 1,
6a488035
TO
1132 );
1133
1134 $params = array_merge($defaults, $params);
f6722559 1135 $result = $this->callAPISuccess('Participant', 'create', $params);
6a488035
TO
1136 return $result['id'];
1137 }
1138
1139 /**
eceb18cc 1140 * Create Payment Processor.
6a488035 1141 *
8950ecdc 1142 * @return int
1143 * Id Payment Processor
6a488035 1144 */
0f07bb06 1145 public function processorCreate($params = array()) {
6a488035
TO
1146 $processorParams = array(
1147 'domain_id' => 1,
1148 'name' => 'Dummy',
8950ecdc 1149 'payment_processor_type_id' => 'Dummy',
6a488035 1150 'financial_account_id' => 12,
a8215a8d 1151 'is_test' => TRUE,
6a488035
TO
1152 'is_active' => 1,
1153 'user_name' => '',
1154 'url_site' => 'http://dummy.com',
1155 'url_recur' => 'http://dummy.com',
1156 'billing_mode' => 1,
8950ecdc 1157 'sequential' => 1,
204efedd 1158 'payment_instrument_id' => 'Debit Card',
6a488035 1159 );
0f07bb06 1160 $processorParams = array_merge($processorParams, $params);
8950ecdc 1161 $processor = $this->callAPISuccess('PaymentProcessor', 'create', $processorParams);
1162 return $processor['id'];
22e39333 1163 }
1164
1165 /**
1166 * Create Payment Processor.
1167 *
1168 * @param array $processorParams
1169 *
0193ebdb 1170 * @return \CRM_Core_Payment_Dummy
1171 * Instance of Dummy Payment Processor
22e39333 1172 */
1173 public function dummyProcessorCreate($processorParams = array()) {
8950ecdc 1174 $paymentProcessorID = $this->processorCreate($processorParams);
7a3b0ca3 1175 return System::singleton()->getById($paymentProcessorID);
6a488035
TO
1176 }
1177
1178 /**
eceb18cc 1179 * Create contribution page.
6a488035 1180 *
c490a46a 1181 * @param array $params
16b10e64
CW
1182 * @return array
1183 * Array of contribution page
6a488035 1184 */
23ead872 1185 public function contributionPageCreate($params = array()) {
1186 $this->_pageParams = array_merge(array(
6a488035
TO
1187 'title' => 'Test Contribution Page',
1188 'financial_type_id' => 1,
1189 'currency' => 'USD',
1190 'financial_account_id' => 1,
6a488035
TO
1191 'is_active' => 1,
1192 'is_allow_other_amount' => 1,
1193 'min_amount' => 10,
1194 'max_amount' => 1000,
23ead872 1195 ), $params);
1196 return $this->callAPISuccess('contribution_page', 'create', $this->_pageParams);
6a488035
TO
1197 }
1198
a646bdd2
SB
1199 /**
1200 * Create a sample batch.
1201 */
1202 public function batchCreate() {
1203 $params = $this->_params;
1204 $params['name'] = $params['title'] = 'Batch_433397';
1205 $params['status_id'] = 1;
1206 $result = $this->callAPISuccess('batch', 'create', $params);
1207 return $result['id'];
1208 }
1209
6a488035 1210 /**
eceb18cc 1211 * Create Tag.
6a488035 1212 *
2a6da8d7 1213 * @param array $params
a6c01b45
CW
1214 * @return array
1215 * result of created tag
6a488035 1216 */
00be9182 1217 public function tagCreate($params = array()) {
fb32de45 1218 $defaults = array(
1219 'name' => 'New Tag3',
1220 'description' => 'This is description for Our New Tag ',
1221 'domain_id' => '1',
1222 );
1223 $params = array_merge($defaults, $params);
6c6e6187 1224 $result = $this->callAPISuccess('Tag', 'create', $params);
fb32de45 1225 return $result['values'][$result['id']];
6a488035
TO
1226 }
1227
1228 /**
eceb18cc 1229 * Delete Tag.
6a488035 1230 *
e16033b4
TO
1231 * @param int $tagId
1232 * Id of the tag to be deleted.
16b10e64
CW
1233 *
1234 * @return int
6a488035 1235 */
00be9182 1236 public function tagDelete($tagId) {
6a488035
TO
1237 require_once 'api/api.php';
1238 $params = array(
1239 'tag_id' => $tagId,
6a488035 1240 );
f6722559 1241 $result = $this->callAPISuccess('Tag', 'delete', $params);
6a488035
TO
1242 return $result['id'];
1243 }
1244
1245 /**
1246 * Add entity(s) to the tag
1247 *
e16033b4 1248 * @param array $params
77b97be7
EM
1249 *
1250 * @return bool
6a488035 1251 */
00be9182 1252 public function entityTagAdd($params) {
f6722559 1253 $result = $this->callAPISuccess('entity_tag', 'create', $params);
6a488035
TO
1254 return TRUE;
1255 }
1256
1257 /**
5210fa35 1258 * Create pledge.
6a488035 1259 *
5210fa35 1260 * @param array $params
1261 * Parameters.
77b97be7 1262 *
a6c01b45 1263 * @return int
5210fa35 1264 * id of created pledge
6a488035 1265 */
5210fa35 1266 public function pledgeCreate($params) {
1267 $params = array_merge(array(
6a488035
TO
1268 'pledge_create_date' => date('Ymd'),
1269 'start_date' => date('Ymd'),
1270 'scheduled_date' => date('Ymd'),
1271 'amount' => 100.00,
1272 'pledge_status_id' => '2',
1273 'financial_type_id' => '1',
1274 'pledge_original_installment_amount' => 20,
1275 'frequency_interval' => 5,
1276 'frequency_unit' => 'year',
1277 'frequency_day' => 15,
1278 'installments' => 5,
5210fa35 1279 ),
1280 $params);
6a488035 1281
f6722559 1282 $result = $this->callAPISuccess('Pledge', 'create', $params);
6a488035
TO
1283 return $result['id'];
1284 }
1285
1286 /**
eceb18cc 1287 * Delete contribution.
6a488035 1288 *
c490a46a 1289 * @param int $pledgeId
6a488035 1290 */
00be9182 1291 public function pledgeDelete($pledgeId) {
6a488035
TO
1292 $params = array(
1293 'pledge_id' => $pledgeId,
6a488035 1294 );
f6722559 1295 $this->callAPISuccess('Pledge', 'delete', $params);
6a488035
TO
1296 }
1297
1298 /**
eceb18cc 1299 * Create contribution.
6a488035 1300 *
c3a3074f 1301 * @param array $params
1302 * Array of parameters.
16b10e64 1303 *
a6c01b45
CW
1304 * @return int
1305 * id of created contribution
6a488035 1306 */
78ab0ca4 1307 public function contributionCreate($params) {
69fccd8f 1308
d6944518 1309 $params = array_merge(array(
6a488035 1310 'domain_id' => 1,
6a488035
TO
1311 'receive_date' => date('Ymd'),
1312 'total_amount' => 100.00,
69fccd8f 1313 'fee_amount' => 5.00,
78ab0ca4 1314 'financial_type_id' => 1,
1315 'payment_instrument_id' => 1,
6a488035 1316 'non_deductible_amount' => 10.00,
6a488035 1317 'source' => 'SSF',
6a488035 1318 'contribution_status_id' => 1,
d6944518 1319 ), $params);
6a488035 1320
f6722559 1321 $result = $this->callAPISuccess('contribution', 'create', $params);
6a488035
TO
1322 return $result['id'];
1323 }
1324
6a488035 1325 /**
eceb18cc 1326 * Delete contribution.
6a488035
TO
1327 *
1328 * @param int $contributionId
8deefe64
EM
1329 *
1330 * @return array|int
6a488035 1331 */
00be9182 1332 public function contributionDelete($contributionId) {
6a488035
TO
1333 $params = array(
1334 'contribution_id' => $contributionId,
6a488035 1335 );
f6722559 1336 $result = $this->callAPISuccess('contribution', 'delete', $params);
6a488035
TO
1337 return $result;
1338 }
1339
1340 /**
eceb18cc 1341 * Create an Event.
6a488035 1342 *
e16033b4
TO
1343 * @param array $params
1344 * Name-value pair for an event.
6a488035 1345 *
a6c01b45 1346 * @return array
6a488035 1347 */
00be9182 1348 public function eventCreate($params = array()) {
6a488035
TO
1349 // if no contact was passed, make up a dummy event creator
1350 if (!isset($params['contact_id'])) {
1351 $params['contact_id'] = $this->_contactCreate(array(
1352 'contact_type' => 'Individual',
1353 'first_name' => 'Event',
1354 'last_name' => 'Creator',
6a488035
TO
1355 ));
1356 }
1357
1358 // set defaults for missing params
1359 $params = array_merge(array(
1360 'title' => 'Annual CiviCRM meet',
1361 'summary' => 'If you have any CiviCRM related issues or want to track where CiviCRM is heading, Sign up now',
1362 'description' => 'This event is intended to give brief idea about progess of CiviCRM and giving solutions to common user issues',
1363 'event_type_id' => 1,
1364 'is_public' => 1,
1365 'start_date' => 20081021,
1366 'end_date' => 20081023,
1367 'is_online_registration' => 1,
1368 'registration_start_date' => 20080601,
1369 'registration_end_date' => 20081015,
1370 'max_participants' => 100,
1371 'event_full_text' => 'Sorry! We are already full',
c039f658 1372 'is_monetary' => 0,
6a488035 1373 'is_active' => 1,
6a488035
TO
1374 'is_show_location' => 0,
1375 ), $params);
1376
8cba5814 1377 return $this->callAPISuccess('Event', 'create', $params);
6a488035
TO
1378 }
1379
f660d2ad 1380 /**
1381 * Create a paid event.
1382 *
1383 * @param array $params
1384 *
1385 * @return array
1386 */
1387 protected function eventCreatePaid($params) {
1388 $event = $this->eventCreate($params);
1389 $this->priceSetID = $this->eventPriceSetCreate(55, 0, 'Radio');
1390 CRM_Price_BAO_PriceSet::addTo('civicrm_event', $event['id'], $this->priceSetID);
1391 $priceSet = CRM_Price_BAO_PriceSet::getSetDetail($this->priceSetID, TRUE, FALSE);
1392 $priceSet = CRM_Utils_Array::value($this->priceSetID, $priceSet);
1393 $this->eventFeeBlock = CRM_Utils_Array::value('fields', $priceSet);
1394 return $event;
1395 }
1396
6a488035 1397 /**
eceb18cc 1398 * Delete event.
6a488035 1399 *
e16033b4
TO
1400 * @param int $id
1401 * ID of the event.
8deefe64
EM
1402 *
1403 * @return array|int
6a488035 1404 */
00be9182 1405 public function eventDelete($id) {
6a488035
TO
1406 $params = array(
1407 'event_id' => $id,
6a488035 1408 );
8cba5814 1409 return $this->callAPISuccess('event', 'delete', $params);
6a488035
TO
1410 }
1411
1412 /**
eceb18cc 1413 * Delete participant.
6a488035
TO
1414 *
1415 * @param int $participantID
8deefe64
EM
1416 *
1417 * @return array|int
6a488035 1418 */
00be9182 1419 public function participantDelete($participantID) {
6a488035
TO
1420 $params = array(
1421 'id' => $participantID,
6a488035 1422 );
a60c0bc8
SL
1423 $check = $this->callAPISuccess('Participant', 'get', $params);
1424 if ($check['count'] > 0) {
1425 return $this->callAPISuccess('Participant', 'delete', $params);
1426 }
6a488035
TO
1427 }
1428
1429 /**
eceb18cc 1430 * Create participant payment.
6a488035 1431 *
100fef9d
CW
1432 * @param int $participantID
1433 * @param int $contributionID
a6c01b45
CW
1434 * @return int
1435 * $id of created payment
6a488035 1436 */
00be9182 1437 public function participantPaymentCreate($participantID, $contributionID = NULL) {
6a488035
TO
1438 //Create Participant Payment record With Values
1439 $params = array(
1440 'participant_id' => $participantID,
1441 'contribution_id' => $contributionID,
6a488035
TO
1442 );
1443
f6722559 1444 $result = $this->callAPISuccess('participant_payment', 'create', $params);
6a488035
TO
1445 return $result['id'];
1446 }
1447
1448 /**
eceb18cc 1449 * Delete participant payment.
6a488035
TO
1450 *
1451 * @param int $paymentID
1452 */
00be9182 1453 public function participantPaymentDelete($paymentID) {
6a488035
TO
1454 $params = array(
1455 'id' => $paymentID,
6a488035 1456 );
f6722559 1457 $result = $this->callAPISuccess('participant_payment', 'delete', $params);
6a488035
TO
1458 }
1459
1460 /**
eceb18cc 1461 * Add a Location.
6a488035 1462 *
100fef9d 1463 * @param int $contactID
a6c01b45
CW
1464 * @return int
1465 * location id of created location
6a488035 1466 */
00be9182 1467 public function locationAdd($contactID) {
6a488035
TO
1468 $address = array(
1469 1 => array(
1470 'location_type' => 'New Location Type',
1471 'is_primary' => 1,
1472 'name' => 'Saint Helier St',
1473 'county' => 'Marin',
86797006 1474 'country' => 'UNITED STATES',
6a488035
TO
1475 'state_province' => 'Michigan',
1476 'supplemental_address_1' => 'Hallmark Ct',
1477 'supplemental_address_2' => 'Jersey Village',
207f62c6 1478 'supplemental_address_3' => 'My Town',
21dfd5f5 1479 ),
6a488035
TO
1480 );
1481
1482 $params = array(
1483 'contact_id' => $contactID,
1484 'address' => $address,
6a488035
TO
1485 'location_format' => '2.0',
1486 'location_type' => 'New Location Type',
1487 );
1488
f6722559 1489 $result = $this->callAPISuccess('Location', 'create', $params);
6a488035
TO
1490 return $result;
1491 }
1492
1493 /**
eceb18cc 1494 * Delete Locations of contact.
6a488035 1495 *
e16033b4
TO
1496 * @param array $params
1497 * Parameters.
6a488035 1498 */
00be9182 1499 public function locationDelete($params) {
c490a46a 1500 $this->callAPISuccess('Location', 'delete', $params);
6a488035
TO
1501 }
1502
1503 /**
eceb18cc 1504 * Add a Location Type.
6a488035 1505 *
100fef9d 1506 * @param array $params
16b10e64
CW
1507 * @return CRM_Core_DAO_LocationType
1508 * location id of created location
6a488035 1509 */
00be9182 1510 public function locationTypeCreate($params = NULL) {
6a488035
TO
1511 if ($params === NULL) {
1512 $params = array(
1513 'name' => 'New Location Type',
1514 'vcard_name' => 'New Location Type',
1515 'description' => 'Location Type for Delete',
1516 'is_active' => 1,
1517 );
1518 }
1519
6a488035
TO
1520 $locationType = new CRM_Core_DAO_LocationType();
1521 $locationType->copyValues($params);
1522 $locationType->save();
1523 // clear getfields cache
2683ce94 1524 CRM_Core_PseudoConstant::flush();
f6722559 1525 $this->callAPISuccess('phone', 'getfields', array('version' => 3, 'cache_clear' => 1));
6a488035
TO
1526 return $locationType;
1527 }
1528
1529 /**
eceb18cc 1530 * Delete a Location Type.
6a488035 1531 *
79d7553f 1532 * @param int $locationTypeId
6a488035 1533 */
00be9182 1534 public function locationTypeDelete($locationTypeId) {
6a488035
TO
1535 $locationType = new CRM_Core_DAO_LocationType();
1536 $locationType->id = $locationTypeId;
1537 $locationType->delete();
1538 }
1539
927f93e2
TM
1540 /**
1541 * Add a Mapping.
1542 *
1543 * @param array $params
1544 * @return CRM_Core_DAO_Mapping
1545 * Mapping id of created mapping
1546 */
1547 public function mappingCreate($params = NULL) {
1548 if ($params === NULL) {
1549 $params = array(
1550 'name' => 'Mapping name',
1551 'description' => 'Mapping description',
1552 // 'Export Contact' mapping.
1553 'mapping_type_id' => 7,
1554 );
1555 }
1556
1557 $mapping = new CRM_Core_DAO_Mapping();
1558 $mapping->copyValues($params);
1559 $mapping->save();
1560 // clear getfields cache
1561 CRM_Core_PseudoConstant::flush();
1562 $this->callAPISuccess('mapping', 'getfields', array('version' => 3, 'cache_clear' => 1));
1563 return $mapping;
1564 }
1565
1566 /**
1567 * Delete a Mapping
1568 *
1569 * @param int $mappingId
1570 */
1571 public function mappingDelete($mappingId) {
1572 $mapping = new CRM_Core_DAO_Mapping();
1573 $mapping->id = $mappingId;
1574 $mapping->delete();
1575 }
1576
6a488035 1577 /**
eceb18cc 1578 * Add a Group.
6a488035 1579 *
2a6da8d7 1580 * @param array $params
a6c01b45
CW
1581 * @return int
1582 * groupId of created group
6a488035 1583 */
00be9182 1584 public function groupCreate($params = array()) {
fadb804f 1585 $params = array_merge(array(
5896d037
TO
1586 'name' => 'Test Group 1',
1587 'domain_id' => 1,
1588 'title' => 'New Test Group Created',
1589 'description' => 'New Test Group Created',
1590 'is_active' => 1,
1591 'visibility' => 'Public Pages',
1592 'group_type' => array(
1593 '1' => 1,
1594 '2' => 1,
1595 ),
1596 ), $params);
6a488035 1597
f6722559 1598 $result = $this->callAPISuccess('Group', 'create', $params);
1599 return $result['id'];
6a488035
TO
1600 }
1601
5e8daa54 1602 /**
1603 * Prepare class for ACLs.
1604 */
1605 protected function prepareForACLs() {
1606 $config = CRM_Core_Config::singleton();
1607 $config->userPermissionClass->permissions = array();
1608 }
1609
1610 /**
1611 * Reset after ACLs.
1612 */
1613 protected function cleanUpAfterACLs() {
1614 CRM_Utils_Hook::singleton()->reset();
1615 $tablesToTruncate = array(
1616 'civicrm_acl',
1617 'civicrm_acl_cache',
1618 'civicrm_acl_entity_role',
1619 'civicrm_acl_contact_cache',
1620 );
1621 $this->quickCleanup($tablesToTruncate);
1622 $config = CRM_Core_Config::singleton();
1623 unset($config->userPermissionClass->permissions);
1624 }
c3137c08 1625 /**
1626 * Create a smart group.
1627 *
1628 * By default it will be a group of households.
1629 *
1630 * @param array $smartGroupParams
1631 * @param array $groupParams
1632 * @return int
1633 */
1634 public function smartGroupCreate($smartGroupParams = array(), $groupParams = array()) {
1635 $smartGroupParams = array_merge(array(
1636 'formValues' => array('contact_type' => array('IN' => array('Household'))),
1637 ),
1638 $smartGroupParams);
1639 $savedSearch = CRM_Contact_BAO_SavedSearch::create($smartGroupParams);
1640
1641 $groupParams['saved_search_id'] = $savedSearch->id;
1642 return $this->groupCreate($groupParams);
1643 }
7811a84b 1644
6c6e6187 1645 /**
eceb18cc 1646 * Function to add a Group.
ef643544 1647 *
7811a84b 1648 * @params array to add group
ef643544 1649 *
257e7666
EM
1650 * @param int $groupID
1651 * @param int $totalCount
6ec61f19 1652 * @param bool $random
a130e045
DG
1653 * @return int
1654 * groupId of created group
ef643544 1655 */
6ec61f19 1656 public function groupContactCreate($groupID, $totalCount = 10, $random = FALSE) {
ef643544 1657 $params = array('group_id' => $groupID);
6c6e6187 1658 for ($i = 1; $i <= $totalCount; $i++) {
6ec61f19 1659 $contactID = $this->individualCreate(array(), 0, $random);
ef643544 1660 if ($i == 1) {
1661 $params += array('contact_id' => $contactID);
1662 }
1663 else {
1664 $params += array("contact_id.$i" => $contactID);
1665 }
1666 }
1667 $result = $this->callAPISuccess('GroupContact', 'create', $params);
7811a84b 1668
ef643544 1669 return $result;
1670 }
1671
6a488035 1672 /**
eceb18cc 1673 * Delete a Group.
6a488035 1674 *
c490a46a 1675 * @param int $gid
6a488035 1676 */
00be9182 1677 public function groupDelete($gid) {
6a488035
TO
1678
1679 $params = array(
1680 'id' => $gid,
6a488035
TO
1681 );
1682
f6722559 1683 $this->callAPISuccess('Group', 'delete', $params);
6a488035
TO
1684 }
1685
5c496c74 1686 /**
eceb18cc 1687 * Create a UFField.
5c496c74 1688 * @param array $params
1689 */
00be9182 1690 public function uFFieldCreate($params = array()) {
5c496c74 1691 $params = array_merge(array(
1692 'uf_group_id' => 1,
1693 'field_name' => 'first_name',
1694 'is_active' => 1,
1695 'is_required' => 1,
1696 'visibility' => 'Public Pages and Listings',
1697 'is_searchable' => '1',
1698 'label' => 'first_name',
1699 'field_type' => 'Individual',
1700 'weight' => 1,
1701 ), $params);
1702 $this->callAPISuccess('uf_field', 'create', $params);
1703 }
2a6da8d7 1704
6a488035 1705 /**
eceb18cc 1706 * Add a UF Join Entry.
6a488035 1707 *
100fef9d 1708 * @param array $params
a6c01b45
CW
1709 * @return int
1710 * $id of created UF Join
6a488035 1711 */
00be9182 1712 public function ufjoinCreate($params = NULL) {
6a488035
TO
1713 if ($params === NULL) {
1714 $params = array(
1715 'is_active' => 1,
1716 'module' => 'CiviEvent',
1717 'entity_table' => 'civicrm_event',
1718 'entity_id' => 3,
1719 'weight' => 1,
1720 'uf_group_id' => 1,
1721 );
1722 }
f6722559 1723 $result = $this->callAPISuccess('uf_join', 'create', $params);
6a488035
TO
1724 return $result;
1725 }
1726
1727 /**
eceb18cc 1728 * Delete a UF Join Entry.
6a488035 1729 *
a130e045
DG
1730 * @param array $params
1731 * with missing uf_group_id
6a488035 1732 */
00be9182 1733 public function ufjoinDelete($params = NULL) {
6a488035
TO
1734 if ($params === NULL) {
1735 $params = array(
1736 'is_active' => 1,
1737 'module' => 'CiviEvent',
1738 'entity_table' => 'civicrm_event',
1739 'entity_id' => 3,
1740 'weight' => 1,
1741 'uf_group_id' => '',
1742 );
1743 }
1744
1745 crm_add_uf_join($params);
1746 }
1747
c03f1689
EM
1748 /**
1749 * @param array $params
1750 * Optional parameters.
d31d0888 1751 * @param bool $reloadConfig
1752 * While enabling CiviCampaign component, we shouldn't always forcibly
1753 * reload config as this hinder hook call in test environment
c03f1689
EM
1754 *
1755 * @return int
1756 * Campaign ID.
1757 */
d31d0888 1758 public function campaignCreate($params = array(), $reloadConfig = TRUE) {
1759 $this->enableCiviCampaign($reloadConfig);
c03f1689
EM
1760 $campaign = $this->callAPISuccess('campaign', 'create', array_merge(array(
1761 'name' => 'big_campaign',
1762 'title' => 'Campaign',
1763 ), $params));
1764 return $campaign['id'];
1765 }
1766
6a488035 1767 /**
eceb18cc 1768 * Create Group for a contact.
6a488035
TO
1769 *
1770 * @param int $contactId
1771 */
00be9182 1772 public function contactGroupCreate($contactId) {
6a488035
TO
1773 $params = array(
1774 'contact_id.1' => $contactId,
1775 'group_id' => 1,
1776 );
1777
f6722559 1778 $this->callAPISuccess('GroupContact', 'Create', $params);
6a488035
TO
1779 }
1780
1781 /**
eceb18cc 1782 * Delete Group for a contact.
6a488035 1783 *
100fef9d 1784 * @param int $contactId
6a488035 1785 */
00be9182 1786 public function contactGroupDelete($contactId) {
6a488035
TO
1787 $params = array(
1788 'contact_id.1' => $contactId,
1789 'group_id' => 1,
1790 );
0f643fb2 1791 $this->civicrm_api('GroupContact', 'Delete', $params);
6a488035
TO
1792 }
1793
1794 /**
eceb18cc 1795 * Create Activity.
6a488035 1796 *
c490a46a 1797 * @param array $params
2a6da8d7 1798 * @return array|int
6a488035 1799 */
5d8b37be 1800 public function activityCreate($params = array()) {
1801 $params = array_merge(array(
1802 'subject' => 'Discussion on warm beer',
1803 'activity_date_time' => date('Ymd'),
1804 'duration_hours' => 30,
1805 'duration_minutes' => 20,
1806 'location' => 'Baker Street',
1807 'details' => 'Lets schedule a meeting',
1808 'status_id' => 1,
3af8de9f 1809 'activity_type_id' => 'Meeting',
5d8b37be 1810 ), $params);
1811 if (!isset($params['source_contact_id'])) {
1812 $params['source_contact_id'] = $this->individualCreate();
1813 }
1814 if (!isset($params['target_contact_id'])) {
1815 $params['target_contact_id'] = $this->individualCreate(array(
6a488035
TO
1816 'first_name' => 'Julia',
1817 'Last_name' => 'Anderson',
1818 'prefix' => 'Ms.',
1819 'email' => 'julia_anderson@civicrm.org',
1820 'contact_type' => 'Individual',
5d8b37be 1821 ));
1822 }
1823 if (!isset($params['assignee_contact_id'])) {
1824 $params['assignee_contact_id'] = $params['target_contact_id'];
6a488035
TO
1825 }
1826
f6722559 1827 $result = $this->callAPISuccess('Activity', 'create', $params);
6a488035 1828
5d8b37be 1829 $result['target_contact_id'] = $params['target_contact_id'];
1830 $result['assignee_contact_id'] = $params['assignee_contact_id'];
6a488035
TO
1831 return $result;
1832 }
1833
1834 /**
eceb18cc 1835 * Create an activity type.
6a488035 1836 *
e16033b4
TO
1837 * @param array $params
1838 * Parameters.
f0be539a 1839 * @return array
6a488035 1840 */
00be9182 1841 public function activityTypeCreate($params) {
f0be539a 1842 return $this->callAPISuccess('ActivityType', 'create', $params);
79d7553f 1843 }
6a488035
TO
1844
1845 /**
eceb18cc 1846 * Delete activity type.
6a488035 1847 *
e16033b4
TO
1848 * @param int $activityTypeId
1849 * Id of the activity type.
f0be539a 1850 * @return array
6a488035 1851 */
00be9182 1852 public function activityTypeDelete($activityTypeId) {
6a488035 1853 $params['activity_type_id'] = $activityTypeId;
f0be539a 1854 return $this->callAPISuccess('ActivityType', 'delete', $params);
79d7553f 1855 }
6a488035
TO
1856
1857 /**
eceb18cc 1858 * Create custom group.
6a488035 1859 *
2a6da8d7 1860 * @param array $params
27dd6252 1861 * @return array
6a488035 1862 */
00be9182 1863 public function customGroupCreate($params = array()) {
f6722559 1864 $defaults = array(
1865 'title' => 'new custom group',
1866 'extends' => 'Contact',
1867 'domain_id' => 1,
1868 'style' => 'Inline',
1869 'is_active' => 1,
1870 );
6a488035 1871
f6722559 1872 $params = array_merge($defaults, $params);
1873
f6722559 1874 //have a crack @ deleting it first in the hope this will prevent derailing our tests
5896d037 1875 $this->callAPISuccess('custom_group', 'get', array(
92915c55
TO
1876 'title' => $params['title'],
1877 array('api.custom_group.delete' => 1),
1878 ));
6a488035 1879
f6722559 1880 return $this->callAPISuccess('custom_group', 'create', $params);
6a488035
TO
1881 }
1882
1883 /**
100fef9d 1884 * Existing function doesn't allow params to be over-ridden so need a new one
6a488035 1885 * this one allows you to only pass in the params you want to change
1e1fdcf6
EM
1886 * @param array $params
1887 * @return array|int
6a488035 1888 */
00be9182 1889 public function CustomGroupCreateByParams($params = array()) {
6a488035
TO
1890 $defaults = array(
1891 'title' => "API Custom Group",
1892 'extends' => 'Contact',
1893 'domain_id' => 1,
1894 'style' => 'Inline',
1895 'is_active' => 1,
6a488035
TO
1896 );
1897 $params = array_merge($defaults, $params);
f6722559 1898 return $this->callAPISuccess('custom_group', 'create', $params);
6a488035
TO
1899 }
1900
1901 /**
eceb18cc 1902 * Create custom group with multi fields.
1e1fdcf6
EM
1903 * @param array $params
1904 * @return array|int
6a488035 1905 */
00be9182 1906 public function CustomGroupMultipleCreateByParams($params = array()) {
6a488035
TO
1907 $defaults = array(
1908 'style' => 'Tab',
1909 'is_multiple' => 1,
1910 );
1911 $params = array_merge($defaults, $params);
f6722559 1912 return $this->CustomGroupCreateByParams($params);
6a488035
TO
1913 }
1914
1915 /**
eceb18cc 1916 * Create custom group with multi fields.
1e1fdcf6
EM
1917 * @param array $params
1918 * @return array
6a488035 1919 */
00be9182 1920 public function CustomGroupMultipleCreateWithFields($params = array()) {
6a488035
TO
1921 // also need to pass on $params['custom_field'] if not set but not in place yet
1922 $ids = array();
1923 $customGroup = $this->CustomGroupMultipleCreateByParams($params);
1924 $ids['custom_group_id'] = $customGroup['id'];
6a488035 1925
5896d037 1926 $customField = $this->customFieldCreate(array(
92915c55
TO
1927 'custom_group_id' => $ids['custom_group_id'],
1928 'label' => 'field_1' . $ids['custom_group_id'],
e525d6af 1929 'in_selector' => 1,
92915c55 1930 ));
6a488035
TO
1931
1932 $ids['custom_field_id'][] = $customField['id'];
f6722559 1933
5896d037 1934 $customField = $this->customFieldCreate(array(
92915c55
TO
1935 'custom_group_id' => $ids['custom_group_id'],
1936 'default_value' => '',
1937 'label' => 'field_2' . $ids['custom_group_id'],
e525d6af 1938 'in_selector' => 1,
92915c55 1939 ));
6a488035 1940 $ids['custom_field_id'][] = $customField['id'];
f6722559 1941
5896d037 1942 $customField = $this->customFieldCreate(array(
92915c55
TO
1943 'custom_group_id' => $ids['custom_group_id'],
1944 'default_value' => '',
1945 'label' => 'field_3' . $ids['custom_group_id'],
e525d6af 1946 'in_selector' => 1,
92915c55 1947 ));
6a488035 1948 $ids['custom_field_id'][] = $customField['id'];
f6722559 1949
6a488035
TO
1950 return $ids;
1951 }
1952
1953 /**
1954 * Create a custom group with a single text custom field. See
1955 * participant:testCreateWithCustom for how to use this
1956 *
e16033b4
TO
1957 * @param string $function
1958 * __FUNCTION__.
5a4f6742
CW
1959 * @param string $filename
1960 * $file __FILE__.
6a488035 1961 *
a6c01b45
CW
1962 * @return array
1963 * ids of created objects
6a488035 1964 */
00be9182 1965 public function entityCustomGroupWithSingleFieldCreate($function, $filename) {
f6722559 1966 $params = array('title' => $function);
6a488035 1967 $entity = substr(basename($filename), 0, strlen(basename($filename)) - 8);
6c6e6187 1968 $params['extends'] = $entity ? $entity : 'Contact';
f6722559 1969 $customGroup = $this->CustomGroupCreate($params);
b422b715 1970 $customField = $this->customFieldCreate(array('custom_group_id' => $customGroup['id'], 'label' => $function));
80085473 1971 CRM_Core_PseudoConstant::flush();
6a488035
TO
1972
1973 return array('custom_group_id' => $customGroup['id'], 'custom_field_id' => $customField['id']);
1974 }
1975
d215c0e1
MH
1976 /**
1977 * Create a custom group with a single text custom field, multi-select widget, with a variety of option values including upper and lower case.
1978 * See api_v3_SyntaxConformanceTest:testCustomDataGet for how to use this
1979 *
1980 * @param string $function
1981 * __FUNCTION__.
1982 * @param string $filename
1983 * $file __FILE__.
1984 *
1985 * @return array
1986 * ids of created objects
1987 */
1988 public function entityCustomGroupWithSingleStringMultiSelectFieldCreate($function, $filename) {
1989 $params = array('title' => $function);
1990 $entity = substr(basename($filename), 0, strlen(basename($filename)) - 8);
1991 $params['extends'] = $entity ? $entity : 'Contact';
1992 $customGroup = $this->CustomGroupCreate($params);
1993 $customField = $this->customFieldCreate(array('custom_group_id' => $customGroup['id'], 'label' => $function, 'html_type' => 'Multi-Select', 'default_value' => 1));
1994 CRM_Core_PseudoConstant::flush();
1995 $options = [
1996 'defaultValue' => 'Default Value',
1997 'lowercasevalue' => 'Lowercase Value',
1998 1 => 'Integer Value',
1999 ];
2000 $custom_field_params = ['sequential' => 1, 'id' => $customField['id']];
2001 $custom_field_api_result = $this->callAPISuccess('custom_field', 'get', $custom_field_params);
2002 $this->assertNotEmpty($custom_field_api_result['values'][0]['option_group_id']);
2003 $option_group_params = ['sequential' => 1, 'id' => $custom_field_api_result['values'][0]['option_group_id']];
2004 $option_group_result = $this->callAPISuccess('OptionGroup', 'get', $option_group_params);
2005 $this->assertNotEmpty($option_group_result['values'][0]['name']);
2006 foreach ($options as $option_value => $option_label) {
2007 $option_group_params = ['option_group_id' => $option_group_result['values'][0]['name'], 'value' => $option_value, 'label' => $option_label];
2008 $option_value_result = $this->callAPISuccess('OptionValue', 'create', $option_group_params);
2009 }
2010
2011 return array('custom_group_id' => $customGroup['id'], 'custom_field_id' => $customField['id'], 'custom_field_option_group_id' => $custom_field_api_result['values'][0]['option_group_id'], 'custom_field_group_options' => $options);
2012 }
2013
2014
6a488035 2015 /**
eceb18cc 2016 * Delete custom group.
6a488035 2017 *
8deefe64
EM
2018 * @param int $customGroupID
2019 *
2020 * @return array|int
6a488035 2021 */
00be9182 2022 public function customGroupDelete($customGroupID) {
6a488035 2023 $params['id'] = $customGroupID;
f6722559 2024 return $this->callAPISuccess('custom_group', 'delete', $params);
6a488035
TO
2025 }
2026
2027 /**
eceb18cc 2028 * Create custom field.
6a488035 2029 *
e16033b4
TO
2030 * @param array $params
2031 * (custom_group_id) is required.
507d3b64 2032 * @return array
6a488035 2033 */
00be9182 2034 public function customFieldCreate($params) {
b422b715 2035 $params = array_merge(array(
2036 'label' => 'Custom Field',
6a488035
TO
2037 'data_type' => 'String',
2038 'html_type' => 'Text',
2039 'is_searchable' => 1,
2040 'is_active' => 1,
5c496c74 2041 'default_value' => 'defaultValue',
b422b715 2042 ), $params);
6a488035 2043
5c496c74 2044 $result = $this->callAPISuccess('custom_field', 'create', $params);
507d3b64
EM
2045 // these 2 functions are called with force to flush static caches
2046 CRM_Core_BAO_CustomField::getTableColumnGroup($result['id'], 1);
2047 CRM_Core_Component::getEnabledComponents(1);
2048 return $result;
6a488035
TO
2049 }
2050
2051 /**
eceb18cc 2052 * Delete custom field.
6a488035
TO
2053 *
2054 * @param int $customFieldID
8deefe64
EM
2055 *
2056 * @return array|int
6a488035 2057 */
00be9182 2058 public function customFieldDelete($customFieldID) {
6a488035
TO
2059
2060 $params['id'] = $customFieldID;
f6722559 2061 return $this->callAPISuccess('custom_field', 'delete', $params);
6a488035
TO
2062 }
2063
2064 /**
eceb18cc 2065 * Create note.
6a488035 2066 *
100fef9d 2067 * @param int $cId
a6c01b45 2068 * @return array
6a488035 2069 */
00be9182 2070 public function noteCreate($cId) {
6a488035
TO
2071 $params = array(
2072 'entity_table' => 'civicrm_contact',
2073 'entity_id' => $cId,
2074 'note' => 'hello I am testing Note',
2075 'contact_id' => $cId,
2076 'modified_date' => date('Ymd'),
2077 'subject' => 'Test Note',
6a488035
TO
2078 );
2079
f6722559 2080 return $this->callAPISuccess('Note', 'create', $params);
6a488035
TO
2081 }
2082
07fd63f5 2083 /**
eceb18cc 2084 * Enable CiviCampaign Component.
d31d0888 2085 *
2086 * @param bool $reloadConfig
2087 * Force relaod config or not
07fd63f5 2088 */
d31d0888 2089 public function enableCiviCampaign($reloadConfig = TRUE) {
07fd63f5 2090 CRM_Core_BAO_ConfigSetting::enableComponent('CiviCampaign');
d31d0888 2091 if ($reloadConfig) {
2092 // force reload of config object
2093 $config = CRM_Core_Config::singleton(TRUE, TRUE);
2094 }
07fd63f5
E
2095 //flush cache by calling with reset
2096 $activityTypes = CRM_Core_PseudoConstant::activityType(TRUE, TRUE, TRUE, 'name', TRUE);
2097 }
2098
6a488035 2099 /**
eceb18cc 2100 * Create custom field with Option Values.
6a488035 2101 *
77b97be7 2102 * @param array $customGroup
e16033b4
TO
2103 * @param string $name
2104 * Name of custom field.
412585fb 2105 * @param array $extraParams
2106 * Additional parameters to pass through.
77b97be7
EM
2107 *
2108 * @return array|int
6a488035 2109 */
412585fb 2110 public function customFieldOptionValueCreate($customGroup, $name, $extraParams = array()) {
6a488035
TO
2111 $fieldParams = array(
2112 'custom_group_id' => $customGroup['id'],
2113 'name' => 'test_custom_group',
2114 'label' => 'Country',
2115 'html_type' => 'Select',
2116 'data_type' => 'String',
2117 'weight' => 4,
2118 'is_required' => 1,
2119 'is_searchable' => 0,
2120 'is_active' => 1,
6a488035
TO
2121 );
2122
2123 $optionGroup = array(
2124 'domain_id' => 1,
2125 'name' => 'option_group1',
2126 'label' => 'option_group_label1',
2127 );
2128
2129 $optionValue = array(
2130 'option_label' => array('Label1', 'Label2'),
2131 'option_value' => array('value1', 'value2'),
2132 'option_name' => array($name . '_1', $name . '_2'),
2133 'option_weight' => array(1, 2),
2134 'option_status' => 1,
2135 );
2136
412585fb 2137 $params = array_merge($fieldParams, $optionGroup, $optionValue, $extraParams);
6a488035 2138
f6722559 2139 return $this->callAPISuccess('custom_field', 'create', $params);
6a488035
TO
2140 }
2141
4cbe18b8
EM
2142 /**
2143 * @param $entities
2144 *
2145 * @return bool
2146 */
00be9182 2147 public function confirmEntitiesDeleted($entities) {
6a488035
TO
2148 foreach ($entities as $entity) {
2149
f6722559 2150 $result = $this->callAPISuccess($entity, 'Get', array());
6a488035
TO
2151 if ($result['error'] == 1 || $result['count'] > 0) {
2152 // > than $entity[0] to allow a value to be passed in? e.g. domain?
2153 return TRUE;
2154 }
2155 }
f0be539a 2156 return FALSE;
6a488035
TO
2157 }
2158
4cbe18b8 2159 /**
0fff773f 2160 * Quick clean by emptying tables created for the test.
2161 *
2162 * @param array $tablesToTruncate
4cbe18b8 2163 * @param bool $dropCustomValueTables
507d3b64 2164 * @throws \Exception
4cbe18b8 2165 */
00be9182 2166 public function quickCleanup($tablesToTruncate, $dropCustomValueTables = FALSE) {
d67f1f28
TO
2167 if ($this->tx) {
2168 throw new Exception("CiviUnitTestCase: quickCleanup() is not compatible with useTransaction()");
2169 }
6a488035 2170 if ($dropCustomValueTables) {
0fff773f 2171 $optionGroupResult = CRM_Core_DAO::executeQuery('SELECT option_group_id FROM civicrm_custom_field');
2172 while ($optionGroupResult->fetch()) {
2173 if (!empty($optionGroupResult->option_group_id)) {
2174 CRM_Core_DAO::executeQuery('DELETE FROM civicrm_option_group WHERE id = ' . $optionGroupResult->option_group_id);
2175 }
2176 }
6a488035
TO
2177 $tablesToTruncate[] = 'civicrm_custom_group';
2178 $tablesToTruncate[] = 'civicrm_custom_field';
2179 }
2180
0b6f58fa
ARW
2181 $tablesToTruncate = array_unique(array_merge($this->_tablesToTruncate, $tablesToTruncate));
2182
6a488035
TO
2183 CRM_Core_DAO::executeQuery("SET FOREIGN_KEY_CHECKS = 0;");
2184 foreach ($tablesToTruncate as $table) {
2185 $sql = "TRUNCATE TABLE $table";
2186 CRM_Core_DAO::executeQuery($sql);
2187 }
2188 CRM_Core_DAO::executeQuery("SET FOREIGN_KEY_CHECKS = 1;");
2189
2190 if ($dropCustomValueTables) {
2191 $dbName = self::getDBName();
2192 $query = "
2193SELECT TABLE_NAME as tableName
2194FROM INFORMATION_SCHEMA.TABLES
2195WHERE TABLE_SCHEMA = '{$dbName}'
2196AND ( TABLE_NAME LIKE 'civicrm_value_%' )
2197";
2198
2199 $tableDAO = CRM_Core_DAO::executeQuery($query);
2200 while ($tableDAO->fetch()) {
2201 $sql = "DROP TABLE {$tableDAO->tableName}";
2202 CRM_Core_DAO::executeQuery($sql);
2203 }
2204 }
2205 }
2206
b38530f2
EM
2207 /**
2208 * Clean up financial entities after financial tests (so we remember to get all the tables :-))
2209 */
00be9182 2210 public function quickCleanUpFinancialEntities() {
b38530f2 2211 $tablesToTruncate = array(
a380f4a0
EM
2212 'civicrm_activity',
2213 'civicrm_activity_contact',
b38530f2 2214 'civicrm_contribution',
39d632fd 2215 'civicrm_contribution_soft',
945f423d 2216 'civicrm_contribution_product',
b38530f2 2217 'civicrm_financial_trxn',
39d632fd 2218 'civicrm_financial_item',
b38530f2
EM
2219 'civicrm_contribution_recur',
2220 'civicrm_line_item',
2221 'civicrm_contribution_page',
2222 'civicrm_payment_processor',
2223 'civicrm_entity_financial_trxn',
2224 'civicrm_membership',
2225 'civicrm_membership_type',
2226 'civicrm_membership_payment',
cab024d4 2227 'civicrm_membership_log',
f9342903 2228 'civicrm_membership_block',
b38530f2
EM
2229 'civicrm_event',
2230 'civicrm_participant',
2231 'civicrm_participant_payment',
2232 'civicrm_pledge',
294cc627 2233 'civicrm_pledge_payment',
1cf3c2b1 2234 'civicrm_price_set_entity',
108ff21a
EM
2235 'civicrm_price_field_value',
2236 'civicrm_price_field',
b38530f2
EM
2237 );
2238 $this->quickCleanup($tablesToTruncate);
4278b952 2239 CRM_Core_DAO::executeQuery("DELETE FROM civicrm_membership_status WHERE name NOT IN('New', 'Current', 'Grace', 'Expired', 'Pending', 'Cancelled', 'Deceased')");
108ff21a 2240 $this->restoreDefaultPriceSetConfig();
6d8a45ed
EM
2241 $var = TRUE;
2242 CRM_Member_BAO_Membership::createRelatedMemberships($var, $var, TRUE);
9fbf312f 2243 $this->disableTaxAndInvoicing();
83644f47 2244 $this->setCurrencySeparators(',');
2245 CRM_Core_PseudoConstant::flush('taxRates');
7a3b0ca3 2246 System::singleton()->flushProcessors();
108ff21a
EM
2247 }
2248
00be9182 2249 public function restoreDefaultPriceSetConfig() {
cdd71d6b 2250 CRM_Core_DAO::executeQuery("DELETE FROM civicrm_price_set WHERE name NOT IN('default_contribution_amount', 'default_membership_type_amount')");
2251 CRM_Core_DAO::executeQuery("UPDATE civicrm_price_set SET id = 1 WHERE name ='default_contribution_amount'");
108ff21a 2252 CRM_Core_DAO::executeQuery("INSERT INTO `civicrm_price_field` (`id`, `price_set_id`, `name`, `label`, `html_type`, `is_enter_qty`, `help_pre`, `help_post`, `weight`, `is_display_amounts`, `options_per_line`, `is_active`, `is_required`, `active_on`, `expire_on`, `javascript`, `visibility_id`) VALUES (1, 1, 'contribution_amount', 'Contribution Amount', 'Text', 0, NULL, NULL, 1, 1, 1, 1, 1, NULL, NULL, NULL, 1)");
5afce5ad 2253 CRM_Core_DAO::executeQuery("INSERT INTO `civicrm_price_field_value` (`id`, `price_field_id`, `name`, `label`, `description`, `amount`, `count`, `max_value`, `weight`, `membership_type_id`, `membership_num_terms`, `is_default`, `is_active`, `financial_type_id`, `non_deductible_amount`) VALUES (1, 1, 'contribution_amount', 'Contribution Amount', NULL, '1', NULL, NULL, 1, NULL, NULL, 0, 1, 1, 0.00)");
b38530f2 2254 }
6a488035
TO
2255 /*
2256 * Function does a 'Get' on the entity & compares the fields in the Params with those returned
2257 * Default behaviour is to also delete the entity
e16033b4 2258 * @param array $params
e4f46be0 2259 * Params array to check against.
e16033b4
TO
2260 * @param int $id
2261 * Id of the entity concerned.
2262 * @param string $entity
2263 * Name of entity concerned (e.g. membership).
2264 * @param bool $delete
2265 * Should the entity be deleted as part of this check.
2266 * @param string $errorText
2267 * Text to print on error.
6a488035 2268 */
4cbe18b8 2269 /**
c490a46a 2270 * @param array $params
100fef9d 2271 * @param int $id
4cbe18b8
EM
2272 * @param $entity
2273 * @param int $delete
2274 * @param string $errorText
2275 *
2276 * @throws Exception
2277 */
00be9182 2278 public function getAndCheck($params, $id, $entity, $delete = 1, $errorText = '') {
6a488035 2279
f6722559 2280 $result = $this->callAPISuccessGetSingle($entity, array(
6a488035 2281 'id' => $id,
6a488035
TO
2282 ));
2283
2284 if ($delete) {
f6722559 2285 $this->callAPISuccess($entity, 'Delete', array(
6a488035 2286 'id' => $id,
6a488035
TO
2287 ));
2288 }
b0aaad8c 2289 $dateFields = $keys = $dateTimeFields = array();
f6722559 2290 $fields = $this->callAPISuccess($entity, 'getfields', array('version' => 3, 'action' => 'get'));
6a488035
TO
2291 foreach ($fields['values'] as $field => $settings) {
2292 if (array_key_exists($field, $result)) {
2293 $keys[CRM_Utils_Array::Value('name', $settings, $field)] = $field;
2294 }
2295 else {
2296 $keys[CRM_Utils_Array::Value('name', $settings, $field)] = CRM_Utils_Array::value('name', $settings, $field);
2297 }
afd404ea 2298 $type = CRM_Utils_Array::value('type', $settings);
2299 if ($type == CRM_Utils_Type::T_DATE) {
2300 $dateFields[] = $settings['name'];
2301 // we should identify both real names & unique names as dates
5896d037 2302 if ($field != $settings['name']) {
afd404ea 2303 $dateFields[] = $field;
2304 }
2305 }
5896d037 2306 if ($type == CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME) {
afd404ea 2307 $dateTimeFields[] = $settings['name'];
2308 // we should identify both real names & unique names as dates
5896d037 2309 if ($field != $settings['name']) {
afd404ea 2310 $dateTimeFields[] = $field;
2311 }
6a488035
TO
2312 }
2313 }
2314
2315 if (strtolower($entity) == 'contribution') {
2316 $params['receive_date'] = date('Y-m-d', strtotime($params['receive_date']));
2317 // this is not returned in id format
2318 unset($params['payment_instrument_id']);
2319 $params['contribution_source'] = $params['source'];
2320 unset($params['source']);
2321 }
2322
2323 foreach ($params as $key => $value) {
afd404ea 2324 if ($key == 'version' || substr($key, 0, 3) == 'api' || !array_key_exists($keys[$key], $result)) {
6a488035
TO
2325 continue;
2326 }
2327 if (in_array($key, $dateFields)) {
2328 $value = date('Y-m-d', strtotime($value));
2329 $result[$key] = date('Y-m-d', strtotime($result[$key]));
2330 }
afd404ea 2331 if (in_array($key, $dateTimeFields)) {
2332 $value = date('Y-m-d H:i:s', strtotime($value));
a72cec08 2333 $result[$keys[$key]] = date('Y-m-d H:i:s', strtotime(CRM_Utils_Array::value($keys[$key], $result, CRM_Utils_Array::value($key, $result))));
afd404ea 2334 }
2335 $this->assertEquals($value, $result[$keys[$key]], $key . " GetandCheck function determines that for key {$key} value: $value doesn't match " . print_r($result[$keys[$key]], TRUE) . $errorText);
6a488035
TO
2336 }
2337 }
2338
2339 /**
eceb18cc 2340 * Get formatted values in the actual and expected result.
e16033b4
TO
2341 * @param array $actual
2342 * Actual calculated values.
2343 * @param array $expected
2344 * Expected values.
6a488035 2345 */
00be9182 2346 public function checkArrayEquals(&$actual, &$expected) {
6a488035
TO
2347 self::unsetId($actual);
2348 self::unsetId($expected);
2349 $this->assertEquals($actual, $expected);
2350 }
2351
2352 /**
100fef9d 2353 * Unset the key 'id' from the array
e16033b4
TO
2354 * @param array $unformattedArray
2355 * The array from which the 'id' has to be unset.
6a488035 2356 */
00be9182 2357 public static function unsetId(&$unformattedArray) {
6a488035
TO
2358 $formattedArray = array();
2359 if (array_key_exists('id', $unformattedArray)) {
2360 unset($unformattedArray['id']);
2361 }
a7488080 2362 if (!empty($unformattedArray['values']) && is_array($unformattedArray['values'])) {
6a488035 2363 foreach ($unformattedArray['values'] as $key => $value) {
6c6e6187 2364 if (is_array($value)) {
6a488035
TO
2365 foreach ($value as $k => $v) {
2366 if ($k == 'id') {
2367 unset($value[$k]);
2368 }
2369 }
2370 }
2371 elseif ($key == 'id') {
2372 $unformattedArray[$key];
2373 }
2374 $formattedArray = array($value);
2375 }
2376 $unformattedArray['values'] = $formattedArray;
2377 }
2378 }
2379
2380 /**
2381 * Helper to enable/disable custom directory support
2382 *
e16033b4
TO
2383 * @param array $customDirs
2384 * With members:.
6a488035
TO
2385 * 'php_path' Set to TRUE to use the default, FALSE or "" to disable support, or a string path to use another path
2386 * 'template_path' Set to TRUE to use the default, FALSE or "" to disable support, or a string path to use another path
2387 */
00be9182 2388 public function customDirectories($customDirs) {
6a488035
TO
2389 $config = CRM_Core_Config::singleton();
2390
2391 if (empty($customDirs['php_path']) || $customDirs['php_path'] === FALSE) {
2392 unset($config->customPHPPathDir);
2393 }
2394 elseif ($customDirs['php_path'] === TRUE) {
2395 $config->customPHPPathDir = dirname(dirname(__FILE__)) . '/custom_directories/php/';
2396 }
2397 else {
2398 $config->customPHPPathDir = $php_path;
2399 }
2400
2401 if (empty($customDirs['template_path']) || $customDirs['template_path'] === FALSE) {
2402 unset($config->customTemplateDir);
2403 }
2404 elseif ($customDirs['template_path'] === TRUE) {
2405 $config->customTemplateDir = dirname(dirname(__FILE__)) . '/custom_directories/templates/';
2406 }
2407 else {
2408 $config->customTemplateDir = $template_path;
2409 }
2410 }
2411
2412 /**
eceb18cc 2413 * Generate a temporary folder.
6a488035 2414 *
2a6da8d7 2415 * @param string $prefix
a6c01b45 2416 * @return string
6a488035 2417 */
00be9182 2418 public function createTempDir($prefix = 'test-') {
6a488035
TO
2419 $tempDir = CRM_Utils_File::tempdir($prefix);
2420 $this->tempDirs[] = $tempDir;
2421 return $tempDir;
2422 }
2423
00be9182 2424 public function cleanTempDirs() {
6a488035
TO
2425 if (!is_array($this->tempDirs)) {
2426 // fix test errors where this is not set
2427 return;
2428 }
2429 foreach ($this->tempDirs as $tempDir) {
2430 if (is_dir($tempDir)) {
2431 CRM_Utils_File::cleanDir($tempDir, TRUE, FALSE);
2432 }
2433 }
2434 }
2435
2436 /**
eceb18cc 2437 * Temporarily replace the singleton extension with a different one.
1e1fdcf6 2438 * @param \CRM_Extension_System $system
6a488035 2439 */
00be9182 2440 public function setExtensionSystem(CRM_Extension_System $system) {
6a488035
TO
2441 if ($this->origExtensionSystem == NULL) {
2442 $this->origExtensionSystem = CRM_Extension_System::singleton();
2443 }
2444 CRM_Extension_System::setSingleton($this->origExtensionSystem);
2445 }
2446
00be9182 2447 public function unsetExtensionSystem() {
6a488035
TO
2448 if ($this->origExtensionSystem !== NULL) {
2449 CRM_Extension_System::setSingleton($this->origExtensionSystem);
2450 $this->origExtensionSystem = NULL;
2451 }
2452 }
f17d75bb 2453
076d8c82
TO
2454 /**
2455 * Temporarily alter the settings-metadata to add a mock setting.
2456 *
2457 * WARNING: The setting metadata will disappear on the next cache-clear.
2458 *
2459 * @param $extras
2460 * @return void
2461 */
00be9182 2462 public function setMockSettingsMetaData($extras) {
e1d39824 2463 Civi::service('settings_manager')->flush();
076d8c82 2464
5896d037
TO
2465 CRM_Utils_Hook::singleton()
2466 ->setHook('civicrm_alterSettingsMetaData', function (&$metadata, $domainId, $profile) use ($extras) {
2467 $metadata = array_merge($metadata, $extras);
2468 });
076d8c82
TO
2469
2470 $fields = $this->callAPISuccess('setting', 'getfields', array());
2471 foreach ($extras as $key => $spec) {
2472 $this->assertNotEmpty($spec['title']);
2473 $this->assertEquals($spec['title'], $fields['values'][$key]['title']);
2474 }
2475 }
2476
4cbe18b8 2477 /**
100fef9d 2478 * @param string $name
4cbe18b8 2479 */
00be9182 2480 public function financialAccountDelete($name) {
f17d75bb
PN
2481 $financialAccount = new CRM_Financial_DAO_FinancialAccount();
2482 $financialAccount->name = $name;
5896d037 2483 if ($financialAccount->find(TRUE)) {
f17d75bb
PN
2484 $entityFinancialType = new CRM_Financial_DAO_EntityFinancialAccount();
2485 $entityFinancialType->financial_account_id = $financialAccount->id;
2486 $entityFinancialType->delete();
2487 $financialAccount->delete();
2488 }
2489 }
fb32de45 2490
2b7d3f8a 2491 /**
2492 * FIXME: something NULLs $GLOBALS['_HTML_QuickForm_registered_rules'] when the tests are ran all together
2493 * (NB unclear if this is still required)
2494 */
00be9182 2495 public function _sethtmlGlobals() {
2b7d3f8a 2496 $GLOBALS['_HTML_QuickForm_registered_rules'] = array(
2497 'required' => array(
2498 'html_quickform_rule_required',
21dfd5f5 2499 'HTML/QuickForm/Rule/Required.php',
2b7d3f8a 2500 ),
2501 'maxlength' => array(
2502 'html_quickform_rule_range',
21dfd5f5 2503 'HTML/QuickForm/Rule/Range.php',
2b7d3f8a 2504 ),
2505 'minlength' => array(
2506 'html_quickform_rule_range',
21dfd5f5 2507 'HTML/QuickForm/Rule/Range.php',
2b7d3f8a 2508 ),
2509 'rangelength' => array(
2510 'html_quickform_rule_range',
21dfd5f5 2511 'HTML/QuickForm/Rule/Range.php',
2b7d3f8a 2512 ),
2513 'email' => array(
2514 'html_quickform_rule_email',
21dfd5f5 2515 'HTML/QuickForm/Rule/Email.php',
2b7d3f8a 2516 ),
2517 'regex' => array(
2518 'html_quickform_rule_regex',
21dfd5f5 2519 'HTML/QuickForm/Rule/Regex.php',
2b7d3f8a 2520 ),
2521 'lettersonly' => array(
2522 'html_quickform_rule_regex',
21dfd5f5 2523 'HTML/QuickForm/Rule/Regex.php',
2b7d3f8a 2524 ),
2525 'alphanumeric' => array(
2526 'html_quickform_rule_regex',
21dfd5f5 2527 'HTML/QuickForm/Rule/Regex.php',
2b7d3f8a 2528 ),
2529 'numeric' => array(
2530 'html_quickform_rule_regex',
21dfd5f5 2531 'HTML/QuickForm/Rule/Regex.php',
2b7d3f8a 2532 ),
2533 'nopunctuation' => array(
2534 'html_quickform_rule_regex',
21dfd5f5 2535 'HTML/QuickForm/Rule/Regex.php',
2b7d3f8a 2536 ),
2537 'nonzero' => array(
2538 'html_quickform_rule_regex',
21dfd5f5 2539 'HTML/QuickForm/Rule/Regex.php',
2b7d3f8a 2540 ),
2541 'callback' => array(
2542 'html_quickform_rule_callback',
21dfd5f5 2543 'HTML/QuickForm/Rule/Callback.php',
2b7d3f8a 2544 ),
2545 'compare' => array(
2546 'html_quickform_rule_compare',
21dfd5f5
TO
2547 'HTML/QuickForm/Rule/Compare.php',
2548 ),
2b7d3f8a 2549 );
2550 // FIXME: …ditto for $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES']
2551 $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'] = array(
2552 'group' => array(
2553 'HTML/QuickForm/group.php',
21dfd5f5 2554 'HTML_QuickForm_group',
2b7d3f8a 2555 ),
2556 'hidden' => array(
2557 'HTML/QuickForm/hidden.php',
21dfd5f5 2558 'HTML_QuickForm_hidden',
2b7d3f8a 2559 ),
2560 'reset' => array(
2561 'HTML/QuickForm/reset.php',
21dfd5f5 2562 'HTML_QuickForm_reset',
2b7d3f8a 2563 ),
2564 'checkbox' => array(
2565 'HTML/QuickForm/checkbox.php',
21dfd5f5 2566 'HTML_QuickForm_checkbox',
2b7d3f8a 2567 ),
2568 'file' => array(
2569 'HTML/QuickForm/file.php',
21dfd5f5 2570 'HTML_QuickForm_file',
2b7d3f8a 2571 ),
2572 'image' => array(
2573 'HTML/QuickForm/image.php',
21dfd5f5 2574 'HTML_QuickForm_image',
2b7d3f8a 2575 ),
2576 'password' => array(
2577 'HTML/QuickForm/password.php',
21dfd5f5 2578 'HTML_QuickForm_password',
2b7d3f8a 2579 ),
2580 'radio' => array(
2581 'HTML/QuickForm/radio.php',
21dfd5f5 2582 'HTML_QuickForm_radio',
2b7d3f8a 2583 ),
2584 'button' => array(
2585 'HTML/QuickForm/button.php',
21dfd5f5 2586 'HTML_QuickForm_button',
2b7d3f8a 2587 ),
2588 'submit' => array(
2589 'HTML/QuickForm/submit.php',
21dfd5f5 2590 'HTML_QuickForm_submit',
2b7d3f8a 2591 ),
2592 'select' => array(
2593 'HTML/QuickForm/select.php',
21dfd5f5 2594 'HTML_QuickForm_select',
2b7d3f8a 2595 ),
2596 'hiddenselect' => array(
2597 'HTML/QuickForm/hiddenselect.php',
21dfd5f5 2598 'HTML_QuickForm_hiddenselect',
2b7d3f8a 2599 ),
2600 'text' => array(
2601 'HTML/QuickForm/text.php',
21dfd5f5 2602 'HTML_QuickForm_text',
2b7d3f8a 2603 ),
2604 'textarea' => array(
2605 'HTML/QuickForm/textarea.php',
21dfd5f5 2606 'HTML_QuickForm_textarea',
2b7d3f8a 2607 ),
2608 'fckeditor' => array(
2609 'HTML/QuickForm/fckeditor.php',
21dfd5f5 2610 'HTML_QuickForm_FCKEditor',
2b7d3f8a 2611 ),
2612 'tinymce' => array(
2613 'HTML/QuickForm/tinymce.php',
21dfd5f5 2614 'HTML_QuickForm_TinyMCE',
2b7d3f8a 2615 ),
2616 'dojoeditor' => array(
2617 'HTML/QuickForm/dojoeditor.php',
21dfd5f5 2618 'HTML_QuickForm_dojoeditor',
2b7d3f8a 2619 ),
2620 'link' => array(
2621 'HTML/QuickForm/link.php',
21dfd5f5 2622 'HTML_QuickForm_link',
2b7d3f8a 2623 ),
2624 'advcheckbox' => array(
2625 'HTML/QuickForm/advcheckbox.php',
21dfd5f5 2626 'HTML_QuickForm_advcheckbox',
2b7d3f8a 2627 ),
2628 'date' => array(
2629 'HTML/QuickForm/date.php',
21dfd5f5 2630 'HTML_QuickForm_date',
2b7d3f8a 2631 ),
2632 'static' => array(
2633 'HTML/QuickForm/static.php',
21dfd5f5 2634 'HTML_QuickForm_static',
2b7d3f8a 2635 ),
2636 'header' => array(
2637 'HTML/QuickForm/header.php',
21dfd5f5 2638 'HTML_QuickForm_header',
2b7d3f8a 2639 ),
2640 'html' => array(
2641 'HTML/QuickForm/html.php',
21dfd5f5 2642 'HTML_QuickForm_html',
2b7d3f8a 2643 ),
2644 'hierselect' => array(
2645 'HTML/QuickForm/hierselect.php',
21dfd5f5 2646 'HTML_QuickForm_hierselect',
2b7d3f8a 2647 ),
2648 'autocomplete' => array(
2649 'HTML/QuickForm/autocomplete.php',
21dfd5f5 2650 'HTML_QuickForm_autocomplete',
2b7d3f8a 2651 ),
2652 'xbutton' => array(
2653 'HTML/QuickForm/xbutton.php',
21dfd5f5 2654 'HTML_QuickForm_xbutton',
2b7d3f8a 2655 ),
2656 'advmultiselect' => array(
2657 'HTML/QuickForm/advmultiselect.php',
21dfd5f5
TO
2658 'HTML_QuickForm_advmultiselect',
2659 ),
2b7d3f8a 2660 );
2661 }
2662
48e399ac
EM
2663 /**
2664 * Set up an acl allowing contact to see 2 specified groups
c206647d 2665 * - $this->_permissionedGroup & $this->_permissionedDisabledGroup
48e399ac 2666 *
c206647d 2667 * You need to have pre-created these groups & created the user e.g
48e399ac
EM
2668 * $this->createLoggedInUser();
2669 * $this->_permissionedDisabledGroup = $this->groupCreate(array('title' => 'pick-me-disabled', 'is_active' => 0, 'name' => 'pick-me-disabled'));
2670 * $this->_permissionedGroup = $this->groupCreate(array('title' => 'pick-me-active', 'is_active' => 1, 'name' => 'pick-me-active'));
ea3ddccf 2671 *
2672 * @param bool $isProfile
48e399ac 2673 */
181f536c 2674 public function setupACL($isProfile = FALSE) {
aaac0e0b
EM
2675 global $_REQUEST;
2676 $_REQUEST = $this->_params;
108ff21a 2677
48e399ac
EM
2678 CRM_Core_Config::singleton()->userPermissionClass->permissions = array('access CiviCRM');
2679 $optionGroupID = $this->callAPISuccessGetValue('option_group', array('return' => 'id', 'name' => 'acl_role'));
e5720c45
SL
2680 $ov = new CRM_Core_DAO_OptionValue();
2681 $ov->option_group_id = $optionGroupID;
2682 $ov->value = 55;
2683 if ($ov->find(TRUE)) {
2684 CRM_Core_DAO::executeQuery("DELETE FROM civicrm_option_value WHERE id = {$ov->id}");
2685 }
6c6e6187 2686 $optionValue = $this->callAPISuccess('option_value', 'create', array(
5896d037 2687 'option_group_id' => $optionGroupID,
48e399ac
EM
2688 'label' => 'pick me',
2689 'value' => 55,
2690 ));
2691
48e399ac
EM
2692 CRM_Core_DAO::executeQuery("
2693 TRUNCATE civicrm_acl_cache
2694 ");
2695
2696 CRM_Core_DAO::executeQuery("
2697 TRUNCATE civicrm_acl_contact_cache
2698 ");
2699
48e399ac
EM
2700 CRM_Core_DAO::executeQuery("
2701 INSERT INTO civicrm_acl_entity_role (
181f536c 2702 `acl_role_id`, `entity_table`, `entity_id`, `is_active`
2703 ) VALUES (55, 'civicrm_group', {$this->_permissionedGroup}, 1);
48e399ac
EM
2704 ");
2705
181f536c 2706 if ($isProfile) {
2707 CRM_Core_DAO::executeQuery("
2708 INSERT INTO civicrm_acl (
2709 `name`, `entity_table`, `entity_id`, `operation`, `object_table`, `object_id`, `is_active`
2710 )
2711 VALUES (
2712 'view picked', 'civicrm_acl_role', 55, 'Edit', 'civicrm_uf_group', 0, 1
2713 );
2714 ");
2715 }
2716 else {
2717 CRM_Core_DAO::executeQuery("
2718 INSERT INTO civicrm_acl (
2719 `name`, `entity_table`, `entity_id`, `operation`, `object_table`, `object_id`, `is_active`
2720 )
2721 VALUES (
2722 'view picked', 'civicrm_group', $this->_permissionedGroup , 'Edit', 'civicrm_saved_search', {$this->_permissionedGroup}, 1
2723 );
2724 ");
2725
2726 CRM_Core_DAO::executeQuery("
2727 INSERT INTO civicrm_acl (
2728 `name`, `entity_table`, `entity_id`, `operation`, `object_table`, `object_id`, `is_active`
2729 )
2730 VALUES (
2731 'view picked', 'civicrm_group', $this->_permissionedGroup, 'Edit', 'civicrm_saved_search', {$this->_permissionedDisabledGroup}, 1
2732 );
2733 ");
181f536c 2734 }
48e399ac 2735
48e399ac
EM
2736 $this->_loggedInUser = CRM_Core_Session::singleton()->get('userID');
2737 $this->callAPISuccess('group_contact', 'create', array(
2738 'group_id' => $this->_permissionedGroup,
2739 'contact_id' => $this->_loggedInUser,
2740 ));
08a2ea5e 2741
2742 if (!$isProfile) {
2743 //flush cache
2744 CRM_ACL_BAO_Cache::resetCache();
08a2ea5e 2745 CRM_ACL_API::groupPermission('whatever', 9999, NULL, 'civicrm_saved_search', NULL, NULL, TRUE);
2746 }
48e399ac
EM
2747 }
2748
cab024d4 2749 /**
100fef9d 2750 * Alter default price set so that the field numbers are not all 1 (hiding errors)
cab024d4 2751 */
00be9182 2752 public function offsetDefaultPriceSet() {
cab024d4
EM
2753 $contributionPriceSet = $this->callAPISuccess('price_set', 'getsingle', array('name' => 'default_contribution_amount'));
2754 $firstID = $contributionPriceSet['id'];
5896d037 2755 $this->callAPISuccess('price_set', 'create', array(
92915c55
TO
2756 'id' => $contributionPriceSet['id'],
2757 'is_active' => 0,
2758 'name' => 'old',
2759 ));
cab024d4
EM
2760 unset($contributionPriceSet['id']);
2761 $newPriceSet = $this->callAPISuccess('price_set', 'create', $contributionPriceSet);
5896d037 2762 $priceField = $this->callAPISuccess('price_field', 'getsingle', array(
92915c55
TO
2763 'price_set_id' => $firstID,
2764 'options' => array('limit' => 1),
2765 ));
cab024d4
EM
2766 unset($priceField['id']);
2767 $priceField['price_set_id'] = $newPriceSet['id'];
2768 $newPriceField = $this->callAPISuccess('price_field', 'create', $priceField);
5896d037 2769 $priceFieldValue = $this->callAPISuccess('price_field_value', 'getsingle', array(
92915c55
TO
2770 'price_set_id' => $firstID,
2771 'sequential' => 1,
2772 'options' => array('limit' => 1),
2773 ));
cab024d4
EM
2774
2775 unset($priceFieldValue['id']);
2776 //create some padding to use up ids
2777 $this->callAPISuccess('price_field_value', 'create', $priceFieldValue);
2778 $this->callAPISuccess('price_field_value', 'create', $priceFieldValue);
2779 $this->callAPISuccess('price_field_value', 'create', array_merge($priceFieldValue, array('price_field_id' => $newPriceField['id'])));
cab024d4
EM
2780 }
2781
4aef704e 2782 /**
eceb18cc 2783 * Create an instance of the paypal processor.
4aef704e 2784 * @todo this isn't a great place to put it - but really it belongs on a class that extends
2785 * this parent class & we don't have a structure for that yet
2786 * There is another function to this effect on the PaypalPro test but it appears to be silently failing
e4f46be0 2787 * & the best protection against that is the functions this class affords
1e1fdcf6 2788 * @param array $params
79d7553f 2789 * @return int $result['id'] payment processor id
4aef704e 2790 */
00be9182 2791 public function paymentProcessorCreate($params = array()) {
4aef704e 2792 $params = array_merge(array(
5896d037
TO
2793 'name' => 'demo',
2794 'domain_id' => CRM_Core_Config::domainID(),
2795 'payment_processor_type_id' => 'PayPal',
2796 'is_active' => 1,
2797 'is_default' => 0,
2798 'is_test' => 1,
2799 'user_name' => 'sunil._1183377782_biz_api1.webaccess.co.in',
2800 'password' => '1183377788',
2801 'signature' => 'APixCoQ-Zsaj-u3IH7mD5Do-7HUqA9loGnLSzsZga9Zr-aNmaJa3WGPH',
2802 'url_site' => 'https://www.sandbox.paypal.com/',
2803 'url_api' => 'https://api-3t.sandbox.paypal.com/',
2804 'url_button' => 'https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif',
2805 'class_name' => 'Payment_PayPalImpl',
2806 'billing_mode' => 3,
2807 'financial_type_id' => 1,
43c8d1dd 2808 'financial_account_id' => 12,
f69a9ac3 2809 // Credit card = 1 so can pass 'by accident'.
2810 'payment_instrument_id' => 'Debit Card',
5896d037
TO
2811 ),
2812 $params);
2813 if (!is_numeric($params['payment_processor_type_id'])) {
4aef704e 2814 // really the api should handle this through getoptions but it's not exactly api call so lets just sort it
2815 //here
2816 $params['payment_processor_type_id'] = $this->callAPISuccess('payment_processor_type', 'getvalue', array(
2817 'name' => $params['payment_processor_type_id'],
2818 'return' => 'id',
2819 ), 'integer');
2820 }
2821 $result = $this->callAPISuccess('payment_processor', 'create', $params);
2822 return $result['id'];
2823 }
a9ac877b 2824
0dbefed3 2825 /**
eceb18cc 2826 * Set up initial recurring payment allowing subsequent IPN payments.
9f68fe61
MW
2827 *
2828 * @param array $recurParams (Optional)
2829 * @param array $contributionParams (Optional)
0dbefed3 2830 */
9f68fe61
MW
2831 public function setupRecurringPaymentProcessorTransaction($recurParams = [], $contributionParams = []) {
2832 $contributionParams = array_merge([
2833 'total_amount' => '200',
2834 'invoice_id' => $this->_invoiceID,
2835 'financial_type_id' => 'Donation',
2836 'contribution_status_id' => 'Pending',
2837 'contact_id' => $this->_contactID,
2838 'contribution_page_id' => $this->_contributionPageID,
2839 'payment_processor_id' => $this->_paymentProcessorID,
2840 'is_test' => 0,
2841 'skipCleanMoney' => TRUE,
2842 ],
2843 $contributionParams
2844 );
b6b59c64 2845 $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', array_merge(array(
0dbefed3
EM
2846 'contact_id' => $this->_contactID,
2847 'amount' => 1000,
2848 'sequential' => 1,
2849 'installments' => 5,
2850 'frequency_unit' => 'Month',
2851 'frequency_interval' => 1,
2852 'invoice_id' => $this->_invoiceID,
2853 'contribution_status_id' => 2,
481312d9 2854 'payment_processor_id' => $this->_paymentProcessorID,
2855 // processor provided ID - use contact ID as proxy.
2856 'processor_id' => $this->_contactID,
9f68fe61
MW
2857 'api.contribution.create' => $contributionParams,
2858 ), $recurParams));
0dbefed3
EM
2859 $this->_contributionRecurID = $contributionRecur['id'];
2860 $this->_contributionID = $contributionRecur['values']['0']['api.contribution.create']['id'];
2861 }
a86d27fc 2862
a9ac877b 2863 /**
100fef9d 2864 * We don't have a good way to set up a recurring contribution with a membership so let's just do one then alter it
b3c283b4
MW
2865 *
2866 * @param array $params Optionally modify params for membership/recur (duration_unit/frequency_unit)
a9ac877b 2867 */
b3c283b4
MW
2868 public function setupMembershipRecurringPaymentProcessorTransaction($params = array()) {
2869 $membershipParams = $recurParams = array();
2870 if (!empty($params['duration_unit'])) {
2871 $membershipParams['duration_unit'] = $params['duration_unit'];
2872 }
2873 if (!empty($params['frequency_unit'])) {
2874 $recurParams['frequency_unit'] = $params['frequency_unit'];
2875 }
2876
2877 $this->ids['membership_type'] = $this->membershipTypeCreate($membershipParams);
69140e67 2878 //create a contribution so our membership & contribution don't both have id = 1
b6b59c64 2879 if ($this->callAPISuccess('Contribution', 'getcount', array()) == 0) {
2880 $this->contributionCreate(array(
2881 'contact_id' => $this->_contactID,
2882 'is_test' => 1,
2883 'financial_type_id' => 1,
2884 'invoice_id' => 'abcd',
2885 'trxn_id' => 345,
2886 ));
2887 }
b3c283b4 2888 $this->setupRecurringPaymentProcessorTransaction($recurParams);
69140e67 2889
a9ac877b
EM
2890 $this->ids['membership'] = $this->callAPISuccess('membership', 'create', array(
2891 'contact_id' => $this->_contactID,
2892 'membership_type_id' => $this->ids['membership_type'],
2893 'contribution_recur_id' => $this->_contributionRecurID,
a9ac877b
EM
2894 'format.only_id' => TRUE,
2895 ));
69140e67
EM
2896 //CRM-15055 creates line items we don't want so get rid of them so we can set up our own line items
2897 CRM_Core_DAO::executeQuery("TRUNCATE civicrm_line_item");
2898
2899 $this->callAPISuccess('line_item', 'create', array(
2900 'entity_table' => 'civicrm_membership',
2901 'entity_id' => $this->ids['membership'],
2902 'contribution_id' => $this->_contributionID,
2903 'label' => 'General',
2904 'qty' => 1,
2905 'unit_price' => 200,
2906 'line_total' => 200,
2907 'financial_type_id' => 1,
5896d037 2908 'price_field_id' => $this->callAPISuccess('price_field', 'getvalue', array(
92915c55
TO
2909 'return' => 'id',
2910 'label' => 'Membership Amount',
b6b59c64 2911 'options' => array('limit' => 1, 'sort' => 'id DESC'),
92915c55 2912 )),
5896d037 2913 'price_field_value_id' => $this->callAPISuccess('price_field_value', 'getvalue', array(
92915c55
TO
2914 'return' => 'id',
2915 'label' => 'General',
b6b59c64 2916 'options' => array('limit' => 1, 'sort' => 'id DESC'),
92915c55 2917 )),
69140e67 2918 ));
5896d037 2919 $this->callAPISuccess('membership_payment', 'create', array(
92915c55
TO
2920 'contribution_id' => $this->_contributionID,
2921 'membership_id' => $this->ids['membership'],
2922 ));
a9ac877b 2923 }
6a488035 2924
4cbe18b8
EM
2925 /**
2926 * @param $message
2927 *
2928 * @throws Exception
a9ac877b 2929 */
00be9182 2930 public function CiviUnitTestCase_fatalErrorHandler($message) {
a9ac877b
EM
2931 throw new Exception("{$message['message']}: {$message['code']}");
2932 }
4aef704e 2933
2934 /**
eceb18cc 2935 * Helper function to create new mailing.
cdc5c450 2936 *
2937 * @param array $params
2938 *
2939 * @return int
4aef704e 2940 */
d15a97f4 2941 public function createMailing($params = array()) {
cdc5c450 2942 $params = array_merge(array(
4aef704e 2943 'subject' => 'maild' . rand(),
21b09c13 2944 'body_text' => 'bdkfhdskfhduew{domain.address}{action.optOutUrl}',
4aef704e 2945 'name' => 'mailing name' . rand(),
2946 'created_id' => 1,
cdc5c450 2947 ), $params);
4aef704e 2948
2949 $result = $this->callAPISuccess('Mailing', 'create', $params);
2950 return $result['id'];
2951 }
2952
2953 /**
eceb18cc 2954 * Helper function to delete mailing.
4aef704e 2955 * @param $id
2956 */
00be9182 2957 public function deleteMailing($id) {
4aef704e 2958 $params = array(
2959 'id' => $id,
2960 );
2961
2962 $this->callAPISuccess('Mailing', 'delete', $params);
2963 }
d67f1f28
TO
2964
2965 /**
eceb18cc 2966 * Wrap the entire test case in a transaction.
d67f1f28
TO
2967 *
2968 * Only subsequent DB statements will be wrapped in TX -- this cannot
2969 * retroactively wrap old DB statements. Therefore, it makes sense to
2970 * call this at the beginning of setUp().
2971 *
2972 * Note: Recall that TRUNCATE and ALTER will force-commit transactions, so
2973 * this option does not work with, e.g., custom-data.
2974 *
2975 * WISHLIST: Monitor SQL queries in unit-tests and generate an exception
2976 * if TRUNCATE or ALTER is called while using a transaction.
2977 *
e16033b4
TO
2978 * @param bool $nest
2979 * Whether to use nesting or reference-counting.
d67f1f28 2980 */
00be9182 2981 public function useTransaction($nest = TRUE) {
d67f1f28
TO
2982 if (!$this->tx) {
2983 $this->tx = new CRM_Core_Transaction($nest);
2984 $this->tx->rollback();
2985 }
2986 }
a335f6b2 2987
b3c30fda 2988 /**
54957108 2989 * Assert the attachment exists.
2990 *
2991 * @param bool $exists
b3c30fda
CW
2992 * @param array $apiResult
2993 */
2994 protected function assertAttachmentExistence($exists, $apiResult) {
2995 $fileId = $apiResult['id'];
2996 $this->assertTrue(is_numeric($fileId));
2997 $this->assertEquals($exists, file_exists($apiResult['values'][$fileId]['path']));
2998 $this->assertDBQuery($exists ? 1 : 0, 'SELECT count(*) FROM civicrm_file WHERE id = %1', array(
2999 1 => array($fileId, 'Int'),
3000 ));
3001 $this->assertDBQuery($exists ? 1 : 0, 'SELECT count(*) FROM civicrm_entity_file WHERE id = %1', array(
3002 1 => array($fileId, 'Int'),
3003 ));
3004 }
3005
c039f658 3006 /**
3007 * Create a price set for an event.
3008 *
3009 * @param int $feeTotal
601c7a24 3010 * @param int $minAmt
f660d2ad 3011 * @param string $type
c039f658 3012 *
3013 * @return int
3014 * Price Set ID.
3015 */
f660d2ad 3016 protected function eventPriceSetCreate($feeTotal, $minAmt = 0, $type = 'Text') {
c039f658 3017 // creating price set, price field
3018 $paramsSet['title'] = 'Price Set';
3019 $paramsSet['name'] = CRM_Utils_String::titleToVar('Price Set');
3020 $paramsSet['is_active'] = FALSE;
3021 $paramsSet['extends'] = 1;
601c7a24 3022 $paramsSet['min_amount'] = $minAmt;
c039f658 3023
f660d2ad 3024 $priceSet = CRM_Price_BAO_PriceSet::create($paramsSet);
3025 $this->_ids['price_set'] = $priceSet->id;
c039f658 3026
c039f658 3027 $paramsField = array(
3028 'label' => 'Price Field',
3029 'name' => CRM_Utils_String::titleToVar('Price Field'),
f660d2ad 3030 'html_type' => $type,
c039f658 3031 'price' => $feeTotal,
3032 'option_label' => array('1' => 'Price Field'),
3033 'option_value' => array('1' => $feeTotal),
3034 'option_name' => array('1' => $feeTotal),
3035 'option_weight' => array('1' => 1),
3036 'option_amount' => array('1' => 1),
3037 'is_display_amounts' => 1,
3038 'weight' => 1,
3039 'options_per_line' => 1,
3040 'is_active' => array('1' => 1),
f660d2ad 3041 'price_set_id' => $this->_ids['price_set'],
c039f658 3042 'is_enter_qty' => 1,
8484a5f0 3043 'financial_type_id' => $this->getFinancialTypeId('Event Fee'),
c039f658 3044 );
f660d2ad 3045 if ($type === 'Radio') {
3046 $paramsField['is_enter_qty'] = 0;
3047 $paramsField['option_value'][2] = $paramsField['option_weight'][2] = $paramsField['option_amount'][2] = 100;
3048 $paramsField['option_label'][2] = $paramsField['option_name'][2] = 'hundy';
3049 }
c039f658 3050 CRM_Price_BAO_PriceField::create($paramsField);
f660d2ad 3051 $fields = $this->callAPISuccess('PriceField', 'get', array('price_set_id' => $this->_ids['price_set']));
3052 $this->_ids['price_field'] = array_keys($fields['values']);
3053 $fieldValues = $this->callAPISuccess('PriceFieldValue', 'get', array('price_field_id' => $this->_ids['price_field'][0]));
3054 $this->_ids['price_field_value'] = array_keys($fieldValues['values']);
c039f658 3055
f660d2ad 3056 return $this->_ids['price_set'];
c039f658 3057 }
3058
481312d9 3059 /**
3060 * Add a profile to a contribution page.
3061 *
3062 * @param string $name
3063 * @param int $contributionPageID
5d6cf648 3064 * @param string $module
481312d9 3065 */
5d6cf648
JM
3066 protected function addProfile($name, $contributionPageID, $module = 'CiviContribute') {
3067 $params = [
481312d9 3068 'uf_group_id' => $name,
5d6cf648 3069 'module' => $module,
481312d9 3070 'entity_table' => 'civicrm_contribution_page',
3071 'entity_id' => $contributionPageID,
3072 'weight' => 1,
5d6cf648
JM
3073 ];
3074 if ($module !== 'CiviContribute') {
3075 $params['module_data'] = [$module => []];
3076 }
3077 $this->callAPISuccess('UFJoin', 'create', $params);
481312d9 3078 }
3079
db62fd2b
PN
3080 /**
3081 * Add participant with contribution
3082 *
3083 * @return array
3084 */
3085 protected function createParticipantWithContribution() {
3086 // creating price set, price field
a630a84e 3087 $this->_contactId = $this->individualCreate();
3088 $event = $this->eventCreate();
3089 $this->_eventId = $event['id'];
db62fd2b
PN
3090 $eventParams = array(
3091 'id' => $this->_eventId,
3092 'financial_type_id' => 4,
3093 'is_monetary' => 1,
3094 );
3095 $this->callAPISuccess('event', 'create', $eventParams);
73c0e107 3096 $priceFields = $this->createPriceSet('event', $this->_eventId);
db62fd2b
PN
3097 $participantParams = array(
3098 'financial_type_id' => 4,
3099 'event_id' => $this->_eventId,
3100 'role_id' => 1,
3101 'status_id' => 14,
3102 'fee_currency' => 'USD',
3103 'contact_id' => $this->_contactId,
3104 );
3105 $participant = $this->callAPISuccess('Participant', 'create', $participantParams);
3106 $contributionParams = array(
3107 'total_amount' => 150,
3108 'currency' => 'USD',
3109 'contact_id' => $this->_contactId,
3110 'financial_type_id' => 4,
3111 'contribution_status_id' => 1,
3112 'partial_payment_total' => 300.00,
f49cdeab 3113 'partial_amount_to_pay' => 150,
db62fd2b
PN
3114 'contribution_mode' => 'participant',
3115 'participant_id' => $participant['id'],
3116 );
3117 foreach ($priceFields['values'] as $key => $priceField) {
3118 $lineItems[1][$key] = array(
3119 'price_field_id' => $priceField['price_field_id'],
3120 'price_field_value_id' => $priceField['id'],
3121 'label' => $priceField['label'],
3122 'field_title' => $priceField['label'],
3123 'qty' => 1,
3124 'unit_price' => $priceField['amount'],
3125 'line_total' => $priceField['amount'],
3126 'financial_type_id' => $priceField['financial_type_id'],
3127 );
3128 }
3129 $contributionParams['line_item'] = $lineItems;
3130 $contribution = $this->callAPISuccess('Contribution', 'create', $contributionParams);
3131 $paymentParticipant = array(
3132 'participant_id' => $participant['id'],
3133 'contribution_id' => $contribution['id'],
3134 );
db62fd2b
PN
3135 $this->callAPISuccess('ParticipantPayment', 'create', $paymentParticipant);
3136 return array($lineItems, $contribution);
3137 }
3138
73c0e107
PN
3139 /**
3140 * Create price set
3141 *
3142 * @param string $component
3143 * @param int $componentId
3144 *
3145 * @return array
3146 */
c91b1cc3 3147 protected function createPriceSet($component = 'contribution_page', $componentId = NULL, $priceFieldOptions = array()) {
5c3d600f
PN
3148 $paramsSet['title'] = 'Price Set' . substr(sha1(rand()), 0, 7);
3149 $paramsSet['name'] = CRM_Utils_String::titleToVar($paramsSet['title']);
73c0e107
PN
3150 $paramsSet['is_active'] = TRUE;
3151 $paramsSet['financial_type_id'] = 4;
3152 $paramsSet['extends'] = 1;
3153 $priceSet = $this->callAPISuccess('price_set', 'create', $paramsSet);
3154 $priceSetId = $priceSet['id'];
3155 //Checking for priceset added in the table.
3156 $this->assertDBCompareValue('CRM_Price_BAO_PriceSet', $priceSetId, 'title',
3157 'id', $paramsSet['title'], 'Check DB for created priceset'
3158 );
c91b1cc3 3159 $paramsField = array_merge(array(
73c0e107
PN
3160 'label' => 'Price Field',
3161 'name' => CRM_Utils_String::titleToVar('Price Field'),
3162 'html_type' => 'CheckBox',
3163 'option_label' => array('1' => 'Price Field 1', '2' => 'Price Field 2'),
3164 'option_value' => array('1' => 100, '2' => 200),
3165 'option_name' => array('1' => 'Price Field 1', '2' => 'Price Field 2'),
3166 'option_weight' => array('1' => 1, '2' => 2),
3167 'option_amount' => array('1' => 100, '2' => 200),
3168 'is_display_amounts' => 1,
3169 'weight' => 1,
3170 'options_per_line' => 1,
3171 'is_active' => array('1' => 1, '2' => 1),
3172 'price_set_id' => $priceSet['id'],
3173 'is_enter_qty' => 1,
8484a5f0 3174 'financial_type_id' => $this->getFinancialTypeId('Event Fee'),
c91b1cc3
E
3175 ), $priceFieldOptions);
3176
73c0e107
PN
3177 $priceField = CRM_Price_BAO_PriceField::create($paramsField);
3178 if ($componentId) {
3179 CRM_Price_BAO_PriceSet::addTo('civicrm_' . $component, $componentId, $priceSetId);
3180 }
3181 return $this->callAPISuccess('PriceFieldValue', 'get', array('price_field_id' => $priceField->id));
3182 }
3183
b80f2ad1
E
3184 /**
3185 * Replace the template with a test-oriented template designed to show all the variables.
3186 *
3187 * @param string $templateName
3188 */
3189 protected function swapMessageTemplateForTestTemplate($templateName = 'contribution_online_receipt') {
3190 $testTemplate = file_get_contents(__DIR__ . '/../../templates/message_templates/' . $templateName . '_html.tpl');
3191 CRM_Core_DAO::executeQuery(
3192 "UPDATE civicrm_option_group og
3193 LEFT JOIN civicrm_option_value ov ON ov.option_group_id = og.id
3194 LEFT JOIN civicrm_msg_template m ON m.workflow_id = ov.id
3195 SET m.msg_html = '{$testTemplate}'
3196 WHERE og.name = 'msg_tpl_workflow_contribution'
3197 AND ov.name = '{$templateName}'
3198 AND m.is_default = 1"
3199 );
3200 }
3201
3202 /**
3203 * Reinstate the default template.
3204 *
3205 * @param string $templateName
3206 */
3207 protected function revertTemplateToReservedTemplate($templateName = 'contribution_online_receipt') {
3208 CRM_Core_DAO::executeQuery(
3209 "UPDATE civicrm_option_group og
3210 LEFT JOIN civicrm_option_value ov ON ov.option_group_id = og.id
3211 LEFT JOIN civicrm_msg_template m ON m.workflow_id = ov.id
3212 LEFT JOIN civicrm_msg_template m2 ON m2.workflow_id = ov.id AND m2.is_reserved = 1
3213 SET m.msg_html = m2.msg_html
3214 WHERE og.name = 'msg_tpl_workflow_contribution'
3215 AND ov.name = '{$templateName}'
3216 AND m.is_default = 1"
3217 );
3218 }
3219
8d35246a
EM
3220 /**
3221 * Flush statics relating to financial type.
3222 */
3223 protected function flushFinancialTypeStatics() {
3224 if (isset(\Civi::$statics['CRM_Financial_BAO_FinancialType'])) {
3225 unset(\Civi::$statics['CRM_Financial_BAO_FinancialType']);
3226 }
4954339a
EM
3227 if (isset(\Civi::$statics['CRM_Contribute_PseudoConstant'])) {
3228 unset(\Civi::$statics['CRM_Contribute_PseudoConstant']);
3229 }
8d35246a 3230 CRM_Contribute_PseudoConstant::flush('financialType');
4954339a
EM
3231 CRM_Contribute_PseudoConstant::flush('membershipType');
3232 // Pseudoconstants may be saved to the cache table.
3233 CRM_Core_DAO::executeQuery("TRUNCATE civicrm_cache");
3234 CRM_Financial_BAO_FinancialType::$_statusACLFt = array();
8d35246a
EM
3235 CRM_Financial_BAO_FinancialType::$_availableFinancialTypes = NULL;
3236 }
3237
3238 /**
3239 * Set the permissions to the supplied array.
3240 *
3241 * @param array $permissions
3242 */
3243 protected function setPermissions($permissions) {
3244 CRM_Core_Config::singleton()->userPermissionClass->permissions = $permissions;
3245 $this->flushFinancialTypeStatics();
3246 }
3247
bf722049 3248 /**
3249 * @param array $params
3250 * @param $context
3251 */
3252 public function _checkFinancialRecords($params, $context) {
3253 $entityParams = array(
3254 'entity_id' => $params['id'],
3255 'entity_table' => 'civicrm_contribution',
3256 );
3257 $contribution = $this->callAPISuccess('contribution', 'getsingle', array('id' => $params['id']));
3258 $this->assertEquals($contribution['total_amount'] - $contribution['fee_amount'], $contribution['net_amount']);
3259 if ($context == 'pending') {
3260 $trxn = CRM_Financial_BAO_FinancialItem::retrieveEntityFinancialTrxn($entityParams);
3261 $this->assertNull($trxn, 'No Trxn to be created until IPN callback');
3262 return;
3263 }
3264 $trxn = current(CRM_Financial_BAO_FinancialItem::retrieveEntityFinancialTrxn($entityParams));
3265 $trxnParams = array(
3266 'id' => $trxn['financial_trxn_id'],
3267 );
3268 if ($context != 'online' && $context != 'payLater') {
3269 $compareParams = array(
3270 'to_financial_account_id' => 6,
3271 'total_amount' => CRM_Utils_Array::value('total_amount', $params, 100),
3272 'status_id' => 1,
3273 );
3274 }
3275 if ($context == 'feeAmount') {
3276 $compareParams['fee_amount'] = 50;
3277 }
3278 elseif ($context == 'online') {
3279 $compareParams = array(
3280 'to_financial_account_id' => 12,
3281 'total_amount' => CRM_Utils_Array::value('total_amount', $params, 100),
3282 'status_id' => 1,
f69a9ac3 3283 'payment_instrument_id' => CRM_Utils_Array::value('payment_instrument_id', $params, 1),
bf722049 3284 );
3285 }
3286 elseif ($context == 'payLater') {
3287 $compareParams = array(
3288 'to_financial_account_id' => 7,
3289 'total_amount' => CRM_Utils_Array::value('total_amount', $params, 100),
3290 'status_id' => 2,
3291 );
3292 }
3293 $this->assertDBCompareValues('CRM_Financial_DAO_FinancialTrxn', $trxnParams, $compareParams);
3294 $entityParams = array(
3295 'financial_trxn_id' => $trxn['financial_trxn_id'],
3296 'entity_table' => 'civicrm_financial_item',
3297 );
3298 $entityTrxn = current(CRM_Financial_BAO_FinancialItem::retrieveEntityFinancialTrxn($entityParams));
3299 $fitemParams = array(
3300 'id' => $entityTrxn['entity_id'],
3301 );
3302 $compareParams = array(
3303 'amount' => CRM_Utils_Array::value('total_amount', $params, 100),
3304 'status_id' => 1,
1a1a2f4f 3305 'financial_account_id' => CRM_Utils_Array::value('financial_account_id', $params, 1),
bf722049 3306 );
3307 if ($context == 'payLater') {
3308 $compareParams = array(
3309 'amount' => CRM_Utils_Array::value('total_amount', $params, 100),
3310 'status_id' => 3,
1a1a2f4f 3311 'financial_account_id' => CRM_Utils_Array::value('financial_account_id', $params, 1),
bf722049 3312 );
3313 }
3314 $this->assertDBCompareValues('CRM_Financial_DAO_FinancialItem', $fitemParams, $compareParams);
3315 if ($context == 'feeAmount') {
3316 $maxParams = array(
3317 'entity_id' => $params['id'],
3318 'entity_table' => 'civicrm_contribution',
3319 );
3320 $maxTrxn = current(CRM_Financial_BAO_FinancialItem::retrieveEntityFinancialTrxn($maxParams, TRUE));
3321 $trxnParams = array(
3322 'id' => $maxTrxn['financial_trxn_id'],
3323 );
3324 $compareParams = array(
3325 'to_financial_account_id' => 5,
3326 'from_financial_account_id' => 6,
3327 'total_amount' => 50,
3328 'status_id' => 1,
3329 );
3330 $trxnId = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($params['id'], 'DESC');
3331 $this->assertDBCompareValues('CRM_Financial_DAO_FinancialTrxn', $trxnParams, $compareParams);
3332 $fitemParams = array(
3333 'entity_id' => $trxnId['financialTrxnId'],
3334 'entity_table' => 'civicrm_financial_trxn',
3335 );
3336 $compareParams = array(
3337 'amount' => 50,
3338 'status_id' => 1,
3339 'financial_account_id' => 5,
3340 );
3341 $this->assertDBCompareValues('CRM_Financial_DAO_FinancialItem', $fitemParams, $compareParams);
3342 }
3343 // This checks that empty Sales tax rows are not being created. If for any reason it needs to be removed the
3344 // line should be copied into all the functions that call this function & evaluated there
3345 // Be really careful not to remove or bypass this without ensuring stray rows do not re-appear
3346 // when calling completeTransaction or repeatTransaction.
3347 $this->callAPISuccessGetCount('FinancialItem', array('description' => 'Sales Tax', 'amount' => 0), 0);
3348 }
3349
8484a5f0 3350 /**
3351 * Return financial type id on basis of name
3352 *
3353 * @param string $name Financial type m/c name
3354 *
3355 * @return int
3356 */
3357 public function getFinancialTypeId($name) {
3358 return CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType', $name, 'id', 'name');
3359 }
3360
204beda3 3361 /**
3362 * Cleanup function for contents of $this->ids.
3363 *
3364 * This is a best effort cleanup to use in tear downs etc.
3365 *
3366 * It will not fail if the data has already been removed (some tests may do
3367 * their own cleanup).
3368 */
3369 protected function cleanUpSetUpIDs() {
3370 foreach ($this->setupIDs as $entity => $id) {
3371 try {
3372 civicrm_api3($entity, 'delete', array('id' => $id, 'skip_undelete' => 1));
3373 }
3374 catch (CiviCRM_API3_Exception $e) {
3375 // This is a best-effort cleanup function, ignore.
3376 }
3377 }
3378 }
3379
adbc354b
PN
3380 /**
3381 * Create Financial Type.
3382 *
3383 * @param array $params
3384 *
3385 * @return array
3386 */
3387 protected function createFinancialType($params = array()) {
3388 $params = array_merge($params,
3389 array(
3390 'name' => 'Financial-Type -' . substr(sha1(rand()), 0, 7),
3391 'is_active' => 1,
3392 )
3393 );
3394 return $this->callAPISuccess('FinancialType', 'create', $params);
3395 }
3396
e1c5a855 3397 /**
3398 * Create Payment Instrument.
3399 *
3400 * @param array $params
3401 * @param string $financialAccountName
3402 *
3403 * @return int
3404 */
3405 protected function createPaymentInstrument($params = array(), $financialAccountName = 'Donation') {
3406 $params = array_merge(array(
3407 'label' => 'Payment Instrument -' . substr(sha1(rand()), 0, 7),
3408 'option_group_id' => 'payment_instrument',
3409 'is_active' => 1,
3410 ),
3411 $params
3412 );
3413 $newPaymentInstrument = $this->callAPISuccess('OptionValue', 'create', $params);
3414
3415 $relationTypeID = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Asset Account is' "));
3416
3417 $financialAccountParams = [
3418 'entity_table' => 'civicrm_option_value',
3419 'entity_id' => key($newPaymentInstrument),
3420 'account_relationship' => $relationTypeID,
3421 'financial_account_id' => $this->callAPISuccess('FinancialAccount', 'getValue', ['name' => $financialAccountName, 'return' => 'id']),
3422 ];
3423 CRM_Financial_BAO_FinancialTypeAccount::add($financialAccountParams);
3424
3425 return CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', $params['label']);
3426 }
3427
ec5da26a 3428 /**
3429 * Enable Tax and Invoicing
3430 */
3431 protected function enableTaxAndInvoicing($params = array()) {
3432 // Enable component contribute setting
3433 $contributeSetting = array_merge($params,
3434 array(
3435 'invoicing' => 1,
3436 'invoice_prefix' => 'INV_',
3437 'credit_notes_prefix' => 'CN_',
3438 'due_date' => 10,
3439 'due_date_period' => 'days',
3440 'notes' => '',
3441 'is_email_pdf' => 1,
3442 'tax_term' => 'Sales Tax',
3443 'tax_display_settings' => 'Inclusive',
3444 )
3445 );
3446 return Civi::settings()->set('contribution_invoice_settings', $contributeSetting);
3447 }
3448
9fbf312f 3449 /**
3450 * Enable Tax and Invoicing
3451 */
3452 protected function disableTaxAndInvoicing($params = array()) {
f436577a 3453 if (!empty(\Civi::$statics['CRM_Core_PseudoConstant']) && isset(\Civi::$statics['CRM_Core_PseudoConstant']['taxRates'])) {
3454 unset(\Civi::$statics['CRM_Core_PseudoConstant']['taxRates']);
3455 }
9fbf312f 3456 // Enable component contribute setting
3457 $contributeSetting = array_merge($params,
3458 array(
3459 'invoicing' => 0,
3460 )
3461 );
3462 return Civi::settings()->set('contribution_invoice_settings', $contributeSetting);
3463 }
3464
7a1f3919
PN
3465 /**
3466 * Add Sales Tax relation for financial type with financial account.
3467 *
3468 * @param int $financialTypeId
3469 *
3470 * @return obj
3471 */
3472 protected function relationForFinancialTypeWithFinancialAccount($financialTypeId) {
3473 $params = array(
3474 'name' => 'Sales tax account ' . substr(sha1(rand()), 0, 4),
3475 'financial_account_type_id' => key(CRM_Core_PseudoConstant::accountOptionValues('financial_account_type', NULL, " AND v.name LIKE 'Liability' ")),
3476 'is_deductible' => 1,
3477 'is_tax' => 1,
3478 'tax_rate' => 10,
3479 'is_active' => 1,
3480 );
3481 $account = CRM_Financial_BAO_FinancialAccount::add($params);
3482 $entityParams = array(
3483 'entity_table' => 'civicrm_financial_type',
7a1f3919 3484 'entity_id' => $financialTypeId,
5b3543ce 3485 'account_relationship' => key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Sales Tax Account is' ")),
7a1f3919 3486 );
5b3543ce 3487
f436577a 3488 // set tax rate (as 10) for provided financial type ID to static variable, later used to fetch tax rates of all financial types
3489 \Civi::$statics['CRM_Core_PseudoConstant']['taxRates'][$financialTypeId] = 10;
3490
5b3543ce
JM
3491 //CRM-20313: As per unique index added in civicrm_entity_financial_account table,
3492 // first check if there's any record on basis of unique key (entity_table, account_relationship, entity_id)
3493 $dao = new CRM_Financial_DAO_EntityFinancialAccount();
3494 $dao->copyValues($entityParams);
3495 $dao->find();
3496 if ($dao->fetch()) {
3497 $entityParams['id'] = $dao->id;
3498 }
3499 $entityParams['financial_account_id'] = $account->id;
3500
7a1f3919
PN
3501 return CRM_Financial_BAO_FinancialTypeAccount::add($entityParams);
3502 }
3503
65e172a3 3504 /**
3505 * Create price set with contribution test for test setup.
3506 *
3507 * This could be merged with 4.5 function setup in api_v3_ContributionPageTest::setUpContributionPage
3508 * on parent class at some point (fn is not in 4.4).
3509 *
3510 * @param $entity
3511 * @param array $params
3512 */
3513 public function createPriceSetWithPage($entity = NULL, $params = array()) {
3514 $membershipTypeID = $this->membershipTypeCreate(array('name' => 'Special'));
3515 $contributionPageResult = $this->callAPISuccess('contribution_page', 'create', array(
3516 'title' => "Test Contribution Page",
3517 'financial_type_id' => 1,
3518 'currency' => 'NZD',
3519 'goal_amount' => 50,
3520 'is_pay_later' => 1,
3521 'is_monetary' => TRUE,
3522 'is_email_receipt' => FALSE,
3523 ));
3524 $priceSet = $this->callAPISuccess('price_set', 'create', array(
3525 'is_quick_config' => 0,
3526 'extends' => 'CiviMember',
3527 'financial_type_id' => 1,
3528 'title' => 'my Page',
3529 ));
3530 $priceSetID = $priceSet['id'];
3531
3532 CRM_Price_BAO_PriceSet::addTo('civicrm_contribution_page', $contributionPageResult['id'], $priceSetID);
3533 $priceField = $this->callAPISuccess('price_field', 'create', array(
3534 'price_set_id' => $priceSetID,
3535 'label' => 'Goat Breed',
3536 'html_type' => 'Radio',
3537 ));
3538 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
3539 'price_set_id' => $priceSetID,
3540 'price_field_id' => $priceField['id'],
3541 'label' => 'Long Haired Goat',
3542 'amount' => 20,
3543 'financial_type_id' => 'Donation',
3544 'membership_type_id' => $membershipTypeID,
3545 'membership_num_terms' => 1,
3546 )
3547 );
3548 $this->_ids['price_field_value'] = array($priceFieldValue['id']);
3549 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
3550 'price_set_id' => $priceSetID,
3551 'price_field_id' => $priceField['id'],
3552 'label' => 'Shoe-eating Goat',
3553 'amount' => 10,
3554 'financial_type_id' => 'Donation',
3555 'membership_type_id' => $membershipTypeID,
3556 'membership_num_terms' => 2,
3557 )
3558 );
3559 $this->_ids['price_field_value'][] = $priceFieldValue['id'];
3560
3561 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
3562 'price_set_id' => $priceSetID,
3563 'price_field_id' => $priceField['id'],
3564 'label' => 'Shoe-eating Goat',
3565 'amount' => 10,
3566 'financial_type_id' => 'Donation',
3567 )
3568 );
3569 $this->_ids['price_field_value']['cont'] = $priceFieldValue['id'];
3570
3571 $this->_ids['price_set'] = $priceSetID;
3572 $this->_ids['contribution_page'] = $contributionPageResult['id'];
3573 $this->_ids['price_field'] = array($priceField['id']);
3574
3575 $this->_ids['membership_type'] = $membershipTypeID;
3576 }
3577
33072bc7 3578 /**
3579 * No results returned.
3580 *
3581 * @implements CRM_Utils_Hook::aclWhereClause
3582 *
3583 * @param string $type
3584 * @param array $tables
3585 * @param array $whereTables
3586 * @param int $contactID
3587 * @param string $where
3588 */
3589 public function aclWhereHookNoResults($type, &$tables, &$whereTables, &$contactID, &$where) {
3590 }
3591
3c9d67b0 3592 /**
3593 * Only specified contact returned.
3594 * @implements CRM_Utils_Hook::aclWhereClause
3595 * @param $type
3596 * @param $tables
3597 * @param $whereTables
3598 * @param $contactID
3599 * @param $where
3600 */
3601 public function aclWhereMultipleContacts($type, &$tables, &$whereTables, &$contactID, &$where) {
3602 $where = " contact_a.id IN (" . implode(', ', $this->allowedContacts) . ")";
3603 }
3604
88ebed7c
JP
3605 /**
3606 * @implements CRM_Utils_Hook::selectWhereClause
3607 *
3608 * @param string $entity
3609 * @param array $clauses
3610 */
3611 public function selectWhereClauseHook($entity, &$clauses) {
3612 if ($entity == 'Event') {
3613 $clauses['event_type_id'][] = "IN (2, 3, 4)";
3614 }
3615 }
3616
29a59599
JP
3617 /**
3618 * An implementation of hook_civicrm_post used with all our test cases.
3619 *
3620 * @param $op
3621 * @param string $objectName
3622 * @param int $objectId
3623 * @param $objectRef
3624 */
3625 public function onPost($op, $objectName, $objectId, &$objectRef) {
3626 if ($op == 'create' && $objectName == 'Individual') {
3627 CRM_Core_DAO::executeQuery(
3628 "UPDATE civicrm_contact SET nick_name = 'munged' WHERE id = %1",
3629 array(
3630 1 => array($objectId, 'Integer'),
3631 )
3632 );
3633 }
3634
3635 if ($op == 'edit' && $objectName == 'Participant') {
3636 $params = array(
3637 1 => array($objectId, 'Integer'),
3638 );
3639 $query = "UPDATE civicrm_participant SET source = 'Post Hook Update' WHERE id = %1";
3640 CRM_Core_DAO::executeQuery($query, $params);
3641 }
3642 }
3643
f8df7165 3644
3645 /**
3646 * Instantiate form object.
3647 *
3648 * We need to instantiate the form to run preprocess, which means we have to trick it about the request method.
3649 *
3650 * @param string $class
3651 * Name of form class.
3652 *
3653 * @return \CRM_Core_Form
3654 */
3655 public function getFormObject($class) {
3656 $form = new $class();
3657 $_SERVER['REQUEST_METHOD'] = 'GET';
3658 $form->controller = new CRM_Core_Controller();
3659 return $form;
3660 }
3661
83644f47 3662 /**
3663 * Get possible thousand separators.
3664 *
3665 * @return array
3666 */
3667 public function getThousandSeparators() {
3668 return array(array('.'), array(','));
3669 }
3670
3671 /**
3672 * Set the separators for thousands and decimal points.
3673 *
3674 * @param string $thousandSeparator
3675 */
3676 protected function setCurrencySeparators($thousandSeparator) {
3677 Civi::settings()->set('monetaryThousandSeparator', $thousandSeparator);
3678 Civi::settings()
3679 ->set('monetaryDecimalPoint', ($thousandSeparator === ',' ? '.' : ','));
3680 }
3681
3682 /**
3683 * Format money as it would be input.
3684 *
3685 * @param string $amount
3686 *
3687 * @return string
3688 */
3689 protected function formatMoneyInput($amount) {
3690 return CRM_Utils_Money::format($amount, NULL, '%a');
3691 }
3692
3ca4bd1b 3693
3694 /**
3695 * Get the contribution object.
3696 *
3697 * @param int $contributionID
3698 *
3699 * @return \CRM_Contribute_BAO_Contribution
3700 */
3701 protected function getContributionObject($contributionID) {
3702 $contributionObj = new CRM_Contribute_BAO_Contribution();
3703 $contributionObj->id = $contributionID;
3704 $contributionObj->find(TRUE);
3705 return $contributionObj;
3706 }
3707
df3320dc 3708 /**
3709 * Enable multilingual.
3710 */
3711 public function enableMultilingual() {
3712 $this->callAPISuccess('Setting', 'create', array(
3713 'lcMessages' => 'en_US',
3714 'languageLimit' => array(
3715 'en_US' => 1,
3716 ),
3717 ));
3718
3719 CRM_Core_I18n_Schema::makeMultilingual('en_US');
3720
3721 global $dbLocale;
3722 $dbLocale = '_en_US';
3723 }
3724
a86d27fc 3725}