CRM-13179 add postal code to address fields on billing pseudoprofile
[civicrm-core.git] / api / v3 / Profile.php
1 <?php
2
3 /*
4 +--------------------------------------------------------------------+
5 | CiviCRM version 4.4 |
6 +--------------------------------------------------------------------+
7 | Copyright CiviCRM LLC (c) 2004-2013 |
8 +--------------------------------------------------------------------+
9 | This file is a part of CiviCRM. |
10 | |
11 | CiviCRM is free software; you can copy, modify, and distribute it |
12 | under the terms of the GNU Affero General Public License |
13 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | |
15 | CiviCRM is distributed in the hope that it will be useful, but |
16 | WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
18 | See the GNU Affero General Public License for more details. |
19 | |
20 | You should have received a copy of the GNU Affero General Public |
21 | License and the CiviCRM Licensing Exception along |
22 | with this program; if not, contact CiviCRM LLC |
23 | at info[AT]civicrm[DOT]org. If you have questions about the |
24 | GNU Affero General Public License or the licensing of CiviCRM, |
25 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
26 +--------------------------------------------------------------------+
27 */
28
29 /**
30 * File for the CiviCRM APIv3 activity profile functions
31 *
32 * @package CiviCRM_APIv3
33 * @subpackage API_ActivityProfile
34 * @copyright CiviCRM LLC (c) 2004-2013
35 * @version $Id: ActivityProfile.php 30486 2011-05-20 16:12:09Z rajan $
36 *
37 */
38
39 /**
40 * Include common API util functions
41 */
42 require_once 'api/v3/utils.php';
43
44 /**
45 * Retrieve Profile field values.
46 *
47 * @param array $params Associative array of property name/value
48 * pairs to get profile field values
49 *
50 * @return Profile field values|CRM_Error
51 *
52 * NOTE this api is not standard & since it is tested we need to honour that
53 * but the correct behaviour is for it to return an id indexed array as this supports
54 * multiple instances
55 *
56 * Note that if contact_id is empty an array of defaults is returned
57 *
58 */
59 function civicrm_api3_profile_get($params) {
60 $nonStandardLegacyBehaviour = is_numeric($params['profile_id']) ? TRUE : FALSE;
61 if(!empty($params['check_permissions']) && !empty($params['contact_id']) && !1 === civicrm_api3('contact', 'getcount', array('contact_id' => $params['contact_id'], 'check_permissions' => 1))) {
62 throw new API_Exception('permission denied');
63 }
64 $profiles = (array) $params['profile_id'];
65 $values = array();
66 foreach ($profiles as $profileID) {
67 $values[$profileID] = array();
68 if (strtolower($profileID) == 'billing') {
69 $values[$profileID] = _civicrm_api3_profile_getbillingpseudoprofile($params);
70 continue;
71 }
72 if(!CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $profileID, 'is_active')) {
73 throw new API_Exception('Invalid value for profile_id : ' . $profileID);
74 }
75
76 $isContactActivityProfile = CRM_Core_BAO_UFField::checkContactActivityProfileType($profileID);
77
78 $profileFields = CRM_Core_BAO_UFGroup::getFields($profileID,
79 FALSE,
80 NULL,
81 NULL,
82 NULL,
83 FALSE,
84 NULL,
85 empty($params['check_permissions']) ? FALSE : TRUE,
86 NULL,
87 CRM_Core_Permission::EDIT
88 );
89
90
91 if ($isContactActivityProfile) {
92 civicrm_api3_verify_mandatory($params, NULL, array('activity_id'));
93
94 $errors = CRM_Profile_Form::validateContactActivityProfile($params['activity_id'],
95 $params['contact_id'],
96 $params['profile_id']
97 );
98 if (!empty($errors)) {
99 throw new API_Exception(array_pop($errors));
100 }
101
102 $contactFields = $activityFields = array();
103 foreach ($profileFields as $fieldName => $field) {
104 if (CRM_Utils_Array::value('field_type', $field) == 'Activity') {
105 $activityFields[$fieldName] = $field;
106 }
107 else {
108 $contactFields[$fieldName] = $field;
109 }
110 }
111
112 CRM_Core_BAO_UFGroup::setProfileDefaults($params['contact_id'], $contactFields, $values[$profileID], TRUE);
113
114 if ($params['activity_id']) {
115 CRM_Core_BAO_UFGroup::setComponentDefaults($activityFields, $params['activity_id'], 'Activity', $values[$profileID], TRUE);
116 }
117 }
118 elseif(!empty($params['contact_id'])) {
119 CRM_Core_BAO_UFGroup::setProfileDefaults($params['contact_id'], $profileFields, $values[$profileID], TRUE);
120 }
121 else{
122 $values[$profileID] = array_fill_keys(array_keys($profileFields), '');
123 }
124 }
125 if($nonStandardLegacyBehaviour) {
126 $result = civicrm_api3_create_success();
127 $result['values'] = $values[$profileID];
128 return $result;
129 }
130 else {
131 return civicrm_api3_create_success($values, $params, 'Profile', 'Get');
132 }
133 }
134
135 function _civicrm_api3_profile_get_spec(&$params) {
136 $params['profile_id']['api.required'] = TRUE;
137 $params['contact_id']['description'] = 'If no contact is specified an array of defaults will be returned';
138 }
139 /**
140 * Update Profile field values.
141 *
142 * @param array $params Associative array of property name/value
143 * pairs to update profile field values
144 *
145 * @return Updated Contact/ Activity object|CRM_Error
146 *
147 * @todo add example
148 * @todo add test cases
149 *
150 */
151 function civicrm_api3_profile_set($params) {
152
153 civicrm_api3_verify_mandatory($params, NULL, array('profile_id'));
154
155 if (!CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $params['profile_id'], 'is_active')) {
156 throw new API_Exception('Invalid value for profile_id');
157 }
158
159 $isContactActivityProfile = CRM_Core_BAO_UFField::checkContactActivityProfileType($params['profile_id']);
160
161 if (CRM_Core_BAO_UFField::checkProfileType($params['profile_id']) && !$isContactActivityProfile) {
162 throw new API_Exception('Can not retrieve values for profiles include fields for more than one record type.');
163 }
164
165 $contactParams = $activityParams = $missingParams = array();
166
167 $profileFields = CRM_Core_BAO_UFGroup::getFields($params['profile_id'],
168 FALSE,
169 NULL,
170 NULL,
171 NULL,
172 FALSE,
173 NULL,
174 TRUE,
175 NULL,
176 CRM_Core_Permission::EDIT
177 );
178
179 if ($isContactActivityProfile) {
180 civicrm_api3_verify_mandatory($params, NULL, array('activity_id'));
181
182 $errors = CRM_Profile_Form::validateContactActivityProfile($params['activity_id'],
183 $params['contact_id'],
184 $params['profile_id']
185 );
186 if (!empty($errors)) {
187 return civicrm_api3_create_error(array_pop($errors));
188 }
189 }
190
191 foreach ($profileFields as $fieldName => $field) {
192 if (CRM_Utils_Array::value('is_required', $field)) {
193 if (!CRM_Utils_Array::value($fieldName, $params) || empty($params[$fieldName])) {
194 $missingParams[] = $fieldName;
195 }
196 }
197
198 if (!isset($params[$fieldName])) {
199 continue;
200 }
201
202 $value = $params[$fieldName];
203 if ($params[$fieldName] && isset($params[$fieldName . '_id'])) {
204 $value = $params[$fieldName . '_id'];
205 }
206
207 if ($isContactActivityProfile && CRM_Utils_Array::value('field_type', $field) == 'Activity') {
208 $activityParams[$fieldName] = $value;
209 }
210 else {
211 $contactParams[$fieldName] = $value;
212 }
213 }
214
215 if (!empty($missingParams)) {
216 throw new API_Exception("Missing required parameters for profile id {$params['profile_id']}: " . implode(', ', $missingParams));
217 }
218
219 $contactParams['version'] = 3;
220 $contactParams['contact_id'] = CRM_Utils_Array::value('contact_id', $params);
221 $contactParams['profile_id'] = $params['profile_id'];
222 $contactParams['skip_custom'] = 1;
223
224 $contactProfileParams = civicrm_api3_profile_apply($contactParams);
225 if (CRM_Utils_Array::value('is_error', $contactProfileParams)) {
226 return $contactProfileParams;
227 }
228
229 // Contact profile fields
230 $profileParams = $contactProfileParams['values'];
231
232 // If profile having activity fields
233 if ($isContactActivityProfile && !empty($activityParams)) {
234 $activityParams['id'] = $params['activity_id'];
235 $profileParams['api.activity.create'] = $activityParams;
236 }
237
238 $groups = $tags = array();
239 if (isset($profileParams['group'])) {
240 $groups = $profileParams['group'];
241 unset($profileParams['group']);
242 }
243
244 if (isset($profileParams['tag'])) {
245 $tags = $profileParams['tag'];
246 unset($profileParams['tag']);
247 }
248
249 return civicrm_api3('contact', 'create', $profileParams);
250
251 $ufGroupDetails = array();
252 $ufGroupParams = array('id' => $params['profile_id']);
253 CRM_Core_BAO_UFGroup::retrieve($ufGroupParams, $ufGroupDetails);
254
255 if (isset($profileFields['group'])) {
256 CRM_Contact_BAO_GroupContact::create($groups,
257 $params['contact_id'],
258 FALSE,
259 'Admin'
260 );
261 }
262
263 if (isset($profileFields['tag'])) {
264 CRM_Core_BAO_EntityTag::create($tags,
265 'civicrm_contact',
266 $params['contact_id']
267 );
268 }
269
270 if (CRM_Utils_Array::value('add_to_group_id', $ufGroupDetails)) {
271 $contactIds = array($params['contact_id']);
272 CRM_Contact_BAO_GroupContact::addContactsToGroup($contactIds,
273 $ufGroupDetails['add_to_group_id']
274 );
275 }
276
277 return $result;
278 }
279
280 /**
281 * Provide formatted values for profile fields.
282 *
283 * @param array $params Associative array of property name/value
284 * pairs to profile field values
285 *
286 * @return formatted profile field values|CRM_Error
287 *
288 * @todo add example
289 * @todo add test cases
290 *
291 */
292 function civicrm_api3_profile_apply($params) {
293
294 civicrm_api3_verify_mandatory($params, NULL, array('profile_id'));
295
296 if (!CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $params['profile_id'], 'is_active')) {
297 return civicrm_api3_create_error('Invalid value for profile_id');
298 }
299
300 $profileFields = CRM_Core_BAO_UFGroup::getFields($params['profile_id'],
301 FALSE,
302 NULL,
303 NULL,
304 NULL,
305 FALSE,
306 NULL,
307 TRUE,
308 NULL,
309 CRM_Core_Permission::EDIT
310 );
311
312 list($data, $contactDetails) = CRM_Contact_BAO_Contact::formatProfileContactParams($params,
313 $profileFields,
314 CRM_Utils_Array::value('contact_id', $params),
315 $params['profile_id'],
316 CRM_Utils_Array::value('contact_type', $params),
317 CRM_Utils_Array::value('skip_custom', $params, FALSE)
318 );
319
320 if (empty($data)) {
321 return civicrm_api3_create_error('Enable to format profile parameters.');
322 }
323
324 return civicrm_api3_create_success($data);
325 }
326
327 /**
328 * Return UFGroup fields
329 */
330 function civicrm_api3_profile_getfields($params) {
331 $dao = _civicrm_api3_get_DAO('UFGroup');
332 $d = new $dao();
333 $fields = $d->fields();
334 return civicrm_api3_create_success($fields);
335 }
336
337 /**
338 * This is a function to help us 'pretend' billing is a profile & treat it like it is one.
339 * It gets standard credit card address fields etc
340 * Note this is 'better' that the inbuilt version as it will pull in fallback values
341 * billing location -> is_billing -> primary
342 *
343 * Note that that since the existing code for deriving a blank profile is not easily accessible our
344 * interim solution is just to return an empty array
345 */
346 function _civicrm_api3_profile_getbillingpseudoprofile(&$params) {
347 $addressFields = array('street_address', 'city', 'state_province_id', 'country_id', 'postal_code');
348 $locations = civicrm_api3('address', 'getoptions', array('field' => 'location_type_id'));
349 $locationTypeID = array_search('Billing', $locations['values']);
350
351 if(empty($params['contact_id'])) {
352 $blanks = array(
353 'billing_first_name' => '',
354 'billing_middle_name' => '',
355 'billing_last_name' => '',
356 );
357 foreach ($addressFields as $field) {
358 $blanks['billing_' . $field . '_' . $locationTypeID] = '';
359 }
360 return $blanks;
361 }
362 $result = civicrm_api3('contact', 'getsingle', array(
363 'id' => $params['contact_id'],
364 'api.address.get.1' => array('location_type_id' => 'Billing', 'return' => $addressFields),
365 // getting the is_billing required or not is an extra db call but probably cheap enough as this isn't an import api
366 'api.address.get.2' => array('is_billing' => True, 'return' => $addressFields),
367 'api.email.get.1' => array('location_type_id' => 'Billing',),
368 'api.email.get.2' => array('is_billing' => True,),
369 'return' => 'api.email.get, api.address.get, api.address.getoptions, email, first_name, last_name, middle_name,' . implode($addressFields, ','),
370 )
371 );
372
373 $values = array(
374 'billing_first_name' => $result['first_name'],
375 'billing_middle_name' => $result['middle_name'],
376 'billing_last_name' => $result['last_name'],
377 );
378
379 if(!empty($result['api.address.get.1']['count'])) {
380 foreach ($addressFields as $fieldname) {
381 $values['billing_' . $fieldname . '-' . $locationTypeID] = isset($result['api.address.get.1']['values'][0][$fieldname]) ? $result['api.address.get.1']['values'][0][$fieldname] : '';
382 }
383 }
384 elseif(!empty($result['api.address.get.2']['count'])) {
385 foreach ($addressFields as $fieldname) {
386 $values['billing_' . $fieldname . '-' . $locationTypeID] = isset($result['api.address.get.2']['values'][0][$fieldname]) ? $result['api.address.get.2']['values'][0][$fieldname] : '';
387 }
388 }
389 else{
390 foreach ($addressFields as $fieldname) {
391 $values['billing_' . $fieldname . '-' . $locationTypeID] = isset($result[$fieldname]) ? $result[$fieldname] : '';
392 }
393 }
394
395 if(!empty($result['api.email.get.1']['count'])) {
396 $values['billing-email'. '-' . $locationTypeID] = $result['api.email.get.1']['values'][0]['email'];
397 }
398 elseif(!empty($result['api.email.get.2']['count'])) {
399 $values['billing-email'. '-' . $locationTypeID] = $result['api.email.get.2']['values'][0]['email'];
400 }
401 else{
402 $values['billing-email'. '-' . $locationTypeID] = $result['email'];
403 }
404 // return both variants of email to reflect inconsistencies in form layer
405 $values['email'. '-' . $locationTypeID] = $values['billing-email'. '-' . $locationTypeID];
406 return $values;
407 }