Merge pull request #799 from eileenmcnaughton/CRM-12659
[civicrm-core.git] / CRM / Activity / Import / Parser / Activity.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.3 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28 /**
29 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2013
32 * $Id$
33 *
34 */
35
36 require_once 'api/api.php';
37
38 /**
39 * class to parse activity csv files
40 */
41 class CRM_Activity_Import_Parser_Activity extends CRM_Activity_Import_Parser {
42
43 protected $_mapperKeys;
44
45 private $_contactIdIndex;
46 private $_activityTypeIndex;
47 private $_activityLabelIndex;
48 private $_activityDateIndex;
49
50 /**
51 * Array of successfully imported activity id's
52 *
53 * @array
54 */
55 protected $_newActivity;
56
57 /**
58 * class constructor
59 */
60 function __construct(&$mapperKeys, $mapperLocType = NULL, $mapperPhoneType = NULL) {
61 parent::__construct();
62 $this->_mapperKeys = &$mapperKeys;
63 }
64
65 /**
66 * the initializer code, called before the processing
67 *
68 * @return void
69 * @access public
70 */
71 function init() {
72 $fields = array_merge(CRM_Activity_BAO_Activity::importableFields(),
73 CRM_Activity_BAO_ActivityTarget::import()
74 );
75
76 $fields = array_merge($fields, array('activity_label' => array('title' => ts('Activity Type Label'),
77 'headerPattern' => '/(activity.)?type label?/i',
78 )));
79
80 foreach ($fields as $name => $field) {
81 $field['type'] = CRM_Utils_Array::value('type', $field, CRM_Utils_Type::T_INT);
82 $field['dataPattern'] = CRM_Utils_Array::value('dataPattern', $field, '//');
83 $field['headerPattern'] = CRM_Utils_Array::value('headerPattern', $field, '//');
84 $this->addField($name, $field['title'], $field['type'], $field['headerPattern'], $field['dataPattern']);
85 }
86
87 $this->_newActivity = array();
88
89 $this->setActiveFields($this->_mapperKeys);
90
91 // FIXME: we should do this in one place together with Form/MapField.php
92 $this->_contactIdIndex = -1;
93 $this->_activityTypeIndex = -1;
94 $this->_activityLabelIndex = -1;
95 $this->_activityDateIndex = -1;
96
97 $index = 0;
98 foreach ($this->_mapperKeys as $key) {
99 switch ($key) {
100 case 'target_contact_id':
101 case 'external_identifier':
102 $this->_contactIdIndex = $index;
103 break;
104
105 case 'activity_label':
106 $this->_activityLabelIndex = $index;
107 break;
108
109 case 'activity_type_id':
110 $this->_activityTypeIndex = $index;
111 break;
112
113 case 'activity_date_time':
114 $this->_activityDateIndex = $index;
115 break;
116 }
117 $index++;
118 }
119 }
120
121 /**
122 * handle the values in mapField mode
123 *
124 * @param array $values the array of values belonging to this line
125 *
126 * @return boolean
127 * @access public
128 */
129 function mapField(&$values) {
130 return CRM_Activity_Import_Parser::VALID;
131 }
132
133 /**
134 * handle the values in preview mode
135 *
136 * @param array $values the array of values belonging to this line
137 *
138 * @return boolean the result of this processing
139 * @access public
140 */
141 function preview(&$values) {
142 return $this->summary($values);
143 }
144
145 /**
146 * handle the values in summary mode
147 *
148 * @param array $values the array of values belonging to this line
149 *
150 * @return boolean the result of this processing
151 * @access public
152 */
153 function summary(&$values) {
154 $erroneousField = NULL;
155 $response = $this->setActiveFieldValues($values, $erroneousField);
156 $index = -1;
157 $errorRequired = FALSE;
158
159 if ($this->_activityTypeIndex > -1 && $this->_activityLabelIndex > -1) {
160 array_unshift($values, ts('Please select either Activity Type ID OR Activity Type Label.'));
161 return CRM_Activity_Import_Parser::ERROR;
162 }
163 elseif ($this->_activityLabelIndex > -1) {
164 $index = $this->_activityLabelIndex;
165 }
166 elseif ($this->_activityTypeIndex > -1) {
167 $index = $this->_activityTypeIndex;
168 }
169
170 if ($index < 0 or $this->_activityDateIndex < 0) {
171 $errorRequired = TRUE;
172 }
173 else {
174 $errorRequired = !CRM_Utils_Array::value($index, $values) || !CRM_Utils_Array::value($this->_activityDateIndex, $values);
175 }
176
177 if ($errorRequired) {
178 array_unshift($values, ts('Missing required fields'));
179 return CRM_Activity_Import_Parser::ERROR;
180 }
181
182 $params = &$this->getActiveFieldParams();
183
184 $errorMessage = NULL;
185
186 //for date-Formats
187 $session = CRM_Core_Session::singleton();
188 $dateType = $session->get('dateTypes');
189 if (!isset($params['source_contact_id'])) {
190 $params['source_contact_id'] = $session->get('userID');
191 }
192 foreach ($params as $key => $val) {
193 if ($key == 'activity_date_time') {
194 if ($val) {
195 $dateValue = CRM_Utils_Date::formatDate($val, $dateType);
196 if ($dateValue) {
197 $params[$key] = $dateValue;
198 }
199 else {
200 CRM_Import_Parser_Contact::addToErrorMsg('Activity date', $errorMessage);
201 }
202 }
203 }
204 elseif ($key == 'activity_engagement_level' && $val &&
205 !CRM_Utils_Rule::positiveInteger($val)
206 ) {
207 CRM_Import_Parser_Contact::addToErrorMsg('Activity Engagement Index', $errorMessage);
208 }
209 }
210 //date-Format part ends
211
212 //checking error in custom data
213 $params['contact_type'] = isset($this->_contactType) ? $this->_contactType : 'Activity';
214
215 CRM_Import_Parser_Contact::isErrorInCustomData($params, $errorMessage);
216
217 if ($errorMessage) {
218 $tempMsg = "Invalid value for field(s) : $errorMessage";
219 array_unshift($values, $tempMsg);
220 $errorMessage = NULL;
221 return CRM_Import_Parser::ERROR;
222 }
223
224 return CRM_Activity_Import_Parser::VALID;
225 }
226
227 /**
228 * handle the values in import mode
229 *
230 * @param int $onDuplicate the code for what action to take on duplicates
231 * @param array $values the array of values belonging to this line
232 *
233 * @return boolean the result of this processing
234 * @access public
235 */
236 function import($onDuplicate, &$values) {
237 // first make sure this is a valid line
238 $response = $this->summary($values);
239
240 if ($response != CRM_Activity_Import_Parser::VALID) {
241 return $response;
242 }
243 $params = &$this->getActiveFieldParams();
244 $activityLabel = array_search('activity_label', $this->_mapperKeys);
245 if ($activityLabel) {
246 $params = array_merge($params, array('activity_label' => $values[$activityLabel]));
247 }
248 //for date-Formats
249 $session = CRM_Core_Session::singleton();
250 $dateType = $session->get('dateTypes');
251 if (!isset($params['source_contact_id'])) {
252 $params['source_contact_id'] = $session->get('userID');
253 }
254 $formatted = array();
255 $customFields = CRM_Core_BAO_CustomField::getFields(CRM_Utils_Array::value('contact_type', $params));
256
257 foreach ($params as $key => $val) {
258 if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) {
259 if ($key == 'activity_date_time' && $val) {
260 $params[$key] = CRM_Utils_Date::formatDate($val, $dateType);
261 }
262 elseif ($customFields[$customFieldID]['data_type'] == 'Date') {
263 CRM_Import_Parser_Contact::formatCustomDate($params, $params, $dateType, $key);
264 }
265 elseif ($customFields[$customFieldID]['data_type'] == 'Boolean') {
266 $params[$key] = CRM_Utils_String::strtoboolstr($val);
267 }
268 }
269 elseif ($key == 'activity_subject') {
270 $params['subject'] = $val;
271 }
272 }
273 //date-Format part ends
274 require_once 'CRM/Utils/DeprecatedUtils.php';
275 $formatError = _civicrm_api3_deprecated_activity_formatted_param($params, $params, TRUE);
276
277 if ($formatError) {
278 array_unshift($values, $formatError['error_message']);
279 return CRM_Activity_Import_Parser::ERROR;
280 }
281
282 $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params,
283 CRM_Core_DAO::$_nullObject,
284 NULL,
285 'Activity'
286 );
287
288 if ($this->_contactIdIndex < 0) {
289
290 //retrieve contact id using contact dedupe rule.
291 //since we are support only individual's activity import.
292 $params['contact_type'] = 'Individual';
293 $params['version'] = 3;
294 $error = _civicrm_api3_deprecated_duplicate_formatted_contact($params);
295
296 if (CRM_Core_Error::isAPIError($error, CRM_Core_ERROR::DUPLICATE_CONTACT)) {
297 $matchedIDs = explode(',', $error['error_message']['params'][0]);
298 if (count($matchedIDs) > 1) {
299 array_unshift($values, 'Multiple matching contact records detected for this row. The activity was not imported');
300 return CRM_Activity_Import_Parser::ERROR;
301 }
302 else {
303 $cid = $matchedIDs[0];
304 $params['target_contact_id'] = $cid;
305 $params['version'] = 3;
306 $newActivity = civicrm_api('activity', 'create', $params);
307 if (CRM_Utils_Array::value('is_error', $newActivity)) {
308 array_unshift($values, $newActivity['error_message']);
309 return CRM_Activity_Import_Parser::ERROR;
310 }
311
312 $this->_newActivity[] = $newActivity['id'];
313 return CRM_Activity_Import_Parser::VALID;
314 }
315 }
316 else {
317 // Using new Dedupe rule.
318 $ruleParams = array(
319 'contact_type' => 'Individual',
320 'used' => 'Unsupervised',
321 );
322 $fieldsArray = CRM_Dedupe_BAO_Rule::dedupeRuleFields($ruleParams);
323
324 $disp = NULL;
325 foreach ($fieldsArray as $value) {
326 if (array_key_exists(trim($value), $params)) {
327 $paramValue = $params[trim($value)];
328 if (is_array($paramValue)) {
329 $disp .= $params[trim($value)][0][trim($value)] . " ";
330 }
331 else {
332 $disp .= $params[trim($value)] . " ";
333 }
334 }
335 }
336
337 if (CRM_Utils_Array::value('external_identifier', $params)) {
338 if ($disp) {
339 $disp .= "AND {$params['external_identifier']}";
340 }
341 else {
342 $disp = $params['external_identifier'];
343 }
344 }
345
346 array_unshift($values, 'No matching Contact found for (' . $disp . ')');
347 return CRM_Activity_Import_Parser::ERROR;
348 }
349 }
350 else {
351 if (CRM_Utils_Array::value('external_identifier', $params)) {
352 $targetContactId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact',
353 $params['external_identifier'], 'id', 'external_identifier'
354 );
355
356 if (CRM_Utils_Array::value('target_contact_id', $params) &&
357 $params['target_contact_id'] != $targetContactId
358 ) {
359 array_unshift($values, 'Mismatch of External identifier :' . $params['external_identifier'] . ' and Contact Id:' . $params['target_contact_id']);
360 return CRM_Activity_Import_Parser::ERROR;
361 }
362 elseif ($targetContactId) {
363 $params['target_contact_id'] = $targetContactId;
364 }
365 else {
366 array_unshift($values, 'No Matching Contact for External identifier :' . $params['external_identifier']);
367 return CRM_Activity_Import_Parser::ERROR;
368 }
369 }
370
371 $params['version'] = 3;
372 $newActivity = civicrm_api('activity', 'create', $params);
373 if (CRM_Utils_Array::value('is_error', $newActivity)) {
374 array_unshift($values, $newActivity['error_message']);
375 return CRM_Activity_Import_Parser::ERROR;
376 }
377
378 $this->_newActivity[] = $newActivity['id'];
379 return CRM_Activity_Import_Parser::VALID;
380 }
381 }
382
383 /**
384 * the initializer code, called before the processing
385 *
386 * @return void
387 * @access public
388 */
389 function fini() {}
390
391 }
392