From f01ce56b46c17f7dc434aa863b527befe1dc62dd Mon Sep 17 00:00:00 2001 From: eileen Date: Thu, 8 Aug 2013 08:58:25 +1200 Subject: [PATCH] CRM-13179 fix profile api to support multiple profiles incl billing. As it is non-standard I've had to be a bit hacky - since there are tests we need to ensure code relying on the non-standard behaviour doesn't break --- api/v3/Profile.php | 145 ++++++++++++++++++++------- api/v3/examples/ProfileGet.php | 40 ++++++-- tests/phpunit/api/v3/ProfileTest.php | 62 ++++++++++-- 3 files changed, 193 insertions(+), 54 deletions(-) diff --git a/api/v3/Profile.php b/api/v3/Profile.php index 48a7ddfefa..004faf41a7 100644 --- a/api/v3/Profile.php +++ b/api/v3/Profile.php @@ -49,37 +49,44 @@ require_once 'api/v3/utils.php'; * * @return Profile field values|CRM_Error * - * @todo add example - * @todo add test cases - * + * NOTE this api is not standard & since it is tested we need to honour that + * but the correct behaviour is for it to return an id indexed array as this supports + * multiple instances */ function civicrm_api3_profile_get($params) { + $nonStandardLegacyBehaviour = is_numeric($params['profile_id']) ? TRUE : FALSE; - civicrm_api3_verify_mandatory($params, NULL, array('profile_id', 'contact_id')); + $profiles = (array) $params['profile_id']; + $values = array(); + foreach ($profiles as $profileID) { + $values[$profileID] = array(); + if (strtolower($profileID) == 'billing') { + $values[$profileID] = _civicrm_api3_profile_getbillingpseudoprofile($params); + continue; + } + if(!CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $profileID, 'is_active')) { + throw new API_Exception('Invalid value for profile_id : ' . $profileID); + } - if (!CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $params['profile_id'], 'is_active')) { - return civicrm_api3_create_error('Invalid value for profile_id'); - } + $isContactActivityProfile = CRM_Core_BAO_UFField::checkContactActivityProfileType($profileID); - $isContactActivityProfile = CRM_Core_BAO_UFField::checkContactActivityProfileType($params['profile_id']); + if (CRM_Core_BAO_UFField::checkProfileType($profileID) && !$isContactActivityProfile) { + throw new API_Exception('Can not retrieve values for profiles include fields for more than one record type.'); + } - if (CRM_Core_BAO_UFField::checkProfileType($params['profile_id']) && !$isContactActivityProfile) { - return civicrm_api3_create_error('Can not retrieve values for profiles include fields for more than one record type.'); - } + $profileFields = CRM_Core_BAO_UFGroup::getFields($profileID, + FALSE, + NULL, + NULL, + NULL, + FALSE, + NULL, + TRUE, + NULL, + CRM_Core_Permission::EDIT + ); - $profileFields = CRM_Core_BAO_UFGroup::getFields($params['profile_id'], - FALSE, - NULL, - NULL, - NULL, - FALSE, - NULL, - TRUE, - NULL, - CRM_Core_Permission::EDIT - ); - $values = array(); if ($isContactActivityProfile) { civicrm_api3_verify_mandatory($params, NULL, array('activity_id')); @@ -88,7 +95,7 @@ function civicrm_api3_profile_get($params) { $params['profile_id'] ); if (!empty($errors)) { - return civicrm_api3_create_error(array_pop($errors)); + throw new API_Exception(array_pop($errors)); } $contactFields = $activityFields = array(); @@ -101,22 +108,31 @@ function civicrm_api3_profile_get($params) { } } - CRM_Core_BAO_UFGroup::setProfileDefaults($params['contact_id'], $contactFields, $values, TRUE); + CRM_Core_BAO_UFGroup::setProfileDefaults($params['contact_id'], $contactFields, $values[$profileID], TRUE); if ($params['activity_id']) { - CRM_Core_BAO_UFGroup::setComponentDefaults($activityFields, $params['activity_id'], 'Activity', $values, TRUE); + CRM_Core_BAO_UFGroup::setComponentDefaults($activityFields, $params['activity_id'], 'Activity', $values[$profileID], TRUE); } } else { - CRM_Core_BAO_UFGroup::setProfileDefaults($params['contact_id'], $profileFields, $values, TRUE); + CRM_Core_BAO_UFGroup::setProfileDefaults($params['contact_id'], $profileFields, $values[$profileID], TRUE); + } + } + if($nonStandardLegacyBehaviour) { + $result = civicrm_api3_create_success(); + $result['values'] = $values[$profileID]; + return $result; + } + else { + return civicrm_api3_create_success($values, $params, 'Profile', 'Get'); } - - $result = civicrm_api3_create_success(); - $result['values'] = $values; - - return $result; } +function _civicrm_api3_profile_get_spec(&$params) { + $params['profile_id']['api.required'] = TRUE; + // does this mean we use a different call to get a 'blank' profile? + $params['contact_id']['api.required'] = TRUE; +} /** * Update Profile field values. * @@ -134,13 +150,13 @@ function civicrm_api3_profile_set($params) { civicrm_api3_verify_mandatory($params, NULL, array('profile_id')); if (!CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $params['profile_id'], 'is_active')) { - return civicrm_api3_create_error('Invalid value for profile_id'); + throw new API_Exception('Invalid value for profile_id'); } $isContactActivityProfile = CRM_Core_BAO_UFField::checkContactActivityProfileType($params['profile_id']); if (CRM_Core_BAO_UFField::checkProfileType($params['profile_id']) && !$isContactActivityProfile) { - return civicrm_api3_create_error('Can not retrieve values for profiles include fields for more than one record type.'); + throw new API_Exception('Can not retrieve values for profiles include fields for more than one record type.'); } $contactParams = $activityParams = $missingParams = array(); @@ -194,7 +210,7 @@ function civicrm_api3_profile_set($params) { } if (!empty($missingParams)) { - return civicrm_api3_create_error("Missing required parameters for profile id {$params['profile_id']}: " . implode(', ', $missingParams)); + throw new API_Exception("Missing required parameters for profile id {$params['profile_id']}: " . implode(', ', $missingParams)); } $contactParams['version'] = 3; @@ -227,10 +243,7 @@ function civicrm_api3_profile_set($params) { unset($profileParams['tag']); } - $result = civicrm_api('contact', 'create', $profileParams); - if (CRM_Utils_Array::value('is_error', $result)) { - return $result; - } + return civicrm_api3('contact', 'create', $profileParams); $ufGroupDetails = array(); $ufGroupParams = array('id' => $params['profile_id']); @@ -318,3 +331,57 @@ function civicrm_api3_profile_getfields($params) { return civicrm_api3_create_success($fields); } +/** + * This is a function to help us 'pretend' billing is a profile & treat it like it is one. + * It gets standard credit card address fields etc + * Note this is 'better' that the inbuilt version as it will pull in fallback values + * billing location -> is_billing -> primary + */ +function _civicrm_api3_profile_getbillingpseudoprofile(&$params) { + $addressFields = array('street_address', 'city', 'state_province_id', 'country_id'); + $result = civicrm_api3('contact', 'getsingle', array( + 'id' => $params['contact_id'], + 'api.address.getoptions' => array('field' => 'location_type_id',), + 'api.address.get.1' => array('location_type_id' => 'Billing', 'return' => $addressFields), + // getting the is_billing required or not is an extra db call but probably cheap enough as this isn't an import api + 'api.address.get.2' => array('is_billing' => True, 'return' => $addressFields), + 'api.email.get.1' => array('location_type_id' => 'Billing',), + 'api.email.get.2' => array('is_billing' => True,), + 'return' => 'api.email.get, api.address.get, api.address.getoptions, email, first_name, last_name, middle_name,' . implode($addressFields, ','), + ) + ); + $locationTypeID = array_search('Billing', $result['api.address.getoptions']['values']); + + $values = array( + 'billing_first_name' => $result['first_name'], + 'billing_middle_name' => $result['middle_name'], + 'billing_last_name' => $result['last_name'], + ); + + if(!empty($result['api.address.get.1']['count'])) { + foreach ($addressFields as $fieldname) { + $values['billing_' . $fieldname . '-' . $locationTypeID] = isset($result['api.address.get.1']['values'][0][$fieldname]) ? $result['api.address.get.1']['values'][0][$fieldname] : ''; + } + } + elseif(!empty($result['api.address.get.2']['count'])) { + foreach ($addressFields as $fieldname) { + $values['billing_' . $fieldname . '-' . $locationTypeID] = isset($result['api.address.get.2']['values'][0][$fieldname]) ? $result['api.address.get.2']['values'][0][$fieldname] : ''; + } + } + else{ + foreach ($addressFields as $fieldname) { + $values['billing_' . $fieldname . '-' . $locationTypeID] = isset($result[$fieldname]) ? $result[$fieldname] : ''; + } + } + + if(!empty($result['api.email.get.1']['count'])) { + $values['billing-email'. '-' . $locationTypeID] = $result['api.email.get.1']['values'][0]['email']; + } + elseif(!empty($result['api.email.get.2']['count'])) { + $values['billing-email'. '-' . $locationTypeID] = $result['api.email.get.2']['values'][0]['email']; + } + else{ + $values['billing-email'. '-' . $locationTypeID] = $result['email']; + } + return $values; +} diff --git a/api/v3/examples/ProfileGet.php b/api/v3/examples/ProfileGet.php index c639ae6ea2..295bf073ad 100644 --- a/api/v3/examples/ProfileGet.php +++ b/api/v3/examples/ProfileGet.php @@ -5,7 +5,11 @@ */ function profile_get_example(){ $params = array( - 'profile_id' => 25, + 'profile_id' => array( + '0' => 25, + '1' => 1, + '2' => 'Billing', + ), 'contact_id' => 1, ); @@ -31,14 +35,32 @@ function profile_get_expectedresult(){ $expectedResult = array( 'is_error' => 0, 'version' => 3, - 'count' => 1, + 'count' => 3, 'values' => array( - 'first_name' => 'abc1', - 'last_name' => 'xyz1', - 'email-Primary' => 'abc1.xyz1@yahoo.com', - 'phone-1-1' => '021 512 755', - 'country-1' => '1228', - 'state_province-1' => '1021', + '25' => array( + 'first_name' => 'abc1', + 'last_name' => 'xyz1', + 'email-Primary' => 'abc1.xyz1@yahoo.com', + 'phone-1-1' => '021 512 755', + 'country-1' => '1228', + 'state_province-1' => '1021', + ), + '1' => array( + 'first_name' => 'abc1', + 'last_name' => 'xyz1', + 'country-1' => '1228', + 'state_province-1' => '1021', + ), + 'Billing' => array( + 'billing_first_name' => 'abc1', + 'billing_middle_name' => '', + 'billing_last_name' => 'xyz1', + 'billing_street_address-5' => '', + 'billing_city-5' => '', + 'billing_state_province_id-5' => '', + 'billing_country_id-5' => '', + 'billing-email-5' => 'abc1.xyz1@yahoo.com', + ), ), ); @@ -49,7 +71,7 @@ function profile_get_expectedresult(){ /* * This example has been generated from the API test suite. The test that created it is called * -* testProfileGet and can be found in +* testProfileGetMultiple and can be found in * http://svn.civicrm.org/civicrm/trunk/tests/phpunit/CiviTest/api/v3/ProfileTest.php * * You can see the outcome of the API tests at diff --git a/tests/phpunit/api/v3/ProfileTest.php b/tests/phpunit/api/v3/ProfileTest.php index f2d4785aed..d4079b1249 100644 --- a/tests/phpunit/api/v3/ProfileTest.php +++ b/tests/phpunit/api/v3/ProfileTest.php @@ -57,13 +57,12 @@ class api_v3_ProfileTest extends CiviUnitTestCase { function tearDown() { $this->quickCleanup(array( - 'civicrm_uf_field', - 'civicrm_uf_join', - 'civicrm_uf_group', 'civicrm_contact', 'civicrm_phone', 'civicrm_address', ), TRUE); + // ok can't be bothered wring an api to do this & truncating is crazy + CRM_Core_DAO::executeQuery(' DELETE FROM civicrm_uf_group WHERE id IN (25, 26)'); } ////////////// test $this->callAPISuccess3_profile_get ////////////////// @@ -102,15 +101,66 @@ class api_v3_ProfileTest extends CiviUnitTestCase { 'profile_id' => 25, 'contact_id' => $contactId, ); - - $result = $this->callAPIAndDocument('profile', 'get', $params, __FUNCTION__, __FILE__); - + $result = $this->callAPISuccess('profile', 'get', $params); foreach ($expected as $profileField => $value) { $this->assertEquals($value, CRM_Utils_Array::value($profileField, $result['values']), "In line " . __LINE__ . " error message: " . "missing/mismatching value for {$profileField}" ); } } + function testProfileGetMultiple() { + $pofileFieldValues = $this->_createIndividualContact(); + $expected = current($pofileFieldValues); + $contactId = key($pofileFieldValues); + $params = array( + 'profile_id' => array(25, 1, 'Billing'), + 'contact_id' => $contactId, + ); + + $result = $this->callAPIAndDocument('profile', 'get', $params, __FUNCTION__, __FILE__); + foreach ($expected as $profileField => $value) { + $this->assertEquals($value, CRM_Utils_Array::value($profileField, $result['values'][25]), " error message: " . "missing/mismatching value for {$profileField}"); + } + $this->assertEquals('abc1', $result['values'][1]['first_name'], " error message: " . "missing/mismatching value for {$profileField}"); + $this->assertFalse(array_key_exists('email-Primary', $result['values'][1]), 'profile 1 doesn not include email'); + $this->assertEquals($result['values']['Billing'], array( + 'billing_first_name' => 'abc1', + 'billing_middle_name' => '', + 'billing_last_name' => 'xyz1', + 'billing_street_address-5' => '', + 'billing_city-5' => '', + 'billing_state_province_id-5' => '', + 'billing_country_id-5' => '', + 'billing-email-5' => 'abc1.xyz1@yahoo.com', + )); + } + + function testProfileGetMultipleHasBillingLocation() { + $individual = $this->_createIndividualContact(); + $contactId = key($individual); + $this->callAPISuccess('address', 'create', array('contact_id' => $contactId , 'street_address' => '25 Big Street', 'city' => 'big city', 'location_type_id' => 5)); + $this->callAPISuccess('email', 'create', array('contact_id' => $contactId , 'email' => 'big@once.com', 'location_type_id' => 2, 'is_billing' => 1)); + + $expected = current($individual); + + $params = array( + 'profile_id' => array(25, 1, 'Billing'), + 'contact_id' => $contactId, + ); + + $result = $this->callAPISuccess('profile', 'get', $params, __FUNCTION__, __FILE__); + $this->assertEquals('abc1', $result['values'][1]['first_name']); + $this->assertEquals($result['values']['Billing'], array( + 'billing_first_name' => 'abc1', + 'billing_middle_name' => '', + 'billing_last_name' => 'xyz1', + 'billing_street_address-5' => '25 Big Street', + 'billing_city-5' => 'big city', + 'billing_state_province_id-5' => '', + 'billing_country_id-5' => '', + 'billing-email-5' => 'big@once.com', + )); + } /** * check contact activity profile without activity id */ -- 2.25.1