CRM-13179 fix profile api to support multiple profiles incl billing.
authoreileen <eileen@fuzion.co.nz>
Wed, 7 Aug 2013 20:58:25 +0000 (08:58 +1200)
committereileen <eileen@fuzion.co.nz>
Wed, 7 Aug 2013 20:58:25 +0000 (08:58 +1200)
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
api/v3/examples/ProfileGet.php
tests/phpunit/api/v3/ProfileTest.php

index 48a7ddfefad2232373f062b555ac9a704950a8b9..004faf41a75c4464416bfbc2cfe975464fdb148d 100644 (file)
@@ -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;
+}
index c639ae6ea20e020e696f9ba62cca87fb45902f14..295bf073adfba7bfc7b998e846ce5ecdf06b4380 100644 (file)
@@ -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
index f2d4785aeda19b7a1784ae929a06953751b57571..d4079b1249498a9335734741ca6f0f818f0433e0 100644 (file)
@@ -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
    */